#include #include #include #include "sokoban.h" static int trydir(int, Point, Point, Route*, Visited*); static int dofind(Point, Point, Route*, Visited*); static Point dir2point(int dir) { switch(dir) { case Up: return Pt(0, -1); case Down: return Pt(0, 1); case Left: return Pt(-1, 0); case Right: return Pt(1, 0); } return Pt(0,0); } Route* newroute(void) { Route *r = malloc(sizeof(Route)); memset(r, 0, sizeof(Route)); return r; } void freeroute(Route *r) { if (r->step != nil) { free(r->step); memset(r, 0, sizeof(Route)); } free(r); } void reverseroute(Route *r) { int i; Step tmp; for (i=1; i< r->nstep; i++) { tmp = r->step[i]; r->step[i] = r->step[i-1]; r->step[i-1] = tmp; } } void pushstep(Route *r, int dir, int count) { if (r->beyond < r->nstep+1) { r->beyond = r->nstep+1; r->step = realloc(r->step, sizeof(Step)*r->beyond); } if (r->step == nil) exits("pushstep out of memory"); r->step[r->nstep].dir = dir; r->step[r->nstep].count = count; r->nstep++; } void popstep(Route*r) { if (r->nstep > 0) { r->nstep--; r->step[r->nstep].dir = 0; r->step[r->nstep].count = 0; } } int validpush(Point g, Step s, Point *t) { int i; Point m = dir2point(s.dir); // first test for Cargo next to us (in direction dir) if (s.count > 0) { g = addpt(g, m); if (!ptinrect(g, Rpt(Pt(0,0), level.max))) return 0; switch (level.board[g.x ][g.y]) { case Wall: case Empty: case Goal: return 0; } } // then test for enough free space for us _and_ Cargo for (i=0; i < s.count; i++) { g = addpt(g, m); if (!ptinrect(g, Rpt(Pt(0,0), level.max))) return 0; switch (level.board[g.x ][g.y]) { case Wall: case Cargo: case GoalCargo: return 0; } } if (t != nil) *t = g; return 1; } int validwalk(Point g, Step s, Point *t) { int i; Point m = dir2point(s.dir); for (i=0; i < s.count; i++) { g = addpt(g, m); if (!ptinrect(g, Rpt(Pt(0,0), level.max))) return 0; switch (level.board[g.x ][g.y]) { case Wall: case Cargo: case GoalCargo: return 0; } } if (t != nil) *t = g; return 1; } int isvalid(Point s, Route* r, int (*isallowed)(Point, Step, Point*)) { int i; Point m = s; for (i=0; i< r->nstep; i++) if (! isallowed(m, r->step[i], &m)) return 0; return 1; } static int trydir(int dir, Point m, Point d, Route *r, Visited *v) { Point p = dir2point(dir); Point n = addpt(m, p); if (ptinrect(n, Rpt(Pt(0,0), level.max)) && v->board[n.x][n.y] == 0) { v->board[n.x][n.y] = 1; switch (level.board[n.x ][n.y]) { case Empty: case Goal: pushstep(r, dir, 1); if (dofind(n, d, r, v)) return 1; else popstep(r); } } return 0; } static int dofind(Point m, Point d, Route *r, Visited *v) { if (eqpt(m, d)) return 1; v->board[m.x][m.y] = 1; return trydir(Left, m, d, r, v) || trydir(Up, m, d, r, v) || trydir(Right, m, d, r, v) || trydir(Down, m, d, r, v); } static int dobfs(Point m, Point d, Route *r, Visited *v) { if (eqpt(m, d)) return 1; v->board[m.x][m.y] = 1; return trydir(Left, m, d, r, v) || trydir(Up, m, d, r, v) || trydir(Right, m, d, r, v) || trydir(Down, m, d, r, v); } int findwalk(Point src, Point dst, Route *r) { Visited* v; int found; v = malloc(sizeof(Visited)); memset(v, 0, sizeof(Visited)); found = dofind(src, dst, r, v); free(v); return found; } void applyroute(Route *r) { int j, i; for (i=0; i< r->nstep; i++) { j = r->step[i].count; while (j > 0) { move(r->step[i].dir); if (animate) { drawscreen(); sleep(200); } j--; } } }