Snake in C++ won't turn twice in a row - c++

I've just recently started to learn C++. I decided to program a little Snake game that runs in the console. It is relatively simple and doesn't look amazing, but it does it's thing as it's supposed to.The only issue I am having, is that my Snake won't turn twice in a row. In other words you can't do tight U-turns with it. It will however turn immediately after pressing the button. (Unless you just turned that is).
My code is 120 lines long so here it is:
First my includes and namespace:
#include <iostream>
#include <vector>
#include <conio.h>
#include <windows.h>
#include <random>
using namespace std;
This function draws the whole field in the console:
void drawGrid(vector<vector<char>> &g, int height, int width, int score, int time)
{
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), { 0,0 });
for (int r = 0; r < height; r++)
{
for (int c = 0; c < width; c++) std::cout << g[c][r] << " ";
std::cout << '|' << endl;
}
std::cout << "Current score: " << score << " ";
std::cout << "\nCurrent speed: " << time << " ";
}
This function checks whether the food is under the snake:
bool foodSnake(vector<int> &f, vector<vector<int>> &t, int l)
{
for (int i = 0; i < l; i++)
if (f[0] == t[i][0] && f[1] == t[i][1]) return true;
return false;
}
And this is the big poobah:
int main(void)
{
int sleeptime = 1000; // how long the break is between each frame
bool foodExists = 0;
int width = 20; //width and height of the field
int height = 15;
mt19937_64 engine; //random distributions for food generation
uniform_int_distribution<int> heightDist(0, height - 1);
uniform_int_distribution<int> widthDist(0, width - 1);
int tailLengthstart = 4;
int tailLength = tailLengthstart;
char movementDirection = 'u'; //starts moving upwards
char input;
bool alive = 1; //keeps the program running on death = 0
vector<int> pos = { (width - 1) / 2,(height - 1) / 2 }; //starts in the middle of field
vector<int> foodPos = pos; // so that the food generates at the beginning
vector<vector<int>> tail(tailLength, pos);
vector<vector<char>> emptyGrid(width, vector<char>(height, ' '));
vector<vector<char>> grid = emptyGrid;
while (alive) //runs main program until alive == 0
{
grid = emptyGrid; // clear grid
grid[pos[0]][pos[1]] = 'Q'; //place head in grid
if (!foodExists) //generates food if it was eaten
{
while (foodSnake(foodPos, tail, tailLength) || foodPos == pos)
{ // keeps regenerating until it isn't under the snake
foodPos[0] = widthDist(engine);
foodPos[1] = heightDist(engine);
}
foodExists = 1;
}
grid[foodPos[0]][foodPos[1]] = 'X'; //place food in grid
for (int i = 0; i < tailLength; i++) grid[tail[i][0]][tail[i][1]] = 'O'; // place tail in grid
drawGrid(grid, height, width, tailLength - tailLengthstart, sleeptime); //call above function to draw the grid
input = '_';
Sleep(sleeptime);
if (_kbhit()) { //this was the best way I found to wait for input
input = _getch();
switch (input)
{ //disallows moving in opposite direction otherwise changes direction
case 'w':
if (movementDirection == 'd') break;
movementDirection = 'u';
break;
case 'a':
if (movementDirection == 'r') break;
movementDirection = 'l';
break;
case 's':
if (movementDirection == 'u') break;
movementDirection = 'd';
break;
case 'd':
if (movementDirection == 'l') break;
movementDirection = 'r';
break;
case '_':
break;
}
}
for (int i = tailLength - 1; i > 0; i--)
tail[i] = tail[i - 1];
tail[0] = pos; //move the tail along
if (movementDirection == 'u') pos[1]--;
if (movementDirection == 'l') pos[0]--;
if (movementDirection == 'r') pos[0]++;
if (movementDirection == 'd') pos[1]++; // move the head
if (pos[0] < 0 || pos[0] > width - 1 || pos[1] < 0 || pos[1] > height - 1)
alive = 0; // if head is out of bounds -> dead
for (int i = 0; i < tailLength; i++)
if (pos == tail[i])
alive = 0; // if head is on tail -> dead
if (foodPos == pos)
{ // if head is on food -> eat
foodExists = 0; // food needs to be generated
tail.push_back(tail[tailLength - 1]); //tail adds a link
tailLength++; // tail is now longer
if (tailLength % 5 == 0) sleeptime *= 0.75; // at certain lengths game speeds up
}
}
this next part happens once you are dead or alive == 0
std::system("cls");
std::cout << endl << endl << endl << endl << "\tYou have died" << endl << endl << endl << endl;
std::cout << endl;
std::system("pause");
return 0;
}
So if anyone has an idea why it's not turning quickly, please help. Or any other improvement ideas are welcome as well.

The problem with movement is caused by fact that you advance tail and changing direction causes head advance immediately. That means that there is always a step before snake would actually turn.
The state set as I see it:
Setup scene.
Check key.
Change direction of movement if key pressed and it isn't opposite of current direction.
Make old head tail and add a head element in set direction from old head.
Check for death
Check for food.
If food found, grow tail by changing TailLength.
If snake length is greater than TailLength, remove tail elements until they are equal.
Render scene
Sleep and go to 2.
It is better to represent snake by a list, not by a vector. It won't reallocate memory on size change or if you will cut first elements out.
If your platform is Windows (obviously, you're using Sleep() function instead of usleep), the answer to this question offers better solution for key detection.
Get key press in windows console
Similar solutions exist for POSIX platforms.

There is a little problem that you're waiting sleeptime even the key was pressed
Sleep(sleeptime);
The main cycle may be like this pseudo code
while (IsAlive())
{
currtime = 0;
DrawState();
while (currtime++ < sleeptime)
{
if (CheckAndProcessKeyboardInput())
break;
SleepOneMilliSecond();
}
}

Related

My character going left but not going right (CONSOLE GAME)

I working on my project this project have a frame to [100] x [25] matrix and i try to add animation but my character is going left but it's not going right.
i tried with "counter" variable but its not work.
int counter = 1;
int counter2 = 1;
int left_border = 1;
int matris1 = sizeof(map)/100;
int matris2 = sizeof(map[0])/4;
int startx = 19;
int starty = 8;
while (true)
...
int right = 0, left = 0;
...
for (int a = 0; a < matris2; a++)
cout << "\n#"; //i have this because i make it square map.
for (int k = 0; k < matris1 - 2; k++)
{
if (left == 1)
{
if (((startx+2)-counter) == left_border)
{
counter = 0;
//cout << "SINIR!!"<< endl ;
}
if (k == (startx-counter) and a == starty)
{
counter += 1;
cout << "O";
}
else {
cout << " ";
}
}
else if (right == 1)
{
if (k == (startx+counter2) and a == starty)
{
counter2 += 1;
cout << "O";
}
its need to be going right but its not.
if you need full code.
https://codeshare.io/UbKVU
[![This is the map and "O" is the character]
https://i.stack.imgur.com/uyGQo.png
The code is very difficult to follow - you should have a coordinate system. I've made a simple example below. Update the player coordinate when a key is pressed and redraw the map x by y position, if the player is there then draw the 'O', otherwise if its a wall draw an 'X' (in this case), otherwise draw a space ' '.
using namespace std;
#include <iostream>
#include <conio.h>
#include <stdlib.h>
#define MAPW 15 // map width
#define MAPH 15 // map height
int map[MAPW][MAPH];
#define WALL 1
#define EMPTY 0
void initmap()
{
// just set the map to have walls around the border
for (int x = 0; x < MAPW; x++)
{
for (int y = 0; y < MAPH; y++)
{
if (x == 0 || y == 0 || x == (MAPW - 1) || y == (MAPH - 1))
map[x][y] = WALL;
else
map[x][y] = EMPTY;
}
}
}
int px = MAPW / 2; // player x
int py = MAPH / 2; // player y
void main()
{
initmap(); // initialize map
cout << "Press A/W/S/D to begin and move";
while (1)
{
if (kbhit()) // key pressed?
{
switch (getch()) // which key?
{
case 'a':
if (px > 0 && map[px - 1][py] != WALL) // can go left?
px--; // update x coordinate
break;
case 'd':
if (px < (MAPW-1) && map[px + 1][py] != WALL) // can go right?
px++; // update x coordinate
break;
case 'w':
if (py > 0 && map[px][py - 1] != WALL) // can go up?
py--; // update y coordinate
break;
case 's':
if (py < MAPH && map[px][py + 1] != WALL) // can go down?
py++; // update y coordinate
break;
}
// update map - clear screen and redraw
system("CLS");
// draw map each line
for (int y = 0; y < MAPH; y++)
{
for (int x = 0; x < MAPW; x++)
{
// its a wall?
if (map[x][y] == WALL)
cout << "X";
else
{
// is the player there?
if (x == px && y == py)
{
// draw the player
cout << "O";
}
else // empty space
cout << " ";
}
}
// next line
cout << "\n";
}
}
}
}

Why doesn't the Player.x and Player.y variables change?

Edit #2: Ok, I did another *.cpp to check if the codes for Arrow Keys were right. Doing that, I noticed keyPressed variable in detectKeyPressing() had the wrong type of variable, so I changed it from char to int and changed the codes.
Once I did that, it worked. Now I have put the limits, so the Player cannot go outside the square. But I have another problem, the movement is too tough and if you press the keys too fast, the instructions run with a annoying delay. I know I should use either Sleep(ms) or Delay(ms), but I don't know when I should use it.
This is the new code:
#include <iostream>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <Windows.h>
using namespace std;
int detectKeyPressing() {
// 0: Escape
// 1: Enter
//2: Up
// 3: Left
// 4: Down
// 5: Right
int keyPressed = 0;
while (keyPressed != 27) {
if (keyPressed == 0 || keyPressed == 224) {
keyPressed = _getch(); //First value of _getch() when any of the arrow keys are pressed is "224", the next one is the code depending of which arrow you pressed
}
else if (keyPressed == 13) {
return 1;
}
else {
switch (keyPressed) {
//Up
case 72:
return 2;
break;
//Left
case 75:
return 3;
break;
//Down
case 80:
return 4;
break;
//Right
case 77:
return 5;
break;
//Default
default:
return -1;
break;
}
}
};
return 0;
};
int mainMenu() {
int enterPressed = 0;
cout << "Press Enter to Begin, or ESC to exit" << endl;
enterPressed = detectKeyPressing();
system("cls");
return enterPressed;
};
void draw(int playerX, int playerY) {
//Player coordinates, made for testing
cout << "Player.x = " << playerX << endl << "Player.y = " << playerY << endl;
//The next 8 spaces go blank
for (int i = 1; i < 8; i++) {
cout << endl;
}
//Square Limit Making
//Top Limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
cout << endl;
//Border limits and inside the Square
for (int ih = 1; ih < 30; ih++) {
//Left border
cout << "|";
//Inside the Square
for (int iw = 1; iw < 78; iw++) {
if (iw == playerX && ih == playerY) {
cout << "a"; //This is supposed to be ♥ but I don't know how to put it in the screen with a cout
}
else {
cout << " ";
}
}
//Right border
cout << "|" << endl;
}
//Bottom limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
}
int main() {
//Hide cursor
HANDLE hCon;
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 1;
cci.bVisible = FALSE;
SetConsoleCursorInfo(hCon, &cci);
//Variable Making
int gameStarted = -1; // 1 if game is running, 0 if not
//int t = 0; //Turn Counter, not useful for now
Sleep(200); //Wait to get a new seed
srand(time(NULL)); //Seed for rand()
//Menu Loop, remember, 1 if game starts running, 0 if you exit
while (gameStarted > 1 || gameStarted < 0) {
gameStarted = mainMenu();
}
//Like Void Start() in Unity
if (gameStarted == 1) {
int pressedKey = -1; //Creating pressedKey at Start
class Player {
public:
int life = 20;
int accuracy = 80 + (rand() % 100) / 20;
int damage = 5 + (accuracy / 10) + (rand() % 100) / 50;
bool isAlive = true;
int x = 39;
int y = 24;
int speed = 1;
};
class Enemy {
public:
int life = 100;
int satisfaction = 0;
bool isAlive = true;
bool isSatisfied = false;
int damage = 2 + (rand() % 100) / 20;
};
Player Player;
Enemy Enemy;
draw(Player.x, Player.y);
//Like Void Update() in Unity
while (gameStarted != 0) {
pressedKey = detectKeyPressing(); // Save detectKeyPressing()'s return in pressedKey
//Draw if proyectile is moving - not yet
//Draw if player is moving (pay attention specially to this part)
if (pressedKey == 0) {
gameStarted = 0; //if ESC is pressed, exit the loop and exits
}
//If any of the Arrow Keys are pressed
else if (pressedKey > 1 && pressedKey < 6) {
switch (pressedKey) {
//Up
case 2:
Sleep(200);
if (Player.y == Player.speed) {
Player.y = Player.speed; //Top Limit
}
else {
Player.y -= Player.speed;
}
break;
//Left
case 3:
Sleep(200);
if (Player.x == Player.speed) {
Player.x = Player.speed; //Left Limit
}
else {
Player.x -= Player.speed;
}
break;
//Down
case 4:
Sleep(200);
if (Player.y == 30 - Player.speed) {
Player.y = 30 - Player.speed; //Bottom Limit
}
else {
Player.y += Player.speed;
}
break;
//Right
case 5:
Sleep(200);
if (Player.x == 78 - Player.speed) {
Player.x = 78 - Player.speed; //Right Limit
}
else {
Player.x += Player.speed;
}
break;
};
system("cls"); //Erase all
draw(Player.x, Player.y); //Redraw everything, with Player.x or Player.y modified
};
};
};
return 0;
};
Edit #1: I fixed the mistakes you told me, here's the main function modified. It isn't working though.
int main(){
//Hide cursor
HANDLE hCon;
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 50;
cci.bVisible = FALSE; //Changed "TRUE" to "FALSE"
SetConsoleCursorInfo(hCon, &cci);
//Variable Making
int gameStarted = -1; // 1 if game is running, 0 if not
//int t = 0; //Turn Counter, not useful for now
Sleep(200); //Wait to get a new seed
srand(time(NULL)); //Seed for rand()
//Menu Loop, remember, 1 if game starts running, 0 if you exit
while (gameStarted > 1 || gameStarted < 0) {
gameStarted = mainMenu();
}
//Like Void Start() in Unity
if (gameStarted == 1) {
int pressedKey = -1; //Creating pressedKey at Start
class Player {
public:
int life = 20;
int accuracy = 80 + (rand() % 100) / 20;
int damage = 5 + (accuracy / 10) + (rand() % 100) / 50;
bool isAlive = true;
int x = 39;
int y = 24;
int speed = 2;
};
class Enemy {
public:
int life = 100;
int satisfaction = 0;
bool isAlive = true;
bool isSatisfied = false;
int damage = 2 + (rand() % 100) / 20;
};
Player Player;
Enemy Enemy;
draw(Player.x, Player.y);
//Like Void Update() in Unity
while (gameStarted != 0) {
pressedKey = detectKeyPressing(); //Save detectKeyPressing()'s return in pressedKey
//Draw if proyectile is moving - not yet
//Draw if player is moving (pay attention specially to this part)
if (pressedKey == 0) {
gameStarted = 0; //if ESC is pressed, exit the loop and exits
}
//If any of the Arrow Keys are pressed
else if (pressedKey > 1 && pressedKey < 6) {
cout << "There's no problem in Else If statement"; //Couts made for testing
switch (pressedKey) {
cout << "There's no problem in Switch statement";
//Up
case 2:
Player.y -= Player.speed;
cout << "You moved Up";
break;
//Left
case 3:
Player.x -= Player.speed; //Fixed Left movement
cout << "You moved Left";
break;
//Down
case 4:
Player.y += Player.speed;
cout << "You moved Down";
break;
//Right
case 5:
Player.x += Player.speed;
cout << "You moved Right";
break;
};
//system("cls"); //Erase all
//draw(Player.x, Player.y); //Redraw everything, with Player.x and Player.y supposedly modified
};
};
};
return 0;
};
Initial Post: I'm trying to do something like an Undertale normal fight and now I'm doing the "dodging attacks" part, but I'm stuck at making the player move (Yep, that "a") because it didn't update when I press an arrow key (for movement). It is supposed to draw, and put the Player in Player.x and Player.y, so I did something in main() to edit these variables depending on the arrow key you pressed, and then erase and re-draw with the Player.x or Player.y modified.
Here's the code:
#include <iostream>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <Windows.h>
using namespace std;
int detectKeyPressing(){
// 0: Escape
// 1: Enter
// 2: Up
// 3: Left
// 4: Down
// 5: Right
char keyPressed = 0;
while (keyPressed != 27){
if(keyPressed == 0){
keyPressed = _getch();
}
else if(keyPressed == 13){
return 1;
}
else{
switch (keyPressed) {
//Up
case 65:
return 2;
break;
//Left
case 68:
return 3;
break;
//Down
case 66:
return 4;
break;
//Right
case 67:
return 5;
break;
//Default
default:
return -1;
break;
}
}
};
return 0;
};
int mainMenu(){
int enterPressed = 0;
cout << "Press Enter to Begin, or ESC to exit" << endl;
enterPressed = detectKeyPressing();
system("cls");
return enterPressed;
};
void draw(int playerX, int playerY) {
//Player coordinates, made for testing
cout << "Player.x = " << playerX << endl << "Player.y = " << playerY << endl;
//The next 8 spaces go blank
for (int i = 1; i < 8; i++) {
cout << endl;
}
//Square Limit Making
//Top Limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
cout << endl;
//Border limits and inside the Square
for (int ih = 1; ih < 30; ih++) {
//Left border
cout << "|";
//Inside the Square
for (int iw = 1; iw < 78; iw++) {
if (iw == playerX && ih == playerY){
cout << "a"; //This is supposed to be ♥ but I don't know how to put it in the screen with a cout
}
else {
cout << " ";
}
}
//Right border
cout << "|" << endl;
}
//Bottom limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
}
int main(){
//Hide cursor
HANDLE hCon;
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 50;
cci.bVisible = TRUE;
SetConsoleCursorInfo(hCon, &cci);
//Variable Making
int gameStarted = -1; // 1 if game is running, 0 if not
//int t = 0; //Turn Counter, not useful for now
Sleep(200); //Wait to get a new seed
srand(time(NULL)); //Seed for rand()
//Menu Loop, remember, 1 if game starts running, 0 if you exit
while (gameStarted > 1 || gameStarted < 0) {
gameStarted = mainMenu();
}
//Like Void Start() in Unity
if (gameStarted == 1) {
class Player {
public:
int life = 20;
int accuracy = 80 + (rand() % 100) / 20;
int damage = 5 + (accuracy / 10) + (rand() % 100) / 50;
bool isAlive = true;
int x = 39;
int y = 24;
int speed = 2;
};
class Enemy {
public:
int life = 100;
int satisfaction = 0;
bool isAlive = true;
bool isSatisfied = false;
int damage = 2 + (rand() % 100) / 20;
};
Player Player;
Enemy Enemy;
draw(Player.x, Player.y);
//Like Void Update() in Unity
while (gameStarted != 0) {
//Draw if proyectile is moving - not yet
//Draw if player is moving (pay attention specially to this part)
if (detectKeyPressing() == 0) {
gameStarted = 0; //if ESC is pressed, exit the loop and exits
}
//If any of the Arrow Keys are pressed
else if (detectKeyPressing() > 1 && detectKeyPressing() < 6) {
switch (detectKeyPressing()) {
//Up
case 2:
Player.y -= Player.speed;
break;
//Left
case 3:
Player.x += Player.speed;
break;
//Down
case 4:
Player.y += Player.speed;
break;
//Right
case 5:
Player.x += Player.speed;
break;
};
system("cls"); //Erase all
draw(Player.x, Player.y); //Redraw everything, with Player.x and Player.y supposedly modified
};
};
};
return 0;
};
I did a few tests and it seems that the else if in "//If any of the Arrow Keys is Pressed" part isn't running but I don't know why.
I would really appreciate any help you can provide. Sorry if anything isn't well written, I'm not a native english speaker.
Where you have this comment
//Draw if proyectile is moving - not yet add a variable to save your pressed key, something like
int pressedKey = detectKeyPressing();
Then, use that variable to check which condition is met within your if-else.
What’s happening is that you’re calling your function, thus asking/waiting for an input each time a condition is being checked.

How do I make an object go from point A to point B but point B is moving? C++

I am making a simple game to help me learn basic c++ code. I want to make a zombie able to follow / chase the player in a 2d snake-like environment. Though I haven't been able to find a way to get this to work yet.
#include <iostream>
#include <Windows.h>
#include <conio.h>
using namespace std;
const int width = 60;
const int height = 20;
int x, y;
int zombX, zombY;
void Setup()
{
x = width / 2;
y = height / 2;
zombX = rand() % width;
zombY = rand() % height;
}
void Draw()
{
system("cls");
for (int i = 0; i < width + 2; i++)
cout << "*";
cout << endl;
for (int i = 0; i < height; i++) //i = height
{
for (int j = 0; j < width; j++)
{
if (j == 0)
cout << "*";
if (i == y && j == x)
cout << "I";
else if (i == zombY && j == zombX)
cout << "Z";
else
{
bool print = false;
if (!print)
cout << " ";
}
if (j == width - 1)
cout << "*";
}
cout << endl;
}
for (int i = 0; i < width + 2; i++)
cout << "*";
cout << endl;
}
In your main loop, before you call Draw you change the position of the zombie. Make its position (on X or Y axis) one step closer to the player.
This can easily be done since you know the current position of the player. If zombie-X is higher than player-X, then decrease zombie-X. Or if opposite then increase zombie-X. Same with the Y position.
To not make the zombie just walk up-down (or left-right) you adjust the X position of the zombie every second time in the main loop, and the Y position every second time. Or you could select X or Y randomly.
In short, your "point B" is always the players current position.
Your game logic should be something like this.
Setup();
do
{
Draw();
Delay();
Update();
}while(!bIsEnd);
Update is where you update your objects position.
Including check for any human input (keyboard/mouse) and
move objects based on it.
Some objects are moved automatically (AI)
This function where you should put your update position's logic(I & Z)
I assume 'I' is human controlled and 'Z' is computer controlled (AI).
For 'I' you can get input from keyboard using _getch() function and do switch case.
For 'Z', because this is a game you should make it challenging.
Not too stupid or too smart.
You can give random for movement (X or Y direction).
For Every 4 update calls, you define its direction by calculating from your
'I' and 'Z' position.
if(X > ZombX)
ZombX += random(2);
else
ZombX -= random(2);
if(Y > ZombY)
ZombY += random(2);
else
ZombY -= random(2);
4 update calls is just example. You may use another constant or develop a a new logic.
if (X == ZombX && Y == ZombY) , you set bIsEnd.

Why can't my code record the results of the game?

I've been trying to do this program for a while now but i have a problem for some reason.
I am supposed to make a program where I have a 8*8 2D array with a mouse situated in the center of an island surrounded with by 1*1 2D array of water and a cat that is located in another fixed location (away from the mouse) The mouse is allowed to move one tile per move and can not move diagonally.
The movement is determined by a random number generator that is limited to 0,1,2 and 3 {each number represents a direction). The mouse is allowed 100 moves and then the game stops, it also stops when the mouse bumps into the cat (death), crosses a bridge that is situated in the middle of the right side(escape)or goes into water (drown) the program is supposed to run a couple of times and record the number of deaths, escapes and drowns.but I keep getting zero deaths, zero escapes and zero drowns every time i try to run the program.
here is my code:
#include<iostream>
#include<stdlib.h>
#include <time.h>
using namespace std;
#define N 9
#define M 9
int direction(int x, int A[M][N], int row, int col)
{
int m;
if (x == 0)
m = A[row - 1][col]; //North
if (x == 1)
m = A[row+1][col]; //South
if (x == 2)
m = A[row][col - 1]; //West
if (x == 3)
m = A[row][col + 1]; //East
return m;
}
int main()
{
int v, S1, S2, S3, S4;
int Mouse, Cat, Bridge;
int death = 0, escape = 0, drown = 0;
int A[M][N];
for (int a = 0;a < 10;a++)
{
for (int i = 0;i < M;i++)
S1 = A[i][0] = 4;
for (int i = 0;i < M;i++)
S2 = A[i][8] = 4;
for (int j = 0;j < N;j++)
S3 = A[0][j] = 4;
for (int j = 0;j < N;j++)
S4 = A[8][j] = 4;
for (int i = 1;i < M;i++)
{
for (int j = 1;j < N;j++)
A[i][j] = 0;
}
Mouse = A[4][4] = 1; //mouse
Cat = A[5][2] = 2; //cat
Bridge = A[4][8] = 3; //bridge
srand((unsigned)time(NULL));
for (int b = 0;b < 100;b++)
{ v = rand() % 4;
int m=direction(v, A, 4, 4);
if (m == Cat)
{
death++;
break;
}
else if (m == Bridge)
{
escape++;
break;
}
else if (m == S1 || m == S2 || m == S3 || m == S4)
{
drown++;
break;
}
}
}
cout << "The mouse died " << death << " times and escaped " << escape << " times and drowned " << drown << " times" << endl;
return 0;
}
The mouse never moves from initial location and the terrain near the mouse is safe. So nothing can happen.
Replace the cicle in the code with
int x = 4,y=4; // Mouse coords
for (int b = 0;b < 100;b++)
{ v = rand() % 4;
int m=direction(v, A, x, y);
if (m == Cat)
{
death++;
break;
}
else if (m == Bridge)
{
escape++;
break;
}
else if (m == S1 || m == S2 || m == S3 || m == S4)
{
drown++;
break;
}
// Nothing happened, move the mouse
A[x][y] = 0; // Clear the actual mouse location
if(v==0) x--;
if(v==1) x++;
if(v==2) y--;
if(v==4) y++;
A[x][y] = 1; // Mark the mouse on the map
}
There are some problems: you said the program should run a couple of times, but actually it runs just once. Worst of all, when the mouse reach the cat, the bridge, or drown, the program exits with:
return 0;
If you want to run it twice (or as many times as you want), you should put a loop like
for (int a = 0;a < 2;a++)
just after the variable declarations and before the initialization of the grid. This way, every time it runs the loop it reinitialize everything except your count variables.
Then, you should substitute the return(0) with a break;, so the inner loop exits every time something happens but the program still runs, and at the end you'll se the output print with your counts.
Oh, and I just saw you call direction with the third and fourth paarmeters fixed to "4".
...oh...and the mouse doesn't move at all. You should also update its location in the grid.

C++ iterate through a 2D vector to find 3 in a row

Hey all, working on a C++ little game, "Connect 3." This is just like Connect 4, except we only need a match of 3 to win the game. I am storing my board in a 2D vector, which holds ints.
vector< vector<int> > vector2d;
And I have an "X" stored as a 1, and an "O" stored as a -1, with 0 being an empty space. It seems to be working so far.
So, in my algorithm for playing against the computer, it finds the best move possible. I have the algorithm finished, but it needs to know when a "base case" has been hit. (It's recursive.) A base case is either:
Someone has gotten 3 in a row, or
The board is full
Checking if the board is full is easy. I just iterate through and see if any space is a "0". If it is, the board isn't full. But before I check that, I need to see if anyone has gotten 3 in a row, which is where I'm having issues. The only way I can think of doing this is big and complicated, going through the board 3 different times, looking for Horizontal matches of 3, vertical matches of 3, and Diagonal matches of 3. I'm not even sure where to begin in doing that, and I'm hoping there is a better way to do this. Help would be much appreciated!
Also, not sure I'm allowed to use Boost, I haven't yet so far, and I'd like to not have to use it. (Not sure if the school computers have it).
Edit: The board does not need to be 3 by 3. It could be 1 by 7, 7 by 7, or any size. If it's not a legal size (0,0), my code will tell the user that, but any other board should work. I've used the vector sizes to see how big the board is.
You don't have to check the whole board every time. Only the new piece makes a difference so you only have to check those end conditions that include the new piece. There are 8 different directions you need to check, but every two of them are on the same line and should be checked together. Directions can be defined as (delta_X, delta_Y) pairs: (1,0),(0,1),(1,1),(1,-1). Your code should traverse in each direction (as in code from Leonid) and try to count as many pieces with the same value as new piece. Then it should traverse in opposite direction which is (-x,-y) from current direction, and count those pieces as well. If the number of counted pieces is N-1 (new piece is already counted) then you have a winner.
So lets say you are using an 3x3 board. There are a finite number of winning lines that can be formed.
1 0 0 1 1 1 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 1 0
1 0 0 0 0 0 0 1 0 0 1 0 0 0 1 1 1 1 0 0 0 0 1 0
1 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 1 1 1 0 1 0
Now if you give each board location a bit assignment as follows:
1 2 4
8 16 32
64 128 256
now you can work out that the 8 winning lines are as follows:
1 | 8 | 64 = 73
1 | 2 | 4 = 7
1 | 16 | 256 = 273
4 | 16 | 64 = 84
4 | 32 | 256 = 292
8 | 16 | 32 = 56
64 | 128 | 256 = 448
2 | 16 | 128 = 146
Now if you store a 1 in any bit position that a given player has you can easily step through each of the "solutions" above and test against the 8 values above.
So suppose the 2 players have the following positions:
1 1 0 0 0 1
1 0 0 0 1 1
1 0 1 0 1 0
If you tot up there values as done for the "solutions" as follows you get
1 | 2 | 8 | 64 | 256 = 331
4 | 16 | 32 | 128 = 180
So we know the winnign line is the 1 | 8 | 64 = 73 line so we can test using a bit wise and as follows
331 & 73 = 73
180 & 73 = 0
So we can easily detect that player 1 has 3 in a row and has one as the result of the "and" is not 0.
This means you can calculate a winner in a maximum of 8 steps (ie checking both players running totals against the 8 possible answers).
Obviously complexity increases as you get larger and it can seem a lot more complicated when you run out of bits (look at std::bitset, for example of how to handle that) but the end game will ALWAYS take less iterations to check than a brute force method. Obviously it takes a bit more time to set up but you only calculate the end game conditions once per board type so that time gets amortised across several plays.
Anyway ... Thats how I'd do it :D
The following C++ O(N*M) solution from algorithmical complexity perspective is the best possible as we need to check in the worst case each cell of the board. It iterates over all cells in the board (i and j), tries to go in 4 directions (k), and from there checks that 3 cells (l) in direction k are occupied and equal.
vector<vector<int> > board(n, vector<int>(m)); // initialize
/* down down-right right up-right */
int di[] = {1, 1, 0, -1 }; // four directions i coordinate
int dj[] = {0, 1, 1, 1 }; // four directions j coordinate
for (int i = 0; i < n; i++) { // for each row
for (int j = 0; j < m; j++) { // for each column
for (int k = 0; k < 4; k++) { // for each direction
int ii = i, jj = j;
bool found = true;
if (board[ii][jj] == 0) continue; // empty space
for (int l = 1; l < 3 && found; l++) { // need 3 in a row
int iii = ii + di[k], jjj = jj + dj[k];
if (iii < 0 || iii >= n) found = false, continue; // off bounds
if (jjj < 0 || jjj >= n) found = false, continue; // off bounds
if (board[iii][jjj] != board[ii][jj]) found = false;
}
if (found) {
printf("Hurray!\n");
return;
}
}
}
}
I made a game like that , the first thing I ever made in C++ actually ( Who needs hello world :P)
And everyone can use it if they want.
Just don't forget it's my first C++ thing and it's definatly not properly coded :P but it has some nice C++ things like that in it. But there's a 100% optimized search algorithm in there that checks the absolute least amount of required permutation to check three in a row win conditions with heavy commenting and ASCII art. That could be quite usefull.
Oh almost forgot the mention, It's a console application thingy (black screen DOS envi ,whatever it's called). It has an AI that (if this is my latest version) Should do pretty well. AND the grid is dynamically built (which was the hard part) U can play 3 in a row, but with a max of 20x20 grid ( lame game I found out, much more fun as 4 in a row with gravity )
Here you go:
// DrieOpEenRij.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <iostream>
#include <string>
#include <typeinfo>
using namespace std;
typedef unsigned short USHORT;
//USE ONLY IN A SQUARE GRID
//This method checks a win for the minimimum amount of spaces covering 100% amount of the grid
//It has 100% coverage and close to 0% overhead, discrimination between who to check for is required and
//so currentMove char is required to check for win on 'H' human and 'C' Computer
void CheckForWin(const char* Grid_ptr , const USHORT GridSize , const USHORT GridWidth ,bool &humanWin, bool &computerWin, const char currentMove)
{
//check for an x from 1-end of array
//for all x's check if that makes a 3 line once per linetype
//check for horizontal win (dont get overhead on edges)
//A non square grid will have been detected by now
const USHORT rowStart = 0;
const USHORT rowEnd = GridWidth-1;
USHORT passRowCounter = 1;
const USHORT Side = GridWidth;
const USHORT cond1 = rowEnd-2;
const USHORT cond2 = GridSize-Side*2;
//Check for all human win options ( after a human move )
if (currentMove == 'H')
{
//Check for human win code
//Check all array slots for an occurence of 'X'
for(USHORT i = 0; i < GridSize; i++)
{
//Local stack variables, optimizations for iterations in loops and if statements,
//also for readability, this is (only efficient and) done only when it is guaranteed
//to be used in every for jump.
USHORT iModSide = i % Side;
USHORT SideMinTwo = Side - 2;
USHORT SidePlusTwo = Side + 2;
USHORT iPlusSide = i + Side;
USHORT iPlusSideTimesTwo = i + Side * 2;
USHORT iPlusOne = i + 1;
USHORT iPlusTwo = i + 2;
//If an X is found evaluate a win scenario
if (Grid_ptr[i] == 'X')
{
//For each row -->
if (iModSide < SideMinTwo)
{
//Check horizontal win from left to right
if (Grid_ptr[i + 1] == 'X' && Grid_ptr[i + 2] == 'X')
{
humanWin = true;
break;
}
}
//For the two values under the 'X' (colomn wise) check for 'X''X'
if (iPlusSideTimesTwo < GridSize)
{
if(Grid_ptr[iPlusSide] == 'X' && Grid_ptr[iPlusSideTimesTwo] == 'X')
{
humanWin = true;
break;
}
}
//CHECK FOR DIAGONAL WIN FROM TOP LEFT TO DOWN RIGHT IN ALL POSSIBLE+LEGAL SLOTS!
// [X] [X] [?] [?] This illustration shows that checking only at X will suffice
// [X] [X] [?] [?] for this specific check in screening for all Top Left --> Down Right
// [?] [?] [?] [?] diagonal wins, similarly the Top Right --> Down Left is done mirrored
// [?] [?] [?] [?] All other wins using this vector are impossible!
// Using this amount of conditions to find it saves a lot of searching and with it time
if (iPlusSideTimesTwo < GridSize && iModSide < SideMinTwo)
{
if (Grid_ptr[i+Side+1] == 'X' && Grid_ptr[iPlusSideTimesTwo+2] == 'X')
{
humanWin = true;
break;
}
}
//CHECK FOR DIAGONAL WIN FROM TOP LEFT TO DOWN RIGHT IN ALL POSSIBLE+LEGAL SLOTS!
// [?] [?] [Y] [Y] This illustration shows that checking only at Y will suffice
// [?] [?] [Y] [Y] for this specific check in screening for all Top Right --> Down Left
// [?] [?] [?] [?] diagonal wins, similarly the Top Left --> Down Right is done mirrored
// [?] [?] [?] [?] This because all other wins using this vector are impossible!
// Using this amount of conditions to find it saves a lot of searching and with it time
if (i % Side > 1 && i + Side*2-2 < GridSize)
{
if (Grid_ptr[i+Side-1] == 'X' && Grid_ptr[i+Side*2-2] == 'X')
{
humanWin = true;
break;
}
}
} //end if arrayvalue is 'X'
} //end for each value in array
} //end if currentMove 'H'
else if (currentMove == 'C')
{
//Check for human win code
//Check all array slots for an occurence of 'X'
for(USHORT i = 0; i < GridSize; i++)
{
//Local stack variables, optimizations for iterations in loops and if statements,
//also for readability, this is (only efficient and) done only when it is guaranteed
//to be used in every for jump.
USHORT iModSide = i % Side;
USHORT SideMinTwo = Side - 2;
USHORT SidePlusTwo = Side + 2;
USHORT iPlusSide = i + Side;
USHORT iPlusSideTimesTwo = i + Side * 2;
USHORT iPlusOne = i + 1;
USHORT iPlusTwo = i + 2;
//If an X is found evaluate a win scenario
if (Grid_ptr[i] == 'O')
{
//For each row -->
if (iModSide < SideMinTwo)
{
//Check horizontal win from left to right
if (Grid_ptr[i + 1] == 'O' && Grid_ptr[i + 2] == 'O')
{
computerWin = true;
break;
}
}
//For the two values under the 'O' (colomn wise) check for 'O''O'
if (iPlusSideTimesTwo < GridSize)
{
if(Grid_ptr[iPlusSide] == 'O' && Grid_ptr[iPlusSideTimesTwo] == 'O')
{
computerWin = true;
break;
}
}
//CHECK FOR DIAGONAL WIN FROM TOP LEFT TO DOWN RIGHT IN ALL POSSIBLE+LEGAL SLOTS!
// [X] [X] [?] [?] This illustration shows that checking only at X will suffice
// [X] [X] [?] [?] for this specific check in screening for all Top Left --> Down Right
// [?] [?] [?] [?] diagonal wins, similarly the Top Right --> Down Left is done mirrored
// [?] [?] [?] [?] All other wins using this vector are impossible!
// Using this amount of conditions to find it saves a lot of searching and with it time
if (iPlusSideTimesTwo < GridSize && iModSide < SideMinTwo)
{
if (Grid_ptr[i+Side+1] == 'O' && Grid_ptr[iPlusSideTimesTwo+2] == 'O')
{
computerWin = true;
break;
}
}
//CHECK FOR DIAGONAL WIN FROM TOP LEFT TO DOWN RIGHT IN ALL POSSIBLE+LEGAL SLOTS!
// [?] [?] [Y] [Y] This illustration shows that checking only at Y will suffice
// [?] [?] [Y] [Y] for this specific check in screening for all Top Right --> Down Left
// [?] [?] [?] [?] diagonal wins, similarly the Top Left --> Down Right is done mirrored
// [?] [?] [?] [?] This because all other wins using this vector are impossible!
// Using this amount of conditions to find it saves a lot of searching and with it time
if (iPlusSideTimesTwo+2 < GridSize && iModSide < SidePlusTwo)
{
if (Grid_ptr[i+Side-1] == 'O' && Grid_ptr[i+Side*2-2] == 'O')
{
computerWin = true;
break;
}
}
} //end if arrayvalue is 'O'
} //end for each value in array
}// else if currentMove 'C'
} //end method
//useAI(char* Grid_ptr) { }
//weighGrid (char* Grid_ptr) { for (USHORT i = 0; i < GridSize(find out); i++) {} }
void PrintGrid(char* Grid_ptr, USHORT GridWidth, USHORT GridHeight, USHORT GridSize)
{
//Abort this method if the Grid is not Square
if (GridWidth != GridHeight)
{
cout << "Warning! \n\nGrid is not square. This method will likely fail!" << endl;
cout << "Aborting method!" << endl;
cout << "Press a key to return to program";
}
else
{
//Since this code block's applicable to a square grid
//Width or Height is not relevant, both should work
//I have chosen to stick with Width everywhere.
USHORT rowStart = 0;
USHORT rowEnd = GridWidth-1;
USHORT passRowCounter = 1;
USHORT Side = GridSize / GridHeight;
for(USHORT i = 0; i < Side; i++)
{
//GO TO NEXT ROW CODE
rowEnd = Side * passRowCounter;
passRowCounter++;
//PRINT ALL IN THIS ROW
for (USHORT j = rowStart; j < rowEnd; j++)
{
cout << Grid_ptr[j];
}
rowStart = rowEnd;
cout << "\n";
}
}
}
void useAI(char* Grid_ptr, USHORT GridSize, USHORT GridWidth)
{
//Check all values in the array
//If the value is '?' weigh the priority
//else continue
//Weighing the priority
//If ('O' Present in legal ranges) add prio +1
//The AI Will function on this concept
//All array slots have a weight, the highest weight means the best position
//From top prio to lowest prio that means -->
//WIN IN ONE MOVE (weight + 50)
//NOT LOSE IN ONE MOVE (weight + 15)
//BLOCK ENEMY + LINK UP OWN ( Equal prio but stacks so both matter ) weight +1
//These weights are determined using 8 directional vectors sprouting from all 'X' and 'O' locations in the grid
//In it's path if it encounters on loc 1 'X' loc 2 + weight = 50 , and vice versa, else +1 for all 8 vectors
//Create a weightgrid to store the data
USHORT* WeightGrid_ptr = new USHORT[GridSize];
USHORT* fattest_ptr = new USHORT(0);
USHORT* fattestIndex_ptr = new USHORT(0);
USHORT Side = GridWidth;
//Suggestion for optimization , make a forumula table to play all 8 vectors instead
//Per vector u need Condition for the direction first space and next space. 24 statements in a list
//A bit complex and harder to read so for now went the east 8 vectors copy pasting. But aware of the
//solution none-the-less! Unfortunatly though it seems like a maze of code, it is well documented and
//it's length is over 50% due to optimizations.
for(USHORT i = 0; i < GridSize; i++)
{
if (Grid_ptr[i] == 'X')
{
//CHECK X --> Mid Right Vector
//If within allowed parameters
if(i % Side < Side-2)
{
if(Grid_ptr[i+1] == '?' && Grid_ptr[i+2] == '?')
{
WeightGrid_ptr[i+1] += 1;
WeightGrid_ptr[i+2] += 1;
}
else if(Grid_ptr[i+1] == 'X')
{
WeightGrid_ptr[i+2] += 15;
}
else if (Grid_ptr[i+2] == 'X')
{
WeightGrid_ptr[i+1] += 15;
}
}
//CHECK X --> Down Right Vector
//If within allowed parameters
if (i % Side < Side -2 && i + Side*2 < GridSize)
{
if (Grid_ptr[i+Side+1] == '?' && Grid_ptr[i+Side*2+2] == '?')
{
WeightGrid_ptr[i+Side+1] += 1;
WeightGrid_ptr[i+Side*2+2] += 1;
}
else if(Grid_ptr[i+Side+1] == 'X')
{
WeightGrid_ptr[i+Side*2+2] += 15;
}
else if (Grid_ptr[i+Side*2+2] == 'X')
{
WeightGrid_ptr[i+Side+1] += 15;
}
}
//CHECK X --> Down Mid Vector
//If within allowed paramaters
if (i + Side*2 < GridSize)
{
if (Grid_ptr[i+Side] == '?' && Grid_ptr[i+Side*2] == '?')
{
WeightGrid_ptr[i+Side] += 1;
WeightGrid_ptr[i+Side*2] += 1;
}
else if (Grid_ptr[i+Side] == 'X')
{
WeightGrid_ptr[i+Side*2] += 15;
}
else if (Grid_ptr[i+Side*2] == 'X')
{
WeightGrid_ptr[i+Side] += 15;
}
}
//CHECK X --> Down Left Vector
//If within allowed paramaters
if(i % Side > 1 && i + Side*2 < GridSize)
{
if (Grid_ptr[i + Side*2-1] == '?' && i + Side*2-2 == '?')
{
WeightGrid_ptr[i+Side*2-1] += 1;
WeightGrid_ptr[i+Side*2-2] += 1;
}
else if(Grid_ptr[i + Side*2-2] == 'X')
{
WeightGrid_ptr[i+Side*2-1] += 15;
}
else if(Grid_ptr[i+Side*2-1] == 'X')
{
WeightGrid_ptr[i+Side*2-2] += 15;
}
}
//CHECK X --> Mid Left Vector
//If within allowed parameters
if(i % Side > 1)
{
if (Grid_ptr[i-1] == '?' && Grid_ptr[i-2] == '?')
{
WeightGrid_ptr[i-1] += 1;
WeightGrid_ptr[i-2] += 1;
}
else if(Grid_ptr[i-1] == 'X')
{
WeightGrid_ptr[i-2] += 15;
}
else if(Grid_ptr[i-2] == 'X')
{
WeightGrid_ptr[i-1] += 15;
}
}
//CHECK X --> Top Left Vector
//If within allowed parameters
if( (i) % (Side > 1) && i > Side*2)
{
if (Grid_ptr[i-Side-1] == '?' && Grid_ptr[i-Side*2-2] == '?')
{
WeightGrid_ptr[i-Side-1] += 1;
WeightGrid_ptr[i-Side*2-2] += 1;
}
else if (Grid_ptr[i-Side-1] == 'X')
{
WeightGrid_ptr[i-Side*2-2] += 15;
}
else if (Grid_ptr[i-Side*2-2] == 'X')
{
WeightGrid_ptr[i-Side-1] += 15;
}
}
//CHECK X --> Mid Top Vector
//If within allowed parameters
if (i > Side*2)
{
if(Grid_ptr[i + Side] == '?' && Grid_ptr[i + Side*2] == '?')
{
WeightGrid_ptr[i + Side] += 1;
WeightGrid_ptr[i + Side*2] += 1;
}
else if(Grid_ptr[i + Side] == 'X')
{
WeightGrid_ptr[i + Side*2] += 15;
}
else if (Grid_ptr[i + Side*2] == 'X')
{
WeightGrid_ptr[i + Side] += 15;
}
}
} //end if 'X' detected
else if (Grid_ptr[i] == 'O')
{
//CHECK 8 VECTORS
//Add weights
//CHECK O --> Mid Right Vector
//If within allowed parameters
if(i % Side < Side-2)
{
if(Grid_ptr[i+1] == '?' && Grid_ptr[i+2] == '?')
{
WeightGrid_ptr[i+1] += 1;
WeightGrid_ptr[i+2] += 1;
}
else if(Grid_ptr[i+1] == 'O')
{
WeightGrid_ptr[i+2] += 50;
}
else if (Grid_ptr[i+2] == 'O')
{
WeightGrid_ptr[i+1] += 50;
}
}
//CHECK O --> Down Right Vector
//If within allowed parameters
if (i % Side < Side -2 && i + Side*2 < GridSize)
{
if (Grid_ptr[i+Side+1] == '?' && Grid_ptr[i+Side*2+2] == '?')
{
WeightGrid_ptr[i+Side+1] += 1;
WeightGrid_ptr[i+Side*2+2] += 1;
}
else if(Grid_ptr[i+Side+1] == 'O')
{
WeightGrid_ptr[i+Side*2+2] += 50;
}
else if (Grid_ptr[i+Side*2+2] == 'O')
{
WeightGrid_ptr[i+Side+1] += 50;
}
}
//CHECK O --> Down Mid Vector
//If within allowed paramaters
if (i + Side*2 < GridSize)
{
if (Grid_ptr[i+Side] == '?' && Grid_ptr[i+Side*2] == '?')
{
WeightGrid_ptr[i+Side] += 1;
WeightGrid_ptr[i+Side*2] += 1;
}
else if (Grid_ptr[i+Side] == 'O')
{
WeightGrid_ptr[i+Side*2] += 50;
}
else if (Grid_ptr[i+Side*2] == 'O')
{
WeightGrid_ptr[i+Side] += 50;
}
}
//CHECK O --> Down Left Vector
//If within allowed paramaters
if(i % Side > 1 && i + Side*2 < GridSize)
{
if (Grid_ptr[i + Side*2-1] == '?' && i + Side*2-2 == '?')
{
WeightGrid_ptr[i+Side*2-1] += 1;
WeightGrid_ptr[i+Side*2-2] += 1;
}
else if(Grid_ptr[i + Side*2-2] == 'O')
{
WeightGrid_ptr[i+Side*2-1] += 50;
}
else if(Grid_ptr[i+Side*2-1] == 'O')
{
WeightGrid_ptr[i+Side*2-2] += 50;
}
}
//CHECK O --> Mid Left Vector
//If within allowed parameters
if(i % Side > 1)
{
if (Grid_ptr[i-1] == '?' && Grid_ptr[i-2] == '?')
{
WeightGrid_ptr[i-1] += 1;
WeightGrid_ptr[i-2] += 1;
}
else if(Grid_ptr[i-1] == 'O')
{
WeightGrid_ptr[i-2] += 50;
}
else if(Grid_ptr[i-2] == 'O')
{
WeightGrid_ptr[i-1] += 50;
}
}
//CHECK O --> Top Left Vector
//If within allowed parameters
if( (i) & (Side > 1) && i > Side*2)
{
if (Grid_ptr[i-Side-1] == '?' && Grid_ptr[i-Side*2-2] == '?')
{
WeightGrid_ptr[i-Side-1] += 1;
WeightGrid_ptr[i-Side*2-2] += 1;
}
else if (Grid_ptr[i-Side-1] == 'O')
{
WeightGrid_ptr[i-Side*2-2] += 50;
}
else if (Grid_ptr[i-Side*2-2] == 'O')
{
WeightGrid_ptr[i-Side-1] += 50;
}
}
//CHECK O --> Mid Top Vector
//If within allowed parameters
if (i > Side*2)
{
if(Grid_ptr[i + Side] == '?' && Grid_ptr[i + Side*2] == '?')
{
WeightGrid_ptr[i + Side] += 1;
WeightGrid_ptr[i + Side*2] += 1;
}
else if(Grid_ptr[i + Side] == 'O')
{
WeightGrid_ptr[i + Side*2] += 50;
}
else if (Grid_ptr[i + Side*2] == 'O')
{
WeightGrid_ptr[i + Side] += 50;
}
}
}
} // end for scan 'X' 'O'
//Get highest value from weightgrid, add an 'O' to that position, end method automatically
for (USHORT q = 0; q < GridSize; q++)
{
if (Grid_ptr[q] == '?')
{
//If a better spot is found
if (WeightGrid_ptr[q] > *fattest_ptr)
{
*fattest_ptr = WeightGrid_ptr[q];
*fattestIndex_ptr = q;
}
}
}
Grid_ptr[*fattestIndex_ptr] = 'O';
//SAFE DELETE POINTER WeightGrid_ptr
if (WeightGrid_ptr != NULL)
{
delete[] WeightGrid_ptr;
WeightGrid_ptr = NULL;
}
//SAFE DELETE POINTER fattest_ptr
if (fattest_ptr != NULL)
{
delete fattest_ptr;
fattest_ptr = NULL;
}
//SAFE DELETE POINTER fattestIndex_ptr
if (fattestIndex_ptr != NULL)
{
delete fattestIndex_ptr;
fattestIndex_ptr = NULL;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
//& adress off |-| &x = 0x?
//* value pointed by |-| a = *b
//Make the required variables on the heap
USHORT GridHeight = 0;
USHORT GridWidth = 0;
USHORT GridSize = 0;
USHORT moveCounter = 0;
char currentMove;
USHORT input;
//bool* humanWin_ptr = new bool(false);
//bool* computerWin_ptr = new bool(false);
bool humanWin_ptr = false;
bool computerWin_ptr = false;
bool Draw = false;
cout << "A challanger has arrived!" << endl;
//WARNING FOR THIS BLOCK! Special condition on for loop!
for(;;)
{
cout << "Please state the width for the grid \n";
scanf_s("%hu", &input);
if (input > 2 && input < 20)
{
GridWidth = input;
break; //CRITICAL CODE
}
else
{
cout << "Input was not correct, please state a number between 3 and 20 \n\n";
cout << "Example of correct input '3' (without quotes) \n";
}
}
//WARNING FOR THIS BLOCK! Special condition on for loop!
for(;;)
{
cout << "Please state the height for the grid \n";
scanf_s("%hu", &input);
if (input > 2 && input < 20)
{
GridHeight = input;
break; //CRITICAL CODE
}
else
{
cout << "Input was not correct, please state a number between 3 and 20 \n\n";
cout << "Example of correct input '3' (without quotes) \n";
}
}
cout << "You have succesfully filled in the paperwork to create the Grid" << endl;
GridSize = GridHeight * GridWidth;
cout << "The total GridSize is " << GridSize << " tiles in size" << endl;
//if (GridWidth != GridHeigth)
//{
// cout << "Warning! \n\nGrid is not square. Program may run irregularly!";
// cout << "Close the program or press a key to continue";
// scanf();
//}
//Note: pointer to a Grid object on the heap
char* Grid_ptr = new char[GridSize];
//Initialize Grid as empty
for (USHORT i = 0; i < GridSize; i++)
{
Grid_ptr[i] = '?';
}
//Visualize this step
cout << "Grid created as empty Grid" << endl;
cout << endl;
cout << "Please read the following introduction if you wish for an explanation of the game" << endl;
cout << "You will be reffered to as Player One equally so the opponent as AI" << endl;
cout << "You always start with the first move" << endl;
cout << "The condition for victory is a line of X X X (3 total) in a single line, colomn or a diagonal line across the Grid" << endl;
cout << "Turns are exchanged per move 1 : 1, there are no time limits so use all you need" << endl;
cout << "Player One can not lose this 3x3 Grid game when the best option is always chosen" << endl;
cout << "Consider playing a larger field if you wish to win, Best of luck!" << endl;
cout << "The grid is filled in like this!" << endl;
PrintGrid(Grid_ptr, GridWidth, GridHeight, GridSize);
while(humanWin_ptr == false && computerWin_ptr == false && Draw == false)
{
cout << "Players One's Turn! \n";
cout << "Please fill in the number your X";
currentMove = 'H';
for(;;)
{
scanf_s("%i" , &input);
if (Grid_ptr[input] == 'X' || Grid_ptr[input] == 'O')
{
cout << "That space is already taken ,try another";
}
else
{
Grid_ptr[input] = 'X';
moveCounter++;
break;
}
}
cout << '\n';
PrintGrid(Grid_ptr, GridWidth, GridHeight, GridSize);
CheckForWin(Grid_ptr, GridSize, GridWidth, humanWin_ptr, computerWin_ptr, currentMove);
cout << "AI is making a move!" << endl;
currentMove = 'C';
useAI(Grid_ptr, GridSize, GridWidth);
cout << '\n';
PrintGrid(Grid_ptr, GridWidth, GridHeight, GridSize);
CheckForWin(Grid_ptr, GridSize, GridWidth, humanWin_ptr, computerWin_ptr, currentMove);
if (humanWin_ptr)
{
cout << "Congratulations you have won the game! \n";
char c;
puts ("Enter any text. Include a Space ('.') in a sentence to exit: \n");
do
{
c=getchar();
putchar (c);
}
while (c != ' ');
}
else if (computerWin_ptr)
{
cout << "The computer won this match, better luck next time! \n";
char c;
puts ("Enter any text. Include a Space ('.') in a sentence to exit: \n");
do
{
c=getchar();
putchar (c);
}
while (c != ' ');
}
if (moveCounter >= GridSize)
{
Draw = true;
cout << "The game was a draw, good fighting!";
}
}
//int ch = 0;
//ch = _getch();
//wint_t _getwch( void );
//SAFE DELETE POINTER GRID
if (Grid_ptr != NULL)
{
delete[] Grid_ptr;
Grid_ptr = NULL;
}
/*
//SAFE DELETE POINTER Human Win
if (humanWin_ptr != NULL)
{
delete humanWin_ptr;
humanWin_ptr = NULL;
}
//SAFE DELETE POINTER Computer Win
if (computerWin_ptr != NULL)
{
delete computerWin_ptr;
computerWin_ptr = NULL;
}*/
return 0;
}
What you are asking seams to be about micro optimization. First implement it right, then profile/measure to find bottlenecks, and then think how to improve.
Since the question is so general (and without the example and code), I do not think it is possible to answer differently.