Минимаксный алгоритм для Ti c Ta c Toe Kotlin - PullRequest
0 голосов
/ 06 апреля 2020

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

Я двигаюсь первым и я 'X' ИИ равен 'O'

X |   |    
----------
  |   |   
----------
  |   |

, тогда возвращаемое значение равно

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

вместо оптимального хода, который должен быть средним.

Что я обнаружил: я попробовал отладку и понял, что после моего первого хода все возвращаемые значения из минимаксной функции равны 10 (10 - это константа, которую я установил для функции, возвращаемой в случае победы ИИ)

findPossibleMoves

fun findPossibleMoves(board: CharArray) : IntArray {
        var possibleMoves: ArrayList<Int> = ArrayList(0)
        for (cellIndex in board.indices) {
            if (board[cellIndex] == ' ') {
                possibleMoves.add(cellIndex)
            }
        }
        return possibleMoves.toIntArray()
    }

findBestMove

fun findBestMove(board: CharArray) : Int {
        var boardClone = CharArray(9)
        for (cellIndex in boardClone.indices) {
            boardClone[cellIndex] = board[cellIndex]
        }

        val possibleMoves = findPossibleMoves(boardClone)
        var bestMove = 0
        var max = -1000

        for (move in possibleMoves) {
            boardClone[move] = currentPlayer

            var value = minimax(boardClone, false, 1)
            Log.wtf("T", "$move $value")

            boardClone[move] = EMPTY

            if (value > max) {
                max = value
                bestMove = move
            }
        }
        Log.wtf("T", "-------------------------------")

        return bestMove
    }

минимакс

fun minimax(board: CharArray, isMaximising: Boolean, depth: Int) : Int {
        if (isGameOver(board)) {
            if (doesWinenrExist(board)) {
                when (getWinner(board)) {
                    PLAYER -> {
                        return -10
                    }

                    CPU -> {
                        return 10
                    }
                }
            }

            return 0
        }

        var possibleMoves = findPossibleMoves(board)

        if (isMaximising) {
            var bestValue = -1000

            for (move in possibleMoves) {
                board[move] = CPU

                var temp = minimax(board, !isMaximising, depth + 1)
                board[move] = EMPTY

                if (temp > bestValue) {
                    bestValue = temp
                }
            }
            return bestValue
        } else {
            var bestValue = 1000

            for (move in possibleMoves) {
                board[move] = PLAYER

                var temp = minimax(board, !isMaximising, depth + 1)
                board[move] = EMPTY

                if (temp < bestValue) {
                    bestValue = temp
                }
            }
            return bestValue
        }
    }

вспомогательные функции

fun isBoardFull(board: CharArray) : Boolean {
        for (cell in board) {
            if (cell == ' ') {
                return false
            }
        }

        return true
    }

fun doesWinenrExist(board: CharArray) : Boolean {
        var board2d: Array<CharArray> = arrayOf(board.sliceArray(0..2), board.sliceArray(3..5), board.sliceArray(6..8))

        //check row
        for (row in board2d) {
             if (row.all { it == PLAYER } || row.all { it == CPU }) {
                 return true
             }
        }

        //check col
        for (i in 0..2) {
            var col: ArrayList<Char> = ArrayList(0)
            for (firstIndexInGroupsOf3 in i until board.size step 3) {
                col.add(board[firstIndexInGroupsOf3])
            }

            if (col.all { it == PLAYER } || col.all { it == CPU }) {
                return true
            }
        }

        //check diag
        for (x in 0..2 step 2) {
            var diag: ArrayList<Char> = ArrayList(0)

            for (y in 0..2) {
                diag.add(board2d[y][if (x == 2) (x - y) else y])
            }

            if (diag.all { it == PLAYER } || diag.all { it == CPU }) {
                return true
            }
        }

        return false
    }

fun isGameOver(board: CharArray) : Boolean {
        return isBoardFull(board) || doesWinenrExist(board)
    }

fun getWinner(board: CharArray) : Char {
        var noOfX = board.count { it == PLAYER }
        var noOfO = board.count { it == CPU }

        return if (noOfO > noOfX) CPU else PLAYER

    }

Очень благодарен за любую помощь от yall! Спасибо!

=============================================== ==========

решено! проблема заключается в getWinner ()

обновленная функция getWinner:

fun getWinner() : Char {
        return currentPlayer

    }
...