Проверьте, имеют ли 3 элемента массива одинаковое значение

Я делаю игру в крестики-нолики (я знаю, довольно легко, но я новичок), и я почти закончил, моя проблема сейчас в том, что я пытаюсь проверить, имеют ли строка, столбец или диагональ таблицы одинаковое значение. и рекурсивно продолжайте играть, если это не так. Моя доска выглядит так:

char xToken = 'x';
char oToken = 'o';
char vertical = '|';
char horizontal = '-';

class Board {
public:
    const static int rows = 6;
    const static int cols = 6;
    char grid[rows][cols]{};

    Board() {
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                grid[i][0] = '0' + i;
                grid[0][j] = '0' + j;

                if (j == 2 || j == 4) {
                    grid[i][j] = vertical;
                }

                if (i == 2 || i == 4) {
                    grid[i][j] = horizontal;
                }
            }
        }
    }

    void printBoard() {
        for (auto & i : grid) {
            for (char j : i) {
                cout << j << "\t";
            }
            cout << endl;
        }
    }
}

Это моя функция play():

void play() {
        int i = 0;
        int j = 0;

        cout << "choose index you want to play in" << endl;
        cout << "Player 1" << endl;
        cout << "Row: " << endl;
        cin >> i;
        cout << "Column: " << endl;
        cin >> j;
        cout << i << ", " << j << endl;
        if (Board().grid[i][j] != vertical && Board().grid[i][j] != horizontal) {
            grid[i][j] = xToken;
            printBoard();
        }

        cout << "choose index you want to play in" << endl;
        cout << "Player 2" << endl;
        cout << "Row: " << endl;
        cin >> i;
        cout << "Column: " << endl;
        cin >> j;
        cout << i << ", " << j << endl;
        if (Board().grid[i][j] != vertical && Board().grid[i][j] != horizontal) {
            grid[i][j] = oToken;
            printBoard();
        }

        if (grid[i][j] == xToken) {
            cout << "You Win!" << endl;
        } else
            play();
    }

Идея в том, что я пытаюсь рекурсивно продолжать игру, если у нас нет трех элементов в строке, столбце или диагонали с одинаковым значением. Сама проблема теперь состоит в том, чтобы найти способ читать доску так, чтобы она могла найти 3 подряд и игра остановилась.

Знаете ли вы, что ваш код всегда имеет дело с пустыми досками Board()? play() не использует сохраненные доски, использует только вновь созданные временные доски.

3CxEZiVlQ 28.07.2024 09:55
arr[0] == arr[1] && arr[1] == arr[2], если у вас массив большего размера, лучше использовать цикл
Alan Birtles 28.07.2024 09:57

@3CxEZiVlQ Да, но есть ли в этом проблемы? Или было бы лучше, если бы я сделал что-нибудь другое? Моя идея состоит в том, чтобы заполнить индексы доски крестиками и нулями по ходу игры.

Pelz04 28.07.2024 10:13

play() учится в Board классе?

Mahdy.n 28.07.2024 10:20

@Mahdy.n Да, это так

Pelz04 28.07.2024 10:21

В вашем коде нет ничего плохого, вам просто нужен кто-то, кто его настроит, и это ваша работа, но если у вас проблемы с кодом, вам не следует каждый раз вызывать конструктор Board().! Также хотите проверить, равны ли строки, столбцы или диагонали? Так что, возможно, вам понадобятся 3 небольшие функции, которые сделают это за вас.

Mahdy.n 28.07.2024 10:41

Предоставьте достаточно кода, чтобы мы увидели, как вы используете этот класс. В настоящее время существует только определение класса и функция потери, которая, согласно вашему комментарию, принадлежит тому же классу, но нет кода драйвера. Еще один комментарий: не рекомендуется смешивать задачи ввода-вывода с игровой логикой. Если play — это метод, он не должен запрашивать ввод данных у пользователя и не должен распечатывать доску; это должно быть сделано вне этого класса.

trincot 28.07.2024 16:53

Здесь не нужно беспокоиться о скорости или эффективности. Просто проверьте каждую строку, затем каждый столбец, а затем две диагонали, чтобы увидеть, есть ли в них три жетона последнего игрока. Это становится простым методом, который можно вызывать после каждого ввода пользователя.

Dúthomhas 28.07.2024 22:41

@Pelz04 Pelz04, поскольку вы новичок в StackOverflow, я хочу помнить, что есть возможность принять ответ, нажав на галочку. Важно отметить, что это не является обязательным: выберите один ответ, который, по вашему мнению, является лучшим решением вашей проблемы. Если отсутствие ответа считается лучшим решением, ничего не делайте.

LoS 29.07.2024 09:54

Мой плохой @LoS, я не знал. Без сомнения, многие ваши материалы были действительно полезны, я ценю это.

Pelz04 29.07.2024 17:52
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
10
138
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Можно выполнить проверку в квадратичном времени, проверив, существует ли строка, столбец или диагональ, содержащая только один и тот же символ.

По матрице m, представляющей таблицу крестиков-ноликов, проверяется, существует ли комбинация типа m[i][j] для jε[0, 3), которая указывает на строки, и для iε[0, 3), что указывает на столбцы, отличные от двух диагоналей m[i][i] и m[i][3 - i] для каждого iε[0, 3). Если одна из этих комбинаций содержит только один и тот же символ, который может быть как нулём, так и крестиком, это означает, что игрок выиграл, в противном случае — нет.

Чтобы упростить алгоритм, можно использовать следующий прием: при условии, что определенное число используется для обозначения нуля или крестика, все ячейки определенной строки, столбца или диагонали суммируются по отдельности, а затем полученное число сравнивается с двумя. константы. Таким образом, если сумма кратна 6 и одному из конкретных чисел, можно сделать вывод, что строка, столбец или диагональ содержат только соответствующий символ, и, следовательно, игрок выиграл. Например, нуль может быть представлен цифрой -1, а крест может быть представлен цифрой 1.

Пример:

std::pair<bool, bool> is_winner()
{
  int sumb = 0;
  int sumd = 0;
  for(int i = 0; i != 3; ++i){
    int sumr = 0;
    int sumc = 0;
    for(int j = 0; j != 3 ; ++j){
      sumr += m[3 * i + j];
      sumc += m[3 * j + i];
    }
    if (sumr == -3 || sumc == -3)
      return {true, false};
    if (sumr == 3 || sumc == 3)
      return {false, true};
    sumb += m[i][i];
    sumd += m[i][3 - i];
  }
  if (sumb == -3 || sumd == -3)
    return {true, false};
  if (sumb == 3 || sumd == 3)
    return {false, true};
  return {false, false};
}

Характер игры таков, что некоторые поля могут быть еще незаполненными. Если они представлены 0, вам следует тщательно выбирать значения для представления x и o. Например, 1 и 2 не подходят, поскольку комбинация 2 и «пусто» может имитировать целый ряд 1. Для строк размера 6 можно использовать 1 и 7 и сравнить сумму с 6 и 42.

anatolyg 28.07.2024 20:49

@anatolyg, спасибо за отзыв. Я думаю, что можно использовать отрицательное число для нулей и положительное число для крестиков.

LoS 28.07.2024 20:59

Теперь, когда ваш класс появился, полезные элементы данных находятся в нечетных индексах вашего массива grid:

grid[1][1]
grid[1][3]
grid[1][5]
grid[3][1]
grid[3][3]
grid[3][5]
grid[5][1]
grid[5][3]
grid[5][5]

Немного неудобно, но пока хватит.

Сначала вам следует подумать об интерфейсе вашего кода. Я предлагаю следующее:

class Board {
public:
...
    bool isWinningPosition(char token) const;
...
};

Этот метод проверяет, появляется ли данный токен во всей строке, целом столбце или всей диагонали. Чтобы реализовать это:

bool Board::isWinningPosition(char token) const
{
    // Check row 1
    // If the token appears at all 3 relevant positions, it wins!
    if (grid[1][1] == token && grid[1][3] == token && grid[1][5] == token)
        return true;

    // Check row 2
    if (...more conditions...)
        return true;

    // Check row 3, then 3 columns, then 2 diagonals, similar to the above

    // If all 8 conditions are false, the token doesn't win yet
    return false;
}

Здесь я жестко запрограммировал размеры игры 3x3. Если вы хотите поддерживать гибкие размеры игрового поля, используйте несколько циклов.


Независимо от требуемой логики, я предлагаю вам перепроектировать хранилище данных. Вам следует отделить данные от представления. Создайте массив 3x3 (а не 6x6) для хранения токенов, и этот массив не должен содержать ничего другого. Это усложнит метод printBoard, но упростит все остальные методы.

Другие вопросы по теме