diff options
author | Tomasz Kramkowski <tk@the-tk.com> | 2015-03-22 23:36:32 +0000 |
---|---|---|
committer | Tomasz Kramkowski <tk@the-tk.com> | 2015-03-22 23:36:32 +0000 |
commit | 269f812561a39e085cc33e864b82e631d8edbb87 (patch) | |
tree | a11c0530be1678623eded501a0835599523d1b59 | |
parent | 6e04d4bb23075ccb35649efd886ba4a3a425f9c7 (diff) | |
download | c-stuff-269f812561a39e085cc33e864b82e631d8edbb87.tar.gz c-stuff-269f812561a39e085cc33e864b82e631d8edbb87.tar.xz c-stuff-269f812561a39e085cc33e864b82e631d8edbb87.zip |
snake.c: Visual enhancements and argument parsing.
-rw-r--r-- | snake.c | 107 |
1 files changed, 92 insertions, 15 deletions
@@ -1,9 +1,24 @@ +/* + * A simple implementation of the snake game. + * Compile with: `make LDLIBS=-lncurses snake' + * + * Copyright (C) 2015 Tomasz Kramkowski <tk@the-tk.com> + * + * This program is free software. It is licensed under version 3 of the + * GNU General Public License. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see [http://www.gnu.org/licenses/]. + */ +#include <argp.h> #include <ncurses.h> #include <stdbool.h> #include <stdint.h> #include <stdlib.h> #include <unistd.h> +#define USEC_SECOND 1000000 + enum colorpair { C_BLANK = 1, C_WALL, @@ -33,7 +48,7 @@ struct snake { struct segment segments[UINT16_MAX]; uint16_t head, tail; enum direction direction; -} snake; +}; struct apple { uint32_t x, y; @@ -45,12 +60,22 @@ struct { uint32_t width, height; bool running; enum state state; + bool alternate_color; } game; +struct arguments { + useconds_t delay; + uint16_t desired_width, desired_height; + bool alternate_color; +} arguments; + +const char *argp_program_version = "1.0rc1"; +const char *argp_program_bug_address = "<snake@the-tk.com>"; + void init_ncurses(void) { - initscr(); cbreak(); + initscr(); noecho(); nonl(); start_color(); @@ -97,7 +122,7 @@ void print_board(void) for (uint16_t i = game.snake.tail; i <= game.snake.head; i++) { chtype ch; - if (i % 2) + if ((i - game.snake.head * !arguments.alternate_color) % 2) ch = ACS_BLOCK | COLOR_PAIR(C_SEGMENT0); else ch = ACS_BLOCK | COLOR_PAIR(C_SEGMENT1); @@ -160,7 +185,7 @@ inline uint16_t rand_to_max(uint16_t max) return random / (double)RAND_MAX * (double)max; } -bool part_of_snake(uint16_t x, uint16_t y) +inline bool part_of_snake(uint16_t x, uint16_t y) { for (uint16_t i = game.snake.tail; i != game.snake.head; i++) if (game.snake.segments[i].x == x && game.snake.segments[i].y == y) @@ -189,7 +214,8 @@ void replace_apple(void) void simulate(void) { - struct segment *current = &game.snake.segments[game.snake.head]; + struct segment *head = &game.snake.segments[game.snake.head]; + struct segment *tail = &game.snake.segments[game.snake.tail]; int64_t dx = 0, dy = 0, nx, ny; switch (game.snake.direction) { @@ -199,8 +225,8 @@ void simulate(void) case D_RIGHT: dx = 1; break; } - nx = (int64_t)current->x + dx; - ny = (int64_t)current->y + dy; + nx = (int64_t)head->x + dx; + ny = (int64_t)head->y + dy; if (nx < 0 || nx >= game.width || ny < 0 || ny >= game.height) { game.running = false; @@ -217,7 +243,7 @@ void simulate(void) return; } - if (part_of_snake(nx, ny)) { + if (part_of_snake(nx, ny) && !(tail->x == nx && tail->y == ny)) { game.running = false; game.state = S_FAIL; return; @@ -226,28 +252,79 @@ void simulate(void) game.snake.head++; game.snake.segments[game.snake.head].x = nx; game.snake.segments[game.snake.head].y = ny; + game.snake.tail++; } void main_loop(void) { - while (true) { + print_board(); + poll_input(); + + while (game.running) { + usleep(arguments.delay); poll_input(); - if (!game.running) - break; simulate(); - if (!game.running) - break; print_board(); - usleep(100000); } } -int main(void) +error_t parse_arg(int key, char *arg, struct argp_state *state) +{ + struct arguments *arguments = state->input; + + switch (key) { + case 'w': + fprintf(stderr, "Width setting is not yet implemented.\n"); + arguments->desired_width = strtol(arg, NULL, 10); + break; + case 'h': + fprintf(stderr, "Height setting is not yet implemented.\n"); + arguments->desired_height = strtol(arg, NULL, 10); + break; + case 'a': + arguments->alternate_color = true; + break; + case 'd': + arguments->delay = strtod(arg, NULL) * (double)USEC_SECOND; + break; + default: + return ARGP_ERR_UNKNOWN; + } + + return 0; +} + +void parse_args(int argc, char **argv) +{ + char *doc = "An ncurses implementation of snake in c."; + + struct argp_option options[] = { + {"width", 'w', "<width>", 0, "Desired width.", 0}, + {"height", 'h', "<height>", 0, "Desired height.", 0}, + {"alternate", 'a', NULL, 0, "Alternate snake colour.", 0}, + {"delay", 'd', "<seconds>", 0, "Delay between ticks in seconds. (default: 0.1)", 0}, + {0} + }; + + struct argp argp = {options, parse_arg, NULL, doc, NULL, NULL, NULL}; + + arguments.desired_width = 0; + arguments.desired_height = 0; + arguments.alternate_color = false; + arguments.delay = (double)USEC_SECOND * 0.1; + + argp_parse(&argp, argc, argv, 0, 0, &arguments); +} + +int main(int argc, char **argv) { + parse_args(argc, argv); init_ncurses(); init_game(); + main_loop(); + endwin(); return EXIT_SUCCESS; } |