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 be开发者_StackOverflow中文版tter 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.
精彩评论