💾 Archived View for runjimmyrunrunyoufuckerrun.com › src › games › fillomino.c captured on 2021-12-17 at 13:26:06.

View Raw

More Information

-=-=-=-=-=-=-

#include <u.h>
#include <libc.h>
#include <draw.h>
#include <keyboard.h>
#include <event.h>
char *data = "/sys/games/lib/fillomino";
char *fontpath = "/lib/font/bit/pelm/ascii.16.font";
ulong rgb[] = {DRed, DGreen, DBlue, DYellow, DCyan, DMagenta};
Image *hue[nelem(rgb)], *bad;
enum{MAXDAT = 1024, CLUE = 0x40, FLOOD = 0x20, SQ = 32};
char sol[MAXDAT * 2], *puz, *vis;
int x, y, cur;
void
flood(int i, int n){
	vis[i] |= FLOOD;
	if(i >= x && (vis[i - x] & ~CLUE) == n) flood(i - x, n);
	if((i + 1) % x && (vis[i + 1] & ~CLUE) == n) flood(i + 1, n);
	if(i + x < x * y && (vis[i + x] & ~CLUE) == n) flood(i + x, n);
	if(i % x && (vis[i - 1] & ~CLUE) == n) flood(i - 1, n);
}
void
redraw(void){
	Rectangle r;
	char s[2];
	int i, j, n, c;
	s[1] = '\0';
	for(i = 0; i < x * y; i++){
		r.min = Pt(screen->r.min.x + i % x * SQ, screen->r.min.y + i / x * SQ);
		r.max = addpt(r.min, Pt(SQ, SQ));
		if(vis[i] == 0){
			draw(screen, r, display->white, nil, ZP);
			continue;
		}
		n = vis[i] & ~CLUE;
		s[0] = n <= 9 ? n + '0' : n - 10 + 'A';
		flood(i, n);
		for(j = c = 0; j < x * y; j++)
			if(vis[j] & FLOOD){
				vis[j] ^= FLOOD;
				c++;
			}
		draw(screen, r, c == n ? hue[n % nelem(hue)]
			: vis[i] & CLUE ? display->white : bad, nil, ZP);
		r.min.x += SQ - stringwidth(font, s) >> 1;
		r.min.y += SQ - font->height >> 1;
		string(screen, r.min, vis[i] & CLUE ? display->black : display->white, ZP, font, s);
	}
	r.min = Pt(screen->r.min.x + cur % x * SQ, screen->r.min.y + cur / x * SQ);
	r.max = addpt(r.min, Pt(SQ, SQ));
	border(screen, r, 4, display->black, ZP);
}
void
eresized(int i){
	if(i && getwindow(display, Refnone) < 0) sysfatal("can't reattach to window");
	if((!i || Dx(screen->r) != x * SQ || Dy(screen->r) != y * SQ)
	&& (i = open("/dev/wctl", OWRITE)) >= 0){
		fprint(i, "resize -dx %d -dy %d",
			x * SQ + 2 * Borderwidth, y * SQ + 2 * Borderwidth);
		close(i);
	}
	redraw();
}
void
main(int, char **argv){
	vlong n;
	int fd;
	if(initdraw(nil, nil, *argv) < 0) sysfatal("initdraw: %r");
	if((font = openfont(display, fontpath)) == nil) sysfatal("openfont: %r");
	for(n = 0; n < nelem(hue); n++)
		if((hue[n] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, rgb[n])) == nil)
			sysfatal("allocimage: %r");
	if((bad = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x777777FF)) == nil)
		sysfatal("allocimage: %r");
	einit(Ekeyboard | Emouse);
	srand(truerand());
	if((fd = open(data, OREAD)) < 0) sysfatal("open: %r");
	n = nrand(seek(fd, -MAXDAT, 2));	/* there's a big one at the end */
	seek(fd, n, 0);		/* so everyone gets a chance */
	read(fd, sol, MAXDAT * 2 - 1);
	close(fd);
	for(vis = sol; *vis; vis++)
		if(vis[0] == '\n' && vis[1] == '\n'){
			vis += 2;
			break;
		}
	for(puz = sol; ; vis++){
		if(*vis == '\n'){
			y++;
			if(vis[1] == '\n') break;
			if(!x) x = puz - sol;
		}
		else if(*vis >= 'A' && *vis <= 'Z') *puz++ = *vis - 'A' | CLUE;
		else if(*vis >= 'a' && *vis <= 'z') *puz++ = *vis - 'a';
		else sysfatal("bad game data: %s:#%lld", data, n);
	}
	if(puz - sol != x * y)
		sysfatal("bad dimensions: %d x %d != %lld: %s:#%lld", x, y, puz - sol, data, n);
	for(n = 0, vis = puz; n < puz - sol; n++)
		*vis++ = sol[n] & CLUE ? sol[n] : 0;
	vis = puz;
	eresized(0);
	for(;;){
		switch(n = ekbd()){
		case Kdel: exits(nil);
		case Kesc: vis = vis == puz ? sol : puz; break;
		case Kup: if((cur -= x) < 0) cur += x * y; break;
		case Kright: if(++cur % x == 0) cur -= x; break;
		case Kdown: cur = (cur + x) % (x * y); break;
		case Kleft: if(cur-- % x == 0) cur += x; break;
		case Kbs: case ' ':
			if(vis == sol || puz[cur] & CLUE) continue;
			puz[cur] = 0;
			break;
		default:
			if(vis == sol || puz[cur] & CLUE) continue;
			if(n >= '1' && n <= '9') puz[cur] = n - '0';
			else if(n >= 'a' && n <= 'p') puz[cur] = n - 'a' + 10;
			else continue;
			break;
		}
		redraw();
	}
}