Skip to content

Commit

Permalink
Adding project files
Browse files Browse the repository at this point in the history
  • Loading branch information
Tugamer89 committed Jan 13, 2023
1 parent 024b728 commit 8494a74
Show file tree
Hide file tree
Showing 5 changed files with 439 additions and 1 deletion.
29 changes: 28 additions & 1 deletion README.md
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)
31 changes: 31 additions & 0 deletions TicTacToe_class.sln
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
223 changes: 223 additions & 0 deletions TicTacToe_class/TicTacToe_class.cpp
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;
}
Loading

0 comments on commit 8494a74

Please sign in to comment.