Крестики-нолики против бота с примитивным рандомайзером в роли ИИ.

Реализация через двумерный массив и объекты-классы (насколько я их понял).
Можно играть первым и вторым номером, игра ведёт счёт.
This commit is contained in:
2024-11-01 15:52:41 +05:00
commit 8268e14e8a
3 changed files with 259 additions and 0 deletions

39
.gitignore vendored Normal file
View File

@ -0,0 +1,39 @@
/cmake-build-debug/.cmake/api/v1/query/cache-v2
/cmake-build-debug/.cmake/api/v1/query/cmakeFiles-v1
/cmake-build-debug/.cmake/api/v1/query/codemodel-v2
/cmake-build-debug/.cmake/api/v1/query/toolchains-v1
/cmake-build-debug/.cmake/api/v1/reply/cache-v2-281607456d1cb183dd29.json
/cmake-build-debug/.cmake/api/v1/reply/cmakeFiles-v1-0029ce9b068fb614e1dc.json
/cmake-build-debug/.cmake/api/v1/reply/codemodel-v2-d0ab181aa7b1350e0211.json
/cmake-build-debug/.cmake/api/v1/reply/directory-.-Debug-d0094a50bb2071803777.json
/cmake-build-debug/.cmake/api/v1/reply/index-2024-10-27T06-42-29-0764.json
/cmake-build-debug/.cmake/api/v1/reply/target-TicTacToe-Debug-266a9f9167a4e0d9612b.json
/cmake-build-debug/.cmake/api/v1/reply/toolchains-v1-a2523d1a0a47b8d9fb88.json
/cmake-build-debug/CMakeFiles/3.28.1/CompilerIdC/a.exe
/cmake-build-debug/CMakeFiles/3.28.1/CompilerIdC/CMakeCCompilerId.c
/cmake-build-debug/CMakeFiles/3.28.1/CompilerIdCXX/a.exe
/cmake-build-debug/CMakeFiles/3.28.1/CompilerIdCXX/CMakeCXXCompilerId.cpp
/cmake-build-debug/CMakeFiles/3.28.1/CMakeCCompiler.cmake
/cmake-build-debug/CMakeFiles/3.28.1/CMakeCXXCompiler.cmake
/cmake-build-debug/CMakeFiles/3.28.1/CMakeDetermineCompilerABI_C.bin
/cmake-build-debug/CMakeFiles/3.28.1/CMakeDetermineCompilerABI_CXX.bin
/cmake-build-debug/CMakeFiles/3.28.1/CMakeRCCompiler.cmake
/cmake-build-debug/CMakeFiles/3.28.1/CMakeSystem.cmake
/cmake-build-debug/CMakeFiles/TicTacToe.dir/main.cpp.obj
/cmake-build-debug/CMakeFiles/clion-Debug-log.txt
/cmake-build-debug/CMakeFiles/clion-environment.txt
/cmake-build-debug/CMakeFiles/cmake.check_cache
/cmake-build-debug/CMakeFiles/CMakeConfigureLog.yaml
/cmake-build-debug/CMakeFiles/rules.ninja
/cmake-build-debug/CMakeFiles/TargetDirectories.txt
/cmake-build-debug/Testing/Temporary/LastTest.log
/cmake-build-debug/.ninja_deps
/cmake-build-debug/.ninja_log
/cmake-build-debug/build.ninja
/cmake-build-debug/cmake_install.cmake
/cmake-build-debug/CMakeCache.txt
/cmake-build-debug/TicTacToe.exe
/.idea/.gitignore
/.idea/misc.xml
/.idea/modules.xml
/.idea/TicTacToe.iml

6
CMakeLists.txt Normal file
View File

@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.28)
project(TicTacToe)
set(CMAKE_CXX_STANDARD 17)
add_executable(TicTacToe main.cpp)

214
main.cpp Normal file
View File

@ -0,0 +1,214 @@
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <chrono>
#include <thread>
#include <windows.h>
#include <string>
using namespace std;
typedef unsigned int unint;
int main() {
//
//ПЕРЕМЕННЫЕ
//
//МЭЙН
const int LINES = 3, COLUMNS = 3;
bool newgame=true, firstnumber;
int turn, humanwin=0, botwin=0;
string wannaplay="y";
const string INCORRECT="INCORRECT VALUE, TRY AGAIN: ", ENDGAME="\nGame says: ''The game ends here.''";
const string XWON="Game says: ''X wins!''", OWON="O wins!", DRAW="Game says: ''Nobody wins - DRAW!''";
const string BOTLOST="Bot says: ''Shee u beat me, I'm worry.''", HUMANLOST="Bot says: ''nahahaha lamer, look how I beat u!''";
const string SEP(15, '-');
const string BOTTHINK="Bot says: ''Wait, I'm thinking.''";
//
//КЛАССЫ
//Класс, отвечающий за формирование и вывод поля
class Board {
public:
bool Xwonflag=false;
bool Owonflag=false;
//ИГРОВОЕ ПОЛЕ
//первое число LINES характеризует строку
//второе число COLUMNS характеризует столбик
string board[LINES][COLUMNS] = {
{"e", "e", "e"},
{"e", "e", "e"},
{"e", "e", "e"}
};
//Функция вывода поля.
//Пустая клетка ("е") выводится координатами, а занятая - своим знаком.
void BoardShow() {
for (int countlines = 0; countlines < LINES; ++countlines) {
for (int countcolumns = 0; countcolumns < COLUMNS; ++countcolumns) {
if (board[countlines][countcolumns]=="e") {
cout << countlines << countcolumns << " ";
}
else {
cout << board[countlines][countcolumns] << " ";
}
}
cout << endl;
}
}
void XWon() {
if ((board[0][0])=="'X'") {
if ((board[0][1])=="'X'" and (board[0][2])=="'X'") {Xwonflag=true;}
else if ((board[1][1])=="'X'" and (board[2][2])=="'X'") {Xwonflag=true;}
else if ((board[1][0])=="'X'" and (board[2][0])=="'X'") {Xwonflag=true;}
}
if (((board[1][0])=="'X'") and ((board[1][1])=="'X'") and ((board[1][2]))=="'X'") {Xwonflag=true;}
if (((board[0][1])=="'X'") and ((board[1][1])=="'X'") and ((board[2][1]))=="'X'") {Xwonflag=true;}
if (((board[0][2])=="'X'") and ((board[1][2])=="'X'") and ((board[2][2]))=="'X'") {Xwonflag=true;}
if ((board[2][0])=="'X'") {
if ((board[2][1])=="'X'" and (board[2][2])=="'X'") {Xwonflag=true;}
else if ((board[1][1])=="'X'" and (board[0][2])=="'X'") {Xwonflag=true;}
}
}
void OWon() {
if ((board[0][0])=="'O'") {
if ((board[0][1])=="'O'" and (board[0][2])=="'O'") {Owonflag=true;}
else if ((board[1][1])=="'O'" and (board[2][2])=="'O'") {Owonflag=true;}
else if ((board[1][0])=="'O'" and (board[2][0])=="'O'") {Owonflag=true;}
}
if (((board[1][0])=="'O'") and ((board[1][1])=="'O'") and ((board[1][2]))=="'O'") {Owonflag=true;}
if (((board[0][1])=="'O'") and ((board[1][1])=="'O'") and ((board[2][1]))=="'O'") {Owonflag=true;}
if (((board[0][2])=="'O'") and ((board[1][2])=="'O'") and ((board[2][2]))=="'O'") {Owonflag=true;}
if ((board[2][0])=="'O'") {
if ((board[2][1])=="'O'" and (board[2][2])=="'O'") {Owonflag=true;}
else if ((board[1][1])=="'O'" and (board[0][2])=="'O'") {Owonflag=true;}
}
}
};
//Ходы игрока и бота
class Turn {
public:
int turnLINEint, turnCOLint;
string Humancount, turnline, turncol;
void HumanTurn() {
//ХОД ИГРОКА
//алгоритм на вычленение первого и второго значений координат
//получает строку вида "XY", первый символ кидает через at в строку для Х,
//второй символ также символ кидает в строку для Y,
//затем переводит обе строки в числа, с которыми можно вести вычисления.
cin >> Humancount;
turnline=Humancount.at(0);
turncol=Humancount.at(1);
turnLINEint=stoi(turnline);
turnCOLint=stoi(turncol);
//cout << "\nlineHUMAN: " << turnLINEint << " colHUMAN: " << turnCOLint << endl;
}
void BotTurn() {
//ХОД БОТА
//рандомит первое значение (строку), засыпает,
//рандомит второе значение (столбец)
srand((time(0)));
turnLINEint=(rand()%3);
Sleep((rand()/3));
srand((time(0)));
turnCOLint=(rand()%3);
//cout << "lineBOT: " << turnLINEint << " colBOT: " << turnCOLint << endl;
}
};
//Объявление объектов
Turn Game;
Board BoardObj;
//
//
//
//
//Заглавие игры. Инструкции для игрока. Выводится только при первом запуске.
cout << "Bot says:" << endl;
cout << "''Wolcome to TicTacToe choom." << endl;
cout << "Look at the clear board." << endl;
BoardObj.BoardShow();
cout << "When u wanna do ur turn - u should type coordinates of the any empty cell." << endl;
cout << "(For example '22' or '10')" << endl;
cout << "I afford I shouldn't explain u rules of the TicTacToe. So let's play brodie.''" << endl;
//
//Основной цикл игры
while (wannaplay=="y") {
//Объявление переменных при старте новой игры на основе булевого флага newgame.
//Флаг newgame становится TRUE на стадии "Заглавие игры",
//становится FALSE в начале цикла после присвоения переменных,
//и снова становится TRUE при окончании цикла (т.е. при чьей-то победе или ничье).
if (newgame) {
//
//Запрос на то, кто первый. 1=игрок, 0=бот.
//Выводит соответствующее сообщение после выбора.
//Обнуляет общие переменные.
//Также снимает флаг newgame, который возвращается в конце игры.
cout << "Bot asks: Wanna be an X? (1/0):";
cin >> firstnumber;
if (firstnumber) {cout << "Bot says: ''Well, u'll be an X.''" << endl;}
else {cout << "Bot says: ''OK, I'll be an X.''\n" << endl;}
turn=1;
newgame=false;
}
cout << SEP << endl;
cout << "Game says: ''Now it's " << turn << " turn.''" << endl;
turn++;
Game.turnLINEint=3;
Game.turnCOLint=3;
//Если первым номером (Х) выступает игрок
if (firstnumber) {
cout << "Enter ur coords:";
while ((BoardObj.board[Game.turnLINEint][Game.turnCOLint]!="e")) {
Game.HumanTurn();
if ((BoardObj.board[Game.turnLINEint][Game.turnCOLint]!="e")) {cout << INCORRECT;}
}
BoardObj.board[Game.turnLINEint][Game.turnCOLint] = "'X'";
Game.turnLINEint=3;
Game.turnCOLint=3;
cout << BOTTHINK << endl;
while ((BoardObj.board[Game.turnLINEint][Game.turnCOLint]!="e")) {Game.BotTurn();}
BoardObj.board[Game.turnLINEint][Game.turnCOLint] = "'O'";
BoardObj.BoardShow();
}
//Если игрок выступает вторым номером (O)
else {
cout << BOTTHINK << endl;
while ((BoardObj.board[Game.turnLINEint][Game.turnCOLint]!="e")) {Game.BotTurn();}
BoardObj.board[Game.turnLINEint][Game.turnCOLint] = "'X'";
BoardObj.BoardShow();
cout << "Enter ur coords:";
Game.turnLINEint=3;
Game.turnCOLint=3;
while ((BoardObj.board[Game.turnLINEint][Game.turnCOLint]!="e")) {
Game.HumanTurn();
if ((BoardObj.board[Game.turnLINEint][Game.turnCOLint]!="e")) {cout << INCORRECT;}
}
BoardObj.board[Game.turnLINEint][Game.turnCOLint] = "'O'";
}
BoardObj.XWon();
BoardObj.OWon();
if ((BoardObj.Xwonflag) or (BoardObj.Owonflag) or (turn>=9)) {
cout << ENDGAME << endl;
newgame=true;
if (BoardObj.Xwonflag) {cout << XWON << endl;}
else if (BoardObj.Owonflag) {cout << OWON << endl;}
else if ((turn>=9) and (!BoardObj.Xwonflag) and (!BoardObj.Owonflag)) {cout << DRAW << endl;}
if ((firstnumber) and (BoardObj.Xwonflag)) {cout << BOTLOST << endl; humanwin=+1;}
else if ((!firstnumber) and (BoardObj.Owonflag)) {cout << BOTLOST << endl; humanwin=+1;}
else {cout << HUMANLOST << endl; botwin=+1;}
cout << SEP << endl;
cout << SEP << endl;
cout << "Wanna play another time?(y/n): ";
cin >> wannaplay;
}
}
//
//СТАТИСТИКА ПРИ ЗАВЕРШЕНИИ ИГРЫ
cout << SEP << endl;
cout << "SOME STATS OF SESSION:" << endl;
cout << "Bot says: ''Hell u won me " << humanwin << " times.\nAnd I won u " << botwin << " times.''" << endl;
//
//компьютер респектует или лошит игрока
if (humanwin<botwin) {cout << "Bot says: ''fuckyeah go back home lamer, u need some training.''" << endl;}
else if (botwin<humanwin) {cout << "Bot says: ''well, dat was not bad how u beat me.''" << endl;}
else if (botwin==humanwin) {cout << "Bot says: ''yeah dat was fairplay.''" << endl;}
return 1488;
}