aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Smeding <hallo@tomsmeding.nl>2018-02-07 13:19:00 +0100
committerTom Smeding <hallo@tomsmeding.nl>2018-02-07 13:19:00 +0100
commit93a5f1b89f48308bb4287a8d39ecde88e4549613 (patch)
treecafcd96282d1d2c341a88633987eb7247a683cc0
Initial
-rw-r--r--.gitignore2
-rw-r--r--Makefile4
-rw-r--r--main.c203
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
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..d1c5138
--- /dev/null
+++ b/main.c
@@ -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();
+ }
+}