almost done. no line completion, scoring, and next-piece display yet
authorJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 11 Feb 2019 00:48:25 +0000 (02:48 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 11 Feb 2019 00:48:25 +0000 (02:48 +0200)
src/game.c
src/pieces.h

index e8b47f3..0adc772 100644 (file)
@@ -1,5 +1,7 @@
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
+#include <time.h>
 #include <inttypes.h>
 #include "game.h"
 #include "pieces.h"
@@ -22,6 +24,8 @@ enum {
        G_CDOT          = 0xf8
 };
 
+enum { ERASE_PIECE, DRAW_PIECE };
+
 enum { BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, YELLOW, WHITE };
 
 /* dimensions of the whole screen */
@@ -33,19 +37,58 @@ enum { BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, YELLOW, WHITE };
 #define PF_COLS                10
 /* offset of the playfield from the left side of the screen */
 #define PF_XOFFS       2
+#define PF_YOFFS       0
 
 #define CHAR(c, fg, bg) \
        ((uint16_t)(c) | ((uint16_t)(fg) << 12) | ((uint16_t)(bg) << 8))
 
-uint16_t scr[SCR_COLS * SCR_ROWS];
+int scr[SCR_COLS * SCR_ROWS];
+
+static int collision(int piece, const int *pos);
+static void stick(int piece, const int *pos);
+static void draw_piece(int piece, const int *pos, int rot, int mode);
+static void drawbg(void);
+static void wrtile(int tileid);
+
+
+static int pos[2], next_pos[2];
+static int cur_piece = -1;
+static int cur_rot, prev_rot;
 
-static void wrchar(uint16_t c);
+enum {
+       TILE_BLACK,
+       TILE_PF,
+       TILE_PFSEP,
+       TILE_IPIECE,
+       TILE_OPIECE,
+       TILE_JPIECE,
+       TILE_LPIECE,
+       TILE_SPIECE,
+       TILE_TPIECE,
+       TILE_ZPIECE
+};
+#define FIRST_PIECE_TILE       TILE_IPIECE
+
+static uint16_t tiles[][2] = {
+       { CHAR(' ', BLACK, BLACK), CHAR(' ', BLACK, BLACK) },                   /* black tile */
+       { CHAR(' ', WHITE, WHITE), CHAR(' ', WHITE, WHITE) },                   /* playfield background */
+       { CHAR(G_CHECKER, WHITE, BLACK), CHAR(G_CHECKER, WHITE, BLACK) },       /* well separator */
+       { CHAR(' ', CYAN, CYAN), CHAR(' ', CYAN, CYAN) },                               /* straight */
+       { CHAR(' ', BLUE, BLUE), CHAR(' ', BLUE, BLUE) },                               /* box */
+       { CHAR(' ', GREEN, GREEN), CHAR(' ', GREEN, GREEN) },                   /* J */
+       { CHAR(' ', YELLOW, YELLOW), CHAR(' ', YELLOW, YELLOW) },               /* L */
+       { CHAR(' ', MAGENTA, MAGENTA), CHAR(' ', MAGENTA, MAGENTA) },   /* S */
+       { CHAR(' ', RED, BLACK), CHAR(' ', RED, BLACK) },               /* T */
+       { CHAR(' ', RED, RED), CHAR(' ', RED, RED) },                                   /* Z */
+};
 
 
 int init_game(void)
 {
        int i, j;
-       uint16_t *row = scr;
+       int *row = scr;
+
+       srand(time(0));
 
        tick_interval = 1000;
 
@@ -54,23 +97,20 @@ int init_game(void)
 
        /* 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);
+                               row[j] = TILE_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);
+                               row[j] = TILE_PFSEP;
                        } else {
-                               row[j] = CHAR(' ', BLACK, WHITE);
+                               row[j] = TILE_PF;
                        }
-
-                       wrchar(row[j]);
                }
-
                row += SCR_COLS;
        }
+
+       drawbg();
        fflush(stdout);
 
        return 0;
@@ -81,9 +121,6 @@ void cleanup_game(void)
        ansi_reset();
 }
 
-static int pos[2] = {0, PF_COLS / 2};
-static int next_pos[2] = {0, PF_COLS / 2};
-
 long update(long msec)
 {
        static long prev_tick;
@@ -93,20 +130,30 @@ long update(long msec)
 
        /* fall */
        while(dt >= tick_interval) {
-               next_pos[0] = (pos[0] + 1) % PF_ROWS;
+               if(cur_piece >= 0) {
+                       next_pos[0] = pos[0] + 1;
+                       if(collision(cur_piece, next_pos)) {
+                               next_pos[0] = pos[0];
+                               fprintf(stderr, "stick at row %d col %d\n", pos[0], pos[1]);
+                               stick(cur_piece, next_pos);
+                               cur_piece = -1;
+                       }
+               } else {
+                       cur_piece = rand() % NUM_PIECES;
+                       fprintf(stderr, "spawn: %d\n", cur_piece);
+                       pos[0] = next_pos[0] = piece_spawnpos[cur_piece][0];
+                       pos[1] = next_pos[1] = PF_COLS / 2 + piece_spawnpos[cur_piece][1];
+               }
+
                dt -= tick_interval;
                prev_tick = msec;
        }
 
-       if(memcmp(pos, next_pos, sizeof pos) != 0) {
-               ansi_setcursor(pos[0], (PF_XOFFS + pos[1]) * 2);
-               wrchar(CHAR(' ', BLACK, WHITE));
-
+       if(cur_piece >= 0 && (memcmp(pos, next_pos, sizeof pos) != 0 || cur_rot != prev_rot)) {
+               draw_piece(cur_piece, pos, prev_rot, ERASE_PIECE);
+               draw_piece(cur_piece, next_pos, cur_rot, DRAW_PIECE);
                memcpy(pos, next_pos, sizeof pos);
-               ansi_setcursor(pos[0], (PF_XOFFS + pos[1]) * 2);
-               wrchar(CHAR(' ', RED, RED));
-
-               fflush(stdout);
+               prev_rot = cur_rot;
        }
        return tick_interval - dt;
 }
@@ -119,14 +166,32 @@ void game_input(int c)
                break;
 
        case 'a':
-               if(pos[1] > 0) {
-                       next_pos[1] = pos[1] - 1;
+               next_pos[1] = pos[1] - 1;
+               if(collision(cur_piece, next_pos)) {
+                       next_pos[1] = pos[1];
                }
                break;
 
        case 'd':
-               if(pos[1] < PF_COLS - 1) {
-                       next_pos[1] = pos[1] + 1;
+               next_pos[1] = pos[1] + 1;
+               if(collision(cur_piece, next_pos)) {
+                       next_pos[1] = pos[1];
+               }
+               break;
+
+       case 'w':
+       case ' ':
+               prev_rot = cur_rot;
+               cur_rot = (cur_rot + 1) & 3;
+               if(collision(cur_piece, next_pos)) {
+                       cur_rot = prev_rot;
+               }
+               break;
+
+       case 's':
+               next_pos[0] = pos[0] + 1;
+               if(collision(cur_piece, next_pos)) {
+                       next_pos[0] = pos[0];
                }
                break;
 
@@ -135,11 +200,75 @@ void game_input(int c)
        }
 }
 
-static void wrchar(uint16_t c)
+static int collision(int piece, const int *pos)
 {
-       unsigned char cc = c & 0xff;
-       unsigned char ca = c >> 8;
+       int i;
+       unsigned char *p = pieces[piece][cur_rot];
+
+       for(i=0; i<4; i++) {
+               int x = PF_XOFFS + pos[1] + BLKX(*p);
+               int y = PF_YOFFS + pos[0] + BLKY(*p);
+               p++;
 
-       ansi_ibmchar(cc, ca);
-       ansi_ibmchar(cc, ca);
+               if(scr[y * SCR_COLS + x] != TILE_PF) return 1;
+       }
+
+       return 0;
+}
+
+static void stick(int piece, const int *pos)
+{
+       int i;
+       unsigned char *p = pieces[piece][cur_rot];
+
+       for(i=0; i<4; i++) {
+               int x = PF_XOFFS + pos[1] + BLKX(*p);
+               int y = PF_YOFFS + pos[0] + BLKY(*p);
+               p++;
+
+               scr[y * SCR_COLS + x] = piece + FIRST_PIECE_TILE;
+       }
+}
+
+static void draw_piece(int piece, const int *pos, int rot, int mode)
+{
+       int i;
+       int tile = mode == ERASE_PIECE ? TILE_PF : FIRST_PIECE_TILE + piece;
+       unsigned char *p = pieces[piece][rot];
+
+       for(i=0; i<4; i++) {
+               int x = PF_XOFFS + pos[1] + BLKX(*p);
+               int y = PF_YOFFS + pos[0] + BLKY(*p);
+               p++;
+
+               ansi_setcursor(y, x * 2);
+               wrtile(tile);
+       }
+       fflush(stdout);
+}
+
+static void drawbg(void)
+{
+       int i, j;
+       int *sptr = scr;
+
+       for(i=0; i<SCR_ROWS; i++) {
+               ansi_setcursor(i, 0);
+               for(j=0; j<SCR_COLS; j++) {
+                       wrtile(*sptr++);
+               }
+       }
+}
+
+static void wrtile(int tileid)
+{
+       int i;
+
+       for(i=0; i<2; i++) {
+               uint16_t c = tiles[tileid][i];
+               unsigned char cc = c & 0xff;
+               unsigned char ca = c >> 8;
+
+               ansi_ibmchar(cc, ca);
+       }
 }
index de396ec..e3a5c54 100644 (file)
@@ -2,8 +2,12 @@
 #define PIECES_H_
 
 #define BLK(x, y)      ((x) | ((y) << 4))
+#define BLKX(c)                ((unsigned char)(c) & 0xf)
+#define BLKY(c)                ((unsigned char)(c) >> 4)
 
-unsigned char pieces[][4][4] = {
+#define NUM_PIECES     7
+
+static unsigned char pieces[NUM_PIECES][4][4] = {
        /* straight piece */
        {
                {BLK(0, 2), BLK(1, 2), BLK(2, 2), BLK(3, 2)},
@@ -55,5 +59,9 @@ unsigned char pieces[][4][4] = {
        }
 };
 
+static int piece_spawnpos[NUM_PIECES][2] = {
+       {-1, -2}, {-1, -3}, {-1, -2}, {-1, -2}, {-1, -2}, {-1, -2}, {-1, -2}
+};
+
 
 #endif /* PIECES_H_ */