--- /dev/null
+#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);
+}
--- /dev/null
+#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);
+}
--- /dev/null
+#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);
+}
--- /dev/null
+#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_ */