예제 #1
0
        /// <summary>
        /// Returns the table with updated stability values after given move.
        /// </summary>
        /// <param name="table">Table after the move with original stability state.</param>
        /// <returns>The table after given move with updated stability values.</returns>
        public static ReversiTable GetTableWithUpdatedStability(this ReversiTable table)
        {
            // Start with all currently unstable cells.
            Queue <Position> unstableCells = new Queue <Position>(table.GetUnstableCells().ToList());

            // Process all unstable cells.
            while (unstableCells.Count > 0)
            {
                Position candidate = unstableCells.Dequeue();

                if (!table.GetStable(candidate.Item1, candidate.Item2) &&
                    table.IsStable(candidate))
                {
                    // Mark the cell as stable.
                    table.SetStable(true, candidate.Item1, candidate.Item2);

                    // All unstable neighbors need to be checked again.
                    foreach (Position delta in ReversiConstants.Directions)
                    {
                        Position neighbor = new Position(candidate.Item1 + delta.Item1, candidate.Item2 + delta.Item2);
                        if (neighbor.Item1 >= 0 && neighbor.Item1 < ReversiTable.Size &&
                            neighbor.Item2 >= 0 && neighbor.Item2 < ReversiTable.Size &&
                            table.GetValue(neighbor.Item1, neighbor.Item2) != Value.None &&
                            !table.GetStable(neighbor.Item1, neighbor.Item2))
                        {
                            unstableCells.Enqueue(neighbor);
                        }
                    }
                }
            }

            return(table);
        }
예제 #2
0
        /// <summary>
        /// Returns the table after given move.
        /// </summary>
        /// <param name="move">The move.</param>
        /// <returns>The table after given move.</returns>
        private ReversiTable GetTableForMove(Tuple <Position, IEnumerable <Position> > move)
        {
            Position cell = move.Item1;

            ReversiTable tableAfterMove = stateTable;

            tableAfterMove.SetValue(Player, cell.Item1, cell.Item2);

            foreach (Position direction in move.Item2)
            {
                int dx = cell.Item1 + direction.Item1;
                int dy = cell.Item2 + direction.Item2;

                while (
                    dx >= 0 && dx < ReversiTable.Size &&
                    dy >= 0 && dy < ReversiTable.Size &&
                    stateTable.GetValue(dx, dy) == Opponent)
                {
                    tableAfterMove.SetValue(Player, dx, dy);
                    dx += direction.Item1;
                    dy += direction.Item2;
                }
            }

            return(tableAfterMove);
        }
예제 #3
0
 /// <summary>
 /// Gets the list of currently unstable occupied cells that are potentially stable.
 /// </summary>
 /// <param name="table">The table.</param>
 /// <returns>The list of unstable cells.</returns>
 public static IEnumerable <Position> GetUnstableCells(this ReversiTable table)
 {
     for (int i = 0; i < ReversiTable.Size; ++i)
     {
         for (int j = 0; j < ReversiTable.Size; ++j)
         {
             if (table.GetValue(i, j) != Value.None && !table.GetStable(i, j))
             {
                 yield return(new Position(i, j));
             }
         }
     }
 }
예제 #4
0
        /// <summary>
        /// Gets the stability score.
        /// </summary>
        /// <param name="table">The table.</param>
        /// <returns>The difference between maximizing and minimizing players' stable cells.</returns>
        public static int GetStabilityScore(this ReversiTable table)
        {
            int score = 0;

            for (int i = 0; i < ReversiTable.Size; ++i)
            {
                for (int j = 0; j < ReversiTable.Size; ++j)
                {
                    if (table.GetStable(i, j))
                    {
                        score += table.GetValue(i, j) == Value.Maximizing ? 1 : -1;
                    }
                }
            }

            return(score);
        }
예제 #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ReversiNode" /> class.
        /// </summary>
        /// <param name="table">The game state.</param>
        /// <param name="currentPlayer">Current player.</param>
        /// <param name="playerCanPass">Indicates whether the current player can pass a move.</param>
        private ReversiNode(
            ReversiTable table,
            Value currentPlayer,
            bool playerCanPass = true)
        {
            canPass    = playerCanPass;
            stateTable = table;

            heuristics = new Lazy <int>(
                () => GetHeuristics(),
                LazyThreadSafetyMode.ExecutionAndPublication);

            children = new Lazy <IReadOnlyList <ReversiNode> >(
                () => GetChildren(),
                LazyThreadSafetyMode.ExecutionAndPublication);

            Debug.Assert(currentPlayer != Value.None, "Verifying that the player value is valid.");
            Player   = currentPlayer;
            Opponent = currentPlayer == Value.Maximizing
                ? Value.Minimizing
                : Value.Maximizing;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ReversiNode" /> class.
        /// </summary>
        /// <param name="table">The game state.</param>
        /// <param name="currentPlayer">Current player.</param>
        /// <param name="playerCanPass">Indicates whether the current player can pass a move.</param>
        private ReversiNode(
            ReversiTable table,
            Value currentPlayer,
            bool playerCanPass = true)
        {
            canPass = playerCanPass;
            stateTable = table;

            heuristics = new Lazy<int>(
                () => GetHeuristics(),
                LazyThreadSafetyMode.ExecutionAndPublication);

            children = new Lazy<IReadOnlyList<ReversiNode>>(
                () => GetChildren(),
                LazyThreadSafetyMode.ExecutionAndPublication);

            Debug.Assert(currentPlayer != Value.None, "Verifying that the player value is valid.");
            Player = currentPlayer;
            Opponent = currentPlayer == Value.Maximizing
                ? Value.Minimizing
                : Value.Maximizing;
        }
예제 #7
0
        /// <summary>
        /// Computes all children nodes of current node.
        /// </summary>
        /// <returns>Children nodes.</returns>
        private IReadOnlyList <ReversiNode> GetChildren()
        {
            var children = GetValidMoves(Player).Select(move =>
            {
                ReversiTable table          = GetTableForMove(move);
                ReversiTable stabilityTable = table.GetTableWithUpdatedStability();

                return(new ReversiNode(stabilityTable, Opponent));
            }).ToList();

            // Check whether it is a terminal node or whether the current player passes.
            if (children.Count == 0 && canPass)
            {
                ReversiNode nextNode = new ReversiNode(stateTable, Opponent, false);

                if (nextNode.Children.Count > 0)
                {
                    children.Add(nextNode);
                }
            }

            return(children.AsReadOnly());
        }
예제 #8
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ReversiNode" /> class with the starting position.
 /// </summary>
 public ReversiNode() : this(
         ReversiTable.InitialState(),
         Value.Maximizing)
 {
 }
예제 #9
0
        /// <summary>
        /// Determines whether the specified cell is stable.
        /// </summary>
        /// <param name="table">The table.</param>
        /// <param name="cell">The cell.</param>
        /// <returns>True if the cell is stable, false otherwise.</returns>
        public static bool IsStable(this ReversiTable table, Position cell)
        {
            if (table.GetValue(cell.Item1, cell.Item2) == Value.None)
            {
                return(false);
            }

            foreach (Position delta in ReversiConstants.StabilityDirections)
            {
                Value    player   = table.GetValue(cell.Item1, cell.Item2);
                Position positive = new Position(cell.Item1 + delta.Item1, cell.Item2 + delta.Item2);
                Position negative = new Position(cell.Item1 - delta.Item1, cell.Item2 - delta.Item2);

                // If one of the cell is on the edge, the direction is stable.
                if (positive.Item1 < 0 || positive.Item1 >= ReversiTable.Size ||
                    positive.Item2 < 0 || positive.Item2 >= ReversiTable.Size ||
                    negative.Item1 < 0 || negative.Item1 >= ReversiTable.Size ||
                    negative.Item2 < 0 || negative.Item2 >= ReversiTable.Size)
                {
                    continue;
                }

                // If at least one of the neighbors is a stable cell belonging to the same player,
                // the direction is stable.
                if ((table.GetStable(positive.Item1, positive.Item2) &&
                     table.GetValue(positive.Item1, positive.Item2) == player) ||
                    (table.GetStable(negative.Item1, negative.Item2) &&
                     table.GetValue(negative.Item1, negative.Item2) == player))
                {
                    continue;
                }

                // If all cells in the line of direction are filled, the direction is stable.
                do
                {
                    if (table.GetValue(positive.Item1, positive.Item2) == Value.None)
                    {
                        return(false);
                    }

                    positive = new Position(positive.Item1 + delta.Item1, positive.Item2 + delta.Item2);
                }while (positive.Item1 >= 0 && positive.Item1 < ReversiTable.Size &&
                        positive.Item2 >= 0 && positive.Item2 < ReversiTable.Size);

                do
                {
                    if (table.GetValue(negative.Item1, negative.Item2) == Value.None)
                    {
                        return(false);
                    }

                    negative = new Position(negative.Item1 - delta.Item1, negative.Item2 - delta.Item2);
                }while (negative.Item1 >= 0 && negative.Item1 < ReversiTable.Size &&
                        negative.Item2 >= 0 && negative.Item2 < ReversiTable.Size);

                // The line is filled.
                continue;
            }

            // No unstable directions found.
            return(true);
        }