📄 sudoku.c
字号:
/* 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,};intreadlevels(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;}voidconvert(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;}voidclearboard(Cell *board){ int i; for(i = 0; i < Psize; i++) { board[i].digit = -1; board[i].solve = 0; board[i].locked = 0; }}voidsolveboard(Cell *board){ int i; for(i = 0; i < Psize; i++) { board[i].digit = board[i].solve; }}intcheckpossible(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;}voidresize(void){ int fd; fd = open("/dev/wctl", OWRITE); if(fd >= 0){ fprint(fd, "resize -dx %d -dy %d", Maxx, Maxy); close(fd); }}voiddrawcell(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);}voiddrawboard(void){ int i; for(i = 0; i < Psize; i++) { drawcell(i / Brdsize, i % Brdsize, brd[i].digit, brd[i].locked ? fixed : display->black); }}voiddrawchecked(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); }}voiddrawscreen(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);}voiddrawbar(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);}voideresized(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();}voidmain(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; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -