protected override int EstimationFunction(MinimaxTreeNode node)
        {
            // winning condition for me
            if (WhoHasMoreBoxes(node, out int blue, out int red) == whoAmI && node.NonExistingLines.Count == 0)
            {
                return(int.MaxValue);
            }

            List <Box> newBoxes = AICommon.TryClosingBoxes(node.ExistingLines,
                                                           (node.Player == MinimaxPlayerType.MAX ? Player.BLUE : Player.RED),
                                                           node.DeltaMove,
                                                           out int[] surroundingEdges);

            // select state in which user can close boxes
            if (newBoxes.Count > 0)
            {
                return(int.MaxValue - 1);
            }

            // this state could lead opponent to close the box, hence negative estimation
            if (surroundingEdges[0] == 2 && surroundingEdges[1] == 2)
            {
                return(-2);
            }
            else if (surroundingEdges[0] == 2 || surroundingEdges[1] == 2)
            {
                return(-1);
            }

            // state is neutral for result for the provided tree depth
            return(0);
        }
        protected override int EstimationFunction(MinimaxTreeNode node)
        {
            int blue, red;

            // winning condition for me
            if (WhoHasMoreBoxes(node, out blue, out red) == whoAmI && node.NonExistingLines.Count == 0)
            {
                return(int.MaxValue);
            }
            // winning condition for opponent
            else if (WhoHasMoreBoxes(node, out blue, out red) != whoAmI && node.NonExistingLines.Count == 0)
            {
                return(int.MinValue);
            }

            List <Box> newBoxes = AICommon.TryClosingBoxes(node.ExistingLines,
                                                           (node.Player == MinimaxPlayerType.MAX ? Player.BLUE : Player.RED),
                                                           node.DeltaMove,
                                                           out int[] surroundingEdges);

            // box closing
            if (newBoxes.Count == 1)
            {
                return(int.MaxValue - 2);    // will close one box
            }
            else if (newBoxes.Count == 2)
            {
                return(int.MaxValue - 1);    // will close two boxes
            }
            // keep state where I will have more boxes
            if ((blue > red && whoAmI == Player.BLUE) || (red > blue && whoAmI == Player.RED))
            {
                return(int.MaxValue / 2 - Math.Abs(blue - red));
            }

            // this state could lead opponent to close the box, hence negative estimation
            if (surroundingEdges[0] == 2 && surroundingEdges[1] == 2)
            {
                return(-2);
            }
            else if (surroundingEdges[0] == 2 || surroundingEdges[1] == 2)
            {
                return(-1);
            }

            if ((blue < red && whoAmI == Player.BLUE) || (red < blue && whoAmI == Player.RED))
            {
                return(int.MinValue / 2 + Math.Abs(blue - red));
            }

            // state is neutral for result for the provided tree depth
            return(0);
        }
Ejemplo n.º 3
0
        private void FinishTurn(LineBetweenCircles line)
        {
            if (line == null)
            {
                throw new Exception("AI returned null for the next move.");
            }

            // will return false if clicked on line that had already been drawn on the canvas
            if (!TransferFromNonExistingToExisting(line))
            {
                return;
            }

            ///////////////////////////////////
            string log = line.ToString();

            int    startPosition = turnRichTextBox.Text.Length;
            string textToAppend  = log + Environment.NewLine;

            turnRichTextBox.AppendText(textToAppend);
            turnRichTextBox.SelectionStart  = startPosition;
            turnRichTextBox.SelectionLength = log.Length;
            turnRichTextBox.SelectionColor  = (currentGame.Turn == Player.BLUE ? Color.Blue : Color.Red);
            turnRichTextBox.ScrollToCaret();
            ///////////////////////////////////

            List <Box> newBoxes = AICommon.TryClosingBoxes(existingCanvasLines, currentGame.Turn, line, out int[] notUsed);

            boxes.AddRange(newBoxes);
            currentGame.Score[(int)currentGame.Turn] += newBoxes.Count;

            if (newBoxes.Count > 0)
            {
                canvas.Refresh();
                UpdateGUI();
            }

            if (boxes.Count == (currentGame.TableSizeX - 1) * (currentGame.TableSizeY - 1))
            {
                currentGame.GameOver = true;
            }

            if (currentGame.GameOver)
            {
                UpdateGUI();
                GUI_GameSettingChanged(null, null);
                MessageBox.Show("Igra je završena");
            }
            else if (currentGame.Opponent2 == null) // pc vs pc will be handled in other method -> PcNextStep
            {
                if (currentGame.Turn == Player.BLUE)
                {
                    if (newBoxes.Count == 0)
                    {
                        SwitchTurn();

                        if (currentGame.Opponent != null)
                        {
                            FinishTurn(currentGame.Opponent.MakeTurn());
                        }
                    }

                    UpdateGUI();
                }
                else
                {
                    if (newBoxes.Count == 0)
                    {
                        SwitchTurn();
                    }
                    else if (newBoxes.Count > 0 && currentGame.Opponent != null)
                    {
                        UpdateGUI();
                        Thread.Sleep(1000);

                        FinishTurn(currentGame.Opponent.MakeTurn());
                    }

                    UpdateGUI();
                }
            }
            else if (currentGame.Opponent != null && currentGame.Opponent2 != null)
            {
                if (newBoxes.Count == 0)
                {
                    SwitchTurn();
                }

                UpdateGUI();
                canvas.Refresh();
            }
        }
Ejemplo n.º 4
0
        private int ConstructTree(MinimaxTreeNode parentNode, int depth, MinimaxPlayerType minimaxPlayer, int alpha, int beta)
        {
            // return estimation function if max tree depth reached or game is in finished state
            if (depth == maxTreeDepth || parentNode.NonExistingLines.Count == 0)
            {
                return(EstimationFunction(parentNode));
            }

            if (minimaxPlayer == MinimaxPlayerType.MAX)
            {
                int bestValue = int.MinValue;

                for (int i = 0; i < parentNode.NonExistingLines.Count; i++)
                {
                    #region New Node Creation
                    MinimaxTreeNode node = new MinimaxTreeNode();

                    // calculate estimation function only for leaf nodes
                    node.Player = (parentNode.Player == MinimaxPlayerType.MAX ? MinimaxPlayerType.MIN : MinimaxPlayerType.MAX);

                    node.ExistingLines.AddRange(parentNode.ExistingLines);
                    node.ExistingLines.Add(parentNode.NonExistingLines[i]);

                    node.NonExistingLines.AddRange(parentNode.NonExistingLines);
                    node.NonExistingLines.Remove(parentNode.NonExistingLines[i]);

                    node.Boxes.AddRange(parentNode.Boxes);
                    List <Box> newBoxes = AICommon.TryClosingBoxes(parentNode.ExistingLines, DeterminePlayerColour(node.Player), parentNode.NonExistingLines[i], out int[] notUsed);
                    node.Boxes.AddRange(newBoxes);

                    node.DeltaMove = parentNode.NonExistingLines[i];
                    #endregion

                    /* don't go through this subtree if the delta move is drawing third edge
                     * unless it the only move
                     */
                    AICommon.TryClosingBoxes(node.ExistingLines,
                                             DeterminePlayerColour(node.Player),
                                             node.DeltaMove,
                                             out int[] surroundingEdges);

                    if ((surroundingEdges[0] == 2 || surroundingEdges[1] == 2))
                    {
                        if (!(i == parentNode.NonExistingLines.Count - 1 && parentNode.Children.Count == 0))
                        {
                            Debug.WriteLine(node.DeltaMove.ToString() + " was thrown.");
                            continue;
                        }
                    }

                    node.EstimationScore = ConstructTree(node, depth + 1, MinimaxPlayerType.MIN, alpha, beta);

                    bestValue = (bestValue > node.EstimationScore ? bestValue : node.EstimationScore);
                    alpha     = (alpha > bestValue ? alpha : bestValue);

                    parentNode.Children.Add(node);

                    if (beta <= alpha)
                    {
                        break;
                    }
                }

                parentNode.EstimationScore = bestValue;
                return(bestValue);
            }
            else
            {
                int bestValue = int.MaxValue;

                for (int i = 0; i < parentNode.NonExistingLines.Count; i++)
                {
                    #region New Node Creation
                    MinimaxTreeNode node = new MinimaxTreeNode();

                    // calculate estimation function only for leaf nodes
                    node.Player = (parentNode.Player == MinimaxPlayerType.MAX ? MinimaxPlayerType.MIN : MinimaxPlayerType.MAX);

                    node.ExistingLines.AddRange(parentNode.ExistingLines);
                    node.ExistingLines.Add(parentNode.NonExistingLines[i]);

                    node.NonExistingLines.AddRange(parentNode.NonExistingLines);
                    node.NonExistingLines.Remove(parentNode.NonExistingLines[i]);

                    node.Boxes.AddRange(parentNode.Boxes);
                    List <Box> newBoxes = AICommon.TryClosingBoxes(parentNode.ExistingLines, DeterminePlayerColour(node.Player), parentNode.NonExistingLines[i], out int[] notUsed);
                    node.Boxes.AddRange(newBoxes);

                    node.DeltaMove = parentNode.NonExistingLines[i];
                    #endregion

                    /* don't go through this subtree if the delta move is drawing third edge
                     * unless it the only move
                     */

                    AICommon.TryClosingBoxes(node.ExistingLines,
                                             DeterminePlayerColour(node.Player),
                                             node.DeltaMove,
                                             out int[] surroundingEdges);

                    if ((surroundingEdges[0] == 2 || surroundingEdges[1] == 2))
                    {
                        if (!(i == parentNode.NonExistingLines.Count - 1 && parentNode.Children.Count == 0))
                        {
                            Debug.WriteLine(node.DeltaMove.ToString() + " was thrown.");
                            continue;
                        }
                    }

                    node.EstimationScore = ConstructTree(node, depth + 1, MinimaxPlayerType.MAX, alpha, beta);

                    bestValue = (bestValue < node.EstimationScore ? bestValue : node.EstimationScore);
                    beta      = (beta < bestValue ? beta : bestValue);

                    parentNode.Children.Add(node);

                    if (beta <= alpha)
                    {
                        break;
                    }
                }

                parentNode.EstimationScore = bestValue;
                return(bestValue);
            }

            throw new Exception("Something wrong in minimax happened");
        }