#include #include #include #include #include #include "pieces.h" #include "ui.h" void clearmap(char** map, int mapH, int mapW) { for (int r = 0; r < mapH; r++) { for (int c = 0; c < mapW; c++) { map[r][c] = ' '; } } } int clearfull(char** map, int mapH, int mapW) { // if a row or column is full, clear it // if a row and a column are full at the same time, clear both // which is why we need to scan all rows/columns before actually clearing them // returns total number of blocks cleared bool* rows_to_clear = malloc(mapH * sizeof(bool)); bool* cols_to_clear = malloc(mapW * sizeof(bool)); int rtc_count = 0; int ctc_count = 0; // scan all rows and columns for (int r = 0; r < mapH; r++) { bool clear = true; for (int c = 0; c < mapW; c++) { if (map[r][c] == ' ') clear = false; } rows_to_clear[r] = clear; } for (int c = 0; c < mapW; c++) { bool clear = true; for (int r = 0; r < mapH; r++) { if (map[r][c] == ' ') clear = false; } cols_to_clear[c] = clear; } // clear rows and columns marked true in `{rows,columns}_to_clear` for (int r = 0; r < mapH; r++) { if (rows_to_clear[r]) { rtc_count++; for (int c = 0; c < mapW; c++) map[r][c] = ' '; } } for (int c = 0; c < mapW; c++) { if (cols_to_clear[c]) { ctc_count++; for (int r = 0; r < mapW; r++) map[r][c] = ' '; } } free(rows_to_clear); free(cols_to_clear); return (rtc_count * mapW + ctc_count * mapH - rtc_count * ctc_count); } void sirtet() { const int H = 8; // canvas height const int W = 8; // canvas width const int P = 3; // maximum # of pieces at hand // init memory and game state char** map = malloc(H * sizeof(char*)); for (int r = 0; r < H; r++) { map[r] = malloc(W * sizeof(char)); } struct piece** hand = malloc(P * sizeof(struct piece*)); srand(time(NULL)); clearmap(map, H, W); refillpieces(hand, P); bool over = false; int points = 0; // initialize ncurses setlocale(LC_ALL, ""); initscr(); clear(); noecho(); cbreak(); keypad(stdscr, true); curs_set(0); // set cursor invisible start_color(); init_pair(1, COLOR_GREEN, COLOR_BLACK); init_pair(2, COLOR_RED, COLOR_BLACK); // begin game loop while (!over) { clear(); printrect(0, 0, H, W); printmap(map, 1, 1, H, W); // display game stats mvprintw(1, 2 * W + 8, "Points: %d", points); refresh(); // select piece and position bool confirmed = false; int pc_idx; struct piece* pc; for (int i = 0; i < P; i++) { // find first non-null piece if (hand[i] != NULL) { pc_idx = i; pc = hand[i]; break; } } int row = 0; int col = 0; while (!confirmed) { printmap(map, 1, 1, H, W); printpieces(hand, H + 2, 0, P, pc_idx); bool pos_placeable = placeable(map, pc, row, col, H, W); printpiece(pc, row + 1, col * 2 + 1, (pos_placeable ? 1 : 2)); // await user input int ch = getch(); switch (ch) { // enter: confirm choice case 10: if (pos_placeable) confirmed = true; break; // arrow keys: move piece on map case KEY_LEFT: if (col > 0) col--; break; case KEY_RIGHT: if (col + pc->w < W) col++; break; case KEY_UP: if (row > 0) row--; break; case KEY_DOWN: if (row + pc->h < H) row++; break; // [ and ]: switch pieces case '[': for (int i = 0; i < P; i++) { // find previous non-null piece pc_idx = (pc_idx + P - 1) % P; if (hand[pc_idx] != NULL) { pc = hand[pc_idx]; break; } } break; case ']': for (int i = 0; i < P; i++) { // find next non-null piece pc_idx = (pc_idx + 1) % P; if (hand[pc_idx] != NULL) { pc = hand[pc_idx]; break; } } break; } } place(map, pc, row, col); points += pc->points; freepiece(pc); hand[pc_idx] = NULL; // clear full rows and columns int blocks_cleared = clearfull(map, H, W); points += blocks_cleared; // if player has no piece left, refill bool pieces_left = false; for (int i = 0; i < P; i++) { if (hand[i] != NULL) { pieces_left = true; break; } } if (!pieces_left) refillpieces(hand, P); // game over if none of the pieces are placeable bool has_placeable = false; for (int i = 0; i < P; i++) { if (hand[i] == NULL) continue; for (int r = 0; r <= H - hand[i]->h; r++) { for (int c = 0; c <= W - hand[i]->w; c++) { if (placeable(map, hand[i], r, c, H, W)) has_placeable = true; } } } if (!has_placeable) { // game over mvprintw(3, 2 * W + 8, "Game over"); mvprintw(4, 2 * W + 8, "Press any key to exit"); refresh(); while (getch() == 0); over = true; } } // free memory for (int r = 0; r < H; r++) { free(map[r]); } free(map); for (int i = 0; i < P; i++) { if (hand[i] != NULL) freepiece(hand[i]); } free(hand); // end ncurses endwin(); } int main(int argc, char *argv[]) { sirtet(); return 0; }