diff options
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | main.c | 203 |
3 files changed, 209 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a7c9ed4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +termio +tetris diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1899fcf --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +all: tetris + +tetris: $(wildcard *.c *.h) + gcc -Wall -Wextra -std=c11 -O2 -fwrapv -o $@ $(filter %.c,$^) -Itermio termio/libtermio.a @@ -0,0 +1,203 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <string.h> +#include <time.h> +#include <sys/select.h> +#include <sys/time.h> +#include <unistd.h> +#include <assert.h> +#include "termio.h" + +#define WID 10 +#define HEI 22 + + +int delay_msec=700; + + +const int stones[7]={ + 0b0000000001110001, + 0b0000000001110100, + 0b0000000000110011, + 0b0000000000110110, + 0b0000000001110010, + 0b0000000001100011, + 0b0000000000001111, +}; + +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 rotateL(int bl){ + return rotateR(rotateR(rotateR(bl))); +} + + +struct board { + int lines[HEI]; + int stone,stx,sty; +}; + +static void persist(struct board *bd){ + // fprintf(stderr,"persist: stone=%d\n",bd->stone); + // usleep(1000000); + 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); + } + } +} + +static void spawn(struct board *bd){ + int idx=rand()%7; + // fprintf(stderr,"%d\n",idx); + // usleep(1000000); + bd->stone=stones[idx]; + bd->stx=WID/2-1; + bd->sty=0; +} + +static void show(const struct board *bd){ + struct board bd2; + memcpy(&bd2,bd,sizeof bd2); + persist(&bd2); + printf("\x1B[H\x1B[2J"); + for(int y=0;y<HEI;y++){ + putchar('|'); + for(int x=0;x<WID;x++){ + if(bd2.lines[y]&(1<<x))printf("█"); + else putchar(' '); + } + putchar('|'); + putchar('\n'); + } + putchar('+'); + for(int x=0;x<WID;x++){ + putchar('-'); + } + putchar('+'); + putchar('\n'); + fflush(stdout); +} + +static bool boardvalid(const struct board *bd){ + for(int y=0;y<4;y++){ + for(int x=0;x<4;x++){ + if((bd->stone&(1<<(4*y+x)))){ + 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; + } + } + return true; +} + +static void advance(struct board *bd){ + fprintf(stderr,"advance: stone=%d\n",bd->stone); + if(bd->stone==0){ + spawn(bd); + return; + } + bd->sty++; + if(!boardvalid(bd)){ + bd->sty--; + persist(bd); + spawn(bd); + return; + } +} + +static void move(struct board *bd,int dir){ + bd->stx+=dir; + if(!boardvalid(bd)){ + bd->stx-=dir; + return; + } +} + +static void rotR(struct board *bd){ + int st=bd->stone; + bd->stone=rotateR(bd->stone); + if(!boardvalid(bd))bd->stone=st; +} + + +int main(void){ + srand(time(NULL)); + + initkeyboard(false); + atexit(endkeyboard); + + struct board bd; + memset(&bd,0,sizeof bd); + show(&bd); + + struct timeval timeleft; + timeleft.tv_sec=0; + timeleft.tv_usec=0; + + while(true){ + show(&bd); + + struct timeval start; + gettimeofday(&start,NULL); + + fd_set inset; + FD_ZERO(&inset); + FD_SET(0,&inset); + struct timeval timeout; + memcpy(&timeout,&timeleft,sizeof timeout); + + int ret=select(1,&inset,NULL,NULL,&timeout); + assert(ret>=0); + + struct timeval end; + gettimeofday(&end,NULL); + + if(ret==0){ + advance(&bd); + timeleft.tv_sec=delay_msec/1000; + timeleft.tv_usec=delay_msec%1000*1000; + continue; + } + end.tv_sec-=start.tv_sec; + end.tv_usec-=start.tv_usec; + if(end.tv_usec<0){ + end.tv_sec--; + end.tv_usec+=1000000; + } + + timeleft.tv_sec-=end.tv_sec; + timeleft.tv_usec-=end.tv_usec; + if(timeleft.tv_usec<0){ + timeleft.tv_sec--; + if(timeleft.tv_sec<0){ + timeleft.tv_sec=timeleft.tv_usec=0; + } else { + timeleft.tv_usec+=1000000; + } + } + + assert(FD_ISSET(0,&inset)); + + int key=tgetkey(); + if(key=='Q'||key=='q')break; + else if(key=='S'||key=='s'||key==KEY_DOWN){ + advance(&bd); + timeleft.tv_sec=delay_msec/1000; + timeleft.tv_usec=delay_msec%1000*1000; + } 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); + else bel(); + } +} |