Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define MIN_ROWS_NUMBER 3
- #define MAX_ROWS_NUMBER 100
- #define MIN_COLUMNS_NUMBER 3
- #define MAX_COLUMNS_NUMBER 100
- #define PLAYER_INITIAL_ROW_POSITION 0
- #define PLAYER_INITIAL_COLUMN_POSITION 0
- #define MAP_ISLAND_SYMBOL 0x23
- #define MAP_VOID_SYMBOL 0x2e
- enum direction {
- TOP = 1 << 0,
- BOTTOM = 1 << 1,
- LEFT = 1 << 2,
- RIGHT = 1 << 3
- };
- enum map_cell_type {
- MAP_CELL_VOID = -127,
- MAP_CELL_ISLAND,
- MAP_CELL_MARKED,
- MAP_CELL_ADJACENT,
- MAP_CELL_UNKNOWN
- };
- // Main board structure
- typedef struct {
- size_t rows;
- size_t columns;
- char** map;
- } board_t; // 24 bytes
- typedef struct {
- size_t row;
- size_t column;
- int current_direction;
- int expected_direction;
- bool dead_end;
- bool started;
- } player_t; // 32 bytes
- // General declarations
- void scan_input(char*** map, size_t* rows, size_t* columns);
- char** scan_map(size_t rows, size_t columns);
- // Board declaration
- board_t* board_init(char** map, size_t rows, size_t columns);
- int board_check(board_t* board);
- char board_get_item(board_t* board, size_t row, size_t column);
- void board_print(board_t* board);
- void board_fill_adjacent_cells(board_t* board);
- int board_is_adjacent_cell(board_t* board, size_t row, size_t column);
- void board_clear(board_t* board);
- // Player declartion
- player_t* player_init(size_t row, size_t column);
- void player_run(player_t* player, board_t* board);
- void player_calc_next(player_t* player, board_t* board);
- int player_get_adjacent_direction_idx(player_t* player, board_t* board);
- int board_is_adjacent_cell(board_t* board, size_t row, size_t column);
- int player_get_adjacent_direction(player_t* player, board_t* board, bool marked);
- int player_get_expected(player_t* player);
- void player_move(player_t* player);
- // Utils declaration
- void panic(const char* const message);
- int check_number_range(int n, int min, int max);
- int main(int argc, char** argv) {
- size_t rows;
- size_t columns;
- char** map;
- scan_input(&map, &rows, &columns);
- board_t* board = board_init(map, rows, columns);
- board_check(board);
- board_print(board);
- player_t* player = player_init(PLAYER_INITIAL_ROW_POSITION, PLAYER_INITIAL_COLUMN_POSITION);
- player_run(player, board);
- board_clear(board);
- return EXIT_SUCCESS;
- }
- // General defintions
- void scan_input(char*** map, size_t* rows, size_t* columns) {
- printf("Enter the rows: ");
- scanf("%li", rows);
- if (!check_number_range(*rows, MIN_ROWS_NUMBER, MAX_ROWS_NUMBER)) {
- panic("Invalid rows number. The number must have range from 3 to 100");
- }
- printf("Enter the columns: ");
- scanf("%li", columns);
- if (!check_number_range(*columns, MIN_COLUMNS_NUMBER, MAX_COLUMNS_NUMBER)) {
- panic("Invalid columns number. The number must have range from 3 to 100");
- }
- // Map input & check
- *map = scan_map(*rows, *columns);
- }
- char** scan_map(size_t rows, size_t columns) {
- char** buffer = malloc(sizeof(char*) * rows);
- printf("Enter the island map: (%lix%li)\n", rows, columns);
- for (size_t current_row = 0; current_row < rows; current_row++) {
- printf("[%li] > ", current_row);
- char* line = calloc(0, sizeof(char) * columns + 1);
- size_t current_column = 0;
- while (current_column + 1 <= columns) {
- char c = getchar();
- if (c == '\r' || c == '\n') {
- continue;
- }
- line[current_column] = c;
- current_column++;
- }
- int length = strlen(line);
- if (length != columns) {
- panic("Unexpected line terminate.");
- }
- for (size_t i = 0; i < columns; i++) {
- if (line[i] != MAP_VOID_SYMBOL && line[i] != MAP_ISLAND_SYMBOL) {
- panic("Invalid map symbol. Available symbols: [.#]");
- break;
- }
- }
- buffer[current_row] = line;
- }
- return buffer;
- }
- // Board defintions
- board_t* board_init(char** map, size_t rows, size_t columns) {
- board_t* board = malloc(sizeof(board_t));
- board->map = map;
- board->rows = rows;
- board->columns = columns;
- board_fill_adjacent_cells(board);
- return board;
- }
- int board_check(board_t* board) {
- char* const incorrect = "Incorrect map. Island must've the padding";
- for (int column = 0; column < board->columns; column++) {
- if (board->map[0][column] == MAP_ISLAND_SYMBOL || board->map[board->rows - 1][column] == MAP_ISLAND_SYMBOL) {
- panic(incorrect);
- }
- }
- for (int row = 0; row < board->rows; row++) {
- if (board->map[row][0] == MAP_ISLAND_SYMBOL || board->map[row][board->columns - 1] == MAP_ISLAND_SYMBOL) {
- panic(incorrect);
- }
- }
- int has_island_part = 0;
- for (int row = 0; row < board->rows; row++) {
- for (int column = 0; column < board->columns; column++) {
- if (board->map[row][column] == MAP_ISLAND_SYMBOL) {
- has_island_part = 1;
- int has_neighbor = 0;
- if (board->map[row - 1][column] == MAP_ISLAND_SYMBOL || board->map[row + 1][column] == MAP_ISLAND_SYMBOL) has_neighbor = 1;
- if (board->map[row][column - 1] == MAP_ISLAND_SYMBOL || board->map[row][column + 1] == MAP_ISLAND_SYMBOL) has_neighbor = 1;
- if (!has_neighbor) panic("Incorrect island map. The island must have 1 adjacent cell at the minimum");
- }
- }
- }
- if (!has_island_part) {
- panic("Incorrect island map. The island not found.");
- }
- }
- char board_get_item(board_t* board, size_t row, size_t column) {
- if (row < 0 || column < 0) return MAP_CELL_UNKNOWN;
- if (row > board->rows - 1 || column > board->columns - 1) return MAP_CELL_UNKNOWN;
- return board->map[row][column];
- }
- int board_is_adjacent_cell(board_t* board, size_t row, size_t column) {
- return (board_get_item(board, row + -1, column) ||
- board_get_item(board, row + 1, column) ||
- board_get_item(board, row, column + -1) ||
- board_get_item(board, row, column + 1) ||
- board_get_item(board, row + -1, column + 1) ||
- board_get_item(board, row + -1, column + -1) ||
- board_get_item(board, row + 1, column + 1) ||
- board_get_item(board, row + 1, column + -1));
- }
- void board_print(board_t* board) {
- printf("\n== The Island Map ==\n");
- for (int i = 0; i < board->rows; i++) {
- for (int j = 0; j < board->columns; j++) {
- printf("%c", board->map[i][j]);
- }
- printf("\n");
- }
- }
- void board_clear(board_t* board) {
- for (size_t row = 0; row < board->rows; row++) {
- free(board->map[row]);
- board->map[row] = NULL;
- }
- free(board->map);
- free(board);
- board = NULL;
- }
- void board_fill_adjacent_cells(board_t* board) {
- for (int i = 0; i < board->rows; i++) {
- for (int j = 0; j < board->columns; j++) {
- int adjacent = board_is_adjacent_cell(board, i, j);
- if (adjacent) {
- board->map[i][j] = MAP_CELL_ADJACENT;
- }
- }
- }
- }
- // Player definitions
- player_t* player_init(size_t row, size_t column) {
- player_t* player = malloc(sizeof(player_t));
- player->row = row;
- player->column = column;
- player->expected_direction = RIGHT;
- player->dead_end = false;
- player->started = false;
- return player;
- }
- void player_run(player_t* player, board_t* board) {
- while (true) {
- board->map[player->row][player->column] = MAP_CELL_MARKED;
- player_calc_next(player, board);
- player_move(player);
- printf("current direction: %i\n", player->current_direction);
- printf("expect direction: %i\n", player->expected_direction);
- printf("player [%li, %li]\n\n", player->row, player->column);
- if (player->started && player->row == PLAYER_INITIAL_ROW_POSITION && player->column == PLAYER_INITIAL_COLUMN_POSITION) {
- player->started = false;
- break;
- } else
- player->started = true;
- }
- }
- void player_calc_next(player_t* player, board_t* board) {
- int adjacent = player_get_adjacent_direction(player, board, 0);
- if (adjacent != 0) {
- player->dead_end = false;
- player->current_direction = adjacent & player->expected_direction ? player->expected_direction : player_get_adjacent_direction_idx(player, board);
- player->expected_direction = player_get_expected(player);
- } else {
- int adjacent_marked = player_get_adjacent_direction(player, board, 1);
- if (!player->dead_end) {
- player->dead_end = true;
- player->current_direction = adjacent_marked;
- player->expected_direction = player_get_expected(player);
- }
- if (adjacent_marked & player->expected_direction) {
- player->current_direction = player->expected_direction;
- player->expected_direction = player_get_expected(player);
- }
- }
- }
- int player_get_adjacent_direction_idx(player_t* player, board_t* board) {
- int max = 0;
- int maxdir;
- int count;
- if (player->current_direction & TOP && (count = board_is_adjacent_cell(board, player->row - 1, player->column)) > max) {
- max = count;
- maxdir = TOP;
- }
- if (player->current_direction & BOTTOM && (count = board_is_adjacent_cell(board, player->row + 1, player->column)) > max) {
- max = count;
- maxdir = BOTTOM;
- }
- if (player->current_direction & RIGHT && (count = board_is_adjacent_cell(board, player->row, player->column + 1)) > max) {
- max = count;
- maxdir = RIGHT;
- }
- if (player->current_direction & LEFT && (count = board_is_adjacent_cell(board, player->row, player->column - 1)) > max) {
- max = count;
- maxdir = LEFT;
- }
- return maxdir;
- }
- int player_get_adjacent_direction(player_t* player, board_t* board, bool marked) {
- char bottom = board_get_item(board, player->row + 1, player->column);
- char top = board_get_item(board, player->row - 1, player->column);
- char left = board_get_item(board, player->row, player->column - 1);
- char right = board_get_item(board, player->row, player->column + 1);
- int flag = 0;
- if (marked) {
- if (bottom == MAP_CELL_MARKED) flag |= BOTTOM;
- if (top == MAP_CELL_MARKED) flag |= TOP;
- if (left == MAP_CELL_MARKED) flag |= LEFT;
- if (right == MAP_CELL_MARKED) flag |= RIGHT;
- return flag;
- }
- if (bottom > 0) flag |= BOTTOM;
- if (top > 0) flag |= TOP;
- if (left > 0) flag |= LEFT;
- if (right > 0) flag |= RIGHT;
- return flag;
- }
- int player_get_expected(player_t* player) {
- if (player->current_direction & BOTTOM) return LEFT;
- if (player->current_direction & TOP) return RIGHT;
- if (player->current_direction & LEFT) return TOP;
- if (player->current_direction & RIGHT) return BOTTOM;
- return 0;
- }
- void player_move(player_t* player) {
- int direction = player->current_direction;
- if (direction & TOP)
- player->row--;
- else if (direction & BOTTOM)
- player->row++;
- else if (direction & RIGHT)
- player->column++;
- else if (direction & LEFT)
- player->column--;
- }
- // Utils defintions
- int check_number_range(int n, int min, int max) {
- return (n >= min && n <= max);
- }
- void panic(const char* const message) {
- fprintf(stderr, "[\033[0;31merror\033[0m]: %s\n", message);
- exit(EXIT_FAILURE);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement