I am a complete novice in programming and am currently taking an introductory level class at my local university, I am currently stuck on a question and the prof provides no help whatsoever.
I am taking 3 inputs from an input file molecules.txt (the first two are element names, the third is the number of the surrounding atoms) and printing them into an output file called geometricalshapes.txt
When I run my program nothing gets printed into the output file
Here is the code I have so far that does not work:
/******************************************************************************************************
* Problem Statement: This program will calculate the molecular geometry of atom A surrounded by b atoms of element B and output the results into a file geometricalshapes.txt
*
* Input: A list of element pairs from molecules.txt, and the number of B atoms surrounding atom A
*
* Output: The determined shape of the element pairs
*
* Main Algorithm: Determine the number of valence electrons 'v' for atom A
* Subtract the number of bonding domains 'b' from 'v' to determine the number of nonbonding electrons
* Determine the number of bonding domains 'n'
* Determine the shape of the molecule
* Ouput the geometrical shape of the molecule
*
* Major Variables: string A - Central Atom
* string B - Surrounding Atom
* string shape - Shape of Molecule
* int b - Number of B atoms
* int v - Number of Valence Electrons
* int e - Number of Nonbonding Elctrons
* int n - Number of Bonding Domains
*
*
* Assumptions: Only single bonds are present
*
* Limitations: Only coded for select elements from given tables
*
* *********************************************************************************************************************************************************************************/
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
// Declaring Variables
string A, B, shape;
int b, v, e, n;
ifstream inputData;
ofstream outputData;
inputData.open("molecules.txt");
if (!inputData)
{
cout << "Problem opening input file. Closing program..." << endl;
return 1;
}
outputData.open("geometricalshape.txt");
if (!outputData)
{
cout << "Problem opening output file. Closing program..." << endl;
return 2;
}
// Gathering data for central atom A
inputData >> A; // priming read
while (inputData) // EOF loop
{
// If-else statements to determine number of valence electrons 'v'
if (A == "Be")
{
v = 3;
}
else if (A == "C")
{
v = 4;
}
else if (A == "Si")
{
v = 4;
}
else if (A == "N")
{
v = 5;
}
else if (A == "P")
{
v = 5;
}
else if (A == "As")
{
v = 5;
}
else if (A == "O")
{
v = 6;
}
else if (A == "S")
{
v = 6;
}
else if (A == "Se")
{
v = 6;
}
else if (A == "F")
{
v = 7;
}
else if (A == "Cl")
{
v = 7;
}
else if (A == "Br")
{
v = 7;
}
else if (A == "I")
{
v = 7;
}
else if (A == "Xe")
{
v = 8;
}
// Input data for surroudning atom and number of atoms
inputData >> B >> b;
// Calculating number of nonbonding electrons
e = v - b;
// Calculating number of bonding doamains
n = e / 2;
// If else statements to determine shape
if (b == 2 && n == 0)
{
shape == "linear";
}
else if (b == 2 && n == 1)
{
shape == "bent";
}
else if (b == 2 && n == 2)
{
shape == "bent";
}
else if (b == 2 && n == 3)
{
shape == "linear";
}
else if (b == 3 && n == 0)
{
shape == "trigonal planar";
}
else if (b == 3 && n == 1)
{
shape == "trigonal pyramidal";
}
else if (b == 3 && n == 2)
{
shape == "T-shaped";
}
else if (b == 4 && n == 0)
{
shape == "tetrahedral";
}
else if (b == 4 && n == 1)
{
shape == "seesaw";
}
else if (b == 4 && n == 2)
{
shape == "square planar";
}
else if (b == 5 && n == 0)
{
shape == "trigonal bipyramidal";
}
else if (b == 5 && n == 1)
{
shape == "square pyramidal";
}
else if (b == 6 && n == 0)
{
shape == "octahedral";
}
else
{
shape == "unknown";
}
// Outputting line data into output document
outputData << "The geometrical shape of one atom " << A << " surrounded by " << b << " "
<< B << " atoms is " << shape << endl;
// Getting next input for A
inputData >> A;
}
return 0;
}
The first few lines on the input file look like:
O F 2
S F 4
Be F 3
C P 1
And I am supposed to get results that look like:
The geometrical shape of one O atom surrounded by 2 F atoms is bent.
The geometrical shape of one S atom surrounded by 4 F atoms is seesaw.
The geometrical shape of one Be atom surrounded by 3 F atoms is trigonal planar.
The geometrical shape of one C atom surrounded by 1 P atoms is unknown.
Any and all help is appreciated! Please try and keep explanations simple as I am still very new to programming!
Among the problems
incorrect file init testing.
untested extractions of B and b
unused test expressions shape == rather than assignments
Fixing all of the above:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
// Declaring Variables
ifstream inputData("molecules.txt");
ofstream outputData("geometricalshape.txt");
if (!inputData.is_open())
{
cout << "Problem opening input file. Closing program..." << endl;
return 1;
}
if (!outputData.is_open())
{
cout << "Problem opening output file. Closing program..." << endl;
return 2;
}
string A, B, shape;
int b, v, e, n;
while (inputData >> A >> B >> b) // EOF loop
{
// If-else statements to determine number of valence electrons 'v'
if (A == "Be")
{
v = 3;
}
else if (A == "C")
{
v = 4;
}
else if (A == "Si")
{
v = 4;
}
else if (A == "N")
{
v = 5;
}
else if (A == "P")
{
v = 5;
}
else if (A == "As")
{
v = 5;
}
else if (A == "O")
{
v = 6;
}
else if (A == "S")
{
v = 6;
}
else if (A == "Se")
{
v = 6;
}
else if (A == "F")
{
v = 7;
}
else if (A == "Cl")
{
v = 7;
}
else if (A == "Br")
{
v = 7;
}
else if (A == "I")
{
v = 7;
}
else if (A == "Xe")
{
v = 8;
}
// Calculating number of nonbonding electrons
e = v - b;
// Calculating number of bonding doamains
n = e / 2;
// If else statements to determine shape
if (b == 2 && n == 0)
{
shape = "linear";
}
else if (b == 2 && n == 1)
{
shape = "bent";
}
else if (b == 2 && n == 2)
{
shape = "bent";
}
else if (b == 2 && n == 3)
{
shape = "linear";
}
else if (b == 3 && n == 0)
{
shape = "trigonal planar";
}
else if (b == 3 && n == 1)
{
shape = "trigonal pyramidal";
}
else if (b == 3 && n == 2)
{
shape = "T-shaped";
}
else if (b == 4 && n == 0)
{
shape = "tetrahedral";
}
else if (b == 4 && n == 1)
{
shape = "seesaw";
}
else if (b == 4 && n == 2)
{
shape = "square planar";
}
else if (b == 5 && n == 0)
{
shape = "trigonal bipyramidal";
}
else if (b == 5 && n == 1)
{
shape = "square pyramidal";
}
else if (b == 6 && n == 0)
{
shape = "octahedral";
}
else
{
shape = "unknown";
}
// Outputting line data into output document
outputData << "The geometrical shape of one atom " << A
<< " surrounded by " << b
<< " " << B
<< " atoms is " << shape
<< endl;
}
return 0;
}
Output (geometricalshape.txt)
The geometrical shape of one atom O surrounded by 2 F atoms is bent
The geometrical shape of one atom S surrounded by 4 F atoms is seesaw
The geometrical shape of one atom Be surrounded by 3 F atoms is trigonal planar
The geometrical shape of one atom C surrounded by 1 P atoms is unknown
I am making a function that validates a user input is a grid reference, between A0 and J9 (a 10 x 10 grid).
I can validate the integer part fine, but am wondering how to validate the alphabetical part, without saying for example:
if(Column == 'A' || Column == 'a' || Column == 'B' ....)
In a similar fashion to saying if int Row < 10.
Also, is there a way to convert to a single character, such as stoi for string to integer?
Here is my functions code, thank you.
void InputLocation(){
bool still_prompt = true;
while (still_prompt)
{
std::string answer;
std::cout << "Enter a grid location from A0 to J9" << std::endl;
std::getline(std::cin, answer);
std::string Column = answer.substr(0, 1);
std::string Row = answer.substr(1, 1);
if (answer.length() > 2 || answer.length() < 2){
std::cerr << "Location input must be of length 2 characters.\n";
continue;
}
else{ // If input has length 2, then get to this stage
try{
int intRow = std::stoi(Row);
if (intRow < 0 || intRow > 9){
std::cerr << "Row number must be between 0 and 9. \n";
continue;
}
}
catch (...){
std::cerr << "Second character of location input must be integer. \n";
continue;
}
}still_prompt = false;
}
}
Individual characters can be treated as numbers, so this is pretty simple to do! For example:
bool test(char character) {
return 'a' <= character && character <= 'j';
}
This function tests if a character is between 'a' and 'j'. This works because under the hood, 'a' and 'j' are just numbers. You can even see what numbers they are just by printing out the value:
int a_value = 'a'; // chars can be implictly converted to int
int j_value = 'j';
std::cout << "value of 'a'": << a_value << '\n';
std::cout << "value of j'j": << j_value << '\n';
Putting it all together. We can check if something is in the correct range just by doing a comparison. The following function will check if a character is within the range a through j.
bool testInRange(char c) {
return ('a' <= c && c <= 'j') || ('A' <= c && c <= 'J');
}
We can also write a function to convert it into an index on the grid:
int charToGridIndex(char c) {
if('A' <= c && c <= 'J')
{
return c - 'A';
}
else if('a' <= c && c <= 'j')
{
return c - 'a';
}
else
{
// Return -1 to indicate an invalid character
return -1;
}
}
Here,
charToGridIndex('a') == 0
charToGridIndex('b') == 1
charToGridIndex('c') == 2
charToGridIndex('d') == 3
charToGridIndex('e') == 4
charToGridIndex('f') == 5
charToGridIndex('g') == 6
charToGridIndex('h') == 7
charToGridIndex('i') == 8
charToGridIndex('j') == 9
I am creating a tic tac toe program. I have different functions for testing different possible outcomes. When I test my diagonal possibility, it works correctly. However, when I try to test rows or columns it always returns 0. I think it's because my return statement and break statements are in the wrong place ,but I can't find the right place.
int testCol (int board[3][3]){//test cols for win
int b = 0;
int c = 0;
for (b = 0; b < 3; b++){
if (board[0][b] == 1 && board[1][b] == 1 && board[2][b] == 1){//test player 1
return 1;
cout << "I work" << endl;
break;
}
else if(board[0][b] == 2 && board[1][b] == 2 && board[2][b] == 2){//test player 2
return 2;
break;
}
else{//if none are true return no win
return 0;
}
}
}
Two things; you need to move the return 0 outside of the loop. Otherwise, you'll never get around to testing all of the possibilities. Second, your output statement is after a return, so it's unreachable.
You dont need a break statement after return. Last return in your function seems to be a false status from function, so you can keep it out of the loop. Your output statement from first if branch should come before your return.
int testCol (int board[3][3]){//test cols for win
int b = 0;
int c = 0;
for (b = 0; b < 3; b++){
if (board[0][b] == 1 && board[1][b] == 1 && board[2][b] == 1){//test player 1
cout << "I work" << endl;
return 1;
}
else if(board[0][b] == 2 && board[1][b] == 2 && board[2][b] == 2){//test player 2
return 2;
}
}
return 0;
}
You return early when you found a full column. If there is no winner, you return 0 after you tested all columns.
Here the fixed version.
int testCol (int board[3][3]){//test cols for win
for (int b = 0; b < 3; b++){
if (board[0][b] == 1 && board[1][b] == 1 && board[2][b] == 1){//test player 1
return 1;
}
else if(board[0][b] == 2 && board[1][b] == 2 && board[2][b] == 2){//test player 2
return 2;
}
}
return 0;
}
I'm trying to make a Sudoku Solving program for a couple of days but I'm stuck with the methods. I found this algorithm here but I don't really understand it:
start at the first empty cell, and put 1 in it.
Check the entire board, and see if there are any conflicts
If there are coflicts on the board, increase the number in the current cell by 1 (so change 1 to 2, 2 to 3, etc)
If the board is clean move, start at step one again.
If all nine possible numbers on a given cell cause a conflict in the board, then you set this cell back to empty, go back to the previous cell, and start again from step 3 (this is where the 'backtracking' comes in).
Here is my code. I think something is wrong with my Help_Solve(...) function. Can you help me to identify the problem, please?
#include <iostream>
#include <iomanip>
#include <time.h>
#include <cstdlib>
#include <windows.h>
using namespace std;
class Sudoku
{
private:
int board[9][9];
int change[9][9];
public:
Sudoku();
void Print_Board();
void Add_First_Cord();
void Solve();
void Help_Solve(int i, int j);
bool Check_Conflicts(int p, int i, int j);
};
Sudoku Game;
void setcolor(unsigned short color) //The function that you'll use to
{ //set the colour
HANDLE hcon = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hcon,color);
}
Sudoku::Sudoku()
{
for(int i = 1; i <= 9; i++)
for(int j = 1; j <= 9; j++)
board[i][j] = 0;
}
void Sudoku::Print_Board()
{
for(int i = 1; i <= 9; i++)
{
for(int j = 1; j <= 9; j++)
{
if(change[i][j] == 1)
{
setcolor(12);
cout << board[i][j] << " ";
setcolor(7);
}
else cout << board[i][j] << " ";
if(j%3 == 0) cout << "| ";
}
cout << endl;
if(i%3 == 0) cout << "------+-------+---------" << endl;
}
}
void Sudoku::Add_First_Cord()
{
board[1][1] = 5; change[1][1] = 1;
board[1][2] = 3; change[1][2] = 1;
board[1][5] = 7; change[1][5] = 1;
board[2][1] = 6; change[2][1] = 1;
board[2][4] = 1; change[2][4] = 1;
board[2][5] = 9; change[2][5] = 1;
board[2][6] = 5; change[2][6] = 1;
board[3][2] = 9; change[3][2] = 1;
board[3][3] = 8; change[3][3] = 1;
board[3][8] = 6; change[3][8] = 1;
board[4][1] = 8; change[4][1] = 1;
board[4][5] = 6; change[4][5] = 1;
board[4][9] = 3; change[4][9] = 1;
board[5][1] = 4; change[5][1] = 1;
board[5][4] = 8; change[5][4] = 1;
board[5][6] = 3; change[5][6] = 1;
board[5][9] = 1; change[5][9] = 1;
board[6][1] = 7; change[6][1] = 1;
board[6][5] = 2; change[6][5] = 1;
board[6][9] = 6; change[6][9] = 1;
board[7][2] = 6; change[7][2] = 1;
board[7][7] = 2; change[7][7] = 1;
board[7][8] = 8; change[7][8] = 1;
board[8][4] = 4; change[8][4] = 1;
board[8][5] = 1; change[8][5] = 1;
board[8][6] = 9; change[8][6] = 1;
board[8][9] = 5; change[8][9] = 1;
board[9][5] = 8; change[9][5] = 1;
board[9][8] = 7; change[9][8] = 1;
board[9][9] = 9; change[9][9] = 1;
}
bool Sudoku::Check_Conflicts(int p, int i, int j)
{
for(int k = 1; k <= 9; k++)
if(board[i][k] == p) return false;
for(int q = 1; q <= 9; q++)
if(board[q][j] == p) return false;
/*
*00
000
000
*/
if((j == 1 || j == 4 || j == 7) && (i == 1 || i == 4 || i == 7))
{
if(board[i][j+1] == p || board[i][j+2] == p || board[i+1][j] == p ||
board[i+2][j] == p || board[i+1][j+1] == p || board[i+1][j+2] == p ||
board[i+2][j+1] == p || board[i+2][j+2] == p)return false;
}
/*
000
000
*00
*/
if((j == 1 || j == 4 || j == 7) && (i == 3 || i == 6 || i == 9))
{
if(board[i-1][j] == p || board[i-2][j] == p || board[i][j+1] == p ||
board[i][j+2] == p || board[i-1][j+1] == p || board[i-1][j+2] == p ||
board[i-2][j+1] == p || board[i-2][j+2] == p)return false;
}
/*
000
*00
000
*/
if((j == 1 || j == 4 || j == 7) && (i == 2 || i == 5 || i == 8))
{
if(board[i-1][j] == p || board[i+1][j] == p || board[i-1][j+1] == p ||
board[i][j+1] == p || board[i+1][j+1] == p || board[i+1][j+2] == p ||
board[i][j+2] == p || board[i+1][j+2] == p)return false;
}
/*
0*0
000
000
*/
if((j == 2 || j == 5 || j == 8) && (i == 1 || i == 5 || i == 7))
{
if(board[i-1][j] == p || board[i+1][j] == p || board[i-1][j+1] == p ||
board[i][j+1] == p || board[i+1][j+1] == p || board[i+1][j+2] == p ||
board[i][j+2] == p || board[i+1][j+2] == p)return false;
}
/*
000
0*0
000
*/
if((j == 2 || j == 5 || j == 8) && (i == 2 || i == 5 || i == 8))
{
if(board[i-1][j] == p || board[i-1][j-1] == p || board[i-1][j+1] == p ||
board[i][j+1] == p || board[i][j-1] == p || board[i+1][j+1] == p ||
board[i][j] == p || board[i+1][j-1] == p)return false;
}
/*
000
000
0*0
*/
if((j == 2 || j == 5 || j == 8) && (i == 3 || i == 6 || i == 9))
{
if(board[i][j-1] == p || board[i][j+1] == p || board[i-1][j] == p ||
board[i-1][j+1] == p || board[i-1][j-1] == p || board[i-2][j] == p ||
board[i-1][j+1] == p || board[i-2][j-1] == p) return false;
}
/*
00*
000
000
*/
if((j == 3 || j == 6 || j == 9) && (i == 1 || i == 4 || i == 7))
{
if(board[i][j-1] == p || board[i][j-2] == p || board[i+1][j] == p ||
board[i+1][j-1] == p || board[i+1][j-2] == p || board[i+2][j] == p ||
board[i+2][j-1] == p || board[i+2][j-2] == p) return false;
}
/*
000
00*
000
*/
if((j == 3 || j == 6 || j == 9) && (i == 2 || i == 5 || i == 8))
{
if(board[i-1][j] == p || board[i-1][j-1] == p || board[i-1][j-2] == p ||
board[i][j-1] == p || board[i][j-2] == p || board[i+1][j] == p ||
board[i+1][j-1] == p || board[i+1][j-2] == p) return false;
}
/*
000
000
00*
*/
if((j == 3 || j == 6 || j == 9) && (i == 3 || i == 6 || i == 9))
{
if(board[i][j-1] == p || board[i][j-1] == p || board[i-1][j] == p ||
board[i-1][j-1] == p || board[i-1][j-2] == p || board[i-2][j] == p ||
board[i-2][j-1] == p || board[i-2][j-2] == p) return false;
}
return true;
}
void Sudoku::Help_Solve(int i, int j)
{
if(j <= 0)
{
i = i-1;
j = 9;
}
if(change[i][j] == 1) return Game.Help_Solve(i, j-1);
for(int p = 1; p <= 9; p++)
if(Game.Check_Conflicts(p, i, j))
{
board[i][j] = p;
return;
}
return Game.Help_Solve(i, j-1);
}
void Sudoku::Solve()
{
for(int i = 1; i <= 9; i++)
{
for(int j = 1; j <= 9; j++)
{
if(board[i][j] == 0 && change[i][j] == 0)
{
Game.Help_Solve(i, j);
}
}
}
for(int i = 1; i <= 9; i++)
for(int j = 1; j <= 9; j++)
if(board[i][j] == 0) Game.Help_Solve(i, j);
}
int main()
{
Game.Add_First_Cord();
Game.Solve();
Game.Print_Board();
system("pause");
return 0;
}
Edit: I need to use recursion right? But maybe the parameters I give to the function are wrong. I really don't know. In Add_First_Cord() I declare the starting values that every sudoku has in the beginning. Here are the values that I use: http://bg.wikipedia.org/wiki/%D0%A4%D0%B0%D0%B9%D0%BB:Sudoku-by-L2G-20050714.gif. I expect to see the solved sudoku as it is shown in wikipedia. But some solved values are right others are not. Here is what I get in the console
Suggested Approach
Implement a generic graph search algorithm
could use either IDFS or A* graph search
I would prefer the second
do this for a general directed graph
node type TNode
node successor function TNode => vector<TNode>
Define your Sudoku states
a state is a 9x9 array with a number 1, 2, ..., or 9 or a blank in each position
Define what a goal Sudoku state is
all 81 cells filled in
all 9 rows have numbers {1, 2, ..., 9} in them
all 9 columns have numbers {1, 2, ..., 9} in them
all 9 3x3 squares have numbers {1, 2, ..., 9} in them
Define your valid Sudoku state successor function
a state S can have number N added at row I, column J if:
cell (I,J) is empty
there is no other N in row I
there is no other N in column J
there is no other N in the 3x3 square containing (I,J)
the state successor function maps a state S to the vector of states that satisfy these rules
Apply your generic graph search algorithm (1) to the Sudoku state graph (2-4)
(optional) If you do choose to use A* graph search, you can also define a heuristic on your Sudoku state space to potentially drastically increase performance
how to design the heuristic is another whole problem, that's more of an art than a science
Current Approach
Your current approach mixes the specification of the graph to be searched and the implementation of the search algorithm. You're going to have a lot of difficulty if you mix those two. This problem naturally separates into two distinct pieces -- the algorithm and the graph -- so you can and should exploit that in your implementation. It will make it much simpler.
The other benefit you get if you go with this separation is that you will be able to reuse your graph search algorithm on a huge number of problems - very cool!
The following assumes you are trying to solve a given board, not generate a puzzle.
Basic (simple) approach
Create a class whose objects can hold a board (here called board_t). This class may internally use array, but must support copying boards.
Have a function void solve(board_t const& board); which repeats the following for each number n:
Copies your input
Enters n in the first empty cell of the copied board
If the copied board is a solution, print the solution and return.
Else If the board is still viable (e.g. no conflicts):
call solve(copied_board)
Performance
This is a recursive backtracking solution, which performs horribly for hard problems. You can significantly speed it up by proper pruning or deductive steps (e.g. if you end up with 8 numbers in a row after inserting one, you can immediately enter the ninth without any kind of search).
Reasoning
While certainly not an impressive technique, it has a high probability of working correctly, since you will only ever be modifying a copy to add a single value. This prevents corruption of your data structures (one problem your idea has is that it will destroy the numbers it finds when backtracking, are not necessarily the ones you just inserted, but may be part of the initial puzzle).
Improving performance is quite simple, once you start picking more intelligent heuristics (e.g. instead of testing the square in order, you could pick the ones with the fewest remaining moves and try to get them out of the way - or do the reverse...) or start doing a bit of deduction and pruning.
Note: The Algorithm Design Manual uses a Soduko solver to show the impact of these techniques on backtracking.
There is one very important modification to recursive algorithms: Use most constrained first approach. This means first to solve a cell with smallest number of possible candidates (when direct row/column/block conflicts are removed).
Another modification is: Change the board in-place; do not copy it. In each recursive call you modify only one cell on the board, and that cell used to be empty. If that call doesn't end up in a solved board somewhere down the recursive call tree, just clear the cell again before returning - this returns the board into original state.
You can find a very short and fast solution in C# on address: Sudoku Solver. It solves arbitrary sudoku board in about 100 steps only, all thanks to the most constrained first heuristic.
This is a classic Constraint Satisfaction Problem. I recommend doing some research on the topic to figure out the successful strategy. You will need to use AC-3 ( Arc Consistency 3) algorithm along with the backtracking techniques to solve the problem.
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.