123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422 |
- /* code from mark huckvale: http://www.phon.ucl.ac.uk/home/mark/sudoku/ */
- #include <u.h>
- #include <libc.h>
- #include <draw.h>
- #include <event.h>
- #include "sudoku.h"
- char *imgdir = "/sys/games/lib/sudoku/images";
- char *lvldir = "/sys/games/lib/sudoku/boards"; /* level library dir */
- int selected; /* which digit do we have selected? */
- Image *background; /* DPaleyellow */
- Image *backselect; /* DPalebluegreen */
- Image *blink; /* DDarkyellow */
- Image *brdr; /* 0x55555555 */
- Image *fixed; /* DBlue */
- Image *wrong; /* DRed */
- Image *dig[10]; /* digit masks */
- Dir *dir;
- int numlevels;
- int curlevel;
- char *buttons[] =
- {
- "new",
- "check",
- "solve",
- "clear",
- "save",
- "load",
- "print",
- "offline",
- "exit",
- 0
- };
- Menu menu =
- {
- buttons
- };
- Menu lmenu =
- {
- nil,
- genlevels,
- 0,
- };
- int
- readlevels(char *leveldir)
- {
- int fd, n;
- if((fd = open(leveldir, OREAD)) < 0)
- return -1;
- n = dirreadall(fd, &dir);
- close(fd);
- return n;
- }
- char *
- genlevels(int i)
- {
- if(numlevels == 0)
- numlevels = readlevels(lvldir);
-
- if(numlevels > 0 && i < numlevels)
- return (dir+i)->name;
- return nil;
- }
- void
- convert(Cell *brd, int *board)
- {
- int i;
-
- for(i = 0; i < Psize; i++) {
- brd[i].digit = board[i] & Digit;
- if(brd[i].digit < 0 || brd[i].digit > 9)
- brd[i].digit = -1;
- brd[i].solve = (board[i] & Solve) >> 4;
- brd[i].locked = board[i] & MLock;
- }
- memcpy(obrd, brd, Psize * sizeof(Cell));
- }
- 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;
- }
- Image *
- eloadfile(char *path)
- {
- Image *img;
- int fd;
- fd = open(path, OREAD);
- if(fd < 0) {
- fprint(2, "cannot open image file %s: %r\n", path);
- exits("image");
- }
- img = readimage(display, fd, 0);
- if(img == nil)
- sysfatal("cannot load image: %r");
- close(fd);
-
- return img;
- }
- void
- clearboard(Cell *board)
- {
- int i;
-
- for(i = 0; i < Psize; i++) {
- board[i].digit = -1;
- board[i].solve = 0;
- board[i].locked = 0;
- }
- }
- void
- solveboard(Cell *board)
- {
- int i;
- for(i = 0; i < Psize; i++) {
- board[i].digit = board[i].solve;
- }
- }
- int
- checkpossible(Cell *board, int x, int y, int num)
- {
- int i, j;
- for(i = 0; i < Brdsize; i++) {
- if(board[i*Brdsize + y].digit == num && i != x)
- return 0;
- if(board[x*Brdsize + i].digit == num && i != y)
- return 0;
- }
- for(i = x - (x%3); i < x - (x%3) + 3; i++)
- for(j = y - (y%3); j < y - (y%3) + 3; j++)
- if((i != x && j != y) && board[i*Brdsize + j].digit == num)
- return 0;
- return 1;
- }
- void
- resize(void)
- {
- int fd;
- fd = open("/dev/wctl", OWRITE);
- if(fd >= 0){
- fprint(fd, "resize -dx %d -dy %d", Maxx, Maxy);
- close(fd);
- }
- }
- void
- drawcell(int x, int y, int num, Image *col)
- {
- Rectangle r = Rect(x*Square, y*Square, (x+1)*Square, (y+1)*Square);
- if(num < 0 || num > 9)
- return;
- r = insetrect(r, Border);
- r = rectaddpt(r, Pt(0, Square));
- r.max = addpt(r.max, Pt(2, 2));
-
- draw(screen, rectaddpt(r, screen->r.min), col, dig[num], ZP);
- }
- void
- drawboard(void)
- {
- int i;
- for(i = 0; i < Psize; i++) {
- drawcell(i / Brdsize, i % Brdsize, brd[i].digit, brd[i].locked ? fixed : display->black);
- }
- }
- void
- drawchecked(Cell *brd)
- {
- int i;
- for(i = 0; i < Psize; i++) {
- if(brd[i].locked)
- drawcell(i / Brdsize, i % Brdsize, brd[i].digit, fixed);
- else
- drawcell(i / Brdsize, i % Brdsize, brd[i].digit,
- checkpossible(brd, i / Brdsize, i % Brdsize, brd[i].digit) ? display->black : wrong);
- }
- }
- void
- drawscreen(void)
- {
- Point l1, l2;
- int i;
- draw(screen, screen->r, brdr, nil, ZP);
- draw(screen, insetrect(screen->r, Border), background, nil, ZP);
- for(i = 0; i < Brdsize; i++) {
- l1 = addpt(screen->r.min, Pt(i*Square, Square));
- l2 = addpt(screen->r.min, Pt(i*Square, Maxy));
- line(screen, l1, l2, Endsquare, Endsquare, (i%3) == 0 ? Thickline : Line, brdr, ZP);
- l1 = addpt(screen->r.min, Pt(0, (i+1)*Square));
- l2 = addpt(screen->r.min, Pt(Maxx, (i+1)*Square));
- line(screen, l1, l2, Endsquare, Endsquare, (i%3) == 0 ? Thickline : Line, brdr, ZP);
- }
- for(i = 1; i < 10; i++) {
- drawbar(i, (selected == i) ? 1 : 0);
- }
- drawboard();
- flushimage(display, 1);
- }
- void
- drawbar(int digit, int selected)
- {
- Rectangle r = Rect((digit - 1)*Square, 0, digit*Square, Square);
- if(digit < 1 || digit > 9)
- return;
- r = insetrect(r, Border);
- r.max = addpt(r.max, Pt(2, 2));
- draw(screen, rectaddpt(r, screen->r.min), selected ? backselect : background, nil, ZP);
- draw(screen, rectaddpt(r, screen->r.min), display->black, dig[digit-1], ZP);
- }
- void
- eresized(int new)
- {
- Point p;
- char path[256];
- int i;
- if(new && getwindow(display, Refnone) < 0)
- sysfatal("can't reattach to window");
-
- if(background == nil)
- background = eallocimage(Rect(0, 0, 1, 1), 1, DPaleyellow);
- if(backselect == nil)
- backselect = eallocimage(Rect(0, 0, 1, 1), 1, DPalebluegreen);
- if(blink == nil)
- blink = eallocimage(Rect(0, 0, 1, 1), 1, DDarkyellow);
- if(brdr == nil)
- brdr = eallocimage(Rect(0, 0, 1, 1), 1, 0x55555555);
- if(fixed == nil)
- fixed = eallocimage(Rect(0, 0, 1, 1), 1, DBlue);
- if(wrong == nil)
- wrong = eallocimage(Rect(0, 0, 1, 1), 1, DRed);
- if(dig[0] == nil) {
- for(i = 0; i < 9; i++) {
- snprint(path, 256, "%s/%d.bit", imgdir, i+1);
- dig[i] = eloadfile(path);
- }
- }
- p = Pt(Dx(screen->r), Dy(screen->r));
- if(!new || !eqpt(p, Pt(Maxx - 8, Maxy - 8)))
- resize();
- drawscreen();
- }
- void
- main(int argc, char *argv[])
- {
- Mouse m;
- Event e;
- Point p;
- int last1 = 0; /* was the button clicked last time? */
- USED(argc, argv);
- if(initdraw(nil, nil, "sudoku") < 0)
- sysfatal("initdraw failed: %r");
- einit(Emouse|Ekeyboard);
- clearboard(brd);
- eresized(0);
- srand(time(0)*getpid());
- makep();
- convert(brd, board);
- drawscreen();
- for(;;) {
- switch(event(&e)) {
- case Emouse:
- m = e.mouse;
- if(m.buttons&1) {
- if(last1 == 0) {
- last1 = 1;
- p = subpt(m.xy, screen->r.min);
- if(ptinrect(p, Rect(0, 0, Maxx, Square+Border))) {
- if(p.x/Square == selected - 1) {
- drawbar(selected, 0);
- selected = 0;
- } else {
- selected = p.x/Square + 1;
- }
- } else {
- Point lp = divpt(p, Square);
- lp.y--;
- if(brd[lp.x * Brdsize + lp.y].locked)
- break;
- if(selected) {
- brd[lp.x * Brdsize + lp.y].digit = selected - 1;
- } else {
- brd[lp.x * Brdsize + lp.y].digit = -1;
- }
- }
- drawscreen();
- }
- } else {
- last1 = 0;
- }
- if(m.buttons&2) {
- char *str;
- int l;
- /* levels start from 1 */
- lmenu.lasthit = curlevel;
- l = emenuhit(2, &m, &lmenu);
- if(l >= 0){
- curlevel = l;
- str = smprint("%s/%s", lvldir, (dir+curlevel)->name);
- if(loadlevel(str, brd) < 0)
- clearboard(brd);
- memcpy(obrd, brd, Psize * sizeof(Cell));
- free(str);
- }
- drawscreen();
- }
- if(m.buttons&4) {
- switch(emenuhit(3, &m, &menu)) {
- case 0: /* new */
- makep();
- convert(brd, board);
- drawscreen();
- break;
- case 1: /* solve */
- drawchecked(brd);
- break;
- case 2: /* solve */
- solveboard(brd);
- drawscreen();
- break;
- case 3: /* clear */
- memcpy(brd, obrd, Psize * sizeof(Cell));
- drawscreen();
- break;
- case 4: /* save */
- savegame(brd);
- drawscreen();
- break;
- case 5: /* load */
- if(loadgame(brd) < 0) {
- clearboard(brd);
- }
- memcpy(obrd, brd, Psize * sizeof(Cell));
- drawscreen();
- break;
- case 6: /* print */
- printboard(brd);
- break;
- case 7: /* offline */
- fprettyprintbrd(brd);
- break;
- case 8: /* exit */
- exits(nil);
- }
- }
- break;
- case Ekeyboard:
- switch(e.kbdc) {
- case 127:
- case 'q':
- case 'Q':
- exits(nil);
- default:
- break;
- }
- break;
- }
- }
- }
|