#include #include #include #include #include Image *c[17]; Rectangle r[16]; int sq[16], score, hues[17] = {DBlack, 0xfbf305ff, 0xff6403ff, 0xdd0907ff, 0xf20884ff, 0x8000a5ff, 0x0000d3ff, 0x02abeaff, 0x1fb714ff, 0x006412ff, 0x562c05ff, 0x90713aff, 0xc0c0c0ff, 0x808080ff, 0x404040ff, DWhite, DPurpleblue}; void eresized(int i){ int d; if(i && getwindow(display, Refnone) < 0) sysfatal("Score: %d\ncan't reattach to window", score); if(Dx(screen->r) > Dy(screen->r)){ d = Dy(screen->r); r[0].min = Pt(screen->r.min.x + screen->r.max.x - d >> 1, screen->r.min.y); }else{ d = Dx(screen->r); r[0].min = Pt(screen->r.min.x, screen->r.min.y + screen->r.max.y - d >> 1); } d >>= 2; r[0].max = Pt(r[0].min.x + d, r[0].min.y + d); draw(screen, screen->r, c[0], nil, ZP); draw(screen, r[0], c[sq[0]], nil, ZP); for(i = 1; i < 16; i++){ r[i] = rectaddpt(r[0], Pt((i & 3) * d, (i >> 2) * d)); draw(screen, r[i], c[sq[i]], nil, ZP); } } void bye(void){ int i, n; for(n = i = 0; i < 16; i++) if(sq[i] > n) n = sq[i]; print("Largest Tile: %d\nScore: %d\n", 1 << n, score); exits(nil); } void newtile(void) { int i, e, n; for(e = i = 0; i < 16; i++) e += !sq[i]; n = nrand(e); while(sq[--i] || n--); sq[i] = 1 + (nrand(10) == 0); if(e > 1) return; for(i = 0; i < 16; i++) if(i & 3 && sq[i] == sq[i - 1] || i < 12 && sq[i] == sq[i + 4]) return; bye(); } int slide(int *one, int *two, int *three, int *four){ int m, n, a[4]; m = n = 0; if(*one) a[n++] = *one; if(*two) a[n++] = *two; if(*three) a[n++] = *three; if(*four) a[n++] = *four; switch(n){ case 0: break; case 1: m = *one || *two || *three; *one = 0; *two = 0; *three = 0; *four = a[0]; break; case 2: m = *one || *two; *one = 0; *two = 0; if(a[0] == a[1]){ m = 1; *three = 0; *four = a[0] + 1; score += 1 << *four; }else{ *three = a[0]; *four = a[1]; } break; case 3: m = *one; *one = 0; if(a[1] == a[2]){ m = 1; *two = 0; *three = a[0]; *four = a[1] + 1; score += 1 << *four; }else if(a[0] == a[1]){ m = 1; *two = 0; *three = a[1] + 1; *four = a[2]; score += 1 << *three; }else{ *two = a[0]; *three = a[1]; *four = a[2]; } break; case 4: if(a[0] == a[1] && a[2] == a[3]){ m = 1; *one = 0; *two = 0; *three = a[0] + 1; *four = a[2] + 1; score += 1 << *three; score += 1 << *four; }else if(a[2] == a[3]){ m = 1; *one = 0; *two = a[0]; *three = a[1]; *four = a[2] + 1; score += 1 << *four; }else if(a[1] == a[2]){ m = 1; *one = 0; *two = a[0]; *three = a[1] + 1; score += 1 << *three; }else if(a[0] == a[1]){ m = 1; *one = 0; *two = a[0] + 1; score += 1 << *two; } break; } return m; } void main(int, char **argv) { Event e; int i; if(initdraw(0, 0, argv[0]) < 0) sysfatal("initdraw: %r"); for(i = 0; i < 17 ; i++) if((c[i] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, hues[i])) == nil) sysfatal("allocimage: %r"); einit(Ekeyboard | Emouse); srand(truerand()); newtile(); newtile(); eresized(0); for(;;) if(event(&e) == Ekeyboard){ switch(e.kbdc){ default: continue; case 'q': case Kdel: bye(); case Kesc: i = open("/dev/wctl", OWRITE); if(i >= 0){write(i, "hide\n", 5);close(i);} break; case Kup: if(slide(sq + 12, sq + 8, sq + 4, sq) | slide(sq + 13, sq + 9, sq + 5, sq + 1) | slide(sq + 14, sq + 10, sq + 6, sq + 2) | slide(sq + 15, sq + 11, sq + 7, sq + 3)) break; continue; case Kdown: if(slide(sq, sq + 4, sq + 8, sq + 12) | slide(sq + 1, sq + 5, sq + 9, sq + 13) | slide(sq + 2, sq + 6, sq + 10, sq + 14) | slide(sq + 3, sq + 7, sq + 11, sq + 15)) break; continue; case Kleft: if(slide(sq + 3, sq + 2, sq + 1, sq) | slide(sq + 7, sq + 6, sq + 5, sq + 4) | slide(sq + 11, sq + 10, sq + 9, sq + 8) | slide(sq + 15, sq + 14, sq + 13, sq + 12)) break; continue; case Kright: if(slide(sq, sq + 1, sq + 2, sq + 3) | slide(sq + 4, sq + 5, sq + 6, sq + 7) | slide(sq + 8, sq + 9, sq + 10, sq + 11) | slide(sq + 12, sq + 13, sq + 14, sq + 15)) break; continue; } newtile(); for(i = 0; i < 16; i++) draw(screen, r[i], c[sq[i]], nil, ZP); } }