How to Implement the Snake Game Using Struct and Constants in C++?

  • C/C++
  • Thread starter FallArk
  • Start date
  • Tags
    Game
In summary: We will need to update it with every move.In summary, the conversation discusses the rules and structure of a game, where the player ('U') and opponent ('X') each start in opposite corners of a game board with a given number of rows and columns. The game involves moving in different directions until one player's "tail" reaches a certain length, causing that player to lose. The conversation also mentions the use of a template and functions to initialize the board, show the board, and place pieces on the board. The move variable is used to keep track of turns, while TAILLENGTH
  • #1
FallArk
127
0
What I should follow:
• "U" is you, the player; you always start in the upper left corner.
• "X" is the opponent, which always starts in the lower right corner.
• NUMROWS and NUMCOLS delimits the size and shape of the game board.
• TAILLENGTH gives the length of the "tail" -- if one player hits the other's tail (or the head), the player loses.
• DO NOT Try to make a version which interacts with the arrow keys; see class discussion regarding why.
• DO NOT USE GLOBAL VARIABLES!
• You HAVE TO use the template given below; your job is to write the missing functions.

Template:
Code:
const int NUMROWS = 7;// CAN BE CHANGED FOR DIFFERENT GAME PLAY 
const int NUMCOLS = 10;// CAN BE CHANGED FOR DIFFERENT GAME PLAY 
const int TAILLENGTH = 15;// CAN BE CHANGED FOR DIFFERENT GAME PLAY

struct _cell {
char marker; int moveNumber;
};

*** OTHER FUNCTIONS THAT YOU WRITE ***

int main() {

int uRow = 0, uCol = 0;
int oRow = NUMROWS - 1, oCol = NUMCOLS - 1;
bool win = true; int move = 0;
_cell board[NUMROWS][NUMCOLS]; initBoard(board);
placePiece(board, uRow, uCol, 'U', move); placePiece(board, oRow, oCol, 'X', move); showBoard(board, move);

while (true) {
move++;
if (!movePlayer(board, uRow, uCol, move)) { win = false;
break;
}
if (!moveOpponent(board, oRow, oCol, move)) break; // player wins
showBoard(board, move);
}

showBoard(board, move); if (win)
cout << "*** YOU WIN! ***" << endl;
else
cout << "*** YOU LOSE! ***" << endl;

string tmp; getline(cin, tmp);
}

what I have:
Code:
[FONT=Century Gothic]void initBoard (char board[NUMROWS][NUMCOLS]) {
    for (int i = 0; i < NUMROWS; ++i) {
        for (int j = 0; j < NUMCOLS; ++j) {
            board[i][j] = '-';
        }
    }
}

void showBoard (char board[NUMROWS][NUMCOLS], int &move) {
    for (int i = 0; i < NUMROWS; ++i) {
        for (int j = 0; j < NUMCOLS; ++j) {
            cout << board[i][j] << " ";
        }
        cout << endl;
    }
    cout << "Enter direction (N/S/E/W): ";
}

void placePiece (char board[NUMROWS][NUMCOLS], int &row, int &col, char player, int &move) {
    if (player == 'U') {
        row = 0, col = 0;
        board[row][col] = 'U';
    }
    else {
        row = NUMROWS - 1, col = NUMCOLS - 1;
        board[row][col] = 'X';
    }

}[/FONT]
As of now, I have a few questions:
1. What is this move variable? (I thought it was the moves left for the player to win but then realized that is wrong)
2. How do I use this TAILLENGTH constant? I understand the snake should be limited to this constant but how should I make it so the snake stop growing after reaching this number?
3. what is the _cell board[NUMROWS][NUMCOLS], it doesn't look like how a struct should be used.


Thanks for any input in advance!
 
Technology news on Phys.org
  • #2
FallArk said:
As of now, I have a few questions:
1. What is this move variable? (I thought it was the moves left for the player to win but then realized that is wrong)
2. How do I use this TAILLENGTH constant? I understand the snake should be limited to this constant but how should I make it so the snake stop growing after reaching this number?
3. what is the _cell board[NUMROWS][NUMCOLS], it doesn't look like how a struct should be used.

Thanks for any input in advance!

Hi FallArk!

1. The move variable is incremented every time both the player and the opponent have made a move - it's the number of turns.
2. We need to keep track of the snake in the board. With every new move the snake grows until TAILLENGTH. When it reaches TAILLENGTH, the tip of the tail needs to be removed with every move that comes next. To achieve that, we need to use the moveNumber to figure out what needs to be removed.
3. board is a matrix that keeps track which cells are occupied so you can tell if there is a collision or not. We will need to update it with every move.
 
  • #3
I like Serena said:
Hi FallArk!

1. The move variable is incremented every time both the player and the opponent have made a move - it's the number of turns.
2. We need to keep track of the snake in the board. With every new move the snake grows until TAILLENGTH. When it reaches TAILLENGTH, the tip of the tail needs to be removed with every move that comes next. To achieve that, we need to use the moveNumber to figure out what needs to be removed.
3. board is a matrix that keeps track which cells are occupied so you can tell if there is a collision or not. We will need to update it with every move.

Thanks for the input! Although I am still confused about the _cell board part. I thought it is suppose to be like:
_cell. marker _cell.movenumber
 
  • #4
FallArk said:
Thanks for the input! Although I am still confused about the _cell board part. I thought it is suppose to be like:
_cell. marker _cell.movenumber

_cell is a type, which can't be referenced like that.
To use it we need the variable board to access it.
It should be [m]board[row][col].marker[/m] or [m]board[row][col].moveNumber[/m].
 
  • #5
I like Serena said:
_cell is a type, which can't be referenced like that.
To use it we need the variable board to access it.
It should be [m]board[row][col].marker[/m] or [m]board[row][col].moveNumber[/m].

Ah ha! It makes way more sense now! Thanks!
 
  • #6
I updated my code and soon realized there is no variable that is a char type, how would I make it so that the user get to input the direction they are going using int move ?
And I also assume I have to let the user input the direction in the showBoard function.
My current code:
Code:
void initBoard (_cell board[NUMROWS][NUMCOLS]) {
    for (int i = 0; i < NUMROWS; ++i) {
        for (int j = 0; j < NUMCOLS; ++j) {
            board[i][j].marker = '-';
        }
    }
}

void showBoard (_cell board[NUMROWS][NUMCOLS], int &move) {
    for (int i = 0; i < NUMROWS; ++i) {
        for (int j = 0; j < NUMCOLS; ++j) {
            cout << board[i][j].marker << " ";
        }
        cout << endl;
    }
    cout << "Enter direction (N/S/E/W): ";
}

void placePiece (_cell board[NUMROWS][NUMCOLS], int &row, int &col, char player, int &move) {
    if (player == 'U') {
        row = 0, col = 0;
        board[row][col].marker = 'U';
    }
    else {
        row = NUMROWS - 1, col = NUMCOLS - 1;
        board[row][col].marker = 'X';
    }

}

bool movePlayer (_cell board[NUMROWS][NUMCOLS], int &Row, int &Col, int &move) {
    
}

bool moveOpponent (_cell board[NUMROWS][NUMCOLS], int &Row, int &Col, int &move) {

}
 
  • #7
FallArk said:
I updated my code and soon realized there is no variable that is a char type, how would I make it so that the user get to input the direction they are going using int move ?
And I also assume I have to let the user input the direction in the showBoard function.

No, getting user input should not be in the [m]showBoard[/m] function - that one should only "show" the board.
Getting input should be done in the [m]movePlayer[/m] function.
Something like this will do the job.

Code:
bool movePlayer (_cell board[NUMROWS][NUMCOLS], int &Row, int &Col, int move) {
    cout << "Enter direction (N/S/E/W): ";

    char direction;
    cin >> direction;

    switch (direction) {
        case 'N': ...
        ...
    }
    ...
}

We need to declare [m]direction[/m] as a local variable and use it to get the direction.
In particular [m]move[/m] should not be used - it's only intended to be an input parameter that should not be changed inside the function.
Instead, [m]move[/m] should be used to store it in the board:
Code:
board[row][col].marker = 'U';
board[row][col].moveNumber = move;

That way we can scan the board for moves that have been made TAILLENGTH turns ago, meaning it should be removed from the board.
 
  • #8
Code:
#include <iostream>

using namespace std;

const int NUMROWS = 7;// CAN BE CHANGED FOR DIFFERENT GAME PLAY
const int NUMCOLS = 10;// CAN BE CHANGED FOR DIFFERENT GAME PLAY
const int TAILLENGTH = 15;// CAN BE CHANGED FOR DIFFERENT GAME PLAYstruct _cell {
char marker; int moveNumber;
};

void initBoard (_cell board[NUMROWS][NUMCOLS]) {
    for (int i = 0; i < NUMROWS; ++i) {
        for (int j = 0; j < NUMCOLS; ++j) {
            board[i][j].marker = '-';
        }
    }
}

void showBoard (_cell board[NUMROWS][NUMCOLS], int &move) {
    for (int i = 0; i < NUMROWS; ++i) {
        for (int j = 0; j < NUMCOLS; ++j) {
            cout << board[i][j].marker << " ";
        }
        cout << endl;
    }
}

void placePiece (_cell board[NUMROWS][NUMCOLS], int &row, int &col, char player, int &move) {
    if (player == 'U') {
        row = 0, col = 0;
        board[row][col].marker = 'U';
    }
    else {
        row = NUMROWS - 1, col = NUMCOLS - 1;
        board[row][col].marker = 'X';
    }

}

bool movePlayer (_cell board[NUMROWS][NUMCOLS], int &Row, int &Col, int &move) {
    cout << "Enter direction (N/S/E/W): ";
    char direction;
    cin >> direction;

    switch (direction) {
        case 'N':
				if (Row - 1 < 0){
					cout << "YOU FELL OFF THE BOARD!" << endl;
					return false;
				}
				else if ((board[Row - 1][Col].marker == 'O') || (board[Row - 1][Col].marker == 'u') || (board[Row - 1][Col].marker == 'o')) {
					return false;
				}
                else {
					board[Row][Col].marker = 'u';
					board[Row - 1][Col].marker = 'U';
					Row = Row - 1;
					board[Row][Col].moveNumber = move;
				}
				break;

			case 'S':
				if (Row + 1 > NUMROWS - 1){
					cout << "YOU FELL OFF THE BOARD!" << endl;
					return false;
				}
				else if ((board[Row + 1][Col].marker == 'O') || (board[Row + 1][Col].marker == 'u') || (board[Row + 1][Col].marker == 'o')) {
					return false;
				}
				else {
					board[Row][Col].marker = 'u';
					board[Row + 1][Col].marker = 'U';
					Row = Row + 1;
					board[Row][Col].moveNumber = move;
				}
				break;

			case 'E':
				if (Col + 1 > NUMCOLS - 1){
					cout << "YOU FELL OFF THE BOARD!" << endl;
					return false;
				}
				else if ((board[Row][Col + 1].marker == 'O') || (board[Row][Col + 1].marker == 'u') || (board[Row][Col + 1].marker == 'o')){
					return false;
				}
				else {
					board[Row][Col].marker = 'u';
					board[Row][Col + 1].marker = 'U';
					Col = Col + 1;
					board[Row][Col].moveNumber = move;
				}
				break;

			case 'W':
				if (Col - 1 < 0){
					cout << "YOU FELL OFF THE BOARD!" << endl;
					return false;
				}
				else if ((board[Row][Col - 1].marker == 'O') || (board[Row][Col - 1].marker == 'u') || (board[Row][Col - 1].marker == 'o')){
					return false;
				}
				else {
					board[Row][Col].marker = 'u';
					board[Row][Col - 1].marker = 'U';
					Col = Col - 1;
					board[Row][Col].moveNumber = move;
				}
				break;
    }
    return true;
}

bool moveOpponent (_cell board[NUMROWS][NUMCOLS], int &Row, int &Col, int &move) {
        if (board[Row - 1][Col].marker == '_') {
            board[Row - 1][Col].marker = 'O';
            board[Row][Col].marker = 'o';
            Row = Row - 1;
        }
        else if (board[Row][Col - 1].marker == '_') {
            board[Row][Col - 1].marker = 'O';
            board[Row][Col].marker = 'o';
            Col = Col - 1;
        }
        else if (board[Row][Col + 1].marker == '_') {
            board[Row][Col + 1].marker = 'O';
            board[Row][Col].marker = 'o';
            Col = Col + 1;
        }
        else if (board[Row + 1][Col].marker == '_') {
            board[Row + 1][Col].marker = 'O';
            board[Row][Col].marker = 'o';
            Row = Row + 1;
        }
        else {
            return false;
    }
}

int main() {

int uRow = 0, uCol = 0;
int oRow = NUMROWS - 1, oCol = NUMCOLS - 1;
bool win = true; int move = 0;
_cell board[NUMROWS][NUMCOLS]; initBoard(board);
placePiece(board, uRow, uCol, 'U', move); placePiece(board, oRow, oCol, 'X', move); showBoard(board, move);

while (true) {
move++;
if (!movePlayer(board, uRow, uCol, move)) { win = false;
break;
}
if (!moveOpponent(board, oRow, oCol, move)) break; // player wins
showBoard(board, move);
}

showBoard(board, move); if (win)
cout << "*** YOU WIN! ***" << endl;
else
cout << "*** YOU LOSE! ***" << endl;

string tmp; getline(cin, tmp);
}
For some reason, after I enter the first direction, the output told me that I win.
I think there is something wrong with the moveOpponent function.
My idea is that the computer controls the opponent and if it can go North, it will go North, if there is nowhere to go, it is boned. But I don't know if I executed it correctly.
 
  • #9
FallArk said:
For some reason, after I enter the first direction, the output told me that I win.
I think there is something wrong with the moveOpponent function.
My idea is that the computer controls the opponent and if it can go North, it will go North, if there is nowhere to go, it is boned. But I don't know if I executed it correctly.

Shouldn't [m]moveOpponent()[/m] return [m]true[/m] somewhere?
 
  • #10
I like Serena said:
Shouldn't [m]moveOpponent()[/m] return [m]true[/m] somewhere?

Ah crap, that's probably why.
Update: I also did something really stupid, my opponent is suppose to be 'X' instead of 'O' :P
 
Last edited:
  • #11
I like Serena said:
Shouldn't [m]moveOpponent()[/m] return [m]true[/m] somewhere?

What about board[***][***].movenumber? It keeps track of the moves, but why should I use it?
 
  • #12
FallArk said:
What about board[***][***].movenumber? It keeps track of the moves, but why should I use it?

- TAILLENGTH gives the length of the "tail" -- if one player hits the other's tail (or the head), the player loses.
When the game starts, we don't have a tail yet.
It will grow with every move.
I interpret the TAILLENGTH to mean that the tail should not grow longer.
If it would, the part that is exceeding TAILLENGTH should be removed.
 
  • #13
I like Serena said:
When the game starts, we don't have a tail yet.
It will grow with every move.
I interpret the TAILLENGTH to mean that the tail should not grow longer.
If it would, the part that is exceeding TAILLENGTH should be removed.

I think TAILLENGTH is the limit of moves, since it is a constant
 
  • #14
hey I'm in compsci 121 too and I am having trouble making the snake stop growing after Taillength is achieved. Can you please tell me what you did because I cannot see it in your code.
 
  • #15
The tail can be removed with a double for-loop over the board.
If [m]move - board[row][col].moveNumber > TAILLENGTH[/m], whatever is there can be removed from the board.
 
  • #16
I like Serena said:
The tail can be removed with a double for-loop over the board.
If [m]move - board[row][col].moveNumber > TAILLENGTH[/m], whatever is there can be removed from the board.
Ah i see now. Thanks!
 
  • #17
Code:
while (true) {
move++;
if (!movePlayer(board, uRow, uCol, move)) {
        win = false;
break;
}
if (!moveOpponent(board, oRow, oCol, move)) break; // player wins
showBoard(board, move);
}

showBoard(board, move); if (win)
cout << "*** YOU WIN! ***" << endl;
else
cout << "*** YOU LOSE! ***" << endl;

Correct me if I'm wrong. So the code above says if the movePlayer function returns false then the game ends, so I also need some kind of a loop in each of the move functions. Right?
 
  • #18
FallArk said:
Correct me if I'm wrong. So the code above says if the movePlayer function returns false then the game ends, so I also need some kind of a loop in each of the move functions. Right?

Huh? :confused:
[m]movePlayer()[/m] is supposed to ask and execute a single move for the player.
If he can't make a move for some reason, the surrounding while-loop breaks off.
What would be the purpose for a loop inside one a move functions?
 
  • #19
I like Serena said:
Huh? :confused:
[m]movePlayer()[/m] is supposed to ask and execute a single move for the player.
If he can't make a move for some reason, the surrounding while-loop breaks off.
What would be the purpose for a loop inside one a move functions?
But i thought the while loop in main only checks for the boolean value
 
  • #20
FallArk said:
But i thought the while loop in main only checks for the boolean value

:confused:
The while-loop in main is the main-loop of the game.
It iterates over every move and executes a move for both the player and the opponent.
Only when one of them can't make a move, it has to break off because it means the game has ended.
 
  • #21
I like Serena said:
:confused:
The while-loop in main is the main-loop of the game.
It iterates over every move and executes a move for both the player and the opponent.
Only when one of them can't make a move, it has to break off because it means the game has ended.

hmm. So the movePlayer function would have to return true at every valid move then? What i did was let the function return true at the very end, I guess that is why the loop won't execute correctly.
 
  • #22
cangrejozurdo said:
hey I'm in compsci 121 too and I am having trouble making the snake stop growing after Taillength is achieved. Can you please tell me what you did because I cannot see it in your code.

My loop won't execute properly:(
And the opponent doesn't move
 
  • #23
I like Serena said:
The tail can be removed with a double for-loop over the board.
If [m]move - board[row][col].moveNumber > TAILLENGTH[/m], whatever is there can be removed from the board.

what is board[row][col].moveNumber supposed to be? is it different from move?
 
  • #24
cangrejozurdo said:
what is board[row][col].moveNumber supposed to be? is it different from move?
I think it tracks the move of the snake. So it should limit the length of it.
 
  • #25
FallArk said:
I think it tracks the move of the snake. So it should limit the length of it.

so is board[NUMROWS][NUMCOLS].moveNumber = move -1?
 
  • #26
cangrejozurdo said:
so is board[NUMROWS][NUMCOLS].moveNumber = move -1?
I don't think so. It should not change in the functions.
 
  • #27
Hey guys I just saw this post and I was wondering if any of you figured out how to make the opponent move. I tried but nothing really came out :(
 
  • #28
I think there is something wrong with my moveOpponent function. I'll be glad if someone can have a look and tell me what's wrong.
Here is my function -
bool moveOpponent (_cell board[NUMROWS][NUMCOLS], int &Row, int &Col, int &move) {
if (board[Row - 1][Col].marker == '_') {
board[Row - 1][Col].marker = 'X';
board[Row][Col].marker = 'x';
Row = Row - 1;
}
else if (board[Row][Col - 1].marker == '_') {
board[Row][Col - 1].marker = 'X';
board[Row][Col].marker = 'x';
Col = Col - 1;
}
else if (board[Row][Col + 1].marker == '_') {
board[Row][Col + 1].marker = 'X';
board[Row][Col].marker = 'x';
Col = Col + 1;
}
else if (board[Row + 1][Col].marker == '_') {
board[Row + 1][Col].marker = 'X';
board[Row][Col].marker = 'x';
Row = Row + 1;
}

return true;

}
 
  • #29
manveenkaur said:
I think there is something wrong with my moveOpponent function. I'll be glad if someone can have a look and tell me what's wrong.
Here is my function -
bool moveOpponent (_cell board[NUMROWS][NUMCOLS], int &Row, int &Col, int &move) {
if (board[Row - 1][Col].marker == '_') {
board[Row - 1][Col].marker = 'X';
board[Row][Col].marker = 'x';
Row = Row - 1;
}
else if (board[Row][Col - 1].marker == '_') {
board[Row][Col - 1].marker = 'X';
board[Row][Col].marker = 'x';
Col = Col - 1;
}
else if (board[Row][Col + 1].marker == '_') {
board[Row][Col + 1].marker = 'X';
board[Row][Col].marker = 'x';
Col = Col + 1;
}
else if (board[Row + 1][Col].marker == '_') {
board[Row + 1][Col].marker = 'X';
board[Row][Col].marker = 'x';
Row = Row + 1;
}

return true;

}
Thats what i did as well.
 
  • #30
So did you not figure out something?
 
  • #31
manveenkaur said:
So did you not figure out something?
Nope.
 
  • #32
How did u guys deal with the tail?
 
  • #33
I am still not able to get a solution. I'll really appreciate it if someone could help me. M problem is that my opponent does not move. Please help!
 
  • #34
manveenkaur said:
I am still not able to get a solution. I'll really appreciate it if someone could help me. M problem is that my opponent does not move. Please help!

It appears that you are using an underscore '_' instead of a regular minus sign '-'. When you make the changes the code should work!
 

FAQ: How to Implement the Snake Game Using Struct and Constants in C++?

How do I play the snake game?

To play the snake game, you will need to use the arrow keys on your keyboard to control the direction of the snake. The objective of the game is to eat as many apples as possible without running into the walls or the snake's own body.

How do I start the snake game?

To start the snake game, you will need to click on the "Start" button or press the spacebar on your keyboard. This will begin the game and the snake will start moving.

How do I increase the speed of the snake?

The speed of the snake can be increased by eating the apples that appear on the screen. Each apple will make the snake move faster, making the game more challenging.

How do I pause the snake game?

To pause the snake game, you can press the "Pause" button or the letter "P" on your keyboard. This will stop the snake from moving and allow you to take a break or resume the game later.

How do I restart the snake game?

To restart the snake game, you can click on the "Restart" button or press the letter "R" on your keyboard. This will reset the game and allow you to start over from the beginning.

Similar threads

Replies
6
Views
3K
Replies
22
Views
4K
Replies
5
Views
5K
Replies
6
Views
3K
Replies
7
Views
75K
Replies
8
Views
2K
Replies
5
Views
2K
Replies
11
Views
9K
Back
Top