#include #include #include #include #include #include Keyboardctl *kbctl; Mousectl *mctl; enum { RIGHT = 0, DOWN, LEFT, UP }; int grid[4][4]; int *grid1 = &grid[0][0]; int gameover; Image *bg, *bgover; int ntiles; Image **imgs; void drawwindow(void); int nempty(void) { int i, n; n = 0; for(i = 0; i < 4*4; i++) if(grid1[i] == 0) n++; return n; } void insert(int pos, int val) { int i, n; n = 0; for(i = 0; i < 4*4; i++) if(grid1[i] == 0){ if(n == pos){ grid1[i] = val; return; } n++; } } void insertrandom(void) { insert(rand() % nempty(), frand() < 0.9 ? 1 : 2); } void buildrow(int *row[4], int n, int dir) { int i; int start, add; add = start = 0; switch(dir){ case RIGHT: add = 1; start = n*4; break; case DOWN: add = 4; start = n; break; case LEFT: add = -1; start = n*4 + 3; break; case UP: add = -4; start = 3*4 + n; } for(i = 0; i < 4; i++) row[i] = &grid1[add*i + start]; } int merge(int *row[4]) { int nrow[4] = { 0 }; int i, j; int moved; j = 3; for(i = 3; i >= 0; i--){ if(*row[i] == 0) ; else if(nrow[j] == 0){ nrow[j] = *row[i]; }else if(nrow[j] == *row[i]){ nrow[j--]++; }else nrow[--j] = *row[i]; } moved = 0; for(i = 0; i < 4; i++){ if(nrow[i] != *row[i]) moved = 1; *row[i] = nrow[i]; } return moved; } int movesleft(void) { int i, j; for(i = 0; i < 4; i++) for(j = 0; j < 4; j++){ if(j > 0) if(grid[i][j] == grid[i][j-1]) return 1; if(i > 0) if(grid[j][i] == grid[j][i-1]) return 1; } return 0; } void move(int dir) { int i; int moved; int *row[4]; moved = 0; for(i = 0; i < 4; i++){ buildrow(row, i, dir); moved = merge(row) || moved; } if(moved) insertrandom(); if(nempty() == 0 && !movesleft()) gameover = 1; drawwindow(); } void init(void) { // srand(1); srand(time(0)); insertrandom(); insertrandom(); } void drawwindow(void) { int i, j; int n; Point p; char s[11]; if(gameover) draw(screen, screen->r, bgover, nil, ZP); else draw(screen, screen->r, bg, nil, ZP); for(i = 0; i < 4; i++) for(j = 0; j < 4; j++){ n = grid[i][j]; snprint(s, 11, "%d", (int)pow(2, n)); if(n >= ntiles) n = ntiles-1; p = addpt(screen->r.min, Pt(j*100+5, i*100+5)); draw(screen, rectaddpt(Rect(0, 0, 90, 90), p), imgs[n], nil, ZP); if(n != 0) string(screen, addpt(p, Pt(20, 20)), n < 3 ? display->black : display->white, ZP, font, s); } flushimage(display, 1); } void kbthread(void*) { Rune r; for(;;){ r = recvul(kbctl->c); switch(r){ case L'e': print("empty: %d\n", nempty()); break; case Kdown: if(!gameover) move(DOWN); break; case Kup: if(!gameover) move(UP); break; case Kleft: if(!gameover) move(LEFT); break; case Kright: if(!gameover) move(RIGHT); break; case L'q': case Kdel: threadexitsall(nil); } } } void mthread(void*) { Mouse m; for(;;){ recv(mctl->c, &m); } } void resthread(void*) { for(;;){ recvul(mctl->resizec); if(getwindow(display, Refnone) < 0) sysfatal("resize failed: %r"); drawwindow(); } } void resize(int x, int y) { int fd; fd = open("/dev/wctl", OWRITE); if(fd >= 0){ fprint(fd, "resize -dx %d -dy %d", x+8, y+8); close(fd); } } void threadmain(int argc, char *argv[]) { int i; int cols[] = { 0xcdc0b4ff, 0xeee4daff, 0xede0c8ff, 0xf2b179ff, 0xf59563ff, 0xf67c5fff, 0xf65e36ff, 0xedcf72ff, 0xedcc61ff, 0xedc850ff, 0xedc53fff, 0xedc22eff, 0x3c3a32ff }; // newwindow(nil); resize(4*100, 4*100); if(initdraw(nil, nil, "2049") < 0) sysfatal("initdraw: %r"); kbctl = initkeyboard("/dev/cons"); if(kbctl == nil) sysfatal("initkeyboard: %r"); mctl = initmouse("/dev/mouse", screen); if(mctl == nil) sysfatal("initmouse: %r"); threadcreate(kbthread, nil, mainstacksize); threadcreate(mthread, nil, mainstacksize); threadcreate(resthread, nil, mainstacksize); ntiles = sizeof cols / sizeof cols[0]; imgs = malloc(ntiles * sizeof imgs[0]); for(i = 0; i < ntiles; i++) imgs[i] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, cols[i]); bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xbbada0ff); bgover = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xf3e1d0ff); init(); drawwindow(); while(1) yield(); }