ref: 9886b6c0b9e3ddbcb6720bd4c4a316f010a57fa2
dir: /game.c/
#include <u.h> #include <libc.h> #include "dat.h" #include "fns.h" #include "/sys/src/games/eui.h" /* FIXME: grace period before freeze */ char playfield[Ncol * Nrow]; Current *cur; int next[4]; int held = -1; enum{ Nlineperlvl = 10, Timeinc = BILLION / 10.0, Thover = 400 * MILLION, }; static vlong ncleared; static int bfield[Nrow]; static u32int trand(void) { static u32int x = 0xffffffff; if(x == 0xffffffff) x = rand(); x = x * 0x41c64e6d + 0x3039 >> 10 & 0x7fff; return x; } static int getpiece(void) { int i, *h, r; static int hist[4] = {FZ, FZ, FS, FS}; for(r=i=0; i<5; i++){ r = trand() % 7; for(h=hist; h<hist+nelem(hist); h++) if(*h == r) break; if(h == hist + nelem(hist)) break; r = trand() % 7; } hist[3] = hist[2]; hist[2] = hist[1]; hist[1] = hist[0]; hist[0] = r; return r; } static int nextpiece(void) { int r, *p; r = next[0]; for(p=next; p<next+nelem(next)-1; p++) p[0] = p[1]; *p = getpiece(); return r; } static void spawn(void) { static Current cur0; memset(&cur0, 0, sizeof cur0); cur0.type = nextpiece(); cur0.rot = Up; cur0.x = Ncol / 2 - 2; cur0.y = Nstartrow - Nextrarows - 1; cur = &cur0; if(collide(cur->x, cur->y, cur->rot)) gameover(); } int collide(int x, int y, int rot) { int n, m, s, b, l, *pp, f; switch(x){ case -3: b = 0b1110111011101110; s = Ncol - 1; m = 1; break; case -2: b = 0b1100110011001100; s = Ncol - 2; m = 3; break; case -1: b = 0b1000100010001000; s = Ncol - 3; m = 7; break; case Ncol-3: b = 0b0001000100010001; s = 1; m = 14; break; case Ncol-2: b = 0b0011001100110011; s = 2; m = 12; break; case Ncol-1: b = 0b0111011101110111; s = 3; m = 8; break; default: b = 0; s = Ncol - Nside - x; m = 15; break; } f = fours[cur->type][rot]; pp = bfield + y; for(n=12; n>=0; n-=4, y++){ if(y >= Nrow) l = 15; else if(x >= Ncol - 3) l = *pp++ << s & m; else l = *pp++ >> s & m; b |= l << n; } return b & f; } static void updatelevel(void) { double t; if(++ncleared % Nlineperlvl != 0) return; if((t = T - Timeinc) >= Timeinc) T = t; else if(T > Timeinc) T = Timeinc; else T *= 0.9; } static void clearlines(void) { int b, *bf; for(bf=bfield+nelem(bfield)-1, b=*bf; b!=0; b=*(--bf)){ if(b != (1 << Ncol) - 1) continue; memmove(bfield+1, bfield, (bf-bfield) * sizeof *bf); memmove(playfield+Ncol, playfield, (bf-bfield) * Ncol); bf++; updatelevel(); } } void hold(void) { int p; if(cur->flags & Fswapped) return; p = held; held = cur->type; spawn(); if(p != -1) cur->type = p; cur->flags |= Fswapped; } static void freeze(void) { char *p; int n, x, y; u32int f; if((y = cur->y) >= Nrow) sysfatal("freeze: oob 1 piece type %d at %d,%d", cur->type, cur->x, cur->y); f = fours[cur->type][cur->rot]; p = playfield + y * Ncol + cur->x; for(n=0, x=1<<(Nside*Nside-1); x>0; x>>=1, p++){ if(f & x){ if(y >= Nrow) sysfatal("freeze: oob 2 piece type %d %d,%d at %zd,%d", cur->type, cur->x, cur->y, p-(playfield+y*Ncol), y); if(*p != 0) sysfatal("freeze: overlapping piece type %d %d,%d at %zd,%d", cur->type, cur->x, cur->y, p-(playfield+y*Ncol), y); *p = cur->type + 1; bfield[y] |= 1 << (Ncol - 1 - cur->x - n); } if(++n == Nside){ p += Ncol - Nside; n = 0; y++; } } clearlines(); disengage(); spawn(); } void drop(void) { while(!collide(cur->x, cur->y+1, cur->rot)) cur->y++; freeze(); } void gameover(void) { print("you're done! finished!\n"); quit(); } void step(void) { u64int t; if(cur == nil){ spawn(); return; }else if(collide(cur->x, cur->y+1, cur->rot)){ t = nanosec(); if(cur->lastmove == 0){ cur->lastmove = t; cur->flags |= Fhovering; }else if((t - cur->lastmove) >= Thover || collide(cur->x-1, cur->y, cur->rot) && collide(cur->x+1, cur->y, cur->rot)) freeze(); return; } cur->flags &= ~Fhovering; cur->lastmove = 0; cur->y++; } void initgame(void) { int *p; for(p=next; p<next+nelem(next); p++) *p = getpiece(); }