/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
* mazen-ng
* Copyright (C) Jacob Zimmermann 2009 <jacob@jzimm.net>
*
* mazen-ng is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* mazen-ng is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma implementation
#include "grid-maze.h"
#include "artwork.h"
#include "tree.h"
#include "normal-walker.h"
using namespace std;
ostream& operator << (ostream& stream, xy p) {
stream << '(' << p.x << ',' << p.y << ')';
return stream;
}
GridMaze::GridMaze (int width, int height): Glib::Object () {
this->_width = width;
this->_height = height;
this->grid = new unsigned[width * height];
for (int k = 0; k < width * height; k++)
grid[k] = 0;
exit_dir = NONE;
}
GridMaze::~GridMaze () {
delete grid;
}
void GridMaze::possible_directions (xy pos, vector<Direction>& dirs) const {
// test up
if (pos.y < height () - 1
&& !vert (pos)
&& !is_no_no (pos)
&& is_clear (pos.up ())
&& ((pos.x == 0) || !horiz (pos.x - 1, pos.y + 1)))
dirs.push_back (UP);
// test down
if (pos.y > 0
&& is_clear (pos.down())
&& (pos.y == 1 || !vert (pos.x, pos.y - 2))
&& (pos.x == 0 || !horiz (pos.x - 1, pos.y - 1)))
dirs.push_back (DOWN);
// test left
if (pos.x > 0
&& is_clear (pos.left ())
&& (pos.x == 1 || !horiz (pos.x - 2, pos.y))
&& (pos.y == 0 || !vert (pos.x - 1, pos.y - 1)))
dirs.push_back (LEFT);
// test right
if (pos.x < width () - 1
&& !horiz (pos)
&& !is_no_no (pos)
&& is_clear (pos.right ())
&& ((pos.y == 0) || !vert (pos.x + 1, pos.y - 1)))
dirs.push_back (RIGHT);
}
void GridMaze::move (xy& pos, Direction dir) {
switch(dir) {
case UP:
set_vert (pos.x, pos.y++);
break;
case DOWN:
set_vert (pos.x, --pos.y);
break;
case RIGHT:
set_horiz (pos.x++, pos.y);
break;
case LEFT:
set_horiz (--pos.x, pos.y);
break;
}
}
void GridMaze::generate () {
// init trees
list<Tree> trees;
list<xy>::const_iterator p;
for (p = tree_positions.begin (); p != tree_positions.end (); ++p) {
if (!is_no_no (*p))
trees.push_back (Tree (*this, *p));
}
// grow trees
bool still_moving;
list<Tree>::iterator tree, end = trees.end ();
do {
still_moving = false;
for (tree = trees.begin (); tree != end; ++tree)
still_moving |= tree->move ();
} while (still_moving);
// precalculate solution
solve ();
}
void GridMaze::run_walker (Walker& walker) {
walker.map (get_exit (), 0);
walker.gen_solution (solution);
}
void GridMaze::solve () {
NormalWalker walker (*this);
run_walker (walker);
}