#include <u.h>#include <libc.h>#include <draw.h>#include <event.h> /* colorflood: make all squares of the same * color within the number of clicks allowed */ enum{ /* difficulty levels (how many circles are initially occupied) */ DEasy = 14, DMed = 21, DHard = 28, /* board sizes for difficulty setting */ SzE = 14, SzM = 21, SzH = 28, Ncolors = 6, Gap = 2, /* empty space between squares */ Won = 1, /* game-ending states */ Lost = 2,}; Font *font;Image *brdr; int lvl = DEasy; /* difficulty level; array size for board */int finished; int moves;int selected = -1;int sx, sy, barsize; int *level;int *olevel; /* so we can restart levels */ Image *colors[Ncolors];int cc[Ncolors] = { DPalegreyblue, DYellow, DPalegreen, DGreen, DBluegreen, DRed,}; int maxmoves[]= { [DEasy] = 25, [DMed] = 35, [DHard] = 50,}; char *mbuttons[] = { "easy", "medium", "hard", 0}; char *rbuttons[] = { "new", "restart", "exit", 0}; Menu mmenu = { mbuttons,}; Menu rmenu ={ rbuttons,}; Image *eallocimage(Rectangle r, int repl, uint color){ Image *tmp; tmp = allocimage(display, r, screen->chan, repl, color); if(tmp == nil) sysfatal("cannot allocate buffer image: %r"); return tmp;} voidallocimages(void){ Rectangle one = Rect(0, 0, 1, 1); int i; for(i = 0; i < Ncolors; i++) colors[i] = eallocimage(one, 1, cc[i]); brdr = eallocimage(one, 1, 0x333333FF);} voidinitlevel(void){ int i; free(level); free(olevel); level = malloc(lvl*lvl*sizeof(int)); olevel = malloc(lvl*lvl*sizeof(int)); if(level == nil || olevel == nil) sysfatal("malloc"); for(i = 0; i < lvl*lvl; i++) olevel[i] = nrand(Ncolors); memcpy(level, olevel, lvl*lvl*sizeof(int)); moves = 0; selected=level[0];} voiddrawlevel(void){ Point p; char *s; int i; barsize = (Dy(screen->r)-lvl*Gap-barsize)/DEasy; sx = (Dx(screen->r)-lvl*Gap)/(lvl); sy = (Dy(screen->r)-lvl*Gap-barsize)/(lvl+1); draw(screen, screen->r, display->white, nil, ZP); for(i = 0; i < Ncolors; i++) { p = addpt(screen->r.min, Pt(i*(barsize/2+Gap)+5, 2)); draw(screen, Rpt(p, addpt(p, Pt(barsize/2, barsize/2))), colors[i], nil, ZP); if(selected == i) border(screen, Rpt(p, addpt(p, Pt(barsize/2, barsize/2))), -1, brdr, ZP); } p = Pt((Ncolors+1)*sx, 2); if(finished) s = smprint("%s", finished == Won ? "won!" : "fail!"); else s = smprint("%d/%d", moves, maxmoves[lvl]); string(screen, addpt(screen->r.min, p), display->black, ZP, font, s); free(s); for(i = 0; i < lvl*lvl; i++) { p = addpt(screen->r.min, Pt((i%lvl)*(sx+Gap)+5, (i/lvl)*(sy+Gap))); p = addpt(p, Pt(0, barsize)); /* move down */ draw(screen, Rpt(p, addpt(p, Pt(sx, sy))), colors[level[i]], nil, ZP); } flushimage(display, 1);} voiddomove(int x, int y, int nc){ int oc = level[x*lvl+y]; level[x*lvl+y] = nc; if(x > 0 && level[(x-1)*lvl+y] == oc) domove(x-1, y, nc); if(x+1 < lvl && level[(x+1)*lvl+y] == oc) domove(x+1, y, nc); if(y > 0 && level[x*lvl + y - 1] == oc) domove(x, y-1, nc); if(y+1 < lvl && level[x*lvl+y+1] == oc) domove(x, y+1, nc); } intcheckfinished(void){ int i; for(i = 1; i < lvl*lvl; i++) if(level[i] != level[i-1]) goto done; return Won;done: if(moves >= maxmoves[lvl]) return Lost; return 0;} voidmove(Point m){ Point p = subpt(m, screen->r.min); int ns; if(p.y < barsize/2+2 && p.x < Ncolors*barsize/2+Ncolors*Gap+5) { ns = (p.x-5)/(barsize/2+Gap); if(ns != selected) { selected = ns; domove(0, 0, selected); moves++; drawlevel(); } } else if(ptinrect(p, Rect(5, barsize/2+2, 5+sx*lvl, barsize/2+2+sy*lvl))) { p=subpt(m,screen->r.min); p=subpt(p, Pt(5+Gap, barsize+Gap)); ns=level[(p.x/(sx+Gap))+((p.y/(sy+Gap)))*lvl]; if(ns != selected) { selected = ns; domove(0, 0, selected); moves++; drawlevel(); } }} voideresized(int new){ if(new && getwindow(display, Refnone) < 0) sysfatal("can't reattach to window"); drawlevel();} void main(int argc, char **argv){ Mouse m; Event ev; int e, mousedown=0; char *fontname; USED(argv, argc); if(initdraw(nil, nil, "glendy") < 0) sysfatal("initdraw failed: %r"); einit(Emouse); srand(time(0)); allocimages(); initlevel(); /* must happen before "eresized" */ eresized(0); fontname = "/lib/font/bit/lucidasans/unicode.8.font"; if((font = openfont(display, fontname)) == nil) sysfatal("font '%s' not found", fontname); for(;;) { e = event(&ev); switch(e) { case Emouse: m = ev.mouse; if(m.buttons == 0) { if(mousedown && !finished) { mousedown = 0; move(m.xy); finished = checkfinished(); drawlevel(); } } if(m.buttons&1) { mousedown = 1; } if(m.buttons&2) { switch(emenuhit(2, &m, &mmenu)) { case 0: lvl = DEasy; initlevel(); break; case 1: lvl = DMed; initlevel(); break; case 2: lvl = DHard; initlevel(); break; } drawlevel(); } if(m.buttons&4) { switch(emenuhit(3, &m, &rmenu)) { case 0: initlevel(); break; case 1: memcpy(level, olevel, lvl*lvl*sizeof(int)); finished = 0; moves = 0; break; case 2: exits(nil); } drawlevel(); } break; } }}
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
/* colorflood: make all squares of the same
* color within the number of clicks allowed
*/
enum{
/* difficulty levels (how many circles are initially occupied) */
DEasy = 14,
DMed = 21,
DHard = 28,
/* board sizes for difficulty setting */
SzE = 14,
SzM = 21,
SzH = 28,
Ncolors = 6,
Gap = 2, /* empty space between squares */
Won = 1, /* game-ending states */
Lost = 2,
};
Font *font;
Image *brdr;
int lvl = DEasy; /* difficulty level; array size for board */
int finished;
int moves;
int selected = -1;
int sx, sy, barsize;
int *level;
int *olevel; /* so we can restart levels */
Image *colors[Ncolors];
int cc[Ncolors] = {
DPalegreyblue,
DYellow,
DPalegreen,
DGreen,
DBluegreen,
DRed,
};
int maxmoves[]= {
[DEasy] = 25,
[DMed] = 35,
[DHard] = 50,
};
char *mbuttons[] =
{
"easy",
"medium",
"hard",
0
};
char *rbuttons[] =
{
"new",
"restart",
"exit",
0
};
Menu mmenu =
{
mbuttons,
};
Menu rmenu =
{
rbuttons,
};
Image *
eallocimage(Rectangle r, int repl, uint color)
{
Image *tmp;
tmp = allocimage(display, r, screen->chan, repl, color);
if(tmp == nil)
sysfatal("cannot allocate buffer image: %r");
return tmp;
}
void
allocimages(void)
{
Rectangle one = Rect(0, 0, 1, 1);
int i;
for(i = 0; i < Ncolors; i++)
colors[i] = eallocimage(one, 1, cc[i]);
brdr = eallocimage(one, 1, 0x333333FF);
}
void
initlevel(void)
{
int i;
free(level);
free(olevel);
level = malloc(lvl*lvl*sizeof(int));
olevel = malloc(lvl*lvl*sizeof(int));
if(level == nil || olevel == nil)
sysfatal("malloc");
for(i = 0; i < lvl*lvl; i++)
olevel[i] = nrand(Ncolors);
memcpy(level, olevel, lvl*lvl*sizeof(int));
moves = 0;
selected=level[0];
}
void
drawlevel(void)
{
Point p;
char *s;
int i;
barsize = (Dy(screen->r)-lvl*Gap-barsize)/DEasy;
sx = (Dx(screen->r)-lvl*Gap)/(lvl);
sy = (Dy(screen->r)-lvl*Gap-barsize)/(lvl+1);
draw(screen, screen->r, display->white, nil, ZP);
for(i = 0; i < Ncolors; i++) {
p = addpt(screen->r.min, Pt(i*(barsize/2+Gap)+5, 2));
draw(screen, Rpt(p, addpt(p, Pt(barsize/2, barsize/2))), colors[i], nil, ZP);
if(selected == i)
border(screen, Rpt(p, addpt(p, Pt(barsize/2, barsize/2))), -1, brdr, ZP);
}
p = Pt((Ncolors+1)*sx, 2);
if(finished)
s = smprint("%s", finished == Won ? "won!" : "fail!");
else
s = smprint("%d/%d", moves, maxmoves[lvl]);
string(screen, addpt(screen->r.min, p), display->black, ZP, font, s);
free(s);
for(i = 0; i < lvl*lvl; i++) {
p = addpt(screen->r.min, Pt((i%lvl)*(sx+Gap)+5, (i/lvl)*(sy+Gap)));
p = addpt(p, Pt(0, barsize)); /* move down */
draw(screen, Rpt(p, addpt(p, Pt(sx, sy))), colors[level[i]], nil, ZP);
}
flushimage(display, 1);
}
void
domove(int x, int y, int nc)
{
int oc = level[x*lvl+y];
level[x*lvl+y] = nc;
if(x > 0 && level[(x-1)*lvl+y] == oc)
domove(x-1, y, nc);
if(x+1 < lvl && level[(x+1)*lvl+y] == oc)
domove(x+1, y, nc);
if(y > 0 && level[x*lvl + y - 1] == oc)
domove(x, y-1, nc);
if(y+1 < lvl && level[x*lvl+y+1] == oc)
domove(x, y+1, nc);
}
int
checkfinished(void)
{
int i;
for(i = 1; i < lvl*lvl; i++)
if(level[i] != level[i-1])
goto done;
return Won;
done:
if(moves >= maxmoves[lvl])
return Lost;
return 0;
}
void
move(Point m)
{
Point p = subpt(m, screen->r.min);
int ns;
if(p.y < barsize/2+2 && p.x < Ncolors*barsize/2+Ncolors*Gap+5) {
ns = (p.x-5)/(barsize/2+Gap);
if(ns != selected) {
selected = ns;
domove(0, 0, selected);
moves++;
drawlevel();
}
}
else if(ptinrect(p, Rect(5, barsize/2+2, 5+sx*lvl, barsize/2+2+sy*lvl))) {
p=subpt(m,screen->r.min);
p=subpt(p, Pt(5+Gap, barsize+Gap));
ns=level[(p.x/(sx+Gap))+((p.y/(sy+Gap)))*lvl];
if(ns != selected) {
selected = ns;
domove(0, 0, selected);
moves++;
drawlevel();
}
}
}
void
eresized(int new)
{
if(new && getwindow(display, Refnone) < 0)
sysfatal("can't reattach to window");
drawlevel();
}
void
main(int argc, char **argv)
{
Mouse m;
Event ev;
int e, mousedown=0;
char *fontname;
USED(argv, argc);
if(initdraw(nil, nil, "glendy") < 0)
sysfatal("initdraw failed: %r");
einit(Emouse);
srand(time(0));
allocimages();
initlevel(); /* must happen before "eresized" */
eresized(0);
fontname = "/lib/font/bit/lucidasans/unicode.8.font";
if((font = openfont(display, fontname)) == nil)
sysfatal("font '%s' not found", fontname);
for(;;) {
e = event(&ev);
switch(e) {
case Emouse:
m = ev.mouse;
if(m.buttons == 0) {
if(mousedown && !finished) {
mousedown = 0;
move(m.xy);
finished = checkfinished();
drawlevel();
}
}
if(m.buttons&1) {
mousedown = 1;
}
if(m.buttons&2) {
switch(emenuhit(2, &m, &mmenu)) {
case 0:
lvl = DEasy;
initlevel();
break;
case 1:
lvl = DMed;
initlevel();
break;
case 2:
lvl = DHard;
initlevel();
break;
}
drawlevel();
}
if(m.buttons&4) {
switch(emenuhit(3, &m, &rmenu)) {
case 0:
initlevel();
break;
case 1:
memcpy(level, olevel, lvl*lvl*sizeof(int));
finished = 0;
moves = 0;
break;
case 2:
exits(nil);
}
drawlevel();
}
break;
}
}
}