aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Kramkowski <tk@the-tk.com>2015-03-22 23:36:32 +0000
committerTomasz Kramkowski <tk@the-tk.com>2015-03-22 23:36:32 +0000
commit269f812561a39e085cc33e864b82e631d8edbb87 (patch)
treea11c0530be1678623eded501a0835599523d1b59
parent6e04d4bb23075ccb35649efd886ba4a3a425f9c7 (diff)
downloadc-stuff-269f812561a39e085cc33e864b82e631d8edbb87.tar.gz
c-stuff-269f812561a39e085cc33e864b82e631d8edbb87.tar.xz
c-stuff-269f812561a39e085cc33e864b82e631d8edbb87.zip
snake.c: Visual enhancements and argument parsing.
-rw-r--r--snake.c107
1 files 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 <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;
}