diff options
Diffstat (limited to '2048_clean.c')
| -rw-r--r-- | 2048_clean.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/2048_clean.c b/2048_clean.c new file mode 100644 index 0000000..ac58325 --- /dev/null +++ b/2048_clean.c @@ -0,0 +1,202 @@ +#include <ncurses.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + +#define waddstr_(text) waddstr(main_window, text) +#define waddch_(ch) waddch(main_window, ch) +#define wprintw_(format, data) wprintw(main_window, format, data) +#define newline waddch_('\n') + +#define repeat(i, n) for (int i = 0; i < n; ++i) + +#define get_tile_at(k) (grid + y * ((x + size) % (size + 1) + k * x) + (size + 1 - y) * i) + +WINDOW *main_window; +char *message = "\0"; +int size, num_rows, num_columns, new_tile_pos, num_empty_slots, changed, last_empty_tile_index, *last_non_empty_tile, + *this_tile, grid_buf[128], *grid = grid_buf; + +void draw_frame_1() { + waddch_('+'); + repeat(i, 8 * size - 1) { + waddch_('-'); + } + waddch_('+'); + newline; +} + +void draw_frame_2() { + waddch_('|'); + repeat(i, size) { + repeat(j, 8) { + waddch_(32); + } + waddch_('\b'); + waddch_('|'); + } + newline; +} + +void show_grid() { + draw_frame_1(); + repeat(i, size) { + draw_frame_2(); + + waddstr_("| "); + repeat(j, size) { + if (!*grid) { + waddstr_(" | "); + } else if (*grid >= 1024) { + wprintw_(" %2dk | ", *grid / 1024); + } else { + wprintw_("%4d | ", *grid); + } + ++grid; + } + newline; + + draw_frame_2(); + + if (i < size - 1) { + waddch_('|'); + repeat(j, size) { + repeat(j, 8) { + waddch_('-'); + } + waddch_('\b'); + if (j < size - 1) { + waddch_('+'); + } + } + waddch_('|'); + newline; + } + } + draw_frame_1(); + grid -= size * size; +} + +int move_grid(int x, int y, int do_change) { + changed = 0; + repeat(i, size) { + last_empty_tile_index = 0; + last_non_empty_tile = 0; + repeat(j, size) { + this_tile = get_tile_at(j); + if (*this_tile) { + if (last_non_empty_tile && *this_tile == *last_non_empty_tile) { + if (do_change) { + *last_non_empty_tile *= 2; + *this_tile = 0; + } + last_non_empty_tile = 0; + changed = 1; + } else { + last_non_empty_tile = get_tile_at(last_empty_tile_index); + if (do_change) { + *last_non_empty_tile = *this_tile; + } + ++last_empty_tile_index; + } + } + } + for (; last_empty_tile_index < size; ++last_empty_tile_index) { + this_tile = get_tile_at(last_empty_tile_index); + changed |= *this_tile; + if (do_change) { + *this_tile = 0; + } + } + } + return !changed; +} + +void put_new_tile() { + num_empty_slots = 0; + repeat(i, size * size) { + if (!grid[i]) { + ++num_empty_slots; + } + } + if (num_empty_slots == 0) { + return; + } + new_tile_pos = rand() % num_empty_slots; + repeat(i, size * size) { + if (!grid[i] && --num_empty_slots == new_tile_pos) { + grid[i] = rand() % 8 ? 2 : 4; + } + } +} + +int main(int argc, char **argv) { + srand(time(0)); + + initscr(); + cbreak(); + noecho(); + curs_set(0); + getmaxyx(stdscr, num_rows, num_columns); + + size = argc > 1 ? (*argv[1] - '0') : 4; + if (size <= 1 || size > 8) { + message = "\1Invalid size given.\n"; + goto quit; + } + + main_window = newwin(0, 0, (num_rows - 4 * size) / 2, (num_columns - 8 * size) / 2); + if (!main_window) { + message = "\1Terminal too small.\n"; + goto quit; + } + + put_new_tile(); + put_new_tile(); + + while (1) { + wclear(main_window); + show_grid(); + waddstr_(" h,j,k,l: move q: quit"); + wrefresh(main_window); + + switch (wgetch(main_window)) { + case 'q': + goto quit; + + case 'h': + move_grid(1, 1, 1); + goto move_end; + case 'j': + move_grid(-1, size, 1); + goto move_end; + case 'k': + move_grid(1, size, 1); + goto move_end; + case 'l': + move_grid(-1, 1, 1); + goto move_end; + + move_end: + if (changed) { + put_new_tile(); + } + if (move_grid(1, 1, 0) & move_grid(-1, 1, 0) & move_grid(1, size, 0) & move_grid(-1, size, 0)) { + message = "\0Game over.\n"; + goto quit; + } + usleep(2048 * 8); + break; + } + } + +quit: + if (main_window) { + delwin(main_window); + } + endwin(); + + fputs(message + 1, stderr); + return *message; +} |
