shithub: asif

ref: 4c3d65037517a27151f9961ac359fcbdc62bbc1d
dir: /app/path/path.c/

View raw version
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <pool.h>
#include "asif.h"
#include "graph.h"
#include "path.h"
#include "dat.h"
#include "fns.h"

extern int	(*mousefn)(Mouse);
extern int	(*keyfn)(Rune);

mainstacksize = 512*1024;

Node *start, *goal;

static setgoalmode;

static int
grmouse(Mouse m)
{
	static Node *old;
	Node *n;

	if(m.buttons == 0){
		old = nil;
		return 0;
	}
	if((n = scrselect(m.xy)) == nil || old == n)
		return 0;
	switch(m.buttons & 7){
	case 1:
		if(old == nil || isblocked(n) ^ isblocked(old))
			toggleblocked(n);
		break;
	case 2:
		break;
	case 4:
		if(setgoalmode){
			if(start != n && !isblocked(n))
				goal = n;
		}else{
			if(goal != n && !isblocked(n))
				start = n;
		}
		break;
	}
	old = n;
	if(start != nil && goal != nil)
		if(pathfn(start, goal) < 0){
			dprint(Logdebug, "grid::findpath: findpath from [%#p,%P] to [%#p,%P]: %r\n",
				start, n2p(start), goal, n2p(goal));
		}
	return 1;
}

static int
setscen(void)
{
	int n;
	char buf[128];

	snprint(buf, sizeof buf, "%d", scenid);
	if(menter("Scenario id?", buf, sizeof buf) < 0){
		fprint(2, "getscen: %r\n");
		return -1;
	}
	if((n = strtol(buf, nil, 10)) < 0 || n > nscen){
		fprint(2, "getscen: invalid id %s\n", buf);
		return -1;
	}
	scenid = n;
	showscen(n);
	return 0;
}

static int
grkey(Rune r)
{
	switch(r){
	case Kdel:
	case 'q':
		threadexitsall(nil);
	case 'r':
		if(doprof){
			reloadscen();
			showscen(scenid);
		}else
			cleargrid();
		updatedrw(0);
		break;
	case ' ':
	case '\n':
		setgoalmode ^= 1;
		break;
	case 'g':
		showgrid ^= 1;
		updatedrw(0);
		break;
	case '0': case '1': case '2': case '3': case '4':
	case '5': case '6': case '7': case '8': case '9':
		if(!doprof)
			break;
		if(setscen() >= 0)
			updatedrw(0);
		break;
	case '+':
	case '=':
		if(nodesz < 1<<16){
			nodesz <<= 1;
			resetdrw();
		}
		break;
	case '-':
		if(nodesz > 1){
			nodesz >>= 1;
			resetdrw();
		}
		break;
	}
	return 0;
}

static void
usage(void)
{
	fprint(2, "usage: %s [-D4] [-a algo] [-d dist] [-s width[,height]] [-m scen]\n", argv0);
	threadexits("usage");
}

void
threadmain(int argc, char **argv)
{
	int w, h, a, d, m;
	char *s, *scenres, *scenmap;

	w = 64;
	h = 64;
	a = -1;
	d = -1;
	m = Move8;
	scenmap = nil;
	scenres = nil;
	ARGBEGIN{
	case 'D':
		if(++debuglevel >= Logparanoid)
			mainmem->flags |= POOL_NOREUSE | POOL_PARANOIA | POOL_LOGGING;
		break;
	case '4':
		m = Move4;
		d = Dmanhattan;
		break;
	case 'a':
		s = EARGF(usage());
		if(strcmp(s, "a∗") == 0)
			a = Pa∗;
		else if(strcmp(s, "dijkstra") == 0)
			a = Pdijkstra;
		else if(strcmp(s, "bfs") == 0)
			a = Pbfs;
		else{
			fprint(2, "unsupported algorithm\n");
			usage();
		}
		break;
	case 'd':
		s = EARGF(usage());
		if(strcmp(s, "octile") == 0)
			d = Doctile;
		else if(strcmp(s, "manhattan") == 0)
			d = Dmanhattan;
		else if(strcmp(s, "euclid") == 0)
			d = Deuclid;
		else{
			fprint(2, "unsupported distance function\n");
			usage();
		}
		break;
	case 'm':
		scenmap = EARGF(usage());
		break;
	case 'r':
		scenres = EARGF(usage());
		break;
	case 's':
		w = strtol(EARGF(usage()), &s, 0);
		if(w <= 0)
			usage();
		if(*s != ','){
			h = w;
			break;
		}
		h = strtol(s+1, nil, 0);
		if(h <= 0)
			usage();
		break;
	default: usage();
	}ARGEND
	if(w <= 0 || w > 512
	|| h <= 0 || h > 512)
		sysfatal("invalid map size, must be in ]0,512]");
	if(d < 0)
		d = m == Move8 ? Doctile : Dmanhattan;
	if(a < 0)
		a = Pa∗;
	keyfn = grkey;
	mousefn = grmouse;
	init(scenmap, scenres, (Vertex){w,h}, m, a, d);
	if(doprof && scenres == nil)
		runscens();
	evloop();
	threadexitsall(nil);
}