Sigrid Haflínudóttiradd -b to run in black and white mode3e6431b6 years agoHistory
330 lines · 5.5 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <draw.h>#include <event.h> enum{	/* sid */	Ssmall,	Snormal,	Slarge,	Scustom, 	/* state */	Tgame,	Twin,	Tfail, 	/* cell flags & masks */	Flood = 1<<7,	Redraw = 1<<6,	ColorMask = 0x0f, 	NumColors = 6,	ButtonSize = 32}; static int sizes[] = {	14, 21, 28, 1}; static int turns[] = {	25, 35, 50, 1}; static const ulong srccolors[NumColors][2] = {	{0x6060a8ff, 0x000000ff},	{0xf6f61dff, 0x303030ff},	{0x46b0e0ff, 0x606060ff},	{0x7ea020ff, 0x909090ff},	{0xf070a0ff, 0xc0c0c0ff},	{0xdc4a20ff, 0xf0f0f0ff},}; static char *mstr[] = {	"14x14 / 25",	"25x25 / 35",	"28x28 / 50",	"exit",	nil, /* the extra for "custom" */	nil}; static int size;static int sid;static int state;static int clickwait;static int turnsleft;static uchar *cells;static Image *colors[NumColors];static Rectangle buttons[NumColors];static Image *colora, *colorb; static voidfloodneighbours(uchar color, int x, int y); static voidredraw(Image *screen, int full){	static Point p, sp, strsize;	int i, x, y, w, h, csize, left;	uchar *c;	Rectangle r;	char s[64];	Font *f; 	sp.x = sp.y = 0; 	/* clear the old caption */	draw(screen, Rect(p.x, p.y, p.x+strsize.x, p.y+strsize.y), colora, nil, ZP); 	if(state == Tgame)		sprint(s, "%d", turnsleft);	else if(state == Twin)		sprint(s, "You won using %d turns (of %d)", turns[sid]-turnsleft, turns[sid]);	else if(state == Tfail)		sprint(s, "You failed"); 	f = display->defaultfont;	strsize = stringsize(f, s); 	w = Dx(screen->r);	h = Dy(screen->r) - ButtonSize - 4 - strsize.y;	csize = (w < h ? w : h) / size;	w = size*csize;	left = screen->r.min.x + (Dx(screen->r) - w)/2; 	/* buttons top */	y = screen->r.min.y + h + 2 + strsize.y; 	if(full){		/* background */		draw(screen, screen->r, colora, nil, ZP); 		/* buttons */		x = left + (w - NumColors*ButtonSize)/2;		for(i = 0; i < NumColors; i++, x += ButtonSize){			buttons[i] = Rect(x, y, x+ButtonSize, y+ButtonSize);			draw(screen, buttons[i], colors[i], nil, ZP);		}	} 	/* caption */	p.x = left + w/2 - strsize.x/2;	p.y = y - strsize.y;	string(screen, p, colorb, sp, f, s); 	/* cells */	c = cells;	for(x = 0; x < size; x++){		for(y = 0; y < size; y++, c++){			if((*c & Redraw) != 0 || full){				*c &= ~Redraw;				r.min.x = left + x*csize;				r.min.y = screen->r.min.y + 2 + y*csize;				r.max.x = r.min.x + csize;				r.max.y = r.min.y + csize;				draw(screen, r, colors[*c & ColorMask], nil, ZP);			}		}	} 	flushimage(display, 1);} static voidfloodrecurse(uchar color, int x, int y){	uchar *c;	c = &cells[x + y*size];	if((*c & Flood) == 0 && (*c & ColorMask) == color){		floodneighbours(color, x, y);	}} static voidfloodneighbours(uchar color, int x, int y){	cells[x + y*size] = color|Flood|Redraw; 	if(x > 0)		floodrecurse(color, x-1, y);	if(x < size-1)		floodrecurse(color, x+1, y);	if(y > 0)		floodrecurse(color, x, y-1);	if(y < size-1)		floodrecurse(color, x, y+1);} static intreflood(uchar color){	int n, x, y; 	color &= ColorMask; 	n = 0;	for(x = 0; x < size; x++){		for(y = 0; y < size; y++){			if(cells[x + y*size] & Flood){				floodneighbours(color, x, y);				n++;			}		}	}	return n;} static voidflood(uchar color){	int n; 	if((cells[0] & Flood) != 0 && (cells[0] & ColorMask) == color)		return; 	if(!turnsleft)		return; 	turnsleft--;	n = reflood(color); 	if(n == size*size){		state = Twin;		clickwait = 1;	}else if(!turnsleft){		state = Tfail;		clickwait = 1;	} 	redraw(screen, 0);} static voidnewgame(int sid){	uchar *c;	int i, maxsize; 	state = Tgame;	size = sizes[sid];	turnsleft = turns[sid];	clickwait = 0; 	if(cells == nil){		maxsize = (size > sizes[Slarge]) ? size : sizes[Slarge];		cells = malloc(maxsize*maxsize);	} 	/* randomize */	c = cells;	for(i = 0; i < size*size; i++){		*c++ = nrand(NumColors);	} 	cells[0] |= Flood|Redraw;	reflood(cells[0]);	redraw(screen, 1);} voideresized(int new){	if(new && getwindow(display, Refnone) < 0)		sysfatal("can't reattach to window: %r");	redraw(screen, 1);} static voidusage(void){	fprint(2, "usage: cflood [-b] [-s size] [-t turns]\n");	exits("usage");} voidmain(int argc, char** argv){	int key, p, i, oldbuttons, sidmax, bw;	Event e;	Mouse m;	Menu menu;	Rectangle r; 	sid = Ssmall;	bw = 0;	ARGBEGIN{	case 's':		sid = Scustom;		sizes[sid] = atoi(ARGF());		if(sizes[sid] < 1)			usage();		break;	case 't':		sid = Scustom;		turns[sid] = atoi(ARGF());		if(turns[sid] < 1)			usage();		break;	case 'b':		bw = 1;		break;	default:		usage();	}ARGEND 	if(initdraw(nil, nil, "cflood") < 0)		sysfatal("initdraw failed"); 	r = Rect(0, 0, 1, 1);	for(i = 0; i < NumColors; i++)		colors[i] = allocimage(display, r, RGB24, 1, srccolors[i][bw]); 	colora = display->white;	colorb = display->black; 	einit(Emouse);	menu.item = mstr;	menu.lasthit = 0;	srand(time(0)); 	sidmax = (sid > Slarge) ? sid : Slarge;	if(sid == Scustom){		/* move "exit" and add "custom" size/turns */		sidmax = sid;		mstr[Scustom+1] = mstr[Scustom];		mstr[Scustom] = smprint("%dx%d / %d", sizes[sid], sizes[sid], turns[sid]);	} 	newgame(sid); 	for(oldbuttons = 0;;){		key = event(&e);		m = e.mouse; 		if(key != Emouse)			continue; 		if(m.buttons & 4){			p = emenuhit(3, &m, &menu);			if(p >= Ssmall && p <= sidmax)				newgame(sid = p);			else if(p > 0)				break;		}else if(clickwait && !oldbuttons && m.buttons){			newgame(sid);		}else if(m.buttons & 1){			for(i = 0; i < NumColors; i++){				if(ptinrect(m.xy, buttons[i])){					flood(i);					break;				}			}		} 		oldbuttons = m.buttons;	} 	exits(nil);}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t