|
-
December 27th, 2014, 02:17 PM
#16
Re: Creating a good computer AI for a tic tac toe game.
Ok I see your point. Regardless of the AI that I'm trying to do, my focus as of now is to get rid of all the if/else in the playerlocation functions and put them into a simple for loop that checks if the tile has an X or an O. If the tile does, then the location has been taken. If the tile doesn't, then the move is valid. I also have to take into consideration that I'm using string commands that dictate where the letter will be place. This is the problem that I'm facing. I don't how to check if the tile is empty and that the command that they picked correspond to where they're trying to place the letter and put it into a simple for loop.
-
December 27th, 2014, 03:31 PM
#17
Re: Creating a good computer AI for a tic tac toe game.
One way to check is via using a map. A possible test program using this method is
Code:
#include <unordered_map>
#include <iostream>
#include <string>
using namespace std;
struct point
{
int r;
int c;
point(int rr, int cc) : r(rr), c(cc){}
};
string toupper(const string& st)
{
string tu;
for (auto ch : st)
tu += toupper(ch);
return tu;
}
const unordered_map<string, point> msp{ make_pair("UL", point(0, 0)), make_pair("UC", point(0, 1)), make_pair("UR", point(0, 2)),
make_pair("LC", point(1, 0)), make_pair("MC", point(1, 1)), make_pair("RC", point(1, 2)),
make_pair("BL", point(2, 0)), make_pair("BC", point(2, 1)), make_pair("BR", point(2,2))};
int main()
{
char board[3][3] = { 0 };
string inp;
auto mit = msp.cbegin();
for (int cnt = 0; cnt < 9;) {
while ((cout << "Enter location: ") && (cin >> inp) && ((mit = msp.find(toupper(inp))) == msp.end()))
cout << "Invalid location" << endl;
char &pos = board[mit->second.r][mit->second.c];
if (pos > ' ')
cout << "Space taken!" << endl;
else {
pos = 'X';
cnt++;
}
}
}
All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!
C++23 Compiler: Microsoft VS2022 (17.6.5)
-
December 27th, 2014, 06:54 PM
#18
Re: Creating a good computer AI for a tic tac toe game.
This isn't really an AI problem. The game is pretty simple. You just need to define the rules. First look to see if you can win. Second see if the user's about to win and block him. If neither of those look for where you've already gone and try to make a sequence that will let you win. Define the rules and the approach before you write code.
-
December 28th, 2014, 08:44 AM
#19
Re: Creating a good computer AI for a tic tac toe game.
 Originally Posted by Freddy Kreuger
Ok I see your point. Regardless of the AI that I'm trying to do, my focus as of now is to get rid of all the if/else in the playerlocation functions and put them into a simple for loop that checks if the tile has an X or an O. If the tile does, then the location has been taken. If the tile doesn't, then the move is valid. I also have to take into consideration that I'm using string commands that dictate where the letter will be place. This is the problem that I'm facing. I don't how to check if the tile is empty and that the command that they picked correspond to where they're trying to place the letter and put it into a simple for loop.
Your code is very long winded with almost duplicate sections of code. There are easier ways to check for a win or a draw using an array of winning positions. There is also no need to have separate code for each player. There just needs to be code for a player which alternates between 'x' and 'o'. A possible way could be
Code:
#include <unordered_map>
#include <iostream>
#include <string>
using namespace std;
struct point
{
int r;
int c;
point(int rr, int cc) : r(rr), c(cc){}
};
const string lft[3] { "T", "M", "B" };
const string top[3] { "L", "C", "R" };
const char sym[2] { 'X', 'O' };
const unordered_map<string, point> msp {make_pair(lft[0] + top[0], point(0, 0)),
make_pair(lft[0] + top[1], point(0, 1)),
make_pair(lft[0] + top[2], point(0, 2)),
make_pair(lft[1] + top[0], point(1, 0)),
make_pair(lft[1] + top[1], point(1, 1)),
make_pair(lft[1] + top[2], point(1, 2)),
make_pair(lft[2] + top[0], point(2, 0)),
make_pair(lft[2] + top[1], point(2, 1)),
make_pair(lft[2] + top[2], point(2, 2)) };
const point win[8][3] {{ { 0, 0 }, { 0, 1 }, { 0, 2 } },
{ { 1, 0 }, { 1, 1 }, { 1, 2 } },
{ { 2, 0 }, { 2, 1 }, { 2, 2 } },
{ { 0, 0 }, { 1, 0 }, { 2, 0 } },
{ { 0, 1 }, { 1, 1 }, { 2, 1 } },
{ { 0, 2 }, { 1, 2 }, { 2, 2 } },
{ { 0, 0 }, { 1, 1 }, { 2, 2 } },
{ { 0, 2 }, { 1, 1 }, { 2, 0 } } };
string toupper(const string& st)
{
string tu;
for (auto ch : st)
tu += toupper(ch);
return tu;
}
void draw(char board[3][3])
{
cout << endl;
for (int t = 0; t < 3; ++t)
cout << " " << top[t];
cout << endl << endl;
for (int rr = 0; rr < 3; ++rr) {
if (rr > 0)
cout << " -----------" << endl;
for (int cc = 0; cc < 3; ++cc) {
if (cc > 0)
cout << " |";
else
cout << lft[rr] << " ";
cout << " " << board[rr][cc];
}
cout << endl;
}
}
int main()
{
char again = 'n';
do {
char board[3][3] = { 0 };
string inp;
auto mit = msp.cbegin();
char gotwin = ' ';
draw(board);
for (int cnt = 0, play = 0; (cnt < 9) && (gotwin == ' ');) {
while ((cout << "\nEnter location for player " << play + 1 << " [" << sym[play] << "]: ") && (cin >> inp) && ((mit = msp.find(toupper(inp))) == msp.end()))
cout << "Invalid location";
char &pos = board[mit->second.r][mit->second.c];
if (pos > ' ')
cout << "Space taken!" << endl;
else {
pos = sym[play];
++cnt;
play = (play + 1) % 2;
draw(board);
for (int w = 0, b; (w < 8) && (gotwin == ' '); ++w)
if (((b = board[win[w][0].r][win[w][0].c]) > ' ') && (b == board[win[w][1].r][win[w][1].c]) && (b == board[win[w][2].r][win[w][2].c]))
gotwin = b;
if (gotwin != ' ')
cout << "\nPlayer " << (gotwin == 'X' ? "1" : "2") << " wins!" << endl;
}
}
if (gotwin == ' ')
cout << "\nDraw!" << endl;
while ((cout << "\nPlay again? [Y, N]: ") && (cin >> again) && ((again = toupper(again)) != 'N' && (again != 'Y')))
cout << "Please enter 'Y' or 'N': ";
} while (again == 'Y');
}
If you want it as a class, I'll leave that as an exercise!
All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!
C++23 Compiler: Microsoft VS2022 (17.6.5)
-
December 30th, 2014, 05:13 PM
#20
Re: Creating a good computer AI for a tic tac toe game.
It looks like a lot of effort (and typing) went into text processing when there is an easier way.
Look at your numeric keypad. Does it look like a tic-tac-toe board? Here are your “commands”:
7 8 9
4 5 6
1 2 3
This simplifies the input and eliminates case sensitivity.
You could keep the board in one-dimensional array where those “commands” are indices into it.
As was noted, I would split your Board class into two: Game and Board, where Game coordinates the play and Board only manages the board.
But first I’d try to remove redundancy. How is playerInputCheck1() different from playerInputCheck2()? Could they be combined?
Same for playerLocationCheck1() and playerLocationCheck2(). If a tile is available for Player1, it should be available for Player2 as well – right?
Your game counters are also redundant: playerWins1 must be equal to playerLose2 and vice versa (or you have a problem).
As for the structure – I would construct an instance of a Game object in main(), let it initialize what’s needed and call , for example, its Play() method.
The board may belong to Game.
Play() may clear the board, choose X or O for the players and alternate moves, possibly checking for the end-of-game status after each move.
Then you may have a base player class with one virtual method Move() returning a valid tile index for that move, and two derived classes for a person and a computer.
Person’s Move() would prompt for an input and validate it, while computer’s Move() will be implemented as your AI.
Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
Convenience and productivity tools for Microsoft Visual Studio:
FeinWindows - replacement windows manager for Visual Studio, and more...
-
January 5th, 2015, 09:32 AM
#21
Re: Creating a good computer AI for a tic tac toe game.
 Originally Posted by VladimirF
As was noted, I would split your Board class into two: Game and Board, where Game coordinates the play and Board only manages the board.
To add to that, I'd add an abstract class called "Player", which would have different implementations, such as "HumanPlayer" "DumbAI" "SmartAI" etc...
A Game would be made of 2 Players and a Board. The game queries the players for the moves, and manages their turns etc.
Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.
-
January 5th, 2015, 10:27 AM
#22
Re: Creating a good computer AI for a tic tac toe game.
This doesn't need an AI.
There is a simple set of steps that will either make the computer win or make sure it doesn't loose and make the game end in a draw.
follow each step taking a box
1) if you can make 3 in a row/column/diagonal, take that box and win
2) if player has 2 in a row/column/diagonal, block the player by taking whichever box prevents 3
3) play the middle piece if available
4) if any row/column ONLY has boxes of your own, pick another box on that row/column, prefer corners. (disregard diagonals here)
5) pick any corner box
6) pick any side box
That isn't an "AI" per se, it's a playing strategy. In this case the strategy can never loose and forces a draw unless the player makes a mistake.
Some games have winnable strategies. Some (like chess) don't and need elaborate AI's to even achieve semi decent play.
There can be things in between where there are "good" (but beatable) strategies once you figure out how to counter the "AI" and where there are multiple strategies the computer can follow (even where a computer can change strategy mid game).
From a pure technical POV, a AI is not based on strategy rules but instead "learns" as it goes by avoiding to make the mistakes that caused it to loose in previous games.
There are very few actual AI's out there, most are simple strategy rules, brute force approaches (looking only a few steps ahead), or even random with discarding 'Obvious' bad moves.
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|