#include #include #include #include enum { HEIGHT = 20, WIDTH = 10, }; struct position { int x; int y; }; struct rotation { struct position tiles[4]; }; struct brick { struct rotation *states; int rotation; struct position position; }; /************************ * Templates for bricks * ************************/ /* T Brick */ struct rotation t_brick_rotations[4] = { { /* first rotation */ .tiles = { {.x = 2, .y = 0}, {.x = 1, .y = 1}, {.x = 2, .y = 1}, {.x = 2, .y = 2} } }, { /* second rotation */ .tiles = { {.x = 2, .y = 0}, {.x = 1, .y = 1}, {.x = 2, .y = 1}, {.x = 3, .y = 1} } }, { /* third rotation */ .tiles = { {.x = 2, .y = 0}, {.x = 2, .y = 1}, {.x = 3, .y = 1}, {.x = 2, .y = 2} } }, { /* fourth rotation */ .tiles = { {.x = 1, .y = 1}, {.x = 2, .y = 1}, {.x = 3, .y = 1}, {.x = 2, .y = 2} } }, }; enum input { I_NONE, I_QUIT, I_LEFT, I_RIGHT, I_DROP, I_ROTATE, }; struct game_state { char running; char grid[WIDTH][HEIGHT]; struct brick current_brick; enum input input; unsigned int tick; }; struct game_state construct_game_state(); struct brick spawn_brick(); int gravitate_brick(struct game_state *game_state); /* (optional) drop brick */ /* check for full line */ /* remove full line */ int brick_collides_x(struct brick brick); int brick_collides_y(struct brick brick); int brick_collides_grid(struct brick brick, struct game_state game_state); void move_brick(struct brick *brick, int direction); void rotate_brick(struct brick *brick); enum input get_input(); void evaluate_input(struct game_state *game_state, enum input input); /* brick to grid */ void brick_to_grid(struct brick brick, struct game_state *game_state); /* loose condition */ void draw_game_state(struct game_state game_state); int brick_on_position(int x, int y, struct brick brick); int main(void) { initscr(); noecho(); nodelay(stdscr, TRUE); struct game_state game_state = construct_game_state(); while (game_state.running) { game_state.tick++; draw_game_state(game_state); enum input input = get_input(); evaluate_input(&game_state, input); if (game_state.tick % 10 == 0) { int brick_fell = gravitate_brick(&game_state); if (!brick_fell) { game_state.current_brick = spawn_brick(); } } usleep(100000); } endwin(); } struct game_state construct_game_state() { struct game_state game_state = { .running = 1, .grid = {0}, .current_brick = spawn_brick(), .tick = 0, }; return game_state; } struct brick spawn_brick() { struct brick brick = { .states = t_brick_rotations, .rotation = 0, .position = {.x = 3, .y=0} }; return brick; } void draw_game_state(struct game_state game_state) { clear(); for (int y = 0; y < HEIGHT; ++y) { printw("|"); for (int x = 0; x < WIDTH; ++x) { if (game_state.grid[x][y] || brick_on_position(x, y, game_state.current_brick)) { printw("O"); } else { printw(" "); } } printw("|\n"); } printw("|"); for (int x = 0; x < WIDTH; ++x) { printw("-"); } printw("|\n"); } int brick_on_position(int x, int y, struct brick brick) { x -= brick.position.x; y -= brick.position.y; struct rotation *rotation = &brick.states[brick.rotation]; for (int i = 0; i < 4; ++i) { if (rotation->tiles[i].x == x && rotation->tiles[i].y == y) { return 1; } } return 0; } enum input get_input() { char in = getch(); switch (in) { case 'w': return I_ROTATE; case 'q': return I_QUIT; case 'a': return I_LEFT; case 'd': return I_RIGHT; case 's': return I_DROP; default: return I_NONE; } } void evaluate_input(struct game_state *game_state, enum input input) { switch (input) { case I_ROTATE: rotate_brick(&game_state->current_brick); break; case I_QUIT: game_state->running = false; break; case I_LEFT: move_brick(&game_state->current_brick, -1); break; case I_RIGHT: move_brick(&game_state->current_brick, 1); break; case I_DROP: while(gravitate_brick(game_state)) { /* void */ } break; default: break; } } void rotate_brick(struct brick *brick) { brick->rotation++; brick->rotation %= 4; if (brick_collides_x(*brick)) { /* for real module, do +4 and -1 */ brick->rotation += 3; brick->rotation %= 4; } } void move_brick(struct brick *brick, int direction) { brick->position.x += direction; if (brick_collides_x(*brick)) { brick->position.x -= direction; } } int brick_collides_x(struct brick brick) { for (int i = 0; i < 4; ++i) { struct position tile_pos = brick.states[brick.rotation].tiles[i]; tile_pos.x += brick.position.x; if (tile_pos.x > WIDTH - 1 || tile_pos.x < 0) { return 1; } } return 0; } int brick_collides_y(struct brick brick) { for (int i = 0; i < 4; ++i) { struct position tile_pos = brick.states[brick.rotation].tiles[i]; tile_pos.y += brick.position.y; if (tile_pos.y > HEIGHT - 1) { return 1; } } return 0; } int brick_collides_grid(struct brick brick, struct game_state game_state) { for (int i = 0; i < 4; ++i) { struct position tile_pos = brick.states[brick.rotation].tiles[i]; tile_pos.x += brick.position.x; tile_pos.y += brick.position.y; if (game_state.grid[tile_pos.x][tile_pos.y]) { return 1; } } return 0; } int gravitate_brick(struct game_state *game_state) { game_state->current_brick.position.y++; if (brick_collides_grid(game_state->current_brick, *game_state) || brick_collides_y(game_state->current_brick)) { game_state->current_brick.position.y--; brick_to_grid(game_state->current_brick, game_state); return 0; } return 1; } void brick_to_grid(struct brick brick, struct game_state *game_state) { for (int i = 0; i < 4; ++i) { struct position tile_pos = brick.states[brick.rotation].tiles[i]; tile_pos.x += brick.position.x; tile_pos.y += brick.position.y; game_state->grid[tile_pos.x][tile_pos.y] = 1; } }