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

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

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;
}