Plan 9 from Bell Labs’s /usr/web/sources/patch/applied/sokoban-multistep/route.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include <draw.h>

#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--;
		}
	}
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.