ОНО РАБОТАЕТ

Рабочая игра в крестики-нолики на поле произвольного размера.
mail@pastecode.io avatar
unknown
c_cpp
a year ago
9.3 kB
1
Indexable
Never
#include <iostream>
#include <fstream>
#include <limits>
#include <random>
#include <string>
using namespace std;

const char PLAYER = 'X';
const char COMPUTER = 'O';
const char EMPTY = '-';
const int max_size = 50;
const int min_size = 3;

void drawBoard(const int fieldSize, char** board) {
    for (int i = 0; i < fieldSize; ++i) {
        for (int j = 0; j < fieldSize; ++j) {
            cout << board[i][j] << ' ';
        }
        cout << endl;
    }
}

bool checkWin(const int fieldSize, char** board, char player) {
    int winCount = (fieldSize == 3) ? 3 : 4;

    // Check rows and columns
    for (int i = 0; i < fieldSize; ++i) {
        bool rowWin = true;
        bool colWin = true;
        for (int j = 0; j < fieldSize; ++j) {
            rowWin &= (board[i][j] == player);
            colWin &= (board[j][i] == player);
        }
        if (rowWin || colWin) {
            return true;
        }
    }

    // Check diagonals
    bool diagonalWin = true;
    bool reverseDiagonalWin = true;
    for (int i = 0; i < fieldSize; ++i) {
        diagonalWin &= (board[i][i] == player);
        reverseDiagonalWin &= (board[i][fieldSize - i - 1] == player);
    }

    if (diagonalWin || reverseDiagonalWin) {
        return true;
    }

    // Check for win on larger board
    if (fieldSize > 3) {
        for (int i = 0; i < fieldSize; ++i) {
            for (int j = 0; j < fieldSize; ++j) {
                bool horizontalWin = true;
                bool verticalWin = true;
                bool diagonalWin = true;
                bool reverseDiagonalWin = true;

                // Check horizontal win
                for (int k = 0; k < winCount; ++k) {
                    if (j + k >= fieldSize || board[i][j + k] != player) {
                        horizontalWin = false;
                        break;
                    }
                }

                // Check vertical win
                for (int k = 0; k < winCount; ++k) {
                    if (i + k >= fieldSize || board[i + k][j] != player) {
                        verticalWin = false;
                        break;
                    }
                }

                // Check diagonal win
                if (i + winCount <= fieldSize && j + winCount <= fieldSize) {
                    for (int k = 0; k < winCount; ++k) {
                        if (board[i + k][j + k] != player) {
                            diagonalWin = false;
                            break;
                        }
                    }
                } else {
                    diagonalWin = false;
                }

                // Check reverse diagonal win
                if (i + winCount <= fieldSize && j - winCount + 1 >= 0) {
                    for (int k = 0; k < winCount; ++k) {
                        if (board[i + k][j - k] != player) {
                            reverseDiagonalWin = false;
                            break;
                        }
                    }
                } else {
                    reverseDiagonalWin = false;
                }

                if (horizontalWin || verticalWin || diagonalWin || reverseDiagonalWin) {
                    return true;
                }
            }
        }
    }

    return false;
}

void computerMove(const int fieldSize, char** board, char player) {
    char opponent = (player == PLAYER) ? COMPUTER : PLAYER;
    for (int i = 0; i < fieldSize; ++i) {
        for (int j = 0; j < fieldSize; ++j) {
            if (board[i][j] == EMPTY) {
                board[i][j] = opponent;
                if (checkWin(fieldSize, board, opponent)) {
                    board[i][j] = COMPUTER;
                    cout << "Computer move: row " << i + 1 << ", column " << j + 1 << endl;
                    return;
                }
                board[i][j] = EMPTY;
            }
        }
    }

    // If no potential winning moves by the player are found, check for potential winning moves by the computer and make a move to win the game
    for (int i = 0; i < fieldSize; ++i) {
        for (int j = 0; j < fieldSize; ++j) {
            if (board[i][j] == EMPTY) {
                board[i][j] = COMPUTER;
                if (checkWin(fieldSize, board, COMPUTER)) {
                    cout << "Computer move: row " << i + 1 << ", column " << j + 1 << endl;
                    return;
                }
                board[i][j] = EMPTY;
            }
        }
    }

    // If no winning moves are found, make a move in the center of the board if it's available
    if (board[fieldSize/2][fieldSize/2] == EMPTY) {
        board[fieldSize/2][fieldSize/2] = COMPUTER;
        cout << "Computer move: row " << fieldSize/2 + 1 << ", column " << fieldSize/2 + 1 << endl;
        return;
    }

    // If the center is not available, make a move in the first available cell
    for (int i = 0; i < fieldSize; ++i) {
        for (int j = 0; j < fieldSize; ++j) {
            if (board[i][j] == EMPTY) {
                board[i][j] = COMPUTER;
                cout << "Computer move: row " << i + 1 << ", column " << j + 1 << endl;
                return;
            }
        }
    }
}

void printResults(const int result[], int numGames) {
    int playerWin = 0;
    int computerWin = 0;
    int draws = 0;

    for (int i = 0; i < numGames; ++i) {
        if (result[i] == 1) {
            ++playerWin;
        }
        else if (result[i] == -1) {
            ++computerWin;
        }
        else {
            ++draws;
        }
    }

    cout << "Player wins: " << playerWin << endl;
    cout << "Computer wins: " << computerWin << endl;
    cout << "Draws: " << draws << endl;
}

int main() {
    string playerName;
    cout << "Enter your name: ";
    getline(cin, playerName);

    int fieldSize;
    cout << "Enter the size of the field (";
    cout << min_size << "-" << max_size << "): ";
    if (!(cin >> fieldSize) || fieldSize < min_size || fieldSize > max_size) {
        cout << "Error. Field size can only be a number "; 
        cout << min_size << "-" << max_size << "!" << endl;
        return 1;
    }

    int numGames = 0;
    int result[max_size] = {0};

    while (true) {
        char** board = new char* [fieldSize];
        for (int i = 0; i < fieldSize; ++i) {
            board[i] = new char[fieldSize];
            for (int j = 0; j < fieldSize; ++j) {
                board[i][j] = EMPTY;
            }
        }

        bool playerOneTurn = true;
        int moves = fieldSize * fieldSize;

        while (moves > 0) {
            drawBoard(fieldSize, board);

            if (playerOneTurn) {
                int row, col;
                cout << playerName << ", enter your move in the format 'row column': ";
                cin >> row >> col;

                row -= 1; // subtract 1 from row
                col -= 1; // subtract 1 from column

                while (cin.fail() || row < 0 || row >= fieldSize || col < 0
                    || col >= fieldSize || board[row][col] != EMPTY) {
                    cin.clear();
                    cin.ignore(numeric_limits<streamsize>::max(), '\n');
                    cout << "Invalid input. Please enter 'row column': ";
                    cin >> row >> col;
                    row -= 1; // subtract 1 from row
                    col -= 1; // subtract 1 from column
                }

                board[row][col] = PLAYER;
                if (checkWin(fieldSize, board, PLAYER)) {
                    drawBoard(fieldSize, board);
                    cout << "You won, " << playerName << "!" << endl;
                    result[numGames] = 1;
                    ++numGames;
                    break;
                }

                playerOneTurn = false;
            }
            else {
                computerMove(fieldSize, board, COMPUTER);
                if (checkWin(fieldSize, board, COMPUTER)) {
                    drawBoard(fieldSize, board);
                    cout << "Computer won!" << endl;
                    result[numGames] = -1;
                    ++numGames;
                    break;
                }

                playerOneTurn = true;
            }

            --moves;
        }

        if (moves == 0) {
            drawBoard(fieldSize, board);
            cout << "Draw!" << endl;
            result[numGames] = 0;
            ++numGames;
        }

        // Release the memory for the board
        for (int i = 0; i < fieldSize; ++i) {
            delete[] board[i];
        }
        delete[] board;

        // Ask the user if they want to play again
        string playAgain;
        cout << "Do you want to play again? (yes/no): ";
        cin >> playAgain;

        while (playAgain != "yes" && playAgain != "no") {
            cout << "Invalid input. Please enter 'yes' or 'no': ";
            cin >> playAgain;
        }

        if (playAgain == "no") {
            break;
        }
    }

    printResults(result, numGames);

    return 0;
}