aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Smeding <tom.smeding@gmail.com>2018-02-10 20:49:27 +0100
committerTom Smeding <tom.smeding@gmail.com>2018-02-10 20:49:27 +0100
commit1146f7be49eb2a5abe4db7ba06f568cc81192111 (patch)
tree1303814193a8c59e272d1018b832700785a42417
parent9307136fb81cde270f5c1e192a3aa5dc307c8dfe (diff)
Nintendo Rotation System
-rw-r--r--main.c77
1 files changed, 41 insertions, 36 deletions
diff --git a/main.c b/main.c
index aa4a20e..910b01f 100644
--- a/main.c
+++ b/main.c
@@ -17,26 +17,16 @@
#define USE_UNICODE
-const int stones[7]={
- 0b0000000001110001,
- 0b0000000001110100,
- 0b0000000000110011,
- 0b0000000000110110,
- 0b0000000001110010,
- 0b0000000001100011,
- 0b0000000000001111,
+const int stones[7][4]={
+ {0b0000010001110000, 0b0000001100100010, 0b0000000001110001, 0b0000001000100110},
+ {0b0000000101110000, 0b0000001000100011, 0b0000000001110100, 0b0000011000100010},
+ {0b0000001101100000, 0b0000010001100010, 0b0000001101100000, 0b0000010001100010},
+ {0b0000001001110000, 0b0000001000110010, 0b0000000001110010, 0b0000001001100010},
+ {0b0000011000110000, 0b0000001001100100, 0b0000011000110000, 0b0000001001100100},
+ {0b0000111100000000, 0b0100010001000100, 0b0000111100000000, 0b0100010001000100},
+ {0b0000011001100000, 0b0000011001100000, 0b0000011001100000, 0b0000011001100000},
};
-static int rotateR(int bl){
- int dest=0;
- for(int y=0;y<4;y++){
- for(int x=0;x<4;x++){
- dest|=(!!(bl&(1<<(4*y+x))))<<(4*x+3-y);
- }
- }
- return dest;
-}
-
static int leveldelay(int level){
int d=700-(level-1)*35;
if(d<50)d=50;
@@ -46,38 +36,51 @@ static int leveldelay(int level){
struct board {
int lines[HEI];
- int stone,stx,sty;
+ int stone,str,stx,sty;
int ncleared,level,delay;
};
static bool boardvalid(const struct board *bd){
+ int st=stones[bd->stone][bd->str];
for(int y=0;y<4;y++){
for(int x=0;x<4;x++){
- if((bd->stone&(1<<(4*y+x)))){
+ int bit=1<<(4*y+x);
+ if(st&bit){
if(bd->sty+y>=HEI)return false;
if(bd->stx+x<0||bd->stx+x>=WID)return false;
}
- if(bd->lines[bd->sty+y]&((!!(bd->stone&(1<<(4*y+x))))<<(bd->stx+x)))return false;
+ if(bd->lines[bd->sty+y]&((!!(st&bit))<<(bd->stx+x)))return false;
}
}
return true;
}
static void persist(struct board *bd){
+ int st=stones[bd->stone][bd->str];
for(int y=0;y<4;y++){
for(int x=0;x<4;x++){
- bd->lines[bd->sty+y]|=(!!(bd->stone&(1<<(4*y+x))))<<(bd->stx+x);
+ bd->lines[bd->sty+y]|=(!!(st&(1<<(4*y+x))))<<(bd->stx+x);
}
}
}
+// [0,mx)
+static int randomrange(unsigned int mx){
+ assert(mx<=(unsigned int)RAND_MAX+1);
+ unsigned int diff=((unsigned int)RAND_MAX+1)%mx;
+ unsigned int r=random();
+ // happens at most 50% of the time
+ if(r>RAND_MAX-diff)return randomrange(mx);
+ return r%mx;
+}
+
// returns false iff game over
static bool spawn(struct board *bd){
- int idx=random()%7;
- bd->stone=stones[idx];
+ bd->stone=randomrange(7);
+ bd->str=random()%4;
bd->stx=WID/2-1;
- bd->sty=0;
+ for(bd->sty=0;(stones[bd->stone][bd->str]&((1<<(4+4*-bd->sty))-1))==0;bd->sty--);
return boardvalid(bd);
}
@@ -146,7 +149,7 @@ static void checklines(struct board *bd){
// returns false iff game over
static bool advance(struct board *bd){
- if(bd->stone==0){
+ if(bd->stone<0){
return spawn(bd);
}
bd->sty++;
@@ -165,9 +168,13 @@ static void move(struct board *bd,int dir){
}
static void rotR(struct board *bd){
- int st=bd->stone;
- bd->stone=rotateR(bd->stone);
- if(!boardvalid(bd))bd->stone=st;
+ bd->str=(bd->str+1)%4;
+ if(!boardvalid(bd))bd->str=(bd->str+3)%4;
+}
+
+static void delaytimeout(const struct board *bd,struct timeval *tv){
+ tv->tv_sec=bd->delay/1000;
+ tv->tv_usec=bd->delay%1000*1000;
}
@@ -186,14 +193,14 @@ int main(void){
struct board bd;
memset(&bd,0,sizeof bd);
+ bd.stone=-1;
bd.ncleared=0;
bd.level=1;
bd.delay=leveldelay(bd.level);
- show(&bd);
+ spawn(&bd);
struct timeval timeleft;
- timeleft.tv_sec=0;
- timeleft.tv_usec=0;
+ delaytimeout(&bd,&timeleft);
while(true){
show(&bd);
@@ -223,8 +230,7 @@ int main(void){
if(ret==0){
if(!advance(&bd))break;
- timeleft.tv_sec=bd.delay/1000;
- timeleft.tv_usec=bd.delay%1000*1000;
+ delaytimeout(&bd,&timeleft);
continue;
}
end.tv_sec-=start.tv_sec;
@@ -250,8 +256,7 @@ int main(void){
if(key=='Q'||key=='q')break;
else if(key=='S'||key=='s'||key==KEY_DOWN){
if(!advance(&bd))break;
- timeleft.tv_sec=bd.delay/1000;
- timeleft.tv_usec=bd.delay%1000*1000;
+ delaytimeout(&bd,&timeleft);
} else if(key=='A'||key=='a'||key==KEY_LEFT)move(&bd,-1);
else if(key=='D'||key=='d'||key==KEY_RIGHT)move(&bd,1);
else if(key=='W'||key=='w'||key==KEY_UP)rotR(&bd);