diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cd531cf --- /dev/null +++ b/.gitignore @@ -0,0 +1,54 @@ +# ---> C +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..66d1277 --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +CC = gcc +FLAGS = -Wall -g +LFLAGS = -lcatwalk + +all: bin/catwalk + +bin/catwalk: obj/main.o obj/interact.o obj/print.o obj/simplegen.o + @mkdir -p $(@D) + $(CC) $(FLAGS) -o $@ $(LFLAGS) $^ + +obj/%.o: src/%.c + @mkdir -p $(@D) + $(CC) $(FLAGS) -o $@ -c $< + +obj/main.o: src/main.c +obj/interact.o: src/interact.c +obj/print.o: src/print.c +obj/simplegen.o: src/simplegen.c + +.PHONY: clean mrproper install +clean: + rm -rf obj +mrproper: clean + rm -rf bin + +install: bin/catwalk + @mkdir -p /usr/local/bin/ + cp bin/catwalk /usr/local/bin/ diff --git a/bin/catwalk b/bin/catwalk new file mode 100755 index 0000000..6ccf49e Binary files /dev/null and b/bin/catwalk differ diff --git a/src/interact.c b/src/interact.c new file mode 100644 index 0000000..1271278 --- /dev/null +++ b/src/interact.c @@ -0,0 +1,307 @@ +/* CATWALK - Test your logic + Copyright (C) 2021 Valentin Moguerou + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULIAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see */ + +#include +#include + +#include +#include + +#include "print.h" +#include "interact.h" + +#define COMMAND_MAX_SIZE 100 +#define STR_STARTS_WITH(s1, s2) (strncmp(s1, s2, strlen(s2)) == 0) + +void print_help() +{ + printf(" | [l]eft, [r]ight - move towards the specified direction\n"); + printf(" | [u]p, [d]own - move towards the specified direction\n"); + printf(" | undo, z - undo the last move\n"); + printf(" | [r]eset - reset the grid\n"); + printf(" | help, ? - show this help\n"); + printf(" | [s]how - show the current grid\n"); + printf(" | exit, [q]uit - exit the program\n"); +} + +void clear_buffer() +{ + int c = 0; + while (c != '\n' && c != EOF) + { + c = getchar(); + } +} + +int is_whitespace(char *str) +{ + if (*str == '\0') + { + return 1; + } + for (char *chr=str; *chr; chr++) + { + if (*chr != ' ' && *chr != '\t') + { + return 0; + } + } + return 1; +} + +void ltrim(char *dest, char *src) +{ + char *ch = src; + while (*ch) + { + if (*ch != ' ' && *ch != '\t') + { + break; + } + ch++; + } + strcpy(dest, ch); +} + +int read_from_stdin(char *str, int length) +{ + char *entry_position = NULL; + + if (fgets(str, length, stdin) != NULL) + { + entry_position = strchr(str, '\n'); + if (entry_position != NULL) + { + *entry_position = '\0'; + } + else + { + clear_buffer(); + } + return 1; + } + else + { + clear_buffer(); + return 0; + } +} + +void interact(int width) +{ + grid *gd = init_grid(width); + + printf("Welcome to Catwalk CLI. Type 'help' or '?' to see all available commands.\n"); + char prompt[COMMAND_MAX_SIZE] = ""; + char buffer[COMMAND_MAX_SIZE] = ""; + + refresh_grid(gd); + init_player_route(gd); + + for(;;) + { + if (is_whitespace(prompt)) + { + printf("catwalk> "); + read_from_stdin(prompt, COMMAND_MAX_SIZE); + ltrim(buffer, prompt); + strcpy(prompt, buffer); + } + else + { + if STR_STARTS_WITH(prompt, "help") + { + print_help(); + strcpy(buffer, prompt+strlen("help")); + ltrim(prompt, buffer); + } + else if STR_STARTS_WITH(prompt, "?") + { + print_help(); + strcpy(buffer, prompt+strlen("?")); + ltrim(prompt, buffer); + } + else if STR_STARTS_WITH(prompt, "show") + { + print_interactive_grid(gd); + strcpy(buffer, prompt+strlen("show")); + ltrim(prompt, buffer); + } + else if STR_STARTS_WITH(prompt, "reset") + { + if (gd->player_route->first->next == NULL) + { + printf("Play first!\n"); + } + else + { + delete_element(gd->player_route->first->next); + gd->player_route->first->next = NULL; + gd->player_route->last = gd->player_route->first; + } + strcpy(buffer, prompt+strlen("reset")); + ltrim(prompt, buffer); + } + else if STR_STARTS_WITH(prompt, "route") + { + print_route(gd->player_route); + strcpy(buffer, prompt+strlen("route")); + ltrim(prompt, buffer); + } + else if (STR_STARTS_WITH(prompt, "exit") || STR_STARTS_WITH(prompt, "quit") || STR_STARTS_WITH(prompt, "q")) + { + break; + } + else if STR_STARTS_WITH(prompt, "undo") + { + if (gd->player_route->first->next == NULL) + { + printf("Can't undo! (single element)\n"); + } + else + { + pop_back(gd->player_route); + } + strcpy(buffer, prompt+strlen("z")); + ltrim(prompt, buffer); + } + else if STR_STARTS_WITH(prompt, "left") + { + switch (move_left(gd->player_route)) + { + case 1: puts("Cannot move: border of the grid"); break; + case 2: puts("Cannot move: already went there"); break; + } + strcpy(buffer, prompt+strlen("left")); + ltrim(prompt, buffer); + } + else if STR_STARTS_WITH(prompt, "right") + { + switch (move_right(gd->player_route)) + { + case 1: puts("Cannot move: border of the grid"); break; + case 2: puts("Cannot move: already went there"); break; + } + strcpy(buffer, prompt+strlen("right")); + ltrim(prompt, buffer); + } + else if STR_STARTS_WITH(prompt, "up") + { + switch (move_up(gd->player_route)) + { + case 1: puts("Cannot move: border of the grid"); break; + case 2: puts("Cannot move: already went there"); break; + } + strcpy(buffer, prompt+strlen("up")); + ltrim(prompt, buffer); + } + else if STR_STARTS_WITH(prompt, "down") + { + switch (move_down(gd->player_route)) + { + case 1: puts("Cannot move: border of the grid"); break; + case 2: puts("Cannot move: already went there"); break; + } + strcpy(buffer, prompt+strlen("down")); + ltrim(prompt, buffer); + } + else if STR_STARTS_WITH(prompt, "s") + { + print_interactive_grid(gd); + strcpy(buffer, prompt+strlen("s")); + ltrim(prompt, buffer); + } + else if STR_STARTS_WITH(prompt, "l") + { + switch (move_left(gd->player_route)) + { + case 1: puts("Cannot move: border of the grid"); break; + case 2: puts("Cannot move: already went there"); break; + } + strcpy(buffer, prompt+strlen("l")); + ltrim(prompt, buffer); + } + else if STR_STARTS_WITH(prompt, "r") + { + switch (move_right(gd->player_route)) + { + case 1: puts("Cannot move: border of the grid"); break; + case 2: puts("Cannot move: already went there"); break; + } + strcpy(buffer, prompt+strlen("r")); + ltrim(prompt, buffer); + } + else if STR_STARTS_WITH(prompt, "u") + { + switch (move_up(gd->player_route)) + { + case 1: puts("Cannot move: border of the grid"); break; + case 2: puts("Cannot move: already went there"); break; + } + strcpy(buffer, prompt+strlen("u")); + ltrim(prompt, buffer); + } + else if STR_STARTS_WITH(prompt, "d") + { + if (gd->player_route->first->next == NULL) + { + printf("Can't undo! (single element)\n"); + } + else + { + pop_back(gd->player_route); + } + strcpy(buffer, prompt+strlen("undo")); + ltrim(prompt, buffer); + } + else if STR_STARTS_WITH(prompt, "z") + { + switch (move_down(gd->player_route)) + { + case 1: puts("Cannot move: border of the grid"); break; + case 2: puts("Cannot move: already went there"); break; + } + strcpy(buffer, prompt+strlen("d")); + ltrim(prompt, buffer); + } + else + { + printf("Unrecognized command : '%s'!\n", prompt); + prompt[0] = '\0'; + } + } + + + if (gd->player_route->last->x == gd->end[0] && gd->player_route->last->y == gd->end[1]) + { + print_interactive_grid(gd); + if (verify(gd)) + { + printf("You won!\n"); + } + else + { + printf("You lost!\n"); + } + + random_start(gd); + refresh_grid(gd); + reset_player_route(gd); + } + } + + delete_grid(gd); +} diff --git a/src/interact.h b/src/interact.h new file mode 100644 index 0000000..d6da3dc --- /dev/null +++ b/src/interact.h @@ -0,0 +1,32 @@ +/* CATWALK - Test your logic + Copyright (C) 2021 Valentin Moguerou + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULIAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see */ + +#ifndef INTERACT_H_INCLUDED +#define INTERACT_H_INCLUDED + +#include + +void print_help(); + +void clear_buffer(); + +int is_whitespace(char *str); + +int read_from_stdin(char *str, int length); + +void interact(int width); + +#endif /* INTERACT_H_INCLUDED */ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..0ca0ac7 --- /dev/null +++ b/src/main.c @@ -0,0 +1,100 @@ +/* CATWALK - Test your logic + Copyright (C) 2021 Valentin Moguerou + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULIAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see */ + +#include +#include +#include +#include + +#include + +#include "interact.h" +#include "simplegen.h" + +#define PROGRAM_VERSION "1.0" + +void help(char *program_name) +{ + printf("\ +Usage : %s [parameters]\n", + program_name); + puts("\n\ + -h, --help Print this help.\n\ + -v, --version Print version info.\n\ + -i, --interactive Launch catwalk-cli in interactive mode (default\n\ + -s, --simple Create a grid, without permitting to play.\n\ + -w, --width Create a grid with the given width.\n\ +--interactive, --simple, --help and --version are mutually exclusive: the last argument is kept.\n\n\ +This program was made with love by Valentin Moguerou ."); +} + +void version() +{ + printf("Catwalk CLI version 1.0\n"); +} + +int main(int argc, char **argv) +{ + int width = 4; + char mode = 'i'; + for (int i=1; i */ + +#include + +#include +#include + +#include "print.h" + +//#define COLORED_PATH +#ifdef COLORED_PATH +# define KNRM "\e[0m" +# define KRED "\e[31m" +#endif + +const char ASCII_START[GRID_CELL_H][GRID_CELL_W] += { + {' ', ' ', '/', '\\', ' ', ' ', ' '}, + {' ', '/', '\\', ' ', '\\', '/', ' '}, + {' ', ' ', ' ', '\\', '/', ' ', ' '} +}; + +const char ASCII_CAT[GRID_CELL_H][GRID_CELL_W] += { + {' ', '/', '\\', '_', '/', '\\', ' '}, + {'(', ' ', 'o', '.', 'o', ' ', ')'}, + {' ', '>', ' ', '^', ' ', '<', ' '} +}; + +const char ASCII_MILK[GRID_CELL_H][GRID_CELL_W] += { + {' ', ' ', '=', '=', ' ', ' ', ' '}, + {' ', '/', 'm', 'i', '\\', ' ', ' '}, + {' ', '\\', 'l', 'k', '/', ' ', ' '} +}; + +void print_interactive_grid(grid *gd) +{ + element *pos = gd->player_route->last; // define pointer to last element of player route + element *el; + for (int y=0; y<(gd->width+1)*(GRID_CELL_H+1); y++) // for each line + { + for (int x=0; x<(gd->width+1)*(GRID_CELL_W+1); x++) // for each column + { + if (xhints->x[x/(GRID_CELL_W+1)-1]); + } + else if (x == GRID_CELL_W/2 && y%(GRID_CELL_H+1) == GRID_CELL_H/2) // left indicators + { + printf("%d", gd->hints->y[y/(GRID_CELL_H+1)-1]); + } + else + { + putchar(CELL_FILL_CHAR); // blank space around numbers + } + } + else // else if body (cells) + { + if ((x+1)%(GRID_CELL_W+1) == 0 && (y+1)%(GRID_CELL_H+1) == 0) + { + putchar(CELL_NODE_CHAR); // cell border intersections + } + else if ((y+1)%(GRID_CELL_H+1) == 0) + { + putchar(HO_BORDER_CHAR); // cell horizontal borders + } + else if ((x+1)%(GRID_CELL_W+1) == 0) + { + putchar(VE_BORDER_CHAR); // cell vertical borders + } + else // if inside cells + { + if (x/(GRID_CELL_W+1)-1 == pos->x && y/(GRID_CELL_H+1)-1 == pos->y) // if cursor position corresponds to the player position + { + putchar(ASCII_CAT[y%(GRID_CELL_H+1)][x%(GRID_CELL_W+1)]); + } + else if (x/(GRID_CELL_W+1)-1 == gd->start[0] && y/(GRID_CELL_H+1)-1 == gd->start[1]) // if the player has moved, if cursor position corresponds to the cat position + { + putchar(ASCII_START[y%(GRID_CELL_H+1)][x%(GRID_CELL_W+1)]); + } + else if (x/(GRID_CELL_W+1)-1 == gd->end[0] && y/(GRID_CELL_H+1)-1 == gd->end[1]) // if corresponds to the milk position + { + putchar(ASCII_MILK[y%(GRID_CELL_H+1)][x%(GRID_CELL_W+1)]); + } + else if (!is_free(gd->player_route, x/(GRID_CELL_W+1)-1, y/(GRID_CELL_H+1)-1)) + { + if (!el) + { + el = find_coordinates(gd->player_route, x/(GRID_CELL_W+1)-1, y/(GRID_CELL_H+1)-1); + } + else if (el->x!=x/(GRID_CELL_W+1)-1 || el->y!=y/(GRID_CELL_H+1)-1) + { + el = find_coordinates(gd->player_route, x/(GRID_CELL_W+1)-1, y/(GRID_CELL_H+1)-1); + } + if (x%(GRID_CELL_W+1) == GRID_CELL_W/2 && y%(GRID_CELL_H+1) == GRID_CELL_H/2) + { + #ifdef COLORED_PATH + printf("%s%c%s", KRED, CELL_NODE_CHAR, KNRM); + #else + putchar(CELL_NODE_CHAR); + #endif + } + else if (x%(GRID_CELL_W+1) == GRID_CELL_W/2 || y%(GRID_CELL_H+1) == GRID_CELL_H/2) + { + if (x%(GRID_CELL_W+1) < GRID_CELL_W/2 && is_left(el, el->previous)) + { + #ifdef COLORED_PATH + printf("%s%c%s", KRED, HO_BORDER_CHAR, KNRM); + #else + putchar(HO_BORDER_CHAR); + #endif + } + else if (x%(GRID_CELL_W+1) > GRID_CELL_W/2 && is_right(el, el->previous)) + { + #ifdef COLORED_PATH + printf("%s%c%s", KRED, HO_BORDER_CHAR, KNRM); + #else + putchar(HO_BORDER_CHAR); + #endif + } + else if (y%(GRID_CELL_H+1) < GRID_CELL_H/2 && is_up(el, el->previous)) + { + #ifdef COLORED_PATH + printf("%s%c%s", KRED, VE_BORDER_CHAR, KNRM); + #else + putchar(VE_BORDER_CHAR); + #endif + } + else if (y%(GRID_CELL_H+1) > GRID_CELL_H/2 && is_down(el, el->previous)) + { + #ifdef COLORED_PATH + printf("%s%c%s", KRED, VE_BORDER_CHAR, KNRM); + #else + putchar(VE_BORDER_CHAR); + #endif + } + else if (x%(GRID_CELL_W+1) < GRID_CELL_W/2 && is_left(el, el->next)) + { + #ifdef COLORED_PATH + printf("%s%c%s", KRED, HO_BORDER_CHAR, KNRM); + #else + putchar(HO_BORDER_CHAR); + #endif + } + else if (x%(GRID_CELL_W+1) > GRID_CELL_W/2 && is_right(el, el->next)) + { + #ifdef COLORED_PATH + printf("%s%c%s", KRED, HO_BORDER_CHAR, KNRM); + #else + putchar(HO_BORDER_CHAR); + #endif + } + else if (y%(GRID_CELL_H+1) < GRID_CELL_H/2 && is_up(el, el->next)) + { + #ifdef COLORED_PATH + printf("%s%c%s", KRED, VE_BORDER_CHAR, KNRM); + #else + putchar(VE_BORDER_CHAR); + #endif + } + else if (y%(GRID_CELL_H+1) > GRID_CELL_H/2 && is_down(el, el->next)) + { + #ifdef COLORED_PATH + printf("%s%c%s", KRED, VE_BORDER_CHAR, KNRM); + #else + putchar(VE_BORDER_CHAR); + #endif + } + else + { + putchar(CELL_FILL_CHAR); + } + } + else + { + putchar(CELL_FILL_CHAR); + } + } + else // if cursor position corresponds to nothing + { + putchar(CELL_FILL_CHAR); + } + } + } + } + putchar('\n'); // newline + } +} + + +void print_simple_grid(grid *gd) +{ + for (int y=0; y<(gd->width+1)*(GRID_CELL_H+1); y++) // for each line + { + for (int x=0; x<(gd->width+1)*(GRID_CELL_W+1); x++) // for each column + { + if (xhints->x[x/(GRID_CELL_W+1)-1]); + } + else if (x == GRID_CELL_W/2 && y%(GRID_CELL_H+1) == GRID_CELL_H/2) // left indicators + { + printf("%d", gd->hints->y[y/(GRID_CELL_H+1)-1]); + } + else + { + putchar(CELL_FILL_CHAR); // blank space around numbers + } + } + else // else if body (cells) + { + if ((x+1)%(GRID_CELL_W+1) == 0 && (y+1)%(GRID_CELL_H+1) == 0) + { + putchar(CELL_NODE_CHAR); // cell border intersections + } + else if ((y+1)%(GRID_CELL_H+1) == 0) + { + putchar(HO_BORDER_CHAR); // cell horizontal borders + } + else if ((x+1)%(GRID_CELL_W+1) == 0) + { + putchar(VE_BORDER_CHAR); // cell vertical borders + } + else // if inside cells + { + if (x/(GRID_CELL_W+1)-1 == gd->start[0] && y/(GRID_CELL_H+1)-1 == gd->start[1]) + { + putchar(ASCII_CAT[y%(GRID_CELL_H+1)][x%(GRID_CELL_W+1)]); + } + else if (x/(GRID_CELL_W+1)-1 == gd->end[0] && y/(GRID_CELL_H+1)-1 == gd->end[1]) + { + putchar(ASCII_MILK[y%(GRID_CELL_H+1)][x%(GRID_CELL_W+1)]); + } + else + { + putchar(CELL_FILL_CHAR); + } + } + } + } + putchar('\n'); // newline + } +} + +void print_indicators(grid *gd) +{ + printf("Indicators :\nX: "); + int i; + for (i=0; iwidth; i++) + { + printf("%d ", gd->hints->x[i]); + } + printf("\nY: "); + for (i=0; iwidth; i++) + { + printf("%d ", gd->hints->y[i]); + } + printf("\n"); +} + +void print_route(route *rt) +{ + element *el = rt->first; + printf("[(%d, %d)", el->x, el->y); + el = el->next; + while (el) + { + printf(", (%d, %d)", el->x, el->y); + el = el->next; + } + printf("]\n"); +} diff --git a/src/print.h b/src/print.h new file mode 100644 index 0000000..dc5f892 --- /dev/null +++ b/src/print.h @@ -0,0 +1,36 @@ +/* CATWALK - Test your logic + Copyright (C) 2021 Valentin Moguerou + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULIAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see */ + +#ifndef PRINT_H_INCLUDED +#define PRINT_H_INCLUDED + +#include +#include + +void print_interactive_grid(grid *gd); +void print_simple_grid(grid *gd); +void print_indicators(grid *gd); +void print_route(route *rt); + +#define GRID_CELL_H 3 +#define GRID_CELL_W 7 + +#define CELL_FILL_CHAR ' ' +#define CELL_NODE_CHAR '+' +#define HO_BORDER_CHAR '-' +#define VE_BORDER_CHAR '|' + +#endif /* PRINT_H_INCLUDED */ diff --git a/src/simplegen.c b/src/simplegen.c new file mode 100644 index 0000000..5cc6748 --- /dev/null +++ b/src/simplegen.c @@ -0,0 +1,31 @@ +/* CATWALK - Test your logic + Copyright (C) 2021 Valentin Moguerou + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULIAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see */ + +#include + +#include + +#include "print.h" + +void simple_generation(int width) +{ + grid *gd = init_grid(width); + refresh_grid(gd); + + print_simple_grid(gd); + + delete_grid(gd); +} diff --git a/src/simplegen.h b/src/simplegen.h new file mode 100644 index 0000000..f3d8cdb --- /dev/null +++ b/src/simplegen.h @@ -0,0 +1,22 @@ +/* CATWALK - Test your logic + Copyright (C) 2021 Valentin Moguerou + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULIAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see */ + +#ifndef SIMPLEGEN_H_INCLUDED +#define SIMPLEGEN_H_INCLUDED + +void simple_generation(int width); + +#endif /* SIMPLEGEN_H_INCLUDED */