Как пройти максимальное количество возможностей Tic Tac Toe?

0

Мне хотелось узнать, сколько там возможностей Tic Tac Toes, поэтому я обыскал в Интернете и нашел математическую теорему, в которой говорится, что в Tic Tac Toe есть 255168 возможных игр.

Веб-сайт: http://www.se16.info/hgb/tictactoe.htm

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

#include <iostream>
#include <time.h>
#include <windows.h>
#include <stdio.h>
using namespace std;

typedef int TTTField[9];

bool checkIfWon(TTTField j){
    if(j[0]==1&&j[1]==1&&j[2]==1) return true;
    if(j[0]==2&&j[1]==2&&j[2]==2) return true;
    if(j[3]==1&&j[4]==1&&j[5]==1) return true;
    if(j[3]==2&&j[4]==2&&j[5]==2) return true;
    if(j[6]==1&&j[7]==1&&j[8]==1) return true;
    if(j[6]==2&&j[7]==2&&j[8]==2) return true;
    if(j[0]==1&&j[3]==1&&j[6]==1) return true;
    if(j[0]==2&&j[3]==2&&j[6]==2) return true;
    if(j[1]==1&&j[4]==1&&j[7]==1) return true;
    if(j[1]==2&&j[4]==2&&j[7]==2) return true;
    if(j[2]==1&&j[5]==1&&j[8]==1) return true;
    if(j[2]==2&&j[5]==2&&j[8]==2) return true;
    if(j[0]==1&&j[4]==1&&j[8]==1) return true;
    if(j[0]==2&&j[4]==2&&j[8]==2) return true;
    if(j[2]==1&&j[4]==1&&j[6]==1) return true;
    if(j[2]==2&&j[4]==2&&j[6]==2) return true;
    return false;
}

bool checkIfItsOver(TTTField j){
    for(int i=0;i<9;i++){
        if(j[i]==0){
            return false;
        }
    }
    return true;
}

bool checkListOfFields(TTTField game, TTTField listOfFields[], int amountAdded){
    int i,j;
    for(j=0;j<amountAdded;j++){
        int temporaryField=0;
        for(i=0;i<9;i++){
            if(game[i]==listOfFields[j][i]) temporaryField++;
        }
        if(temporaryField==9)return true;
    }
    return false;
}

void clearField(TTTField game){
    int i;
    for(i=0;i<9;i++) game[i]=0;
}

void addlistOfFields(TTTField game, TTTField listOfFields[], int amountAdded){
    for(int i=0;i<9;i++) listOfFields[amountAdded][i]=game[i];
}

int main(){
    TTTField listOfFields[50000];
    TTTField temporaryField;
    int amountAdded=0,randA,round=1,roundCounter=0,amountPassed=0,amountOfWins=0,amountOfDraws=0,winWith5=0,winWith6=0,winWith7=0,winWith8=0,winWith9=0,roundAmountFinished=0;
    for(int i=0;roundCounter<100000;i++){
        clearField(temporaryField);
        roundAmountFinished=0;
        do{
            do{
                randA=rand()%9;
            }while(temporaryField[randA]!=0);
            temporaryField[randA]=round;
            if(checkIfWon(temporaryField)){
                break;
            }
            if(checkIfItsOver(temporaryField)){
                break;
            }
            round=round==1?2:1;
            roundAmountFinished++;
        }while(1);
        if(!checkListOfFields(temporaryField,listOfFields,amountAdded)){
            addlistOfFields(temporaryField,listOfFields,amountAdded);
            amountAdded++;
            if(checkIfWon(temporaryField)){
                amountOfWins++;
            }
            if(checkIfItsOver(temporaryField)){
                amountOfDraws++;
            }
            switch(roundAmountFinished){
                case 4:
                    winWith5++;
                    break;
                case 5:
                    winWith6++;
                    break;
                case 6:
                    winWith7++;
                    break;
                case 7:
                    winWith8++;
                    break;
                case 8:
                    winWith9++;
                    break;
            }
        }
        if(amountPassed==amountAdded){
            roundCounter++;
        }else roundCounter=0;
        amountPassed=amountAdded;
    }
    system("cls");
    printf("Total: %d, roundCounter: %d\nWins with 5 rounds:%d\nWins with 6 rounds:%d\nWins with 7 rounds:%d\nWins with 8 rounds:%d\nWins with 9 rounds:%d\namountOfWins: %d, amountOfDraws: %d",amountAdded,roundCounter,winWith5,winWith6,winWith7,winWith8,winWith9,amountOfWins,amountOfDraws);

    return 0;
}

Но он возвращает мне общее количество: 1916, что отличается от того, что было на веб-сайте, и мне интересно, что не так с моим кодом.

Некоторая информация о коде:

  • Поле представляет собой массив целых чисел с 9 индексами, в которых 1 представляет собой кресты, а 2 представляет круги, также 0 для нулевого поля.
  • Он генерирует случайное значение от 0 до 9 (если оно не было выбрано раньше), чем оно помещает 1 или 2 (в зависимости от того, кто вокруг него), всегда проверяя, выиграл ли кто-то, или игра привела к ничьей.
  • Закончив игру, он проверяет, есть ли эта возможность в списке, если она ничего не сделает и перейдет к другой.
  • Он завершится, когда пройдет 100 тыс. Возможностей без добавления в список одного.

В чем проблема?

  • 2
    Первый ход имеет 9 полей для выбора, затем 8, затем 7, затем 6, затем 5. Это самое раннее, что может произойти победа. И есть 9 * 8 * 7 * 6 * 5 = 15 120 способов, которыми могут произойти эти первые пять ходов. Итак, мы знаем, что реальный ответ должен быть (намного) больше этого. (Точно так же есть 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 = 362 880 возможных ходов, не учитывающих ранние победы, поэтому реальный ответ должен быть меньше этого).
  • 0
    Хорошо, спасибо за комментарий, но что касается математической теоремы о том, сколько возможностей может произойти, я поместил страницу, показывающую, сколько их существует, то, что я хотел, это просмотреть каждую из них с помощью своего кода.
Показать ещё 2 комментария
Теги:

3 ответа

5

Я только что заметил, checkListOfFields считает одинаковые платы одинаковыми играми, но это не совсем так. Вы вычисляете количество конечных позиций досок, а не игр, которые (хотя и интересны) - совсем другое.

Рассмотрим эти две игры:

X| |   X|O|   X|O|X
-----  -----  -----
 | |    | |    | | 
-----  -----  -----
 | |    | |    | | 

 | |X   |O|X  X|O|X
-----  -----  -----
 | |    | |    | | 
-----  -----  -----
 | |    | |    | | 

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

  • 0
    Замечание NICE, не понял, что, что касается кода, мне, вероятно, придется многое изменить, чтобы заставить его работать правильно?
  • 0
    @GuilhermeGarciadaRosa: На самом деле я не прочитал весь ваш код, но я подозреваю, что вы можете просто удалить if(!checkListOfFields(temporaryField,listOfFields,amountAdded)) и, возможно, это сработает.
Показать ещё 5 комментариев
3

Я бы, вероятно, написал эту проблему рекурсивно. Ваш метод будет принимать состояние платы, добавить часть, проверить, закончится ли она (полная или выиграть), а если нет, снова вызовите метод с новым состоянием платы. И каждый раз, когда вы полны или выигрываете, увеличивайте количество глобальных счетчиков. Когда метод вернется, переместите свой кусок на новое место.

Вот приблизительное представление о том, что я сделал бы:

recurseBoard(vector<vector<square> >& board, int pieceType) {
    for (int i = 0; i < 3; i++) {
       for (int j = 0; j < 3; j++) {
          // If there a piece there already, skip
          if (board[i][j] != 0) continue;
          // add the piece
          board[i][j] = pieceType;
          // if it full or win, increment counter
          if (victory(board)) count++;
          else (recurseBoard(board), otherPieceType);
          // Clear the piece you just added
          board[i][j] = 0;
      }
   }
}
  • 0
    Хорошее объяснение, есть намеки на типы? Должен ли я использовать такой тип, как Джош?
  • 0
    Использование enum для типа является довольно хорошим способом. Что касается использования векторов, это помогает с управлением памятью, но это немного зависит от личных предпочтений.
Показать ещё 2 комментария
1

Если бы я был вами, я бы начал с создания enum для квадратных значений вместо того, чтобы проезжать и сравнивать числа:

enum square {X, O, EMPTY};

Итак, вы можете сохранить доски как 2d векторы:

vector<vector<square> > board (3, vector<square>(3, EMPTY));

Тогда поиск количества возможных игр может произойти через рекурсию:

int find_games(vector<vector<square> >& board, square move) {
    if(game_over(board)) return 1;
    int num_moves = 0;
    for(int x = 0; x < board.size(); x++) {
        for(int y = 0; y < board[x].size(); y++) {
            if(board[x][y] != EMPTY) continue;
            board[x][y] = move; //test if player made a move here...
            num_moves += find_games(board, (move == X) ? Y : X);
            board[x][y] = EMPTY; //set space back to empty
        }
    }
    return number_moves;
}
  • 0
    Очень интересно! собираюсь взглянуть на это, а позже я дам правильный ответ

Ещё вопросы

Сообщество Overcoder
Наверх
Меню