I write a snake game in c++ using a 2d array. I use for head the symbol 'o' and for tail the symbol '*'. How i change the tail position in 2d array if i have a tail bigger than one star *. Because with one star it's ok.
void Movement(char grid[gridsize][gridsize]){
char move;
int i, j ;
bool check = true, tail = false;
cout << "Make Your move w/s/a/d " << endl;
cin >> move ;
for(i = 0; i < gridsize; i++)
{
for(j = 0; j < gridsize; j++)
{
if(grid[i][j] == 'o')
{
goto Theend;
}
}
}
Theend:
int ii, jj;
for(ii = 0; ii < gridsize; ii++)
{
for(jj = 0; jj < gridsize; jj++)
{
if(grid[ii][jj] == '*')
{
tail = true;
goto Thefinalend;
}
}
}
Thefinalend:
switch (move)
{
case 'w':
grid[i-1][j] = 'o';
break;
case 'a':
grid[i][j-1] = 'o';
break;
case 's':
grid[i+1][j] = 'o';
break;
case 'd':
grid[i][j+1] = 'o';
break;
default:
cout << "Not correct input " << endl;
break;
}
grid[i][j] = ' ';
AppleEat(grid, i, j);
if(tail == true)
Swaptail(grid, i, j);
}
void AppleEat(char grid[gridsize][gridsize], int ibefore, int jbefore)
{
int i, j;
for(i = 0; i < gridsize; i++)
{
for(j = 0; j < gridsize; j++)
{
if(grid[i][j] == 'o')
{
goto Theend;
}
}
}
Theend:
if(iA == i && jA == j){
RandomPlaceApple(grid);
grid[ibefore][jbefore] = '*';
}
}
void Swaptail(char grid[gridsize][gridsize], int ibefore , int jbefore )
{
for(int ii = 0; ii < gridsize; ii++){
for(int jj = 0; jj < gridsize; jj++){
if(grid[ii][jj] == '*')
{
swap(grid[ii][jj], grid[ibefore][jbefore]);
}
}
}
}
I want to make the snake tail move. I try to search for the farthest position of the tail '*' but that was not good idea.
You will need to keep track of the tail positions in a separate data structure, such as a queue or a linked list, I don't think there is a more optimal approach.
For example, you could create a struct (or class, preference) to represent each segment of the tail, which contains the x and y coordinates of the segment. Then, in your Movement function, you could use a queue to keep track of the tail segments. When the snake eats an apple, you would enqueue a new tail segment onto the queue, and when the snake moves, you would dequeue the oldest tail segment from the queue and update its position in the 2D array.
Something like:
#include <queue>
struct TailSegment {
int x;
int y;
};
std::queue<TailSegment> tail;
...
if(tail == true)
MoveTail(grid);
...
Theend:
if(iA == i && jA == j){
RandomPlaceApple(grid);
tail.push({ibefore, jbefore});
}
...
void MoveTail(char grid[gridsize][gridsize])
{
TailSegment last = tail.front();
grid[last.x][last.y] = '*';
}
Related
i'm trying to make a unbeatable tic tac toe for a side project and i can't make it right (i can actually beat it ironically).
It's actually a implementation of the MiniMax algorithm; i came with this code
#include <iostream>
#include <string>
using namespace std;
struct Move
{
int line, columns;
};
//Return the number of remainings turn based on the number of lest boxes
int remainingsTurns(char grid[3][3])
{
int remainingTurn = 0;
for (int k = 0; k < 3; k++)
{
for (int i = 0; i < 3; i++)
{
if (grid[k][i] == ' ')
{
remainingTurn++;
}
}
}
return remainingTurn;
}
//Print the grid on screen
void printGrid(char grid[3][3])
{
for (int k = 0; k < 3; k++)
{
for (int i = 0; i < 3; i++)
{
cout << "| " << grid[k][i] << " ";
}
cout << "|" << endl;
}
}
//Give a value to the board
int evaluateBoard(char grid[3][3])
{
//Check the board for lines
for (int k = 0; k < 3; k++)
{
if (grid[k][0] == grid[k][1] && grid[k][1] == grid[k][2])
{
if (grid[k][0] == 'x')
{
return +10;
}
else if (grid[k][0] == 'o')
{
return -10;
}
}
}
//Check the board for columns
for (int k = 0; k < 3; k++)
{
if (grid[0][k] == grid[1][k] && grid[1][k] == grid[2][k])
{
if (grid[0][k] == 'x')
{
return +10;
}
else if (grid[0][k] == 'o')
{
return -10;
}
}
}
//Check the board for diagonals
if (grid[0][0] == grid[1][1] && grid[0][0] == grid[2][2])
{
if (grid[0][0] == 'x')
{
return +10;
}
else if (grid[0][0] == 'o')
{
return -10;
}
}
if (grid[0][2] == grid[1][1] && grid[0][2] == grid[2][0])
{
if (grid[0][0] == 'x')
{
return +10;
}
else if (grid[0][0] == 'o')
{
return -10;
}
}
//if no ictory return 0
return 0;
}
// MiniMax algorithm
int miniMax(char grid[3][3], int turn, bool maxMove)
{
int score = evaluateBoard(grid);
if (score == 10)
{
return score;
}
if (score == -10)
{
return score;
}
//Check if the game is a tie
if (remainingsTurns(grid) == 0)
{
return 0;
}
if (maxMove)
{
int best = -1000;
for (int k = 0; k < 3; k++)
{
for (int i = 0; i < 3; i++)
{
if (grid[k][i] == ' ')
{
grid[k][i] = 'x';
best = max(best, miniMax(grid, turn + 1, !maxMove));
grid[k][i] = ' ';
}
}
}
return best;
}
else
{
int best = 1000;
for (int k = 0; k < 3; k++)
{
for (int i = 0; i < 3; i++)
{
if (grid[k][i] == ' ')
{
grid[k][i] = 'o';
best = min(best, miniMax(grid, turn + 1, !maxMove));
grid[k][i] = ' ';
}
}
}
return best;
}
}
Move playerMov(char grid[3][3])
{
Move playerMove;
int input = -1;
cout << "Enter the column you want to play (1, 2 or 3)" << endl;
cin >> input;
if (input == 1 || input == 2 || input == 3)
{
playerMove.columns = input-1;
input = -1;
}
else
{
cout << "Error, enter a valid number!" << endl;
playerMov(grid);
}
cout << "Enter the line you want to play (1, 2 or 3)" << endl;
cin >> input;
if (input == 1 || input == 2 || input == 3)
{
playerMove.line = input-1;
input = -1;
}
else
{
cout << "Error, enter a valid number!" << endl;
playerMov(grid);
}
return playerMove;
}
//return the best move using the MiniMax
Move findMove(char grid[3][3])
{
int best = -1000;
Move move;
move.line = -1;
move.columns = -1;
//Check all move to find if this move is the best possible move
for (int k = 0; k < 3; k++)
{
for (int i = 0; i < 3; i++)
{
if (grid[k][i] == ' ')
{
grid[k][i] = 'x';
int moveValue = miniMax(grid, 0, false);
grid[k][i] = ' ';
if (moveValue > best)
{
move.line = k;
move.columns = i;
}
}
}
}
return move;
}
int main()
{
char grid[3][3];
int turn = 0;
Move playerMove, algoMove;
for (int k = 0; k < 3; k++)
{
for (int i = 0; i < 3; i++)
{
grid[k][i] = ' ';
}
}
cout << "Welcome to the unbeatable Tic Tac Toe !" << endl;
do
{
printGrid(grid);
playerMove = playerMov(grid);
grid[playerMove.line][playerMove.columns] = 'o';
Move computerMove = findMove(grid);
grid[computerMove.line][computerMove.columns] = 'x';
} while (remainingsTurns(grid) > 0);
cout << endl;
}
but the movements of the algorithm doesn't seems right, it always choose the bottom right corner and i don't understand why...
This implementation is largely inspired by this article from Geek for Geek where i tried to steal the algorithm but i can't get it right to make it fit for single player.
What do i miss?
There are multiple bugs in your code:
You are checking the value of grid[0][0] in grid[0][2] == grid[1][1] && grid[0][2] == grid[2][0] case of the function evaluateBoard. It should be grid[0][2].
playerMov(grid); in the function playerMov should be return playerMov(grid);. Otherwise, the re-entered "correct" values will be dropped and (partly) uninitalized playerMov will be returned.
You should update best to moveValue when moveValue > best in the function findMove. (this should be the cause of the issue on your question)
I am a beginner in c++ and i made my first game, a snake game. I made it without any graphics library.
So far the things were good, my snake was just running fine and eating the fruit and score is also increasing.
At the moment my snake just runs while the key is pressed, but now I want to run my snake continuously and just change its direction with keys as we have seen in old snake games.
So far I have tried many things from my side, like a loop and all, but the things just didn't work in the way I wanted it to be.
There is my code-
#include<iostream>
#include<conio.h>
#include<Windows.h>
using namespace std;
bool gameOver;
const int width = 20;
const int height = 20;
int x, y, fruitX, fruitY, score;
int tailX[100], tailY[100];
int n_Tail;
enum eDirection {STOP = 0, LEFT , RIGHT ,UP , DOWN};
eDirection dir;
void setup()
{
gameOver = false;
dir = STOP;
x = width / 2;
y = height / 2;
fruitX = rand() % width;
fruitY = rand() % height;
score = 0;
}
void draw()
{
system("cls");
for(int i = 0 ;i < width+1; i++)
{
cout << "#"; //for Upper wall
}
cout << "\n";
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width ; j++)
{
if (j==0)
{
cout <<"#";
}
if (i == y && j == x)
{
cout <<"0";
}
else if (i == fruitY && j == fruitX)
{
cout <<"f";
width - 1;
}
else if (j== width -1)
{
cout << "#";
}
else
{
bool print = false;
for (int k = 0; k <n_Tail; k++)
{
if (tailX[k] == j && tailY[k] == i )
{
cout << "o";
print = true;
}
}
if (!print)
{
cout <<" ";
}
}
}
cout << "\n";
}
for (int i = 0; i < width+1; i++)
{
cout << "#"; //for lower wall
}
cout <<"\n";
cout << "Score = " << score;
}
void input()
{
switch (_getch())
{
case 'a': dir = LEFT;
break;
case 'w': dir = UP;
break;
case 's': dir = DOWN;
break;
case 'd': dir = RIGHT;
break;
}
}
void logics()
{
int prevX = tailX[0];
int prevY = tailY[0];
int prev2X, prev2Y;
tailX[0] = x;
tailY[0] = y;
for (int i = 1; i < n_Tail; i++)
{
prev2X = tailX[i];
prev2Y = tailY[i];
tailX[i] = prevX;
tailY[i] = prevY;
prevX = prev2X;
prevY = prev2Y;
}
switch (dir)
{
case LEFT:
x--;
break;
case RIGHT:
x++;
break;
case UP:
y--;
break;
case DOWN:
y++;
break;
default:
y--;
}
for (int i = 0; i < n_Tail; i++)
{
if (tailX[i] == x && tailY[i] == y)
{
gameOver = true;
}
}
//if (x> width||x<0||y>height||y<0)
//{
//gameOver = true;
//}
if (x > width-2)x = 0; else if (x < 0)x = width - 2;
if (y > height-1)y = 0; else if (y < 0)y = height - 1;
{
}
if (x == fruitX && y == fruitY)
{
score = score + 10;
fruitX = rand() % width;
fruitY = rand() % height;
n_Tail++;
}
}
int main()
{
setup();
while (!gameOver)
{
draw();
input();
logics();
Sleep(10);
}
}
someone please help me with this so i can continue learning c++ peacefully.
As I'm sure you noticed when you used your debugger.
No? No debugger? This is your essential read!
You're using _getch to read the input.
getch is blocking - meaning it will wait until you press a key. It's not really what you want.
This post explains how to make a non-blocking version.
I'm making a board game, and I was just wondering how to search through an array to find an element (let's name it N in this case), and each time N is counted, the counter goes up one. If N connects one side to the other the player wins.
This solution is only for one row of the array, hence why the counter is reset at the start of each 'i' iteration.
void board::winner(int x, int y)
{
int count = 0;
for (int i = 0; i < col; i++)
{
count = 0;
for (int j = 0; j < row; xaxis++)
{
if (arr[i][j] == 'N')
{
count++;
}
}
if (count == col) // == to col because we are testing straight lines
{
cout << "P2 wins!";
}
}
Move you initialization of count to above the first for loop.
Move the if statement after the end of the first for loop.
void board::winner(int x, int y)
{
int count = 0;
for (int i = 0; i < col; i++)
{
for (int j = 0; j < row; xaxis++)
{
if (arr[i][j] == 'N')
{
count++;
}
}
}
if (count == col)
{
cout << "P2 wins!";
}
}
You can make the loop more efficient by terminating the loops after the first duplicate is found:
for (int i = 0; i < col; ++i)
{
for (int j = 0; j < row; ++j)
{
if (arr[i][j] == 'N')
{
++count;
if (count > 1)
{
break;
}
}
}
if (count > 1)
{
break;
}
}
The above code will terminate as soon as the first duplicate is found, thus not searching the entire board.
So I'm currently working on a small project named dungeon crawl, where the user controls a char, player, and tries to reach another char, treasure. So far I have been able to program this but every time I print the board, it prints another game board right below the previous one! I want the board to constantly update the position of the player, not move the player and then print out a whole new board! I know this is a logic error but I cannot seem to find an answer, thanks in advance guys:
class Player
{
public:
int posX = 5;
int posY = 10;
char avatar = 'G';
};
class Treasure
{
public:
int posX = 2;
int posY = 10;
char avatar = 'X';
};
char board[10][20];
char player_move = 0;
bool player_win = 0;
Player p;
Treasure t;
void fill_board()
{
for (int i = 0; i < 10; ++i)
{
for (int j = 0; j < 20; ++j)
board[i][j] = '.';
}
}
void print_board()
{
for (int i = 0; i < 10; ++i)
{
for (int j = 0; j < 20; ++j)
{
cout << board[i][j];
}
cout << endl;
}
}
void set_player()
{
board[p.posX][p.posY] = p.avatar;
}
void erase_board(char b[][20])
{
for (int i = 0; i < 20; ++i)
{
for (int j = 0; j < 40; ++j)
board[i][j] = 0;
}
}
int main()
{
// Make board
fill_board();
// Set initial player position
board[p.posX][p.posY] = p.avatar;
// Set treasure position
board[t.posX][t.posY] = t.avatar;
// Start of game
player_win = false;
cout << "Welcome to dungeon crawl! To move press 'w', 'a', 's' , 'd' " << endl;
cout << endl;
//Prints board
print_board();
//Player movement
while (player_win == false)
{
cin >> player_move;
switch (player_move)
{
case 'w':
board[p.posX][p.posY] = '.';
p.posX -= 1;
break;
case 's':
board[p.posX][p.posY] = '.';
p.posX += 1;
break;
case 'a':
board[p.posX][p.posY] = '.';
p.posY -= 1;
break;
case 'd':
board[p.posX][p.posY] = '.';
p.posY += 1;
break;
}
set_player();
print_board();
// Check if player has won
if (p.posX == t.posX && p.posY == t.posY)
player_win = true;
}
cout << "\nCongratulations you win!!" << endl;
return 0;
}
Hi there I am writing a small console game for school. The problem if have is that pushing 'w' and 'a' works (they minus 1 to the row or col element of 2d array) but the 'd' and 's' do not work (they add 1 to the row or col element of 2d array). If you try the code, you will notice that pushing s or d will make the screen glitch out.
Please refer to Move() and Update() of the CGame class.
TY
#include <iostream>
#include <string>
#include <conio.h>
#include <ctime>
#include <cstdlib>
using namespace std;
const char PLAYER = 'H';
const char WALLS = '=';
const int ROWS = 20;
const int COLS = 50;
//Map class generates map, player and enemies
class CMap{
public:
char m_cMap[20][50];
//Map constructor
CMap(int _row, int _col){
//Spawn boarders
for (int i = 0; i < ROWS; i++){
for (int j = 0; j < COLS; j++){
if (i == 0 || i == ROWS - 1){
m_cMap[i][j] = WALLS;
}else if (j == 0 || j == COLS - 1){
m_cMap[i][j] = WALLS;
}else{
m_cMap[i][j] = ' ';
}
}
}
//Spawn player
m_cMap[_row][_col] = PLAYER;
}
};
class CGame{
private:
void Move(CMap& _map, char _move, int _i, int _j){
_map.m_cMap[_i][_j] = ' ';
switch (_move){
case 'w':
case 'W':
_i--;
break;
case 's':
case 'S':
_i++;
break;
case 'a':
case 'A':
_j--;
break;
case 'd':
case 'D':
_j++;
break;
default:
break;
}
_map.m_cMap[_i][_j] = PLAYER;
}
public:
//Functions for the main gameloop
void Update(CMap& _map, char _move){
for (int i = 0; i < ROWS; i++){
for (int j = 0; j < COLS; j++){
//Move Player
if (_map.m_cMap[i][j] == PLAYER){
Move(_map, _move, i, j);
}
//Move Enemies...
}
}
}
void Check(CMap _map){}
void Display(CMap _map){
system("CLS");
for (int i = 0; i < ROWS; i++){
for (int j = 0; j < COLS; j++){
cout << _map.m_cMap[i][j];
}
cout << endl;
}
}
};
int main(){
//Generate random numbers for player spawn
srand(time(0));
int randRow = (rand() % 17) + 1;
int randCol = randRow + 20;
//Instantiate the game and map objects
CGame game;
CMap map(randRow, randCol);
//Game loop
bool gg = false;
while (!gg){
//PlayerController
char move = 0;
if (_kbhit){
move = _getch();
}
game.Update(map, move);
//game.Check(map);
game.Display(map);
}
}
The problem is that when you move your player you don't break the cycles. And they move it again since the player gets detected again. Modify your Update function like this:
//Functions for the main gameloop
void Update(CMap& _map, char _move){
bool moved = false;
for (int i = 0; i < ROWS; i++){
for (int j = 0; j < COLS; j++){
//Move Player
if (_map.m_cMap[i][j] == PLAYER){
Move(_map, _move, i, j);
moved = true;
break;
}
//Move Enemies...
}
if (moved)
break;
}
}