From: John Tsiombikas Date: Fri, 8 Feb 2019 05:49:33 +0000 (+0200) Subject: initial commit X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=ansitris;a=commitdiff_plain;h=f71c261ce691d78fccb3f377ae5299edbf0e0062 initial commit --- f71c261ce691d78fccb3f377ae5299edbf0e0062 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6cdde3a --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.o +*.d +*.swp +*.log +ansitris diff --git a/Makefile b/Makefile new file mode 100644 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 index 0000000..c0af0c4 --- /dev/null +++ b/src/ansi.c @@ -0,0 +1,99 @@ +#include +#include + +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 index 0000000..5e1e482 --- /dev/null +++ b/src/ansi.h @@ -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 index 0000000..f1622aa --- /dev/null +++ b/src/game.c @@ -0,0 +1,101 @@ +#include +#include +#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 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 index 0000000..0fe598e --- /dev/null +++ b/src/game.h @@ -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 index 0000000..6f27d73 --- /dev/null +++ b/src/main.c @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include +#include +#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 index 0000000..de396ec --- /dev/null +++ b/src/pieces.h @@ -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_ */