Advertisement
the_usik

c_island_flyby

Dec 13th, 2021
1,140
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 11.67 KB | None | 0 0
  1. #include <stdbool.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5.  
  6. #define MIN_ROWS_NUMBER 3
  7. #define MAX_ROWS_NUMBER 100
  8.  
  9. #define MIN_COLUMNS_NUMBER 3
  10. #define MAX_COLUMNS_NUMBER 100
  11.  
  12. #define PLAYER_INITIAL_ROW_POSITION 0
  13. #define PLAYER_INITIAL_COLUMN_POSITION 0
  14.  
  15. #define MAP_ISLAND_SYMBOL 0x23
  16. #define MAP_VOID_SYMBOL 0x2e
  17.  
  18. enum direction {
  19.     TOP = 1 << 0,
  20.     BOTTOM = 1 << 1,
  21.     LEFT = 1 << 2,
  22.     RIGHT = 1 << 3
  23. };
  24.  
  25. enum map_cell_type {
  26.     MAP_CELL_VOID = -127,
  27.     MAP_CELL_ISLAND,
  28.     MAP_CELL_MARKED,
  29.     MAP_CELL_ADJACENT,
  30.     MAP_CELL_UNKNOWN
  31. };
  32.  
  33. // Main board structure
  34. typedef struct {
  35.     size_t rows;
  36.     size_t columns;
  37.     char** map;
  38. } board_t;  // 24 bytes
  39.  
  40. typedef struct {
  41.     size_t row;
  42.     size_t column;
  43.     int current_direction;
  44.     int expected_direction;
  45.     bool dead_end;
  46.     bool started;
  47. } player_t;  // 32 bytes
  48.  
  49. // General declarations
  50. void scan_input(char*** map, size_t* rows, size_t* columns);
  51. char** scan_map(size_t rows, size_t columns);
  52.  
  53. // Board declaration
  54. board_t* board_init(char** map, size_t rows, size_t columns);
  55. int board_check(board_t* board);
  56. char board_get_item(board_t* board, size_t row, size_t column);
  57. void board_print(board_t* board);
  58. void board_fill_adjacent_cells(board_t* board);
  59. int board_is_adjacent_cell(board_t* board, size_t row, size_t column);
  60. void board_clear(board_t* board);
  61.  
  62. // Player declartion
  63. player_t* player_init(size_t row, size_t column);
  64. void player_run(player_t* player, board_t* board);
  65. void player_calc_next(player_t* player, board_t* board);
  66. int player_get_adjacent_direction_idx(player_t* player, board_t* board);
  67. int board_is_adjacent_cell(board_t* board, size_t row, size_t column);
  68. int player_get_adjacent_direction(player_t* player, board_t* board, bool marked);
  69. int player_get_expected(player_t* player);
  70. void player_move(player_t* player);
  71.  
  72. // Utils declaration
  73. void panic(const char* const message);
  74. int check_number_range(int n, int min, int max);
  75.  
  76. int main(int argc, char** argv) {
  77.     size_t rows;
  78.     size_t columns;
  79.     char** map;
  80.  
  81.     scan_input(&map, &rows, &columns);
  82.     board_t* board = board_init(map, rows, columns);
  83.     board_check(board);
  84.     board_print(board);
  85.  
  86.     player_t* player = player_init(PLAYER_INITIAL_ROW_POSITION, PLAYER_INITIAL_COLUMN_POSITION);
  87.     player_run(player, board);
  88.  
  89.     board_clear(board);
  90.     return EXIT_SUCCESS;
  91. }
  92.  
  93. // General defintions
  94. void scan_input(char*** map, size_t* rows, size_t* columns) {
  95.     printf("Enter the rows: ");
  96.     scanf("%li", rows);
  97.     if (!check_number_range(*rows, MIN_ROWS_NUMBER, MAX_ROWS_NUMBER)) {
  98.         panic("Invalid rows number. The number must have range from 3 to 100");
  99.     }
  100.  
  101.     printf("Enter the columns: ");
  102.     scanf("%li", columns);
  103.     if (!check_number_range(*columns, MIN_COLUMNS_NUMBER, MAX_COLUMNS_NUMBER)) {
  104.         panic("Invalid columns number. The number must have range from 3 to 100");
  105.     }
  106.  
  107.     // Map input & check
  108.     *map = scan_map(*rows, *columns);
  109. }
  110.  
  111. char** scan_map(size_t rows, size_t columns) {
  112.     char** buffer = malloc(sizeof(char*) * rows);
  113.  
  114.     printf("Enter the island map: (%lix%li)\n", rows, columns);
  115.  
  116.     for (size_t current_row = 0; current_row < rows; current_row++) {
  117.         printf("[%li] > ", current_row);
  118.         char* line = calloc(0, sizeof(char) * columns + 1);
  119.         size_t current_column = 0;
  120.         while (current_column + 1 <= columns) {
  121.             char c = getchar();
  122.             if (c == '\r' || c == '\n') {
  123.                 continue;
  124.             }
  125.  
  126.             line[current_column] = c;
  127.             current_column++;
  128.         }
  129.  
  130.         int length = strlen(line);
  131.  
  132.         if (length != columns) {
  133.             panic("Unexpected line terminate.");
  134.         }
  135.  
  136.         for (size_t i = 0; i < columns; i++) {
  137.             if (line[i] != MAP_VOID_SYMBOL && line[i] != MAP_ISLAND_SYMBOL) {
  138.                 panic("Invalid map symbol. Available symbols: [.#]");
  139.                 break;
  140.             }
  141.         }
  142.  
  143.         buffer[current_row] = line;
  144.     }
  145.  
  146.     return buffer;
  147. }
  148.  
  149. // Board defintions
  150. board_t* board_init(char** map, size_t rows, size_t columns) {
  151.     board_t* board = malloc(sizeof(board_t));
  152.     board->map = map;
  153.     board->rows = rows;
  154.     board->columns = columns;
  155.     board_fill_adjacent_cells(board);
  156.  
  157.     return board;
  158. }
  159.  
  160. int board_check(board_t* board) {
  161.     char* const incorrect = "Incorrect map. Island must've the padding";
  162.  
  163.     for (int column = 0; column < board->columns; column++) {
  164.         if (board->map[0][column] == MAP_ISLAND_SYMBOL || board->map[board->rows - 1][column] == MAP_ISLAND_SYMBOL) {
  165.             panic(incorrect);
  166.         }
  167.     }
  168.  
  169.     for (int row = 0; row < board->rows; row++) {
  170.         if (board->map[row][0] == MAP_ISLAND_SYMBOL || board->map[row][board->columns - 1] == MAP_ISLAND_SYMBOL) {
  171.             panic(incorrect);
  172.         }
  173.     }
  174.  
  175.     int has_island_part = 0;
  176.  
  177.     for (int row = 0; row < board->rows; row++) {
  178.         for (int column = 0; column < board->columns; column++) {
  179.             if (board->map[row][column] == MAP_ISLAND_SYMBOL) {
  180.                 has_island_part = 1;
  181.                 int has_neighbor = 0;
  182.  
  183.                 if (board->map[row - 1][column] == MAP_ISLAND_SYMBOL || board->map[row + 1][column] == MAP_ISLAND_SYMBOL) has_neighbor = 1;
  184.                 if (board->map[row][column - 1] == MAP_ISLAND_SYMBOL || board->map[row][column + 1] == MAP_ISLAND_SYMBOL) has_neighbor = 1;
  185.                 if (!has_neighbor) panic("Incorrect island map. The island must have 1 adjacent cell at the minimum");
  186.             }
  187.         }
  188.     }
  189.  
  190.     if (!has_island_part) {
  191.         panic("Incorrect island map. The island not found.");
  192.     }
  193. }
  194.  
  195. char board_get_item(board_t* board, size_t row, size_t column) {
  196.     if (row < 0 || column < 0) return MAP_CELL_UNKNOWN;
  197.     if (row > board->rows - 1 || column > board->columns - 1) return MAP_CELL_UNKNOWN;
  198.     return board->map[row][column];
  199. }
  200.  
  201. int board_is_adjacent_cell(board_t* board, size_t row, size_t column) {
  202.     return (board_get_item(board, row + -1, column) ||
  203.             board_get_item(board, row + 1, column) ||
  204.             board_get_item(board, row, column + -1) ||
  205.             board_get_item(board, row, column + 1) ||
  206.             board_get_item(board, row + -1, column + 1) ||
  207.             board_get_item(board, row + -1, column + -1) ||
  208.             board_get_item(board, row + 1, column + 1) ||
  209.             board_get_item(board, row + 1, column + -1));
  210. }
  211.  
  212. void board_print(board_t* board) {
  213.     printf("\n== The Island Map ==\n");
  214.     for (int i = 0; i < board->rows; i++) {
  215.         for (int j = 0; j < board->columns; j++) {
  216.             printf("%c", board->map[i][j]);
  217.         }
  218.  
  219.         printf("\n");
  220.     }
  221. }
  222.  
  223. void board_clear(board_t* board) {
  224.     for (size_t row = 0; row < board->rows; row++) {
  225.         free(board->map[row]);
  226.         board->map[row] = NULL;
  227.     }
  228.  
  229.     free(board->map);
  230.     free(board);
  231.     board = NULL;
  232. }
  233.  
  234. void board_fill_adjacent_cells(board_t* board) {
  235.     for (int i = 0; i < board->rows; i++) {
  236.         for (int j = 0; j < board->columns; j++) {
  237.             int adjacent = board_is_adjacent_cell(board, i, j);
  238.             if (adjacent) {
  239.                 board->map[i][j] = MAP_CELL_ADJACENT;
  240.             }
  241.         }
  242.     }
  243. }
  244.  
  245. // Player definitions
  246. player_t* player_init(size_t row, size_t column) {
  247.     player_t* player = malloc(sizeof(player_t));
  248.     player->row = row;
  249.     player->column = column;
  250.     player->expected_direction = RIGHT;
  251.     player->dead_end = false;
  252.     player->started = false;
  253.  
  254.     return player;
  255. }
  256.  
  257. void player_run(player_t* player, board_t* board) {
  258.     while (true) {
  259.         board->map[player->row][player->column] = MAP_CELL_MARKED;
  260.         player_calc_next(player, board);
  261.         player_move(player);
  262.  
  263.         printf("current direction: %i\n", player->current_direction);
  264.         printf("expect direction: %i\n", player->expected_direction);
  265.         printf("player [%li, %li]\n\n", player->row, player->column);
  266.  
  267.         if (player->started && player->row == PLAYER_INITIAL_ROW_POSITION && player->column == PLAYER_INITIAL_COLUMN_POSITION) {
  268.             player->started = false;
  269.             break;
  270.         } else
  271.             player->started = true;
  272.     }
  273. }
  274.  
  275. void player_calc_next(player_t* player, board_t* board) {
  276.     int adjacent = player_get_adjacent_direction(player, board, 0);
  277.     if (adjacent != 0) {
  278.         player->dead_end = false;
  279.         player->current_direction = adjacent & player->expected_direction ? player->expected_direction : player_get_adjacent_direction_idx(player, board);
  280.         player->expected_direction = player_get_expected(player);
  281.     } else {
  282.         int adjacent_marked = player_get_adjacent_direction(player, board, 1);
  283.         if (!player->dead_end) {
  284.             player->dead_end = true;
  285.             player->current_direction = adjacent_marked;
  286.             player->expected_direction = player_get_expected(player);
  287.         }
  288.  
  289.         if (adjacent_marked & player->expected_direction) {
  290.             player->current_direction = player->expected_direction;
  291.             player->expected_direction = player_get_expected(player);
  292.         }
  293.     }
  294. }
  295.  
  296. int player_get_adjacent_direction_idx(player_t* player, board_t* board) {
  297.     int max = 0;
  298.     int maxdir;
  299.     int count;
  300.  
  301.     if (player->current_direction & TOP && (count = board_is_adjacent_cell(board, player->row - 1, player->column)) > max) {
  302.         max = count;
  303.         maxdir = TOP;
  304.     }
  305.  
  306.     if (player->current_direction & BOTTOM && (count = board_is_adjacent_cell(board, player->row + 1, player->column)) > max) {
  307.         max = count;
  308.         maxdir = BOTTOM;
  309.     }
  310.  
  311.     if (player->current_direction & RIGHT && (count = board_is_adjacent_cell(board, player->row, player->column + 1)) > max) {
  312.         max = count;
  313.         maxdir = RIGHT;
  314.     }
  315.  
  316.     if (player->current_direction & LEFT && (count = board_is_adjacent_cell(board, player->row, player->column - 1)) > max) {
  317.         max = count;
  318.         maxdir = LEFT;
  319.     }
  320.  
  321.     return maxdir;
  322. }
  323.  
  324. int player_get_adjacent_direction(player_t* player, board_t* board, bool marked) {
  325.     char bottom = board_get_item(board, player->row + 1, player->column);
  326.     char top = board_get_item(board, player->row - 1, player->column);
  327.     char left = board_get_item(board, player->row, player->column - 1);
  328.     char right = board_get_item(board, player->row, player->column + 1);
  329.  
  330.     int flag = 0;
  331.     if (marked) {
  332.         if (bottom == MAP_CELL_MARKED) flag |= BOTTOM;
  333.         if (top == MAP_CELL_MARKED) flag |= TOP;
  334.         if (left == MAP_CELL_MARKED) flag |= LEFT;
  335.         if (right == MAP_CELL_MARKED) flag |= RIGHT;
  336.         return flag;
  337.     }
  338.  
  339.     if (bottom > 0) flag |= BOTTOM;
  340.     if (top > 0) flag |= TOP;
  341.     if (left > 0) flag |= LEFT;
  342.     if (right > 0) flag |= RIGHT;
  343.     return flag;
  344. }
  345.  
  346. int player_get_expected(player_t* player) {
  347.     if (player->current_direction & BOTTOM) return LEFT;
  348.     if (player->current_direction & TOP) return RIGHT;
  349.     if (player->current_direction & LEFT) return TOP;
  350.     if (player->current_direction & RIGHT) return BOTTOM;
  351.  
  352.     return 0;
  353. }
  354.  
  355. void player_move(player_t* player) {
  356.     int direction = player->current_direction;
  357.     if (direction & TOP)
  358.         player->row--;
  359.     else if (direction & BOTTOM)
  360.         player->row++;
  361.     else if (direction & RIGHT)
  362.         player->column++;
  363.     else if (direction & LEFT)
  364.         player->column--;
  365. }
  366.  
  367. // Utils defintions
  368. int check_number_range(int n, int min, int max) {
  369.     return (n >= min && n <= max);
  370. }
  371.  
  372. void panic(const char* const message) {
  373.     fprintf(stderr, "[\033[0;31merror\033[0m]: %s\n", message);
  374.     exit(EXIT_FAILURE);
  375. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement