Thread: 2D Array Cave Game

  1. #1
    Registered User
    Join Date
    Apr 2016
    Posts
    48

    2D Array Cave Game

    Hello, I'm a real noob in C programming, started about 2 months ago. I'm posting in this section because I'm not sure if my problem is advanced/specific enough to be in the game section.

    So, I have this school project where I have to recreate a modified version of the game "Hunt the Wumpus". In this version here what has to happen.

    - There will be 3 abysses, 1 Wumpus and 1 treasure. If you fall on a abyss location or enter the wumpus location, you die.

    - Score : You have one arrow, using it to kill the wumpus. It's used by throwing the arrow in the adjacent place. You get the treasure by going in its location.
    Kill Wumpus : +10k points.
    Get treasure : +1k points.
    Die : -1k points.
    Escape the cave : +1k points. (Return to location [0][0]
    Walk one step : -1 point.

    -Senses:
    If the player is one house away from an abyss or wumpus, he will feel a strong breeze or stench ( B, C). Two houses or diagonal = medium ( Bb, Cc ). Three houses = week ( b, c ).

    So getting to my problems. I'm kinda lost on how to initialize the players, creating a function for the senses and throwing the arrow.

    A friend told me to take a look at a Mine field in c program and use it as a base. So this is basically what I've done until now.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define MAX 1000
    
    typedef struct WumpusWorld{
        int array[12][12];    //Stores the interface
        int arrayB[12][12];    //Stores the world
        int wumpus;            //Stores the monster
        int arrow;            //Stores arrow
        int gold;            //Stores treasure
        int abyss;            //Stores number of abyss
        int steps;          //Stores number of steps 
    }World;
    
    
    //---------------------------------------------------------------------------------------------
    //Function to retrieve players choice. Used to start and exit game.
    //---------------------------------------------------------------------------------------------
        int choice(){
            int option;
            do{
                fflush(stdin);
                scanf("%d", &option);
                if(option < 1 || option > 3)
                {
                    printf("Option not valid. Try again.");
                }
            }
                while(option < 1 || option > 3);
                return option;
                
        } // End of choice function
    
    //---------------------------------------------------------------------------------------------
    //Fuction for initial menu
    //---------------------------------------------------------------------------------------------
    
        int menu1(){
            int option = 0;
            printf("------------------------------------\n");
            printf("|\t\t\t\t\t\|\n");
            printf("|\tWelcome to the World of Wumpus!\t|\n");
            printf("|\t 1-Play 2-Exit \t|\n");
            printf("------------------------------------\n\n");
            option = choice();
            return option;
        } //Function end
    //---------------------------------------------------------------------------------------------    
    //Functions trasforms int to char
    //---------------------------------------------------------------------------------------------
    
        int intchar ( int i){
            switch (i){
                case 0: return '0';
                case 1: return '1';
                case 2: return '2';
                case 3: return '3';
                case 4: return '4';
                case 5: return '5';
                case 6: return '6';
                case 7: return '7';
                case 8: return '8';
                case 9: return '9';
            }
        }
        
    //---------------------------------------------------------------------------------------------    
    //Function to print array
    //---------------------------------------------------------------------------------------------
        
        void Prints(int cont){
            int i,j,lin,col;
            printf("\t 1 2 3 4 5 6 7 8 9 10\n")
            for(i = 0; i < 10;i++){
                printf("%d", i);
                printf("\t");
                for(j = 0; j < 10;j++){
                    printf("[%c]", World[cont].array[i][j]);
                    printf("\n");
            }
            printf("\n[ ]Empty\t [x]Current Position\t [?]Unexplored\t 99 - Exit\n\n");
                }
    }// end of print function
            
    //---------------------------------------------------------------------------------------------
    //Function to generate random abyss positions
    //---------------------------------------------------------------------------------------------
    
    void abyssraffle(int c){
        int lin,col,arm;
        int qnt = 0;
        srand(time(NULL));
        do{
            do{
                lin=rand()%9+1;
                col=rand()%9+1;
                if(World[c].arrayB[lin][col]==9){
                    arm = -1;
                    }else{
                    World[c].arrayB[lin][col]=9;
                    arm = 0;
                    }
            }while(arm==-1);
            qnt++;
        }while(qnt<World[c].abyss);
    }
    
    //---------------------------------------------------------------------------------------------
    //Function to generate wumpus in random position
    //---------------------------------------------------------------------------------------------
    
    void abysswumpus(int w){
        int lin,col,wum;
        int qnt = 0;
        srand(time(NULL));
        do{
            do{
                lin=rand()%9+1;
                col=rand()%9+1;
                if(World[w].arrayB[lin][col]==9){
                    wum = -1;
                    }else{
                    World[w].arrayB[lin][col]=9;
                    wum = 0;
                    }
            }while(wum==-1);
            qnt++;
        }while(qnt<World[w].wumpus);
    }
    
    //---------------------------------------------------------------------------------------------
    //Fucnction to start array empty
    //---------------------------------------------------------------------------------------------
    
    void start(int cont){
        int i,j;                            //Starts world with -1 to indicate empty
        for(i = 0;i < 12;i++)
            for(j = 0;j < 12;j++)
                World[cont].arrayB[i][j]=-1;
                
        for(i = 0;i < 12;i++)                //Starts interface
            for(j = 0;j < 12;j++)
                World[cont].array[i][j]='?';
            
    }
    
    //---------------------------------------------------------------------------------------------
    //Fucnction to move player ( Doubts starting here )
    //---------------------------------------------------------------------------------------------
    
    char move(){
        
        char input;
    
        while (input != 27) {
        
        input = getch();
    
        switch (input) {
            case 119:
                World.array[][]=array[a][b-1]='x';
                World.arrayB[][]=array[a][b-1]=//?;
            break;
    
            case 115:
                World.array[][]=array[a][b+1]='x';
                World.arrayB[][]=array[a][b+1]=//?;
            break;
    
            case 97:
                World.array[][]=array[a-1][b]='x';
                World.arrayB[][]=array[a-1][b]=//?;
            break;
            
            case 100:
                World.array[][]=array[a+1][b]='x';
                World.arrayB[][]=array[a+1][b]=//?;
            break;
        }
    }

  2. #2
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Your friend gave you some bad advice. This problem has only a passing resemblance to minefield. And if the minefield code you found is badly-written then you're copying garbage.

    Your code doesn't even have a main function. Are we to gather that you wrote all this code and haven't even ran it once? That's not the way to go about it.

    You need to write your program a little at a time, creating runnable/testable versions as you go. Put this code aside and begin anew. Create just enough code to fill the matrix with the wumpus, abysses and treasure and print it out to see if it's working correctly.

    I don't see the point in having a separate "interface" and "world".

    Applying fflush() to stdin is at best non-standard, at worst undefined. You really shouldn't use it.

    srand() should only be called once in the program. Put it as the first executable statement in main.

  3. #3
    Registered User
    Join Date
    Apr 2016
    Posts
    48
    Quote Originally Posted by algorism View Post
    I don't see the point in having a separate "interface" and "world".
    I imagined this because the wumpus and abysses locations would be unknown. So while the interface matrix would be in char so the player visually see whats happening, the interface matrix would be "under" the interface with the values of the wumpus and abysses locations and make the action happen. I'm not if I explained correctly.

    And yeah, I'm starting again.

  4. #4
    Registered User
    Join Date
    Apr 2016
    Posts
    48
    Quote Originally Posted by algorism View Post
    You need to write your program a little at a time, creating runnable/testable versions as you go. Put this code aside and begin anew. Create just enough code to fill the matrix with the wumpus, abysses and treasure and print it out to see if it's working correctly.
    So, any next sugesstion ?

    Code:
    lude <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    #define MAX 1000
    
    typedef struct WumpusWorld{
        char array[12][12];    //Stores the interface
        int arrayB[12][12];    //Stores the world
        int wumpus;            //Stores the monster
        int arrow;            //Stores arrow
        int gold;            //Stores treasure
        int abyss;            //Stores number of abyss
        int steps;          //Stores number of steps 
    }World;
    
    //--------------------------------------------------------
    //Starts matrix
    //--------------------------------------------------------
    
    void interface(){
        World world;
        int i,j;    
        for(i = 0;i < 10; i++){
            for(j = 0;j < 10; j++){
                world.array[i][j] = 1;    
            }
        }
        world.array[0][0] = 9;    
    }
    
    //--------------------------------------------------------
    //Genreates random wumpus position
    //--------------------------------------------------------
    
    void generateW( int thing){
        World world;
        int i,j,k;
        for(k = 0; k < thing; k++){
            i=rand()%10;
            j=rand()%10;
            if((world.array[i][j] != 2) && (world.array[i][j] != 3) && (world.array[i][j] != 4) && (world.array[i][j] != 9) ){
            world.array[i][j] = 2;
            }
        }
    }
    
    //--------------------------------------------------------
    //Genreates random abyss position
    //--------------------------------------------------------
    
    void generateA( int thing){
        World world;
        int i,j,k;
        for(k = 0; k < thing; k++){
            i=rand()%10;
            j=rand()%10;
            if((world.array[i][j] != 2) && (world.array[i][j] != 3) && (world.array[i][j] != 4) && (world.array[i][j] != 9) ){
            world.array[i][j] = 3;
            }
        }
    }
    
    //--------------------------------------------------------
    //Genreates random treasure position
    //--------------------------------------------------------
    
    void generateT( int thing){
        World world;
        int i,j,k;
        for(k = 0; k < thing; k++){
            i=rand()%10;
            j=rand()%10;
            if((world.array[i][j] != 2) && (world.array[i][j] != 3) && (world.array[i][j] != 4) && (world.array[i][j] != 9) ){
            world.array[i][j] = 4;
            }
        }
    }
    
    //--------------------------------------------------------
    //Prints the "cave"
    //--------------------------------------------------------
    
    void print(){
        World world;
        int i,j;    
        for(i = 0;i < 10; i++){
            for(j = 0;j < 10; j++){
                if((world.array[i][j] == 1) || (world.array[i][j] == 9) ){
                printf("[-]");    
                }
                else if(world.array[i][j] == 2){
                printf("[W]");
                }
                else if(world.array[i][j] == 3){
                printf("[A]");    
                }
                else if(world.array[i][j] == 4){
                printf("[T]");    
                }
        }
        printf("\n");    
    }    
        
        
        
        
    }
    
    
    int main(){
        
        srand(time(NULL));
        struct WumpusWorld World;
        World.wumpus = 1;
        World.abyss = 3;
        World.gold = 1;
        int i,j;
        
        interface();
        generateW(World.wumpus);
        generateA(World.abyss);
        generateT(World.gold);
        print();
            
    }

  5. #5
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Your explanation for the second array seems reasonable. Alternatively you could use a single array and use lowercase letters for unseen objects and uppercase for seen objects.

    You seem to only be using a 10 by 10 array so why is it declared as 12 by 12? Is that a holdover from the minefield code? It was probably used there to create a border around the board so that special tests for the board's edge could be avoided. But you don't seem to be using it.

    You should use a macro constant for the size (10).
    You should use named constants for 1, 2, 3, 4, 9.
    Your "generate" functions are almost identical. They could be one function.

    Most importantly, all of your functions operate on a local variable (world), and yet it seems to work! What's happening is that the same stack space is being accessed in each function, so it creates the impression that it is correct when it actually isn't. To do it properly you need to pass the struct into the functions, something like this:
    Code:
    void initWorld(World *world) {
        int i, j;
        for (i = 0; i < SIZE; i++)   // assuming SIZE has been declared as 10
            for (j = 0; j < SIZE; j++)
                world->array[i][j] = EMPTY;  // assuming EMPTY has been declared
        world->array[0][0] = EXIT;  // assuming EXIT has been declared (and assuming that's what is meant here)
    }
    
    // from main:
        World world;
        initWorld(&world);

  6. #6
    Registered User
    Join Date
    Apr 2016
    Posts
    48
    Quote Originally Posted by algorism View Post
    Your explanation for the second array seems reasonable. Alternatively you could use a single array and use lowercase letters for unseen objects and uppercase for seen objects.

    You seem to only be using a 10 by 10 array so why is it declared as 12 by 12? Is that a holdover from the minefield code? It was probably used there to create a border around the board so that special tests for the board's edge could be avoided. But you don't seem to be using it.

    You should use a macro constant for the size (10).
    You should use named constants for 1, 2, 3, 4, 9.
    Your "generate" functions are almost identical. They could be one function.

    Most importantly, all of your functions operate on a local variable (world), and yet it seems to work! What's happening is that the same stack space is being accessed in each function, so it creates the impression that it is correct when it actually isn't. To do it properly you need to pass the struct into the functions, something like this:
    Code:
    void initWorld(World *world) {
        int i, j;
        for (i = 0; i < SIZE; i++)   // assuming SIZE has been declared as 10
            for (j = 0; j < SIZE; j++)
                world->array[i][j] = EMPTY;  // assuming EMPTY has been declared
        world->array[0][0] = EXIT;  // assuming EXIT has been declared (and assuming that's what is meant here)
    }
    
    // from main:
        World world;
        initWorld(&world);
    Now that you mentioned it with that "EXIT", I realized that the same place where the player spawns is also the exit. I managed to implement the stuff you said ( I think ), not sure about the constants. So here is the updated code: You can see a failed attempt do make the player move through the cave.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    #include <conio.h>
    
    #define MAX 1000
    #define SIZE 10
    
    #define EMPTY 1
    #define PLAYER 9
    #define WUMPUS 2
    #define ABYSS 3
    #define TREASURE 4
    
    
    typedef struct WumpusWorld{
        char array[SIZE][SIZE];    //Stores the interface
        int arrayB[SIZE][SIZE];    //Stores the world
        int wumpus;            //Stores the monster
        int arrow;            //Stores arrow
        int gold;            //Stores treasure
        int abyss;            //Stores number of abyss
        int steps;          //Stores number of steps 
    }World;
    
    //--------------------------------------------------------
    //Starts matrix and player position
    //--------------------------------------------------------
    
    void initmatrix(World *world){
        int i,j;    
        for(i = 0;i < SIZE; i++){
            for(j = 0;j < SIZE; j++){
                world->array[i][j] = EMPTY;    
            }
        }    
        world->array[0][0] = PLAYER; //Player
    }    
    
    
    //--------------------------------------------------------
    //Genreates random wumpus, abysses and treasure positions
    //--------------------------------------------------------
    
    void generate(World *world, int limit, char object){
        int i,j,k;
        for(k = 0; k < limit; k++){
            i=rand()%10;
            j=rand()%10;
            if((world->array[i][j] != WUMPUS) && (world->array[i][j] != ABYSS) && (world->array[i][j] != TREASURE) && (world->array[i][j] != PLAYER) ){
            world->array[i][j] = object;
            }
        }
    }
    
    //--------------------------------------------------------
    //Prints the "cave"
    //--------------------------------------------------------
    
    void print(World *world){
        int i,j;    
        for(i = 0;i < 10; i++){
            for(j = 0;j < 10; j++){
                if((world->array[i][j] == EMPTY)){
                printf("[-]");    
                }
                else if(world->array[i][j] == WUMPUS){
                printf("[W]");
                }
                else if(world->array[i][j] == ABYSS){
                printf("[A]");    
                }
                else if(world->array[i][j] == TREASURE){
                printf("[T]");    
                }
                else if(world->array[i][j] == PLAYER){
                printf("[X]");    
                }
        }
        printf("\n");    
    }    
    }
    
    //-----------------------------------------------------------
    // Move
    //-----------------------------------------------------------
    
    void move(World *world,char input){
        int i,j;
        switch (input) {
            case 119: //W
            for(i=0; i < 10;i++){
            for(j=0; j < 10;j++){
                if(world->array[i][j] == PLAYER){
                    world->array[i][j] = EMPTY;
                    world->array[i+1][j] = PLAYER;
                    }
                }
            }
            break;
    
            case 115: //S
                for(i=0; i < 10;i++){
                for(j=0; j < 10;j++){
                if(world->array[i][j] == PLAYER){
                    world->array[i][j] = EMPTY;
                    world->array[i-1][j] = PLAYER;
                    }
                }
            }
            break;
    
            case 97: //A
            for(i=0; i < 10;i++){
            for(j=0; j < 10;j++){
                if(world->array[i][j] == PLAYER){
                    world->array[i][j] = EMPTY;
                    world->array[i][j-1] = PLAYER;
                    }
                }
            }
            break;
            
            case 100: //D
            for(i=0; i < 10;i++){
            for(j=0; j < 10;j++){
                if(world->array[i][j] == PLAYER){
                    world->array[i][j] = EMPTY;
                    world->array[i][j+1] = PLAYER;
                    }
                }
            }
            break;
        }
    }
    
    
    int main(){
        
        srand(time(NULL));
        World world;
        world.wumpus = 1;
        world.abyss = 3;
        world.gold = 1;
        
        initmatrix(&world);
        generate(&world, world.wumpus, WUMPUS);
        generate(&world, world.abyss, ABYSS);
        generate(&world, world.gold, TREASURE);
        print(&world);
        
        char input;
        input = getch();
        while ( input != 27){
        move(&world, input);
    
        }
    }

  7. #7
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Not bad.

    I'm assuming that you're allowed to use conio.h, but since it's windows-specific and I'm on linux I had to add a little code to make it work. Alternatively you could use getchar and require that the user press enter after the letter (and you'll need another getchar to eat the newline character). But if you're allowed to use conio.h then that's okay.

    Isn't this
    Code:
            if((world->array[i][j] != WUMPUS) && (world->array[i][j] != ABYSS) && (world->array[i][j] != TREASURE) && (world->array[i][j] != PLAYER) ){
    just a longwinded way to say this
    Code:
            if (world->array[i][j] == EMPTY){
    You should probably change "gold" to "treasure" (or vice-versa). No need for two different terms.

    If you set EMPTY to '-' instead of 1, WUMPUS to 'W' instead of 2, etc., then you could get rid of the switch in print (printWorld is a better name) and replace it with
    Code:
        printf("[%c]", world->array[i][j]);
    For the move function, don't write 119 if you just mean 'W'. Just use 'W'. Ditto for the others keys. You also probably want to allow lowercase, too. So something like:
    Code:
    case 'W': case 'w':
    etc.
    I guess you still have to use 27 for escape, but you could define a constant for it:
    Code:
    #define ESCAPE_KEY 27
    As for your attempted movement, you need to put the getch inside the loop, otherwise you'll only ever read one character (before the loop). And you'll need to display the world again to see the result of the movement.

    Instead of having to search through the array to find the player you could store the player's current position in your struct. Also, you need to ensure that the player doesn't move up if he's on the top row, left if he's in the left column, etc. Your looping tactic is not quite right, anyway, since you'd have to end the loop (i.e., return) once you've found the player and moved it, otherwise you might find it again and move it again, etc., depending on which way it moved.

  8. #8
    Registered User
    Join Date
    Apr 2016
    Posts
    48
    Quote Originally Posted by algorism View Post
    Not bad.

    I'm assuming that you're allowed to use conio.h, but since it's windows-specific and I'm on linux I had to add a little code to make it work. Alternatively you could use getchar and require that the user press enter after the letter (and you'll need another getchar to eat the newline character). But if you're allowed to use conio.h then that's okay.

    Isn't this
    Code:
            if((world->array[i][j] != WUMPUS) && (world->array[i][j] != ABYSS) && (world->array[i][j] != TREASURE) && (world->array[i][j] != PLAYER) ){
    just a longwinded way to say this
    Code:
            if (world->array[i][j] == EMPTY){
    You should probably change "gold" to "treasure" (or vice-versa). No need for two different terms.

    If you set EMPTY to '-' instead of 1, WUMPUS to 'W' instead of 2, etc., then you could get rid of the switch in print (printWorld is a better name) and replace it with
    Code:
        printf("[%c]", world->array[i][j]);
    For the move function, don't write 119 if you just mean 'W'. Just use 'W'. Ditto for the others keys. You also probably want to allow lowercase, too. So something like:
    Code:
    case 'W': case 'w':
    etc.
    I guess you still have to use 27 for escape, but you could define a constant for it:
    Code:
    #define ESCAPE_KEY 27
    As for your attempted movement, you need to put the getch inside the loop, otherwise you'll only ever read one character (before the loop). And you'll need to display the world again to see the result of the movement.

    Instead of having to search through the array to find the player you could store the player's current position in your struct. Also, you need to ensure that the player doesn't move up if he's on the top row, left if he's in the left column, etc. Your looping tactic is not quite right, anyway, since you'd have to end the loop (i.e., return) once you've found the player and moved it, otherwise you might find it again and move it again, etc., depending on which way it moved.
    The professor just told us to do it in Python or C, did not add any other restrictions to libraries or anything, so I guess conio.h is usable.

    Yeah, it is a longsided way, lol. It's so obvious, don't know why I did that.

    The loop seems fixed. But the moving function is messed up, it changes everything to empty. I didn't implement the player position in the struct because, even though it sounds trivial, I could not figure it out. And I need to refresh the matrix so it does not print a new matrix everytime.

    This is the updated code
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    #include <conio.h>
    
    #define MAX 1000
    #define SIZE 10
    
    #define EMPTY '-'
    #define PLAYER 'P'
    #define WUMPUS 'W'
    #define ABYSS 'A'
    #define GOLD 'G'
    #define ESCAPE_KEY 27
    
    
    typedef struct WumpusWorld{
        char array[SIZE][SIZE];    //Stores the interface
        int arrayB[SIZE][SIZE];    //Stores the world
        int wumpus;            //Stores the monster
        int arrow;            //Stores arrow
        int gold;            //Stores treasure
        int abyss;            //Stores number of abyss
        int steps;          //Stores number of steps 
    }World;
    
    //--------------------------------------------------------
    //Starts matrix and player position
    //--------------------------------------------------------
    
    void initmatrix(World *world){
        int i,j;    
        for(i = 0;i < SIZE; i++){
            for(j = 0;j < SIZE; j++){
                world->array[i][j] = EMPTY;    
            }
        }    
        world->array[0][0] = PLAYER; //Player
    }    
    
    
    //--------------------------------------------------------
    //Genreates random wumpus, abysses and treasure positions
    //--------------------------------------------------------
    
    void generate(World *world, int limit, char object){
        int i,j,k;
        for(k = 0; k < limit; k++){
            i=rand()%10;
            j=rand()%10;
            if(world->array[i][j] == EMPTY){
            world->array[i][j] = object;
            }
        }
    }
    
    //--------------------------------------------------------
    //Prints the "cave"
    //--------------------------------------------------------
    
    void printWorld(World *world){
        int i,j;    
        for(i = 0;i < 10; i++){
            for(j = 0;j < 10; j++){
                printf("[%c]", world->array[i][j]);
        }
        printf("\n");    
    }    
    }
    
    //-----------------------------------------------------------
    // Move
    //-----------------------------------------------------------
    
    void move(World *world,char input){
        int i,j;
        switch (input) {
            case 'w': //W
            for(i=0; i < 10;i++){
            for(j=0; j < 10;j++){
                if(world->array[i][j] == PLAYER){
                    world->array[i][j] = EMPTY;
                    world->array[i+1][j] = PLAYER;
                    }
                }
            }
            break;
    
            case 's': //S
                for(i=0; i < 10;i++){
                for(j=0; j < 10;j++){
                if(world->array[i][j] == PLAYER){
                    world->array[i][j] = EMPTY;
                    world->array[i-1][j] = PLAYER;
                    }
                }
            }
            break;
    
            case 'a': //A
            for(i=0; i < 10;i++){
            for(j=0; j < 10;j++){
                if(world->array[i][j] == PLAYER){
                    world->array[i][j] = EMPTY;
                    world->array[i][j-1] = PLAYER;
                    }
                }
            }
            break;
            
            case 'd': //D
            for(i=0; i < 10;i++){
            for(j=0; j < 10;j++){
                if(world->array[i][j] == PLAYER){
                    world->array[i][j] = EMPTY;
                    world->array[i][j+1] = PLAYER;
                    }
                }
            }
            break;
        }
    }
    
    
    int main(){
        
        srand(time(NULL));
        World world;
        world.wumpus = 1;
        world.abyss = 3;
        world.gold = 1;
        
        initmatrix(&world);
        generate(&world, world.wumpus, WUMPUS);
        generate(&world, world.abyss, ABYSS);
        generate(&world, world.gold, GOLD);
        printWorld(&world);
        
        char input;
        while ( input != ESCAPE_KEY){
        input = getch();
        move(&world, input);
        printf("\n");
        printWorld(&world);
        }
    }

  9. #9
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    MAX seems unnecessary.

    You're not using SIZE everywhere. Search and replace all 10's with SIZE. That way you could easily change the world size to, e.g., 15 if you wanted. It also documents what the 10's actually mean.

    I need to refresh the matrix so it does not print a new matrix everytime.
    If you mean instead of a new matrix being printed below the old one you want to print it over top of the old one then an easy way to do that is to add this to the beginning of the printWorld function:
    Code:
    system("cls"); // cls is windows-specific
    To add the player position to the code so you don't have to search for the player all the time, add two ints, row and col, to the struct and initialize them to 0. Then rewrite the move function. Set the current array[row][col] to EMPTY, update the row or col depending on input, and set the new position to PLAYER. Also remember that you need to ensure that row is greater than 0 if you're decrementing it and that it's less than SIZE minus one if you're incrementing it. Ditto for col.

  10. #10
    Registered User
    Join Date
    Apr 2016
    Posts
    48
    So I did the fixes you told me. Worked. But now I'm not sure if I should try doing the senses or the action ( dying if stepping on abyss or wumpus, get the gold, score).
    I tried to put this in the d movement to see if the player dies but it did not work and I don't know why. Any suggestion ?

    Code:
    if(world->array[world->lin][world->col+1] == ABYSS){
                    printf("You have fallen in ABYSS");
                }
    Whole updated code:
    Code:
    include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    #include <conio.h>
    
    #define SIZE 10
    
    #define EMPTY '-'
    #define PLAYER 'P'
    #define WUMPUS 'W'
    #define ABYSS 'A'
    #define GOLD 'G'
    #define ESCAPE_KEY 27
    
    
    typedef struct WumpusWorld{
        char array[SIZE][SIZE];    //Stores the interface
        int arrayB[SIZE][SIZE];    //Stores the world
        int wumpus;                //Stores the monster
        int arrow;                //Stores arrow
        int gold;                //Stores treasure
        int abyss;                //Stores number of abyss
        int steps;                //Stores number of steps 
        int lin = 0;            //Stores player line
        int col = 0;            //Stores player column
    }World;
    
    //--------------------------------------------------------
    //Starts matrix and player position
    //--------------------------------------------------------
    
    void initmatrix(World *world){
        int i,j;    
        for(i = 0;i < SIZE; i++){
            for(j = 0;j < SIZE; j++){
                world->array[i][j] = EMPTY;    
            }
        }    
        world->array[world->lin][world->col] = PLAYER; //Player
    }    
    
    
    //--------------------------------------------------------
    //Genreates random wumpus, abysses and treasure positions
    //--------------------------------------------------------
    
    void generate(World *world, int limit, char object){
        int i,j,k;
        for(k = 0; k < limit; k++){
            i=rand()%10;
            j=rand()%10;
            if(world->array[i][j] == EMPTY){
            world->array[i][j] = object;
            }
        }
    }
    
    //--------------------------------------------------------
    //Prints the "cave"
    //--------------------------------------------------------
    
    void printWorld(World *world){
        system("cls");
        int i,j;    
        for(i = 0;i < SIZE; i++){
            for(j = 0;j < SIZE; j++){
                printf("[%c]", world->array[i][j]);
        }
        printf("\n");    
    }    
    }
    
    //-----------------------------------------------------------
    // Move
    //-----------------------------------------------------------
    
    void move(World *world,char input){
        int i,j;
        switch (input) {
            case 'w': //W
            if(world->lin > 0){
                world->array[world->lin][world->col] = EMPTY;
                world->lin --;
                world->array[world->lin][world->col] = PLAYER;
            }
            
            break;
    
            case 's': //S
            if(world->lin < (SIZE - 1)){
                world->array[world->lin][world->col] = EMPTY;
                world->lin ++;
                world->array[world->lin][world->col] = PLAYER;
            }
            break;
    
            case 'a': //A
            if(world->col > 0){
                world->array[world->lin][world->col] = EMPTY;
                world->col --;
                world->array[world->lin][world->col] = PLAYER;
            }
            break;
            
            case 'd': //D
            if(world->col < (SIZE - 1)){
                world->array[world->lin][world->col] = EMPTY;
                world->col ++;
                world->array[world->lin][world->col] = PLAYER;
                }
            break;
        }
    }
    
    
    int main(){
        
        srand(time(NULL));
        World world;
        world.wumpus = 1;
        world.abyss = 3;
        world.gold = 1;
        
        initmatrix(&world);
        generate(&world, world.wumpus, WUMPUS);
        generate(&world, world.abyss, ABYSS);
        generate(&world, world.gold, GOLD);
        printWorld(&world);
        
        char input;
        while ( input != ESCAPE_KEY){
        input = getch();
        move(&world, input);
        printf("\n");
        printWorld(&world);
        }
    }

  11. #11
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    That's strange that it worked for you because it doesn't even compile for me. The problem is that you can't initialize lin and col the way you have. You need to do it in initmatrix.

    In move you don't need i and j anymore. And your code is a little repetitive. You don't need to set the current position to EMPTY and the next to PLAYER in every case. You can set it to EMPTY before the switch and set the new location to PLAYER after the switch.

    I tried to put this in the d movement to see if the player dies but it did not work and I don't know why.
    I wouldn't put it in the d movement since it applies to any movement. That would lead to repetitive code, which we're trying to avoid (remember all the generate functions!). I wouldn't put it in move at all. That function is doing enough.

    However that leads to a bit of a problem since move sets the new location to PLAYER, erasing whatever was there. How about saving the current value of the new location, then setting that location to PLAYER, and then returning the old value from move?. Then in main you can receive that value and act on it.

    Another possibility is to never store PLAYER in the matrix at all. Since we've saved his position you can change printWorld to print him in the right place.

    I notice that you still have two 10's in your code (in generate). They should be SIZE.
    I also notice that your indentation is a little wonky in places.

  12. #12
    Registered User
    Join Date
    Apr 2016
    Posts
    48
    Quote Originally Posted by algorism View Post
    However that leads to a bit of a problem since move sets the new location to PLAYER, erasing whatever was there. How about saving the current value of the new location, then setting that location to PLAYER, and then returning the old value from move?. Then in main you can receive that value and act on it.
    I did not quiet get this part, am I supposed to that in move or in another function ?

  13. #13
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Since the location that the player moves to is overwritten by the 'P' you will lose the information about what was there before the player moved. So, in the move function, you could first save what was originally in the new position, then put the 'P' there, then return the old value of the location. Then in main you can receive that value and do what you want with it.
    Code:
    move pseudocode:
    
      matrix[row][col] = EMPTY
    
      switch (...) {
        Update player position (row and col).
       }
    
      oldsymbol = matrix[row][col]
      matrix[row][col] = PLAYER
      return oldsymbol
    
    In main:
    
      sym = move(...)
      switch (sym) {
      case ABYSS:
        printf("Aaaaaaaaaaaaaa\n");
        break;
      ...
      }
    The more I think about it, though, it might be best to not write the 'P' into the matrix at all. In fact, the whole thing would be done without a matrix at all, just keeping the row,col positions of all the objects. But give the above a try for now.

  14. #14
    Registered User
    Join Date
    Apr 2016
    Posts
    48
    Code:
    //-----------------------------------------------------------
    // Move
    //-----------------------------------------------------------
    
    char move(World *world,char input){
        char oldsymbol;
        world->array[world->lin][world->col] = EMPTY;
            switch (input) {
                if((world->lin > 0) && (world->lin < (SIZE - 1)) && (world->col > 0) && (world->col < (SIZE - 1))){
                    case 'w': //W
                    if(world->lin > 0){
                        world->lin --;
                    }
                    break;
    
                    case 's': //S
                    if(world->lin < (SIZE - 1)){
                        world->lin ++;
                    }
                    break;
    
                    case 'a': //A
                    if(world->col > 0){
                        world->col --;
                    }
                    break;
            
                    case 'd': //D
                    if(world->col < (SIZE - 1)){
                        world->col ++;
                    }
                    break;
                }
            }
            
        oldsymbol = world->array[world->lin][world->col];
        world->array[world->lin][world->col] = PLAYER;
        return oldsymbol;
    }
    
    
    int main(){
        
        srand(time(NULL));
        World world;
        world.wumpus = 1;
        world.abyss = 3;
        world.gold = 1;
        
        initmatrix(&world);
        generate(&world, world.wumpus, WUMPUS);
        generate(&world, world.abyss, ABYSS);
        generate(&world, world.gold, GOLD);
        printWorld(&world);
        
        char symbol;
        char input;
        while ( input != ESCAPE_KEY){
            input = getch();
            symbol = move(&world, input);
            
            switch (symbol) {
            case ABYSS:
                printf("AAAAAAAAAAAAAAAAAAAAAA\n");
                printf("You have fallen into the abyss!");
                return 0;
                break;    
            
            case WUMPUS:
                printf("MUAAAAAAAAAAAAAAAHHHHH\n");
                printf("Wumpus has eaten you!");
                return 0;
                break;    
            }
            
            printf("\n");
            printWorld(&world);
        }
    }
    One problem with this is the gold. When I print the message that the player obtains the gold, system("cls"); in print already removes it. I need it to stay until the player moves again. With ABYSS and WUMPUS, I returned 0, but really I would need to go back to a start menu.

    Now I was thinking about the senses. The way it's going I can't do them on the seen matrix because move would erase the sense value when the player steps on it, but it would need to stay there when he comes back.
    So then maybe the unseen matrix would enter here. I could generate the senses in here and create an unseen player that moves with the the seen player. Then another print function to show the player the senses of the house he is on.

    Or I could try this other method without a matrix you are suggesting.

  15. #15
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    The if statement around your switch cases is wrong in multiple ways. If I understand the point of it, it's unnecessary and incorrect since the individual tests for each movement direction handle the edges. Also, I don't think you can put an if inside a switch but outside a case like that. Just get rid of it.

    I should also note at this point that you're not handling the input loop in main quite right. It should be something like:
    Code:
    while (1) {
        int input = getch();
        if (input == ESCAPE_KEY)
            break;
        ...
    }
    I don't understand about the GOLD. If the player has found it then he's already stepped on it and the player would be displayed in that position, so I'm not sure why (or how) the gold would also be displayed. But your code doesn't show any gold-handling code so I can't really comment on it in detail.

    Anyway, aren't the game objects supposed to be invisible to the player? We haven't really gotten to that part yet, but as I understand it the only visible thing is the player himself. I don't really know the game, though, so correct me if I'm mistaken.

    If it is the case that only the player is visible, then it might be a good idea to not actually put the player symbol in the matrix at all. It's not really necessary since we know his position (lin, col). That way the matrix would just contain the hidden stuff and you wouldn't need a separate hidden matrix.

    As for going back to a start menu, something like (pseudocode) :
    Code:
    playGame:
      init game
      print world
      display senses
      loop:
        get input (quit loop if escape key)
        move
        detect collision
        print world
        display senses
    
    main:
      loop:
        menu (quit if don't want to play)
        playGame
    I just realized that in initializing the game you need to ensure that no objects are placed in position 0,0 (where the player starts).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. tic tac toe game( 3*3 to 5*5) with multidimensional array
    By modi365 in forum C++ Programming
    Replies: 3
    Last Post: 01-17-2015, 08:37 AM
  2. Replies: 0
    Last Post: 09-04-2014, 07:23 AM
  3. my game of life, array help
    By phoking in forum C++ Programming
    Replies: 3
    Last Post: 03-03-2014, 09:31 AM
  4. Need help w/2d array game function
    By cpp4ever in forum Game Programming
    Replies: 4
    Last Post: 11-14-2001, 07:30 PM
  5. Need help w/2d array game function
    By cpp4ever in forum C++ Programming
    Replies: 7
    Last Post: 11-10-2001, 11:21 AM