예제 #1
0
    public void DisplayBoardValues(AIBoardData aiBoardData)
    {
        for (int i = 0; i < 32; i++)
        {
            string cellText = "";
            if (aiBoardData.boardData[i].faceup)
            {
                cellText = "^";
            }
            else
            {
                cellText = "v";
            }

            if (aiBoardData.boardData[i].value == CellValue.King)
            {
                cellText += "K";
            }
            else
            {
                cellText += ((int)aiBoardData.boardData[i].value).ToString();
            }
            textCells[i].GetComponent <TextMeshProUGUI>().text = cellText;
        }

        textCells[32].GetComponent <TextMeshProUGUI>().text = aiBoardData.chanceNode.ToString();
        textCells[33].GetComponent <TextMeshProUGUI>().text = aiBoardData.flipIndex.ToString();
        textCells[34].GetComponent <TextMeshProUGUI>().text = aiBoardData.scoreOffset.ToString();
    }
예제 #2
0
    public void CalculateFaceDownProbability100Percent()
    {
        AISearch    ai        = new AISearch();
        AIBoardData testBoard = CreateTestBoardFaceDownOnly1();

        Assert.AreEqual(1, ai.ProbabilityOfPieceFlip(testBoard, Player.Red, CellValue.One));
    }
예제 #3
0
    public void EvaluatePosition2()
    {
        AISearch    ai        = new AISearch();
        AIBoardData testBoard = CreateTestBoardFaceDown1();

        Assert.AreEqual(1, ai.EvaluatePosition(testBoard));
    }
예제 #4
0
    public float ProbabilityOfPieceFlip(AIBoardData board, Player player, CellValue cellValue)
    //calculate the probability of getting a certain piece while it is facedown
    {
        int   value               = (int)player * (int)cellValue;
        float probability         = 0;
        int   totalFaceDownPieces = 0;
        int   targetPieceCounter  = 0;

        for (int i = 0; i < board.boardData.Length; i++)
        {
            if (!board.boardData[i].faceup && board.boardData[i].value != 0)
            {
                totalFaceDownPieces++;

                int currCellValue = (int)board.boardData[i].player * (int)board.boardData[i].value;
                if (currCellValue == value)
                {
                    targetPieceCounter++;
                }
            }
        }
        if (totalFaceDownPieces > 0)
        {
            probability = (float)targetPieceCounter / (float)totalFaceDownPieces;
        }

        return(probability);
    }
예제 #5
0
    public double EvaluatePosition(AIBoardData board)
    {
        double pieceScore = 0;

        for (int i = 0; i < board.boardData.Length; i++)
        {
            pieceScore += (int)board.boardData[i].value * (int)board.boardData[i].player;
        }
        return(pieceScore + board.scoreOffset);
    }
예제 #6
0
    public double ExpectiMax(AIBoardData board, bool maximizingPlayer, int depth)
    {
        bool canFlip = true;

        if (depth <= 0)
        {
            return(EvaluatePosition(board));
        }
        else if (maximizingPlayer)
        {
            double value = double.MinValue;
            foreach (AIBoardData possibleBoard in GenerateMoves(board, Player.Red, canFlip))
            {
                if (possibleBoard.chanceNode)
                {
                }
                else if (possibleBoard.gameWon)
                {
                    value = (int)CellValue.King;
                }

                else
                {
                    value = Math.Max(value, ExpectiMax(possibleBoard, false, depth - 1));
                }
            }
            return(value);
        }
        else if (!maximizingPlayer)
        {
            double value = double.MaxValue;
            foreach (AIBoardData possibleBoard in GenerateMoves(board, Player.Blue, canFlip))
            {
                if (possibleBoard.chanceNode)
                {
                }

                //Stop calculating moves if there is game winning move
                else if (possibleBoard.gameWon)
                {
                    value = -(int)CellValue.King;
                }

                else
                {
                    value = Math.Min(value, ExpectiMax(possibleBoard, true, depth - 1));
                }
            }
            return(value);
        }
        else
        {
            return(0);
        }
    }
예제 #7
0
    public IEnumerator FinishMove()
    {
        if (canMove())
        {
            AISearch    ai        = new AISearch();
            AIBoardData testBoard = ScanBoard();
            yield return(new WaitForSeconds(1));

            AIBoardData bestBoard = ai.BestMove(testBoard, 4, 1);
            MakeMove(testBoard, bestBoard);
        }
    }
예제 #8
0
    public AIBoardData CreateTestBoard1()
    {
        //| 0   | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
        //| 0   | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
        //| 0   | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
        //| 1r^ | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
        AICellData[] boardData = new AICellData[32];
        boardData[0] = new AICellData {
            value = CellValue.One, player = Player.Red, faceup = true
        };
        AIBoardData board = new AIBoardData(boardData, false);

        return(board);
    }
예제 #9
0
    public AIBoardData BestMove(AIBoardData board, int depth, int flipDepth)
    //Check if there is any checkmate from all one move away positions from current board.
    //Then calculate best move up to #depth of moves using ExpectiMax algorithm
    {
        List <AIBoardData> possibleBoards = new List <AIBoardData>();

        possibleBoards = GenerateMoves(board, Player.Blue, true);
        AIBoardData bestBoard = possibleBoards[0];
        double      bestScore = double.MaxValue;

        for (int i = 0; i < possibleBoards.Count; i++)
        {
            if (possibleBoards[i].chanceNode)
            {
                double newScore = ExpectiMaxChanceNode(possibleBoards[i], true, depth - 1);
                if (newScore < bestScore)
                {
                    bestBoard = possibleBoards[i];
                    bestScore = newScore;
                }
            }
            else if (!possibleBoards[i].gameWon)
            {
                if (possibleBoards[i].takePiece)
                {
                    possibleBoards[i].scoreOffset -= 0.5;
                }
                double newScore = ExpectiMax(possibleBoards[i], true, depth - 1);
                if (newScore < bestScore)
                {
                    bestBoard = possibleBoards[i];
                    bestScore = newScore;
                }
            }
            else
            {
                return(possibleBoards[i]);
            }
        }

        Debug.Log(bestScore);
        Debug.Log(bestBoard.gameWon);

        return(bestBoard);
    }
예제 #10
0
    public AIBoardData GenerateFlipMove(AIBoardData board, Player color, CellValue value)
    {
        int         index         = board.flipIndex;
        AIBoardData possibleBoard = new AIBoardData((AICellData[])board.boardData.Clone(), false);

        possibleBoard.boardData[index].value  = value;
        possibleBoard.boardData[index].player = color;
        possibleBoard.boardData[index].faceup = true;
        possibleBoard.chanceNode  = false;
        possibleBoard.scoreOffset = board.scoreOffset;
        possibleBoard.flipIndex   = -1;

        int scoreOffSet = (int)board.boardData[index].player * (int)board.boardData[index].value -
                          (int)possibleBoard.boardData[index].player * (int)possibleBoard.boardData[index].value;

        possibleBoard.scoreOffset += scoreOffSet;
        return(possibleBoard);
    }
예제 #11
0
 void MakeMove(AIBoardData startBoard, AIBoardData endBoard)
 {
     if (endBoard.chanceNode)
     {
         int x = endBoard.flipIndex % boardX;
         int y = endBoard.flipIndex / boardX;
         board.cells[x, y].FlipMove();
     }
     else
     {
         int moveFromX = endBoard.moveFromIndex % boardX;
         int moveFromY = endBoard.moveFromIndex / boardX;
         int moveToX   = endBoard.moveToIndex % boardX;
         int moveToY   = endBoard.moveToIndex / boardX;
         board.cells[moveFromX, moveFromY].MoveTo(board.cells[moveToX, moveToY]);
         Debug.Log(moveFromX + " " + moveFromY + " to: " + moveToX + " " + moveToY);
     }
 }
예제 #12
0
    public double ExpectiMaxChanceNode(AIBoardData board, bool maximizingPlayer, int depth)
    {
        double        value;
        List <double> averages = new List <double>();
        double        probability;

        probability = ProbabilityOfPieceFlip(board, Player.Blue, CellValue.One);
        averages.Add(probability * ExpectiMax(GenerateFlipMove(board, Player.Blue, CellValue.One), maximizingPlayer, depth - 1));

        probability = ProbabilityOfPieceFlip(board, Player.Blue, CellValue.Two);
        averages.Add(probability * ExpectiMax(GenerateFlipMove(board, Player.Blue, CellValue.Two), maximizingPlayer, depth - 1));

        probability = ProbabilityOfPieceFlip(board, Player.Blue, CellValue.Three);
        averages.Add(probability * ExpectiMax(GenerateFlipMove(board, Player.Blue, CellValue.Three), maximizingPlayer, depth - 1));

        probability = ProbabilityOfPieceFlip(board, Player.Blue, CellValue.Four);
        averages.Add(probability * ExpectiMax(GenerateFlipMove(board, Player.Blue, CellValue.Four), maximizingPlayer, depth - 1));

        probability = ProbabilityOfPieceFlip(board, Player.Blue, CellValue.King);
        averages.Add(probability * ExpectiMax(GenerateFlipMove(board, Player.Blue, CellValue.King), maximizingPlayer, depth - 1));

        probability = ProbabilityOfPieceFlip(board, Player.Red, CellValue.One);
        averages.Add(probability * ExpectiMax(GenerateFlipMove(board, Player.Red, CellValue.One), maximizingPlayer, depth - 1));

        probability = ProbabilityOfPieceFlip(board, Player.Red, CellValue.Two);
        averages.Add(probability * ExpectiMax(GenerateFlipMove(board, Player.Red, CellValue.Two), maximizingPlayer, depth - 1));

        probability = ProbabilityOfPieceFlip(board, Player.Red, CellValue.Three);
        averages.Add(probability * ExpectiMax(GenerateFlipMove(board, Player.Red, CellValue.Three), maximizingPlayer, depth - 1));

        probability = ProbabilityOfPieceFlip(board, Player.Red, CellValue.Four);
        averages.Add(probability * ExpectiMax(GenerateFlipMove(board, Player.Red, CellValue.Four), maximizingPlayer, depth - 1));

        probability = ProbabilityOfPieceFlip(board, Player.Red, CellValue.King);
        averages.Add(probability * ExpectiMax(GenerateFlipMove(board, Player.Red, CellValue.King), maximizingPlayer, depth - 1));

        value              = SumOfList(averages);
        board.scoreOffset += Random.Range(-0.1f, 0.15f);
        return(value);
    }
예제 #13
0
    public AIBoardData CreateTestBoardFaceDownOnly1()
    {
        //| 0   | 0   | 0 | 0 | 0 | 0 | 0 | 0 |
        //| 1r. | 1r. | 0 | 0 | 0 | 0 | 0 | 0 |
        //| 1r. | 0   | 0 | 0 | 0 | 0 | 0 | 0 |
        //| 1r. | 0   | 0 | 0 | 0 | 0 | 0 | 0 |
        AICellData[] boardData = new AICellData[32];
        boardData[0] = new AICellData {
            value = CellValue.One, player = Player.Red, faceup = false
        };
        boardData[8] = new AICellData {
            value = CellValue.One, player = Player.Red, faceup = false
        };
        boardData[16] = new AICellData {
            value = CellValue.One, player = Player.Red, faceup = false
        };
        boardData[17] = new AICellData {
            value = CellValue.One, player = Player.Red, faceup = false
        };
        AIBoardData board = new AIBoardData(boardData, false);

        return(board);
    }
예제 #14
0
    public void TestScanBoard()
    {
        AIBoardData testBoard = CreateTestBoard1();

        Assert.AreEqual(CellValue.One, testBoard.boardData[0].value);
    }
예제 #15
0
    public List <AIBoardData> GenerateMoves(AIBoardData board, Player player, bool canFlip)

    //TO DO remove canflip if unused
    {
        AIBoardData        curBoard       = board;
        List <AIBoardData> possibleBoards = new List <AIBoardData>();

        for (int index = 0; index < curBoard.boardData.Length; index++)
        {
            //generate board with piece index to be flipped
            if (!curBoard.boardData[index].faceup)
            {
                AIBoardData possibleBoard = new AIBoardData((AICellData[])curBoard.boardData.Clone(), true);
                possibleBoard.flipIndex  = index;
                possibleBoard.chanceNode = true;
                possibleBoard.boardData[index].faceup = false;
                possibleBoards.Add(possibleBoard);
            }

            // horizontal and vertical piece movement
            else
            {
                if (index + boardX < curBoard.boardData.Length && ValidMove(curBoard.boardData[index], curBoard.boardData[index + boardX], player))
                {
                    //resolvemove top
                    possibleBoards.Add(ResolveMove(index, index + boardX));
                }
                if (index - boardX >= 0 && ValidMove(curBoard.boardData[index], curBoard.boardData[index - boardX], player))
                {
                    //resolvemove btm
                    possibleBoards.Add(ResolveMove(index, index - boardX));
                }
                if (index + 1 < curBoard.boardData.Length && ValidMove(curBoard.boardData[index], curBoard.boardData[index + 1], player))
                {
                    //resolvemove right
                    possibleBoards.Add(ResolveMove(index, index + 1));
                }
                if (index - 1 >= 0 && ValidMove(curBoard.boardData[index], curBoard.boardData[index - 1], player))
                {
                    //resolvemove left
                    possibleBoards.Add(ResolveMove(index, index - 1));
                }
            }
        }

        AIBoardData ResolveMove(int start, int end)
        {
            //make a clone of a new possibleBoard within one move away from current board
            AIBoardData possibleBoard = new AIBoardData((AICellData[])curBoard.boardData.Clone(), false);

            //Resolve if both pieces are equal (remove both pieces)
            if (curBoard.boardData[start].value == curBoard.boardData[end].value && curBoard.boardData[start].value != CellValue.King)
            {
                possibleBoard.boardData[end].value  = 0;
                possibleBoard.boardData[end].player = Player.Empty;
            }

            //Resolve if king has been taken (game over)
            else if (curBoard.boardData[end].value == CellValue.King)
            {
                possibleBoard.boardData[end].value  = curBoard.boardData[start].value;
                possibleBoard.boardData[end].player = curBoard.boardData[start].player;
                possibleBoard.gameWon = true;
            }

            //Resolve if taking piece
            else if (curBoard.boardData[start].value > curBoard.boardData[end].value || curBoard.boardData[start].value == CellValue.King)
            {
                if (curBoard.boardData[end].value != CellValue.Empty)
                {
                    possibleBoard.takePiece = true;
                }
                possibleBoard.boardData[end].value  = curBoard.boardData[start].value;
                possibleBoard.boardData[end].player = curBoard.boardData[start].player;
            }

            possibleBoard.moveFromIndex           = start;
            possibleBoard.moveToIndex             = end;
            possibleBoard.boardData[start].value  = 0;
            possibleBoard.boardData[start].player = Player.Empty;
            possibleBoard.scoreOffset             = curBoard.scoreOffset;
            possibleBoard.flipIndex = curBoard.flipIndex;

            return(possibleBoard);
        }

        return(possibleBoards);
    }