From 269f812561a39e085cc33e864b82e631d8edbb87 Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Sun, 22 Mar 2015 23:36:32 +0000 Subject: snake.c: Visual enhancements and argument parsing. --- snake.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 92 insertions(+), 15 deletions(-) diff --git a/snake.c b/snake.c index bda1c1d..50adaed 100644 --- a/snake.c +++ b/snake.c @@ -1,9 +1,24 @@ +/* + * A simple implementation of the snake game. + * Compile with: `make LDLIBS=-lncurses snake' + * + * Copyright (C) 2015 Tomasz Kramkowski + * + * 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 #include #include #include #include #include +#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 = ""; + 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', "", 0, "Desired width.", 0}, + {"height", 'h', "", 0, "Desired height.", 0}, + {"alternate", 'a', NULL, 0, "Alternate snake colour.", 0}, + {"delay", 'd', "", 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; } -- cgit v1.2.3-54-g00ecf