Пример #1
0
        public HexBoard GetBoard()
        {
            lock (this.locker)
            {
                HexBoard result;
                if (this.available.Count == 0)
                {
                    // no boards available, so make a new one
                    result = new HexBoard(this.BoardSize);
                }
                else
                {
                    // return any available board - less jiggering to take the end one
                    int boardIndex = this.available.Count - 1;
                    result = this.available[boardIndex];
                    this.available.RemoveAt(boardIndex);

                    if (this.available.Count == 0)
                    {
                        Task.Factory.StartNew(() => this.available.Add(new HexBoard(this.BoardSize)));
                    }
                }

                // board is now in use
                this.inUse.Add(result);
                return result;
            }
        }
Пример #2
0
        public HexBoard GetBoard()
        {
            lock (this.locker)
            {
                HexBoard result;
                if (this.available.Count == 0)
                {
                    // no boards available, so make a new one
                    result = new HexBoard(this.BoardSize);
                }
                else
                {
                    // return any available board - less jiggering to take the end one
                    int boardIndex = this.available.Count - 1;
                    result = this.available[boardIndex];
                    this.available.RemoveAt(boardIndex);

                    if (this.available.Count == 0)
                    {
                        Task.Factory.StartNew(() => this.available.Add(new HexBoard(this.BoardSize)));
                    }
                }

                // board is now in use
                this.inUse.Add(result);
                return(result);
            }
        }
Пример #3
0
        public void GetAgainDoesNotIncreaseCount()
        {
            BoardCache boardCache = new BoardCache(10);

            const int TestSize = 10;
            HexBoard[] usedBoards = new HexBoard[TestSize];

            // add some boards
            for (int i = 0; i < TestSize; i++)
            {
                usedBoards[i] = boardCache.GetBoard();
            }

            // remove them
            for (int i = 0; i < TestSize; i++)
            {
                boardCache.Release(usedBoards[i]);
            }

            // get again, count should not change since there are now boards ready to use
            for (int i = 0; i < TestSize; i++)
            {
                usedBoards[i] = boardCache.GetBoard();
                Assert.IsNotNull(usedBoards[i]);
                Assert.AreEqual(TestSize, boardCache.BoardCount);
            }
        }
Пример #4
0
 public void ConstructorSetsProperties()
 {
     HexBoard hexBoard = new HexBoard(BoardSize);
     Assert.IsNotNull(hexBoard);
     Assert.AreEqual(BoardSize, hexBoard.Size);
     Assert.AreEqual(0, hexBoard.MovesPlayedCount);
 }
Пример #5
0
 /// <summary>
 /// Initializes a new instance of the HexBoard class from an existing HexBoard
 /// </summary>
 /// <param name="originalBoard">the board to copy</param>
 public HexBoard(HexBoard originalBoard)
 {
     if (originalBoard != null)
     {
         this.InitCells(originalBoard.Size);
         this.CopyStateFrom(originalBoard);
     }
 }
Пример #6
0
 /// <summary>
 /// board is no longer in use
 /// So put in on the in-use list
 /// </summary>
 /// <param name="board">the board to release</param>
 public void Release(HexBoard board)
 {
     lock (this.locker)
     {
         this.inUse.Remove(board);
         this.available.Add(board);
     }
 }
Пример #7
0
 /// <summary>
 /// Initializes a new instance of the HexBoard class from an existing HexBoard
 /// </summary>
 /// <param name="originalBoard">the board to copy</param>
 public HexBoard(HexBoard originalBoard)
 {
     if (originalBoard != null)
     {
         this.InitCells(originalBoard.Size);
         this.CopyStateFrom(originalBoard);
     }
 }
Пример #8
0
        public void BetweenEdgeTest()
        {
            HexBoard hexBoard = new HexBoard(BoardSize);
            for (int x = 0; x < hexBoard.Size; x++)
            {
                for (int y = 0; y < hexBoard.Size; y++)
                {
                    Location testLoc = new Location(x, y);

                    Cell[] resultX = hexBoard.BetweenEdge(testLoc, true);

                    if (y == 1)
                    {
                        // second or second-last row
                        if (x < hexBoard.Size - 1)
                        {
                            Assert.AreEqual(2, resultX.Length, testLoc.ToString());
                        }
                    }
                    else if (y == hexBoard.Size - 2)
                    {
                        // second or second-last row
                        if (x > 0)
                        {
                            Assert.AreEqual(2, resultX.Length, testLoc.ToString());
                        }
                    }
                    else
                    {
                        Assert.AreEqual(0, resultX.Length, testLoc.ToString());
                    }

                    Cell[] resultY = hexBoard.BetweenEdge(testLoc, false);

                    if (x == 1)
                    {
                        // second or second-last row
                        if (y < hexBoard.Size - 1)
                        {
                            Assert.AreEqual(2, resultY.Length, testLoc.ToString());
                        }
                    }
                    else if (x == hexBoard.Size - 2)
                    {
                        // second or second-last row
                        if (y > 0)
                        {
                            Assert.AreEqual(2, resultY.Length, testLoc.ToString());
                        }
                    }
                    else
                    {
                        Assert.AreEqual(0, resultY.Length, testLoc.ToString());
                    }
                }
            }
        }
Пример #9
0
        public Minimax(HexBoard board, GoodMoves goodMoves, ICandidateMoves candidateMovesFinder)
        {
            this.actualBoard = board;
            this.goodMoves = goodMoves;
            this.candidateMovesFinder = candidateMovesFinder;

            this.boardCache = new BoardCache(board.Size);
            this.pathLengthFactory = new PathLengthAStarFactory();
        }
Пример #10
0
        public void CountEmptyTest()
        {
            CandidateMovesAll allMoves = new CandidateMovesAll();
            HexBoard testBoard = new HexBoard(BoardSize);

            Location[] moves = allMoves.CandidateMoves(testBoard, 0).ToArray();

            Assert.AreEqual(BoardCellCount, moves.Length);
        }
Пример #11
0
        /// <summary>
        /// Initializes a new instance of the HexGame class, with a board size
        /// </summary>
        /// <param name="boardSize">size of the board</param>
        public HexGame(int boardSize)
        {
            this.board = new HexBoard(boardSize);
            IPathLengthFactory pathLengthFactory = new PathLengthAStarFactory();

            this.xPathLength = pathLengthFactory.CreatePathLength(this.board);
            this.yPathLength = pathLengthFactory.CreatePathLength(this.board);
            this.goodMoves = new GoodMoves();
            this.goodMoves.DefaultGoodMoves(boardSize, 5);
        }
Пример #12
0
        public void BoardCopyTest()
        {
            HexBoard hexBoard = new HexBoard(BoardSize);
            HexBoard copyBoard = new HexBoard(hexBoard);

            Assert.IsTrue(copyBoard.Equals(hexBoard));

            copyBoard.PlayMove(0, 0, true);

            Assert.IsFalse(copyBoard.Equals(hexBoard));
        }
Пример #13
0
        public void CountOneMoveTest()
        {
            CandidateMovesAll allMoves = new CandidateMovesAll();
            HexBoard testBoard = new HexBoard(BoardSize);

            testBoard.PlayMove(5, 5, true);

            IEnumerable<Location> moves = allMoves.CandidateMoves(testBoard, 0);

            Assert.AreEqual(BoardCellCount - 1, moves.Count());
        }
Пример #14
0
        public void TestCalculateMove3PlayerX()
        {
            HexBoard board = new HexBoard(5);
            PlayFourMoves(board);

            Minimax minimax = MakeMinimaxForBoard(board);

            MinimaxResult firstPlayerResult = minimax.DoMinimax(4, true);

            Location firstPlayerExpectedMove = new Location(2, 1);
            Assert.AreEqual(firstPlayerExpectedMove, firstPlayerResult.Move, "Wrong first player location");
        }
Пример #15
0
        public void TestCalculateMove2MinimaxPlayerY()
        {
            HexBoard board = new HexBoard(3);
            PlayTwoMoves(board);

            Minimax minimax = MakeMinimaxForBoard(board);
            MinimaxResult secondPlayerResult = minimax.DoMinimax(2, false);

            Location expectedPlay = new Location(0, 2);
            Assert.AreEqual(expectedPlay, secondPlayerResult.Move, "Wrong play location");
            Assert.IsFalse(MoveScoreConverter.IsWin(secondPlayerResult.Score));
        }
        public void CountOneMoveTest()
        {
            GoodMoves goods = new GoodMoves();
            CandidateMovesSelective moveFinder = new CandidateMovesSelective(goods, 0);
            HexBoard testBoard = new HexBoard(BoardSize);

            testBoard.PlayMove(5, 5, true);

            IEnumerable<Location> moves = moveFinder.CandidateMoves(testBoard, 0);

            Assert.Greater(BoardCellCount - 1, moves.Count());
        }
Пример #17
0
        public void GoodMoveAtLevel3()
        {
            HexBoard board = new HexBoard(6);
            PlayToWinInThreeMoves(board);

            Minimax minimax = MakeMinimaxForBoard(board);

            MinimaxResult bestMove = minimax.DoMinimax(3, true);
            Location win = new Location(1, 3);

            Assert.AreEqual(win, bestMove.Move, "Wrong play location");
        }
Пример #18
0
        /// <summary>
        ///  get candidate moves - 
        ///  this list is comprehensive - it will contain all empty cells on the board
        ///  and sorted - good moves come first
        ///  the list returned may be longer than the valid cells
        ///  but then will have a null location at the end
        ///  Actual length is (BoardSize ^ 2) - number of moves already played
        /// </summary>
        /// <param name="board">the board to read</param>
        /// <param name="lookaheadDepth">the current depth of lookahead</param>
        /// <returns>the locations</returns>
        public IEnumerable<Location> CandidateMoves(HexBoard board, int lookaheadDepth)
        {
            // No potential good moves? return them all then
            if (this.goodMoves.GetCount(lookaheadDepth) == 0)
            {
                return board.EmptyCells();
            }

            int maxListLength = (board.Size * board.Size) - this.cellsPlayedCount;

            // enough space for all the possible moves
            Location[] result = new Location[maxListLength];
            int resultIndex = 0;

            // mask out the ones that have been used - intialised to false
            bool[,] maskCellSelected = new bool[board.Size, board.Size];

            // good moves are found first
            Location[] myGoodMoves = this.goodMoves.GetGoodMoves(lookaheadDepth);

            // copy in the good moves
            foreach (Location goodMoveLoc in myGoodMoves)
            {
                if (board.GetCellAt(goodMoveLoc).IsEmpty() && (!maskCellSelected[goodMoveLoc.X, goodMoveLoc.Y]))
                {
                    result[resultIndex] = goodMoveLoc;
                    resultIndex++;
                    maskCellSelected[goodMoveLoc.X, goodMoveLoc.Y] = true;
                }
            }

            // copy in all moves where the cell is empty;
            // and not already in by virtue of being a good move
            foreach (Cell testCell in board.GetCells())
            {
                if (testCell.IsEmpty() && (!maskCellSelected[testCell.X, testCell.Y]))
                {
                    result[resultIndex] = testCell.Location;
                    resultIndex++;
                }
            }

            // null marker at the end
            if (resultIndex < maxListLength)
            {
                result[resultIndex] = Location.Null;
            }

            return result;
        }
Пример #19
0
        public void BoardLayoutTest()
        {
            HexBoard hexBoard = new HexBoard(BoardSize);
            for (int x = 0; x < hexBoard.Size; x++)
            {
                for (int y = 0; y < hexBoard.Size; y++)
                {
                    Cell cell = hexBoard.GetCellAt(x, y);

                    Assert.IsNotNull(cell);
                    Assert.IsTrue(cell.X == x);
                    Assert.IsTrue(cell.Y == y);
                }
            }
        }
Пример #20
0
        public void AddBoardIncreasesCount()
        {
            BoardCache boardCache = new BoardCache(10);

            const int TestSize = 10;
            HexBoard[] usedBoards = new HexBoard[TestSize];

            // add some boards
            for (int i = 0; i < TestSize; i++)
            {
                usedBoards[i] = boardCache.GetBoard();
                Assert.IsNotNull(usedBoards[i]);
                Assert.AreEqual(i + 1, boardCache.BoardCount);
            }
        }
Пример #21
0
        public void RightMoveAtLevel5PlayerY()
        {
            HexBoard board = new HexBoard(6);
            PlayToWinInThreeMoves(board);

            Minimax minimax = MakeMinimaxForBoard(board);

            MinimaxResult bestMove = minimax.DoMinimax(5, false);

            List<Location> playerYWinningLocations = new List<Location>
                {
                    new Location(1, 3),
                    new Location(2, 2)
                };
            Assert.IsTrue(playerYWinningLocations.Contains(bestMove.Move), "Wrong play location");
        }
Пример #22
0
        public void CopyStateFrom(HexBoard otherBoard)
        {
            if (otherBoard != null)
            {
                if (otherBoard.Size != this.Size)
                {
                    throw new Exception("Board sizes do not match");
                }

                foreach (Cell cell in this.cells)
                {
                    cell.IsOccupied = otherBoard.GetCellAt(cell.Location).IsOccupied;
                }

                this.movesPlayedCount = otherBoard.MovesPlayedCount;
            }
        }
Пример #23
0
        public void SpeedTest()
        {
            const int RandSeed = 24;
            const int BoardCount = 100;
            const int BoardSize = 12;

            Random rands = new Random(RandSeed);
            HexBoard[] boards = new HexBoard[BoardCount];

            // make some boards
            for (int loopIndex = 0; loopIndex < BoardCount; loopIndex++)
            {
                boards[loopIndex] = RandomBoard(BoardSize, 10 + loopIndex, rands);
            }

            // time it the old way
            DateTime oldStart = DateTime.Now;

            foreach (HexBoard board in boards)
            {
                PathLengthLoop oldPath = new PathLengthLoop(board);
                oldPath.PlayerScore(true);
                oldPath.PlayerScore(false);
            }

            DateTime oldEnd = DateTime.Now;

            // and the new way
            DateTime newStart = DateTime.Now;

            foreach (HexBoard board in boards)
            {
                PathLengthAStar newPath = new PathLengthAStar(board);
                newPath.PlayerScore(true);
                newPath.PlayerScore(false);
            }

            DateTime newEnd = DateTime.Now;

            TimeSpan oldDuration = oldEnd - oldStart;
            TimeSpan newDuration = newEnd - newStart;

            double ratio = newDuration.Milliseconds / (double)oldDuration.Milliseconds;

            Assert.IsTrue(ratio < 1.0);
        }
Пример #24
0
        public void TestCalculateMove2Situation()
        {
            HexBoard board = new HexBoard(3);
            PlayTwoMoves(board);

            // test score at this point
            PathLengthLoop pathLength = new PathLengthLoop(board);
            int playerScoreX = pathLength.PlayerScore(true);
            Assert.AreEqual(2, playerScoreX, "playerScoreX");

            int playerScoreY = pathLength.PlayerScore(false);
            Assert.AreEqual(2, playerScoreY, "playerScoreY");

            // no advantage
            int moveScore = pathLength.SituationScore();
            Assert.AreEqual(0, moveScore, "moveScore");
        }
Пример #25
0
        public void TestCalculateMove3PathLength()
        {
            HexBoard board = new HexBoard(5);
            PlayFourMoves(board);

            // test score at this point
            PathLengthLoop pathLength = new PathLengthLoop(board);
            int playerScore = pathLength.PlayerScore(true);
            Assert.AreEqual(3, playerScore);

            playerScore = pathLength.PlayerScore(false);
            Assert.AreEqual(3, playerScore);

            // no advantage
            int moveScore = pathLength.SituationScore();
            Assert.AreEqual(moveScore, 0);
        }
Пример #26
0
        public void ClearTest()
        {
            HexBoard hexBoard = new HexBoard(BoardSize);

            // set a cell
            hexBoard.PlayMove(1, 1, true);
            Assert.AreEqual(Occupied.PlayerX, hexBoard.GetCellOccupiedAt(1, 1));

            Location loc11 = new Location(1, 1);
            Assert.AreEqual(Occupied.PlayerX, hexBoard.GetCellOccupiedAt(1, 1));
            Assert.AreEqual(Occupied.PlayerX, hexBoard.GetCellOccupiedAt(loc11));

            // reset it
            hexBoard.Clear();
            Assert.AreEqual(Occupied.Empty, hexBoard.GetCellOccupiedAt(1, 1));
            Assert.AreEqual(Occupied.Empty, hexBoard.GetCellOccupiedAt(loc11));
        }
Пример #27
0
        public void TestMinimax3()
        {
            HexBoard board = new HexBoard(5);
            Minimax minimax = MakeMinimaxForBoard(board);

            /*
                on a 5 * 5 board, red(playerx) has 3, 0 and 1, 4
                needs to play 2,2 to win - should know this at look ahead 5
             */

            board.PlayMove(3, 0, true);
            board.PlayMove(1, 4, true);

            MinimaxResult bestMove = minimax.DoMinimax(5, true);
            Location expectedMove = new Location(2, 2);

            Assert.IsTrue(MoveScoreConverter.IsWin(bestMove.Score), "No win " + bestMove.Score);
            Assert.AreEqual(expectedMove, bestMove.Move, "Wrong expected move");
        }
Пример #28
0
        public void CountDownTest()
        {
            CandidateMovesAll allMoves = new CandidateMovesAll();
            HexBoard testBoard = new HexBoard(BoardSize);

            int emptyCellCount = BoardSize * BoardSize;

            for (int x = 0; x < BoardSize; x++)
            {
                for (int y = 0; y < BoardSize; y++)
                {
                    // as cells are played, less empty cells are left
                    testBoard.PlayMove(x, y, true);
                    emptyCellCount--;

                    IEnumerable<Location> moves = allMoves.CandidateMoves(testBoard, 0);
                    Assert.AreEqual(emptyCellCount, moves.Count());
                }
            }
        }
Пример #29
0
        public void TestCalculateMove3PlayerY()
        {
            HexBoard board = new HexBoard(5);
            PlayFourMoves(board);

            Minimax minimax = MakeMinimaxForBoard(board);

            // test score at this point
            PathLengthLoop pathLength = new PathLengthLoop(board);
            int playerScore = pathLength.PlayerScore(true);
            Assert.AreEqual(3, playerScore);

            playerScore = pathLength.PlayerScore(false);
            Assert.AreEqual(3, playerScore);

            MinimaxResult secondPlayerResult = minimax.DoMinimax(4, false);

            Location secondPlayerExpectedMove = new Location(1, 2);
            Assert.AreEqual(secondPlayerExpectedMove, secondPlayerResult.Move, "Wrong second player location");
        }
Пример #30
0
        /// <summary>
        /// // get the candidate moves
        /// </summary>
        /// <param name="board">the board to get moves from</param>
        /// <param name="lookaheadDepth">the lookahead depth</param>
        /// <returns>the candiate move locations</returns>
        public IEnumerable<Location> CandidateMoves(HexBoard board, int lookaheadDepth)
        {
            int maxListLength = (board.Size * board.Size) - this.cellsPlayedCount;

            // enough space for all the possible moves
            List<Location> result = new List<Location>(maxListLength);

            // mask out the ones that have been used - intialised to false
            bool[,] maskCellSelected = new bool[board.Size, board.Size];

            if (lookaheadDepth < this.goodMoves.Depth)
            {
                // good moves are found first
                Location[] myGoodMoves = this.goodMoves.GetGoodMoves(lookaheadDepth);

                // copy in the good moves
                foreach (Location goodMoveLoc in myGoodMoves)
                {
                    if (board.GetCellAt(goodMoveLoc).IsEmpty() && (!maskCellSelected[goodMoveLoc.X, goodMoveLoc.Y]))
                    {
                        result.Add(goodMoveLoc);
                        maskCellSelected[goodMoveLoc.X, goodMoveLoc.Y] = true;
                    }
                }
            }

            // copy in all moves where the cell is empty,
            // and not already in by virtue of being a good move
            foreach (Cell testCell in board.GetCells())
            {
                if (testCell.IsEmpty() && (!maskCellSelected[testCell.X, testCell.Y]))
                {
                    if (IsIncluded(testCell, board) || HasFilledNeighbour(testCell, board))
                    {
                        result.Add(testCell.Location);
                    }
                }
            }

            return result.ToArray();
        }
Пример #31
0
        /// <summary>
        /// are two boards the same, ie same state in all cells
        /// </summary>
        /// <param name="otherBoard">the other board</param>
        /// <returns>the equality boolean</returns>
        public bool Equals(HexBoard otherBoard)
        {
            if (otherBoard == null)
            {
                return(false);
            }

            if (otherBoard.Size != this.Size)
            {
                return(false);
            }

            foreach (Cell cell in this.cells)
            {
                if (cell.IsOccupied != otherBoard.GetCellAt(cell.Location).IsOccupied)
                {
                    return(false);
                }
            }

            return(true);
        }
Пример #32
0
        public void ReleaseBoardIncreasesCount()
        {
            BoardCache boardCache = new BoardCache(10);

            const int TestSize = 10;
            HexBoard[] usedBoards = new HexBoard[TestSize];

            // add some boards
            for (int i = 0; i < TestSize; i++)
            {
                usedBoards[i] = boardCache.GetBoard();
            }

            // remove them
            for (int i = 0; i < TestSize; i++)
            {
                boardCache.Release(usedBoards[i]);

                // count doesn't go down
                Assert.AreEqual(TestSize, boardCache.BoardCount);
                Assert.AreEqual(i + 1, boardCache.AvailableCount);
            }
        }
Пример #33
0
        private static void PlayerScoreAlmostBarricaded(IPathLengthFactory pathLengthFactory)
        {
            HexBoard hexBoard = new HexBoard(BoardSize);
            PathLengthBase pathLength = pathLengthFactory.CreatePathLength(hexBoard);

            // almost barricated board
            for (int y = 0; y < hexBoard.Size; y++)
            {
                if (y != 3)
                {
                    hexBoard.PlayMove(2, y, true);
                }
            }

            int xScore = pathLength.PlayerScore(true);
            Assert.IsTrue(xScore > 0);

            int yScore = pathLength.PlayerScore(false);
            Assert.IsTrue(yScore > xScore);

            // strong advantage to player 1
            int advantageMoveScore = pathLength.SituationScore();
            Assert.IsTrue(advantageMoveScore > 0);
        }
Пример #34
0
        private static void PlayerScoreBaricaded(IPathLengthFactory pathLengthFactory)
        {
            HexBoard hexBoard = new HexBoard(BoardSize);
            PathLengthBase pathLength = pathLengthFactory.CreatePathLength(hexBoard);

            // baricaded board
            for (int y = 0; y < hexBoard.Size; y++)
            {
                hexBoard.PlayMove(2, y, true);
            }

            int xScore = pathLength.PlayerScore(true);
            Assert.AreEqual(xScore, 0);

            int yScore = pathLength.PlayerScore(false);
            Assert.IsTrue(yScore > hexBoard.Size);

            // winning advantage to player 1
            int winMoveScore = pathLength.SituationScore();
            AssertWinner(winMoveScore, Occupied.PlayerX);
        }
Пример #35
0
        private static void PlayerScoreZigZag(IPathLengthFactory pathLengthFactory)
        {
            HexBoard hexBoard = new HexBoard(BoardSize);
            PathLengthBase pathLength = pathLengthFactory.CreatePathLength(hexBoard);

            for (int y = 0; y < hexBoard.Size - 1; y++)
            {
                hexBoard.PlayMove(2, y, true);
                hexBoard.PlayMove(5, hexBoard.Size - (1 + y), true);

                int xScore = pathLength.PlayerScore(true);
                Assert.IsTrue(xScore > 0);

                int yScore = pathLength.PlayerScore(false);
                Assert.IsTrue(yScore >= hexBoard.Size);
                if (y > (hexBoard.Size / 2))
                {
                    Assert.IsTrue(yScore > xScore);
                }

                // some advantage to player 1
                int advantageMoveScore = pathLength.SituationScore();
                Assert.IsTrue(advantageMoveScore >= y);
            }
        }