diff --git a/tetris.c b/tetris.c index aa5d426..c2e3c46 100644 --- a/tetris.c +++ b/tetris.c @@ -2,6 +2,8 @@ #include #include +#include + enum { HEIGHT = 20, WIDTH = 10, @@ -18,7 +20,7 @@ struct rotation { struct brick { struct rotation *states; - int state; + int rotation; struct position position; }; @@ -63,13 +65,8 @@ struct rotation t_brick_rotations[4] = { }; -struct game_state { - char running; - char game_grid[WIDTH][HEIGHT]; - struct brick current_brick; -}; - enum input { + I_NONE, I_QUIT, I_LEFT, I_RIGHT, @@ -77,29 +74,42 @@ enum input { 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(); -/* gravitate brick (darf der das?) */ +int gravitate_brick(struct game_state *game_state); /* (optional) drop brick */ -/* should brick fall? */ - -/* rotate brick */ - /* check for full line */ /* remove full line */ -/* move brick */ +int brick_collides_x(struct brick brick); -/* get input */ +int brick_collides_y(struct brick brick); -/* evaluate input */ +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 */ @@ -108,22 +118,32 @@ 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); - //get input - //evaluate input - //game logic - game_state.current_brick.position.y++; - sleep(1); + 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, - .game_grid = {0}, - .current_brick = spawn_brick() + .grid = {0}, + .current_brick = spawn_brick(), + .tick = 0, }; return game_state; } @@ -131,37 +151,37 @@ struct game_state construct_game_state() { struct brick spawn_brick() { struct brick brick = { .states = t_brick_rotations, - .state = 0, + .rotation = 0, .position = {.x = 3, .y=0} }; return brick; } void draw_game_state(struct game_state game_state) { - system("clear"); + clear(); for (int y = 0; y < HEIGHT; ++y) { - printf("|"); + printw("|"); for (int x = 0; x < WIDTH; ++x) { - if (game_state.game_grid[x][y] + if (game_state.grid[x][y] || brick_on_position(x, y, game_state.current_brick)) { - printf("O"); + printw("O"); } else { - printf(" "); + printw(" "); } } - printf("|\n"); + printw("|\n"); } - printf("|"); + printw("|"); for (int x = 0; x < WIDTH; ++x) { - printf("-"); + printw("-"); } - printf("|\n"); + 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.state]; + 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; @@ -169,3 +189,116 @@ int brick_on_position(int x, int y, struct brick brick) { } 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; + } +}