Click here to Skip to main content
15,881,938 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
#ifndef MY_GAME_H
#define MY_GAME_H
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <curses.h>

#define EMPTY ' '
#define BORDER '*'
#define PLAYER 'P'
#define GOAL 'G'
#define COLLAPSED 'X'

typedef struct position {
    int row;
    int col;
} Position;

typedef struct node {
    Position pos;
    char collapsed_color;
    struct node* next;
} Node;

typedef struct list {
    Node* head;
    int size;
} List;

int ROW, COL;
char** map;
Position player, goal;
List history;

void initialize() {
    int i, j;

    map = (char**)malloc(ROW * sizeof(char*));
    for (i = 0; i < ROW; i++) {
        map[i] = (char*)malloc(COL * sizeof(char));
        for (j = 0; j < COL; j++) {
            if (i == 0 || i == ROW - 1 || j == 0 || j == COL - 1) {
                map[i][j] = BORDER;
            }
            else {
                map[i][j] = EMPTY;
            }
        }
    }

    map[player.row][player.col] = PLAYER;
    map[goal.row][goal.col] = GOAL;
}


void print_map() {
    int i, j;
    clear(); // Clear the virtual screen
    for (i = 0; i < ROW; i++) {
        for (j = 0; j < COL; j++) {
            if (i == player.row && j == player.col) {
                attron(COLOR_PAIR(1));
                addch(map[i][j]);
                attroff(COLOR_PAIR(1));
            }
            else if (i == goal.row && j == goal.col) {
                attron(COLOR_PAIR(2));
                addch(map[i][j]);
                attroff(COLOR_PAIR(2));
            }
            else if (map[i][j] == COLLAPSED) {
                if (i == history.head->pos.row && j == history.head->pos.col) {
                    attron(COLOR_PAIR(3));
                    addch(map[i][j]);
                    attroff(COLOR_PAIR(3));
                }
                else {
                    addch(map[i][j]);
                }
            }
            else {
                addch(map[i][j]);
            }
        }
        addch('\n');
    }
    refresh(); // Update the physical screen
}



void collapse_floor() {
    int i, j;
    Node* new_node = (Node*)malloc(sizeof(Node));
    new_node->collapsed_color = 'r';
    do {
        new_node->pos.row = rand() % (ROW - 2) + 1;
        new_node->pos.col = rand() % (COL - 2) + 1;
    } while (map[new_node->pos.row][new_node->pos.col] != EMPTY);
    new_node->next = history.head;
    history.head = new_node;
    history.size++;

    map[new_node->pos.row][new_node->pos.col] = COLLAPSED;
}

void move_player(int row_offset, int col_offset) {
    if (map[player.row + row_offset][player.col + col_offset] == EMPTY) {
        map[player.row][player.col] = EMPTY;
        player.row += row_offset;
        player.col += col_offset;
        map[player.row][player.col] = PLAYER;

        collapse_floor();
    }
    else if (map[player.row + row_offset][player.col + col_offset] == GOAL){
        map[player.row][player.col] = EMPTY;
        player.row += row_offset;
        player.col += col_offset;
        map[player.row][player.col] = PLAYER;
        print_map();
        printf("\nYou Win!\n");
        exit(0);
    }
}

void undo_move() {
    if (history.size > 1) {
        Node* old_node = history.head;
        history.head = history.head->next;
        history.size--;

        if (map[player.row][player.col] == COLLAPSED) {
            map[player.row][player.col] = EMPTY;
        }

        player = history.head->pos;

        if (map[player.row][player.col] == COLLAPSED) {
            map[player.row][player.col] = PLAYER;
            map[old_node->pos.row][old_node->pos.col] = COLLAPSED;
        } else {
            map[player.row][player.col] = PLAYER;
            if (map[old_node->pos.row][old_node->pos.col] == COLLAPSED) {
                map[old_node->pos.row][old_node->pos.col] = EMPTY;
            }
            map[old_node->pos.row][old_node->pos.col] = COLLAPSED;
        }

        free(old_node);
    }
}

void end_game() {
    printf("Game over!\n");
    exit(0);  // Terminate the program with exit status 0 (success)
}


int main(int argc, char* argv[]) {
    int i, j;
    srand(time(NULL));

    int rows, cols, player_row = -1, player_col = -1, goal_row = -1, goal_col = -1;
    char **map;

    FILE *file = fopen("input.txt", "r");
    if (file == NULL) {
        printf("Error: File not found\n");
        exit(1);
    }

    fscanf(file, "%d %d", &rows, &cols);

    map = (char **)malloc(rows * sizeof(char *));
    for (i = 0; i < rows; i++) {
        map[i] = (char *)malloc(cols * sizeof(char));
    }

    for (i = 0; i < rows; i++) {
        for (j = 0; j < cols; j++) {
            fscanf(file, " %c", &map[i][j]);
            if (map[i][j] == 'P') {
                player_row = i;
                player_col = j;
            } else if (map[i][j] == 'G') {
                goal_row = i;
                goal_col = j;
            }
        }
    }

    fclose(file);

    // Check if player and goal positions are within the borders of the map
    if (player_row < 0 || player_row >= rows || player_col < 0 || player_col >= cols ||
        goal_row < 0 || goal_row >= rows || goal_col < 0 || goal_col >= cols) {
        printf("Invalid player or goal position.\n");
        exit(1);
    }

    ROW = rows;
    COL = cols;
    player.row = player_row;
    player.col = player_col;
    goal.row = goal_row;
    goal.col = goal_col;


    history.head = (Node*)malloc(sizeof(Node));
    history.head->pos = player;
    history.head->collapsed_color = 'r';
    history.head->next = NULL;
    history.size = 1;

    initscr();
    start_color();
    init_pair(1, COLOR_BLUE, COLOR_BLACK);
    init_pair(2, COLOR_YELLOW, COLOR_BLACK);
    init_pair(3, COLOR_RED, COLOR_BLACK);

    initialize();

    print_map();

    while (1) {
        int ch = getch();
        switch (ch) {
            case 'w':
                move_player(-1, 0);
                break;
            case 'a':
                move_player(0, -1);
                break;
            case 's':
                move_player(1, 0);
                break;
            case 'd':
                move_player(0, 1);
                break;
            case 'u':
                undo_move();
                break;
            case 'q':
                end_game();
                break;
        }

        if (player.row == goal.row && player.col == goal.col) {
            end_game();
        }

        print_map();
    }

    endwin();

    for (i = 0; i < ROW; i++) {
        free(map[i]);
    }

    free(map);

    while (history.size > 0) {
        undo_move();
    }

    return 0;
}
#endif /* MY_GAME_H */


What I have tried:

In the int main() function, the dimensions of the map, position of player and goal are read off a txt file called input.txt. An example of the txt file would be as follows:
10 20
4 2 P
9 2 G

The code does well to read the dimensions of the map and print it on the terminal accordingly. However, it does not do the same for the position of the Player (P) and the Goal (G) within the map. They are rather printed inside the borders of the map, no matter what positions I may give them. In what way would I update the int main() function so that the txt file is read correctly for the positions.
Posted
Updated 2-Apr-23 14:30pm

I assume that a line like 4 2 P Means that the player is at row 4 column 2.

Take a look at what you have to locate the player and the goal. You're reading in a single character each time, and comparing it to whether it's a 'P' or a 'G', but you never read in the coordinates. What you probably want is something more like
C
int row, column;
char key;
/* read in player position */
fscanf("%d %d %c", &row, &column, &key);
map[row][col] = key;
/* repeat for Goal */
You'll probably want to do error checking, such as checking the row and column are in bounds, and that the key is an expected value.
 
Share this answer
 
As k5054 has already noted, the file is not read correctly. All values from the file are needed to initialize the grid.

I would also avoid the global variables as far as possible. First of all it would make sense to define an own data type for the grid.
C
typedef struct {
    int rows, cols;
    char** map;
    Position player, goal;
    List history;
} Grid;

Then function calls would be possible without the need for global variables.
C
void mallocgrid(Grid* grid);
void freegrid(Grid* grid);
// Check if player and goal positions are within the borders of the map
int checkPGErr(Grid* grid); // return 1 if error

The main program could then look like this:
C
int row = 0, col = 0, cnt;
char key = -1;
Grid grid;

/* read in size of grid */
cnt = fscanf(file, "%d %d", &row, &col);
if (cnt != 2)
   { puts("Error"); return -1; }
grid.rows = row;
grid.cols = col;

grid.player.row = -1;
grid.player.col = -1;
grid.goal.row = 0;
grid.goal.col = 0;

mallocgrid(&grid);   // create grid here

/* read in position for player */
cnt = fscanf(file, "%d %d %c", &row, &col, &key);
if ((cnt != 3) || (key != PLAYER)) 
    { puts("Error: Player not found!"); return -1; }
else {
   grid.player.row = row;
   grid.player.col = col;
   grid.map[row][col] = PLAYER;
}

/* read in position for goal */
cnt = fscanf(file, "%d %d %c", &row, &col, &key);

// ...

freegrid(&grid);
return 0;
}
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900