initial commit
authorJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 8 Feb 2019 05:49:33 +0000 (07:49 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 8 Feb 2019 05:49:33 +0000 (07:49 +0200)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
src/ansi.c [new file with mode: 0644]
src/ansi.h [new file with mode: 0644]
src/game.c [new file with mode: 0644]
src/game.h [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/pieces.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..6cdde3a
--- /dev/null
@@ -0,0 +1,5 @@
+*.o
+*.d
+*.swp
+*.log
+ansitris
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..c7e9e8c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,23 @@
+src = $(wildcard src/*.c)
+obj = $(src:.c=.o)
+dep = $(obj:.o=.d)
+bin = ansitris
+
+CFLAGS = -pedantic -Wall -g
+
+$(bin): $(obj)
+       $(CC) -o $@ $(obj) $(LDFLAGS)
+
+-include $(dep)
+
+%.d: %.c
+       @echo depfile $@
+       @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
+
+.PHONY: clean
+clean:
+       rm -f $(obj) $(bin)
+
+.PHONY: cleandep
+cleandep:
+       rm -f $(dep)
diff --git a/src/ansi.c b/src/ansi.c
new file mode 100644 (file)
index 0000000..c0af0c4
--- /dev/null
@@ -0,0 +1,99 @@
+#include <stdio.h>
+#include <string.h>
+
+enum {
+       CS_ASCII = 'B',
+       CS_GRAPH = '0'
+};
+
+#define GMAP_FIRST     0xb0
+#define GMAP_LAST      0xda
+
+unsigned char gmap[] = {
+       0x61, 0x61, 0x61,               /* checker */
+       0x78,                                   /* vline */
+       0x75, 0x75, 0x75,               /* right T */
+       0x6b, 0x6b,                             /* upper-right corner */
+       0x75,                                   /* right T */
+       0x78,                                   /* vline */
+       0x6b,                                   /* upper-right corner */
+       0x6a, 0x6a, 0x6a,               /* lower-right corner */
+       0x6b,                                   /* upper-right corner */
+       0x6d,                                   /* lower-left corner */
+       0x76,                                   /* bottom T */
+       0x77,                                   /* top T */
+       0x74,                                   /* left T */
+       0x71,                                   /* hline */
+       0x6e,                                   /* cross */
+       0x74, 0x74,                             /* left T */
+       0x6d,                                   /* lower-left corner */
+       0x6c,                                   /* upper-left corner */
+       0x76,                                   /* bottom T */
+       0x77,                                   /* top T */
+       0x74,                                   /* left T */
+       0x71,                                   /* hline */
+       0x6e,                                   /* cross */
+       0x76, 0x76,                             /* bottom T */
+       0x77, 0x77,                             /* top T */
+       0x6d, 0x6d,                             /* lower-left corner */
+       0x6c, 0x6c,                             /* upper-left corner */
+       0x6e, 0x6e,                             /* cross */
+       0x6a,                                   /* lower-right corner */
+       0x6c                                    /* upper-left corner */
+};
+
+static unsigned char cmap[] = {0, 4, 2, 6, 1, 5, 3, 7};
+
+static unsigned char cur_attr = 0xff;
+static int cur_cs = CS_ASCII;
+
+void ansi_reset(void)
+{
+       fputs("\033c", stdout);
+       fflush(stdout);
+}
+
+void ansi_clearscr(void)
+{
+       fputs("\033[2J", stdout);
+}
+
+void ansi_setcursor(int row, int col)
+{
+       printf("\033[%d;%dH", row + 1, col + 1);
+}
+
+void ansi_ibmchar(unsigned char c, unsigned char attr)
+{
+       char cmd[32];
+       char *ptr = cmd;
+
+       if(c >= GMAP_FIRST && c <= GMAP_LAST) {
+               if(cur_cs == CS_ASCII) {
+                       memcpy(ptr, "\033(0", 3);
+                       ptr += 3;
+                       cur_cs = CS_GRAPH;
+               }
+
+               c = gmap[c - GMAP_FIRST];
+       } else {
+               if(cur_cs == CS_GRAPH) {
+                       memcpy(ptr, "\033(B", 3);
+                       ptr += 3;
+                       cur_cs = CS_ASCII;
+               }
+       }
+
+       if(attr != cur_attr) {
+               unsigned char fg = cmap[attr & 7];
+               unsigned char bg = cmap[(attr >> 4) & 7];
+
+               ptr += sprintf(ptr, "\033[;%d;%dm", fg + 30, bg + 40);
+               cur_attr = attr;
+       }
+
+       *ptr++ = c;
+       *ptr = 0;
+
+       fputs(cmd, stdout);
+}
diff --git a/src/ansi.h b/src/ansi.h
new file mode 100644 (file)
index 0000000..5e1e482
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef ANSI_H_
+#define ANSI_H_
+
+void ansi_reset(void);
+void ansi_clearscr(void);
+
+void ansi_setcursor(int row, int col);
+
+/* convert a PC cga/ega/vga char+attr to an ANSI sequence and write it to stdout */
+void ansi_ibmchar(unsigned char c, unsigned char attr);
+
+#endif /* ANSI_H_ */
diff --git a/src/game.c b/src/game.c
new file mode 100644 (file)
index 0000000..f1622aa
--- /dev/null
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <inttypes.h>
+#include "game.h"
+#include "pieces.h"
+#include "ansi.h"
+
+enum {
+       G_DIAMOND       = 0x04,
+       G_CHECKER       = 0xb1,
+       G_LR_CORNER     = 0xd9,
+       G_UR_CORNER     = 0xbf,
+       G_UL_CORNER     = 0xda,
+       G_LL_CORNER     = 0xc0,
+       G_CROSS         = 0xc5,
+       G_HLINE         = 0xc4,
+       G_L_TEE         = 0xc3,
+       G_R_TEE         = 0xb4,
+       G_B_TEE         = 0xc1,
+       G_T_TEE         = 0xc2,
+       G_VLINE         = 0xb3,
+       G_CDOT          = 0xf8
+};
+
+enum { BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, YELLOW, WHITE };
+
+/* dimensions of the whole screen */
+#define SCR_ROWS       20
+#define SCR_COLS       20
+
+/* dimensions of the playfield */
+#define PF_ROWS                18
+#define PF_COLS                10
+/* offset of the playfield from the left side of the screen */
+#define PF_XOFFS       2
+
+#define CHAR(c, fg, bg) \
+       ((uint16_t)(c) | ((uint16_t)(fg) << 12) | ((uint16_t)(bg) << 8))
+
+uint16_t scr[SCR_COLS * SCR_ROWS];
+
+static void wrchar(uint16_t c);
+
+
+int init_game(void)
+{
+       int i, j;
+       uint16_t *row = scr;
+
+       ansi_clearscr();
+
+       /* fill the screen buffer, and draw */
+       for(i=0; i<SCR_ROWS; i++) {
+               ansi_setcursor(i, 0);
+
+               for(j=0; j<SCR_COLS; j++) {
+                       if(i > PF_ROWS || j < PF_XOFFS - 1 || j > PF_XOFFS + PF_COLS) {
+                               row[j] = CHAR(' ', WHITE, BLACK);
+                       } else if((i == PF_ROWS && j >= PF_XOFFS && j < PF_XOFFS + PF_COLS) ||
+                                       j == PF_XOFFS - 1 || j == PF_XOFFS + PF_COLS) {
+                               row[j] = CHAR(G_CHECKER, WHITE, BLACK);
+                       } else {
+                               row[j] = CHAR(' ', BLACK, WHITE);
+                       }
+
+                       wrchar(row[j]);
+               }
+
+               row += SCR_COLS;
+       }
+       fflush(stdout);
+
+       return 0;
+}
+
+void cleanup_game(void)
+{
+       ansi_reset();
+}
+
+void proc_input(void)
+{
+       int c = fgetc(stdin);
+
+       switch(c) {
+       case 27:
+               quit = 1;
+               break;
+
+       default:
+               break;
+       }
+}
+
+static void wrchar(uint16_t c)
+{
+       unsigned char cc = c & 0xff;
+       unsigned char ca = c >> 8;
+
+       ansi_ibmchar(cc, ca);
+       ansi_ibmchar(cc, ca);
+}
diff --git a/src/game.h b/src/game.h
new file mode 100644 (file)
index 0000000..0fe598e
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef GAME_H_
+#define GAME_H_
+
+int quit;
+
+int init_game(void);
+void cleanup_game(void);
+
+void proc_input(void);
+
+#endif /* GAME_H_ */
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..6f27d73
--- /dev/null
@@ -0,0 +1,81 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <sys/stat.h>
+#include "game.h"
+
+int init(void);
+void cleanup(void);
+
+const char *termfile = "/dev/tty";
+struct termios saved_term;
+
+int main(int argc, char **argv)
+{
+       if(argc > 1) {
+               termfile = argv[1];
+       }
+
+       if(init() == -1) {
+               return 1;
+       }
+
+       for(;;) {
+               proc_input();
+               if(quit) break;
+       }
+
+       cleanup();
+       return 0;
+}
+
+int init(void)
+{
+       int fd;
+       struct termios term;
+
+       if((fd = open(termfile, O_RDWR)) == -1) {
+               fprintf(stderr, "failed to open terminal device: %s: %s\n", termfile, strerror(errno));
+               return -1;
+       }
+
+       if(tcgetattr(fd, &term) == -1) {
+               fprintf(stderr, "failed to get terminal attributes: %s\n", strerror(errno));
+               return -1;
+       }
+       saved_term = term;
+       term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
+       term.c_oflag &= ~OPOST;
+       term.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+       term.c_cflag = (term.c_cflag & ~(CSIZE | PARENB)) | CS8;
+
+       if(tcsetattr(fd, TCSAFLUSH, &term) == -1) {
+               fprintf(stderr, "failed to change terminal attributes: %s\n", strerror(errno));
+               return -1;
+       }
+
+       close(0);
+       close(1);
+       close(2);
+       dup(fd);
+       dup(fd);
+
+       umask(002);
+       open("ansitris.log", O_WRONLY | O_CREAT, 0664);
+
+
+       if(init_game() == -1) {
+               return -1;
+       }
+
+       return 0;
+}
+
+void cleanup(void)
+{
+       cleanup_game();
+       tcsetattr(0, TCSAFLUSH, &saved_term);
+}
diff --git a/src/pieces.h b/src/pieces.h
new file mode 100644 (file)
index 0000000..de396ec
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef PIECES_H_
+#define PIECES_H_
+
+#define BLK(x, y)      ((x) | ((y) << 4))
+
+unsigned char pieces[][4][4] = {
+       /* straight piece */
+       {
+               {BLK(0, 2), BLK(1, 2), BLK(2, 2), BLK(3, 2)},
+               {BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(1, 3)},
+               {BLK(0, 2), BLK(1, 2), BLK(2, 2), BLK(3, 2)},
+               {BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(1, 3)}
+       },
+       /* box */
+       {
+               {BLK(1, 1), BLK(2, 1), BLK(1, 2), BLK(2, 2)},
+               {BLK(1, 1), BLK(2, 1), BLK(1, 2), BLK(2, 2)},
+               {BLK(1, 1), BLK(2, 1), BLK(1, 2), BLK(2, 2)},
+               {BLK(1, 1), BLK(2, 1), BLK(1, 2), BLK(2, 2)}
+       },
+       /* J block */
+       {
+               {BLK(0, 1), BLK(1, 1), BLK(2, 1), BLK(2, 2)},
+               {BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(0, 2)},
+               {BLK(0, 0), BLK(0, 1), BLK(1, 1), BLK(2, 1)},
+               {BLK(1, 0), BLK(2, 0), BLK(1, 1), BLK(1, 2)}
+       },
+       /* L block */
+       {
+               {BLK(0, 1), BLK(0, 2), BLK(1, 1), BLK(2, 1)},
+               {BLK(0, 0), BLK(1, 0), BLK(1, 1), BLK(1, 2)},
+               {BLK(0, 1), BLK(1, 1), BLK(2, 1), BLK(2, 0)},
+               {BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(2, 2)}
+       },
+       /* S block */
+       {
+               {BLK(1, 1), BLK(2, 1), BLK(0, 2), BLK(1, 2)},
+               {BLK(0, 0), BLK(0, 1), BLK(1, 1), BLK(1, 2)},
+               {BLK(1, 1), BLK(2, 1), BLK(0, 2), BLK(1, 2)},
+               {BLK(0, 0), BLK(0, 1), BLK(1, 1), BLK(1, 2)}
+       },
+       /* T block */
+       {
+               {BLK(0, 1), BLK(1, 1), BLK(2, 1), BLK(1, 2)},
+               {BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(0, 1)},
+               {BLK(0, 1), BLK(1, 1), BLK(2, 1), BLK(1, 0)},
+               {BLK(1, 0), BLK(1, 1), BLK(1, 2), BLK(2, 1)}
+       },
+       /* Z block */
+       {
+               {BLK(0, 1), BLK(1, 1), BLK(1, 2), BLK(2, 2)},
+               {BLK(0, 1), BLK(1, 1), BLK(1, 0), BLK(0, 2)},
+               {BLK(0, 1), BLK(1, 1), BLK(1, 2), BLK(2, 2)},
+               {BLK(0, 1), BLK(1, 1), BLK(1, 0), BLK(0, 2)}
+       }
+};
+
+
+#endif /* PIECES_H_ */