-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
439 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,28 @@ | ||
# TicTacToe_class | ||
# Tic-Tac-Toe Game | ||
|
||
This is a C++ implementation of the Tic-Tac-Toe game where a human player plays against an AI. The game uses a 2D matrix to represent the board and players can input their desired position to place their symbol (O or X). The game constantly checks for a winning player or a tie and displays the final result. The code also includes a function to generate a random move for the AI at the start of the game. | ||
|
||
## Getting Started | ||
|
||
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. | ||
|
||
### Prerequisites | ||
|
||
You will need to have a Windows operating system and Visual Studio installed on your machine. | ||
|
||
### Installing | ||
|
||
You can download the source code of the project from the GitHub repository. Once you have the files, you can open the solution in Visual Studio and build the project. | ||
|
||
### Running the Game | ||
|
||
Once the project is built and the executable is generated, you can run the game by executing the file in the command prompt. | ||
|
||
## Built With | ||
|
||
- [Visual Studio](https://visualstudio.microsoft.com/) - The IDE used for development | ||
- [C++](http://www.cplusplus.com/) - The programming language used | ||
|
||
## Author | ||
|
||
- **Tugamer89** - _Initial work_ - [Tugamer89](https://github.com/Tugamer89) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 17 | ||
VisualStudioVersion = 17.4.33205.214 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TicTacToe_class", "TicTacToe_class\TicTacToe_class.vcxproj", "{01785574-4FCB-41B4-94D0-DADD02222524}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|x64 = Debug|x64 | ||
Debug|x86 = Debug|x86 | ||
Release|x64 = Release|x64 | ||
Release|x86 = Release|x86 | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{01785574-4FCB-41B4-94D0-DADD02222524}.Debug|x64.ActiveCfg = Debug|x64 | ||
{01785574-4FCB-41B4-94D0-DADD02222524}.Debug|x64.Build.0 = Debug|x64 | ||
{01785574-4FCB-41B4-94D0-DADD02222524}.Debug|x86.ActiveCfg = Debug|Win32 | ||
{01785574-4FCB-41B4-94D0-DADD02222524}.Debug|x86.Build.0 = Debug|Win32 | ||
{01785574-4FCB-41B4-94D0-DADD02222524}.Release|x64.ActiveCfg = Release|x64 | ||
{01785574-4FCB-41B4-94D0-DADD02222524}.Release|x64.Build.0 = Release|x64 | ||
{01785574-4FCB-41B4-94D0-DADD02222524}.Release|x86.ActiveCfg = Release|Win32 | ||
{01785574-4FCB-41B4-94D0-DADD02222524}.Release|x86.Build.0 = Release|Win32 | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {7A6506B1-C571-4E6D-A5B7-4B3E658B4A8F} | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
#include <iostream> | ||
#include <vector> | ||
#include <random> | ||
#include <string> | ||
#include <chrono> | ||
#include <thread> | ||
|
||
using namespace std; | ||
|
||
const int BOARD_DIMENSION = 3; | ||
const int CLS_DELAY_MS = 1500; | ||
enum States {LOST = -1, TIE, WON}; | ||
|
||
class TicTacToe { | ||
public: | ||
TicTacToe() : gameBoard(BOARD_DIMENSION, vector<string>(BOARD_DIMENSION, " ")), gameResult(TIE) {} | ||
|
||
void playGame() { | ||
#ifdef _WIN32 | ||
system("cls"); | ||
#else | ||
system("clear"); | ||
#endif | ||
printBoard(); | ||
|
||
do { | ||
string position; | ||
|
||
if (isHumanTurn) { | ||
cout << endl << endl << "Place an " << humanSymbol << " to: "; | ||
cin >> position; | ||
|
||
if (!isValidPosition(position)) { | ||
cout << "Invalid position!" << endl; | ||
this_thread::sleep_for(std::chrono::milliseconds(CLS_DELAY_MS)); | ||
continue; | ||
} | ||
} | ||
else if (isFirstMove) { | ||
position = getRandomAIPosition(); | ||
isFirstMove = false; | ||
} | ||
else { | ||
position = getAIMove(); | ||
} | ||
|
||
makeMove(position, (isHumanTurn ? humanSymbol : aiSymbol)); | ||
isHumanTurn = !isHumanTurn; | ||
|
||
#ifdef _WIN32 | ||
system("cls"); | ||
#else | ||
system("clear"); | ||
#endif | ||
printBoard(); | ||
} while (!isGameOver()); | ||
|
||
switch (gameResult) { | ||
case LOST: | ||
cout << endl << "You lost!" << endl; | ||
break; | ||
case TIE: | ||
cout << endl << "Tie!" << endl; | ||
break; | ||
case WON: | ||
cout << endl << "You won!" << endl; | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
bool isHumanTurn; | ||
bool isFirstMove; | ||
string humanSymbol = "O"; | ||
string aiSymbol = "X"; | ||
|
||
private: | ||
vector<vector<string>> gameBoard; | ||
States gameResult; | ||
|
||
void printBoard() const { | ||
cout << " 1 2 3" << endl; | ||
for (int i = 0; i < BOARD_DIMENSION; i++) { | ||
cout << " " << i + 1; | ||
for (int j = 0; j < BOARD_DIMENSION; j++) | ||
cout << " " << gameBoard[i][j] << (j != BOARD_DIMENSION - 1 ? " |" : ""); | ||
cout << endl << (i != BOARD_DIMENSION - 1 ? " -----------" : "") << endl; | ||
} | ||
} | ||
bool isGameOver() { | ||
if (gameBoard[1][1] != " " && ( | ||
(gameBoard[0][0] == gameBoard[1][1] && gameBoard[1][1] == gameBoard[2][2]) || | ||
(gameBoard[0][2] == gameBoard[1][1] && gameBoard[1][1] == gameBoard[2][0]) | ||
)) { | ||
gameResult = (gameBoard[1][1] == humanSymbol ? WON : (gameBoard[1][1] == aiSymbol ? LOST : TIE)); | ||
return true; | ||
} | ||
|
||
for (int i = 0; i < BOARD_DIMENSION; i++) { | ||
if (gameBoard[i][0] != " " && gameBoard[i][0] == gameBoard[i][1] && gameBoard[i][0] == gameBoard[i][2]) { | ||
gameResult = (gameBoard[i][0] == humanSymbol ? WON : (gameBoard[i][0] == aiSymbol ? LOST : TIE)); | ||
return true; | ||
} | ||
|
||
if (gameBoard[0][i] != " " && gameBoard[0][i] == gameBoard[1][i] && gameBoard[0][i] == gameBoard[2][i]) { | ||
gameResult = (gameBoard[0][i] == humanSymbol ? WON : (gameBoard[0][i] == aiSymbol ? LOST : TIE)); | ||
return true; | ||
} | ||
} | ||
|
||
for (int i = 0; i < BOARD_DIMENSION; i++) | ||
for (int j = 0; j < BOARD_DIMENSION; j++) | ||
if (gameBoard[i][j] == " ") | ||
return false; | ||
|
||
gameResult = TIE; | ||
return true; | ||
} | ||
bool isValidPosition(const string& pos) { | ||
if (pos.length() != 2) | ||
return false; | ||
if (pos[0] < '1' || pos[0] > '3' || pos[1] < '1' || pos[1] > '3') | ||
return false; | ||
if (gameBoard[pos[0] - '1'][pos[1] - '1'] != " ") | ||
return false; | ||
return true; | ||
} | ||
void makeMove(const string& pos, const string& player) { | ||
gameBoard[pos[0] - '1'][pos[1] - '1'] = player; | ||
} | ||
string intPos2String(int i, int j) { | ||
return to_string(i + 1) + to_string(j + 1); | ||
} | ||
string getRandomAIPosition() { | ||
random_device rd; | ||
mt19937 mt(rd()); | ||
uniform_int_distribution<int> dist(0, 2); | ||
int i, j; | ||
do { | ||
i = dist(mt); | ||
j = dist(mt); | ||
} while (gameBoard[i][j] != " "); | ||
return intPos2String(i, j); | ||
} | ||
string getAIMove() { | ||
int bestVal = INT_MIN; | ||
string bestMove = ""; | ||
|
||
for (int i = 0; i < BOARD_DIMENSION; i++) { | ||
for (int j = 0; j < BOARD_DIMENSION; j++) { | ||
if (gameBoard[i][j] == " ") { | ||
gameBoard[i][j] = aiSymbol; | ||
int moveVal = minimax(0, false); | ||
gameBoard[i][j] = " "; | ||
|
||
if (moveVal > bestVal) { | ||
bestMove = intPos2String(i, j); | ||
bestVal = moveVal; | ||
} | ||
} | ||
} | ||
} | ||
|
||
return bestMove; | ||
} | ||
int minimax(int depth, bool isMax) { | ||
if (isGameOver()) | ||
return (gameResult == WON ? -10 + depth : (gameResult == LOST ? 10 - depth : 0)); | ||
|
||
if (isMax) { | ||
int best = INT_MIN; | ||
for (int i = 0; i < BOARD_DIMENSION; i++) { | ||
for (int j = 0; j < BOARD_DIMENSION; j++) { | ||
if (gameBoard[i][j] == " ") { | ||
gameBoard[i][j] = aiSymbol; | ||
best = max(best, minimax(depth + 1, !isMax)); | ||
gameBoard[i][j] = " "; | ||
} | ||
} | ||
} | ||
return best; | ||
} | ||
else { | ||
int best = INT_MAX; | ||
for (int i = 0; i < BOARD_DIMENSION; i++) { | ||
for (int j = 0; j < BOARD_DIMENSION; j++) { | ||
if (gameBoard[i][j] == " ") { | ||
gameBoard[i][j] = humanSymbol; | ||
best = min(best, minimax(depth + 1, !isMax)); | ||
gameBoard[i][j] = " "; | ||
} | ||
} | ||
} | ||
return best; | ||
} | ||
} | ||
}; | ||
|
||
int main() { | ||
#ifdef _WIN32 | ||
system("cls"); | ||
#else | ||
system("clear"); | ||
#endif | ||
TicTacToe game; | ||
|
||
string start; | ||
cout << "Who starts: "; | ||
cin >> start; | ||
game.isHumanTurn = start != game.aiSymbol; | ||
game.isFirstMove = !game.isHumanTurn; | ||
|
||
game.playGame(); | ||
|
||
string res; | ||
cout << endl << "Play again (y/n): "; | ||
cin >> res; | ||
if (res == "y") | ||
main(); | ||
|
||
return 0; | ||
} |
Oops, something went wrong.