shithub: asif

ref: f09e8fb805ae93f613f29fb30fa5de5d1980d891
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	dopan(Point);
extern Point pan;

mainstacksize = 128*1024;

Node *start, *goal;
int mousemode;

static int
grmouse(Mouse m, Point Δ)
{
	static Node *old;
	int r;
	Node *n;

	if(m.buttons == 0){
		old = nil;
		return -1;
	}else if((m.buttons & 7) == 2)
		return dopan(Δ) >= 0 ? 0 : -1;
	if((n = scrselect(m.xy)) == nil || old == n)
		return 0;
	r = 0;
	switch(m.buttons & 7){
	case 1: break; /* just selecting the node */
	case 4:
		switch(mousemode){
		case Mmodegoal: if(n != start && !isblocked(n)){ goal = n; r=1; } break;
		case Mmodestart: if(n != goal && !isblocked(n)){ start = n; r=1; } break;
		case Mmodeblock:
			if(n != start && n != goal
			&& (old == nil || isblocked(n) ^ isblocked(old))){
				toggleblocked(n);
				r = 1;
			}
			break;
		}
	}
	old = n;
	if(r){
		trypath(start, goal);
		return 1;
	}
	return 0;
}

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

	snprint(buf, sizeof buf, "%d", curscen);
	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;
	}
	showscen(n);
	return 0;
}

static int
grkey(Rune r)
{
	switch(r){
	case Kdel:
	case 'q': threadexitsall(nil);
	case 'r': reloadscen(); return 1;
	case ' ':
	case '\n': mousemode = (mousemode + 1) % Mmodes; return 0;
	case 'g': showgrid ^= 1; return 0;
	case '0': case '1': case '2': case '3': case '4':
	case '5': case '6': case '7': case '8': case '9':
		return setscen() >= 0 ? 0 : -1;
	case '+':
	/* FIXME: no hud when screen too small */
	case '=': return nodesz < 1<<16 ? (nodesz <<= 1, 4) : -1;
	case '-': return nodesz > 1     ? (nodesz >>= 1, 4) : -1;
	case 'z': pan = ZP; return 2;
	}
	return 0;
}

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

void
threadmain(int argc, char **argv)
{
	int w, h, a, d, m;
	char *s, *map, *scen, *res;

	w = -1;
	h = -1;
	a = -1;
	d = -1;
	m = -1;
	doprof = 0;
	map = nil;
	scen = nil;
	res = 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, "euclidean") == 0)
			d = Deuclid;
		else if(strcmp(s, "chebyshev") == 0)
			d = Dchebyshev;
		else{
			fprint(2, "unsupported distance function\n");
			usage();
		}
		break;
	case 'm':
		map = EARGF(usage());
		break;
	case 'p':
		doprof = 1;
		break;
	case 'r':
		res = EARGF(usage());
		break;
	case 'S':
		scen = 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
	init(map, (Vertex){w,h}, m, a, d);
	if(scen != nil){
		if(map == nil)
			sysfatal("mat not run scenarios without a map");
		readscens(scen);
		if(doprof){
			runallscens();
			writeresults();
			threadexitsall(nil);
		}
		if(res != nil && readresults(res) < 0)
			dprint(Lognone, "path::readresults: %r\n");
	}
	initgraphics(grkey, grmouse);
	if(scen != nil){
		showscen(0);
		updatedrw(0, 1);
	}
	evloop();
	threadexitsall(nil);
}