public void InvalidIndexesAreInvalid(int someBadIndex)
        {
            var player1 = new Player(1);
            var board   = new LocalBoard();

            Assert.False(board.Move(player1, someBadIndex).IsValid);
        }
        public void ValidIndexesAreValid(int someGoodIndex)
        {
            var player1 = new Player(1);
            var board   = new LocalBoard();

            Assert.True(board.Move(player1, someGoodIndex).IsValid);
        }
Example #3
0
        /// <summary>
        /// play of the bot
        /// </summary>
        public override void play()
        {
            // init array of scores for different possibilities
            int[] lScores         = { 0, 0, 0, 0, 0, 0, 0 };
            int[] lScoresByThread = { 0, 0, 0, 0, 0, 0, 0 };

            // copy the board
            Board board = new Board(LocalBoard);

            AsyncCheckBestThread[] threads = { null, null, null, null, null, null, null };

            Console.Write("bot is thinking");
            // check each possibility
            string scoreprintA = "|";

            for (int y = 0; y < 7; y++)
            {
                // create copy for use in task
                board = new Board(LocalBoard);
                // check reseted board asynchronously
                threads[y] = new AsyncCheckBestThread(this, board, y, nDifficulty, nPlayerNo);
            }
            // wait until all tasks are done
            for (int y = 0; y < 7; y++)
            {
                // thread is active
                while (threads[y].isThreadActive())
                {
                    // pause execution a bit
                    Thread.Sleep(10);
                }
                // get the result after
                lScores[y] = threads[y].getResult();
                // for debugging
                scoreprintA = scoreprintA + lScores[y] + "|";
            }

            int maxValue = lScores.Max();
            int maxIndex = lScores.ToList().IndexOf(maxValue);

            best_column = maxIndex;
            // check the best possibility. if valid, do it, otherwise change column
            // TODO multiple same values -> choose random one to make things more intersting
            while (LocalBoard.getFirstEmpty(best_column) == -1)
            {
                best_column += 1;
                if (best_column == 7)
                {
                    best_column = 0;
                }
            }
            // play the game
            Program.play(nPlayerNo, best_column);
        }
Example #4
0
        /// <summary>
        /// Evaluation function
        /// </summary>
        /// <param name="whiteTurn">Players turn
        /// <param name="minOrMax">Minimizing or maximizing operation
        /// <returns>The number that correspond to the score of the function</returns>
        public float Eval(bool whiteTurn, int minOrMax)
        {
            // Retrieve board informations
            Tuple <int, int> cornersScore = CornersScore();
            int whiteMobility             = LocalBoard.GetNextPossibleMoves(true).Capacity;
            int blackMobility             = LocalBoard.GetNextPossibleMoves(false).Capacity;

            // Assign variables
            if ((minOrMax == 1) ^ whiteTurn)
            {
                maxPlayerScore    = LocalBoard.BlackScore;
                minPlayerScore    = LocalBoard.WhiteScore;
                maxPlayerCorners  = cornersScore.Item2;
                minPlayerCorners  = cornersScore.Item1;
                maxPlayerMobility = blackMobility;
                minPlayerMobility = whiteMobility;
            }
            else
            {
                maxPlayerScore    = LocalBoard.WhiteScore;
                minPlayerScore    = LocalBoard.BlackScore;
                maxPlayerCorners  = cornersScore.Item1;
                minPlayerCorners  = cornersScore.Item2;
                maxPlayerMobility = whiteMobility;
                minPlayerMobility = blackMobility;
            }

            // Parity Score
            float scoreParity = 0f;

            if (maxPlayerScore + minPlayerScore != 0)
            {
                scoreParity = (100f * (maxPlayerScore - minPlayerScore)) / (maxPlayerScore + minPlayerScore);
            }

            // Mobility Score
            float scoreMobility = 0f;

            if (maxPlayerMobility + minPlayerMobility != 0)
            {
                scoreMobility = (100f * (maxPlayerMobility - minPlayerMobility)) / (maxPlayerMobility + minPlayerMobility);
            }

            // Corners Score
            float scoreCorners = 0f;

            if (maxPlayerCorners + minPlayerCorners != 0)
            {
                scoreCorners = (100f * (maxPlayerCorners - minPlayerCorners)) / (maxPlayerCorners + minPlayerCorners);
            }

            // Result
            return(WEIGHT_SCORE * scoreParity + WEIGHT_MOBILITY * scoreMobility + WEIGHT_CORNERS * scoreCorners);
        }
Example #5
0
        /// <summary>
        /// user input for the column he wants to play in his turn
        /// </summary>
        /// <param name="player">current player</param>
        /// <returns>column number of the column he wants to play</returns>
        public int readColumn(int player)
        {
            int column = -1;

            while (column == -1)
            {
                LocalBoard.drawBoard();
                print("it is your turn, player " + player + "! \nwhere do you want to play?");
                string s = Console.ReadLine();
                if (s.Equals("m"))
                {
                    Console.Clear();
                    Program.menu();
                    column = -1;
                    Console.ReadLine();
                }
                if (s.Equals(""))
                {
                    print("you have to enter a Number between 0 and 6 and not nothing!");
                    print("press Enter to acknowledge");
                    column = -1;
                    Console.ReadLine();
                }
                else
                {
                    if (Int32.TryParse(s, out column))
                    {
                        if (column > 6 || column < 0)
                        {
                            print("you have to enter a Number between 0 and 6!");
                            print("press Enter to acknowledge");
                            column = -1;
                            Console.ReadLine();
                        }
                        else if (LocalBoard.getFirstEmpty(column) == -1)
                        {
                            print("can't play here, column full");
                            print("press Enter to acknowledge");
                            column = -1;
                            Console.ReadLine();
                        }
                    }
                    else
                    {
                        print("you have to enter a Number and not some nonsense!");
                        print("press Enter to acknowledge");
                        column = -1;
                        Console.ReadLine();
                    }
                }
            }
            return(column);
        }
        public void PlayerCanNotMoveOnAnOccupiedSpace()
        {
            var player1 = new Player(1);
            var player2 = new Player(2);

            var board = new LocalBoard();

            var move1Result  = board.Move(player1, 1);
            var move2Results = board.Move(player2, 1);

            Assert.True(move1Result.IsValid);
            Assert.False(move2Results.IsValid);
        }
Example #7
0
        /// <summary>
        /// Applies the board state to this node and return the new node
        /// </summary>
        /// <param name="move">The move to apply to the board</param>
        /// <returns>The new node if this board state</returns>
        public IANode Apply(Tuple <int, int> move, bool whiteTurn)
        {
            Board board = LocalBoard.DeepCopyBoard();

            bool   isPlayable = board.IsPlayable(move.Item1, move.Item2, whiteTurn);
            IANode node       = null;

            if (isPlayable)
            {
                board.PlayMove(move.Item1, move.Item2, whiteTurn);

                node = new IANode(board, move, board.GetNextPossibleMoves(!whiteTurn));
            }

            return(node);
        }
Example #8
0
        /// <summary>
        /// Compute the number of corners taken
        /// </summary>
        /// <returns>How many corners by each player are taken</returns>
        private Tuple <int, int> CornersScore()
        {
            int whiteCorners = 0;
            int blackCorners = 0;

            int[,] grid = LocalBoard.GetBoard();

            if (grid[0, 0] == 0)
            {
                whiteCorners++;
            }
            else if (grid[0, 0] == 1)
            {
                blackCorners++;
            }

            if (grid[0, grid.GetLength(1) - 1] == 0)
            {
                whiteCorners++;
            }
            else if (grid[0, grid.GetLength(1) - 1] == 1)
            {
                blackCorners++;
            }

            if (grid[grid.GetLength(0) - 1, 0] == 0)
            {
                whiteCorners++;
            }
            else if (grid[grid.GetLength(0) - 1, 0] == 1)
            {
                blackCorners++;
            }

            if (grid[grid.GetLength(0) - 1, grid.GetLength(1) - 1] == 0)
            {
                whiteCorners++;
            }
            else if (grid[grid.GetLength(0) - 1, grid.GetLength(1) - 1] == 1)
            {
                blackCorners++;
            }

            return(new Tuple <int, int>(whiteCorners, blackCorners));
        }
Example #9
0
        /// <summary>
        /// checks the best solution for a play by the bot
        /// </summary>
        /// <param name="board">board to play on</param>
        /// <param name="column">column to play</param>
        /// <param name="depth">how many more iterations should be done</param>
        /// <param name="currPlayer">player whose turn it is</param>
        /// <returns></returns>
        private int checkBest(Board board, int column, int depth, int currPlayer)
        {
            // init score for node
            int score = 0; // no move is pretty bad
            // store different things at beginning of testing node
            Board preBoard  = new Board(board);
            int   prePlayer = currPlayer;
            Board virtBoard = new Board(board);

            // depth not reached, otherwise return default score; do not play
            if (depth == 0)
            {
                return(score);
            }
            // if no valid play, return default score; do not play
            if (board.getFirstEmpty(column) == -1)
            {
                return(score);
            }

            // valid -> play
            virtBoard = playLocal(prePlayer, column, virtBoard);
            // check for win or loose
            if (virtBoard.checkwin(nPlayerNo, false))
            {
                //Program.drawBoard(board);
                score = winWeight * depth;
                printScore(score, depth);
                if (bAccurateLog)
                {
                    print("found possible win for " + nPlayerNo);
                }
                //print("BOTWIN");
                return(score);
            }
            else if (virtBoard.checkwin(nOpponentNo, false))
            {
                //Program.drawBoard(board);
                score = looseWeight * depth;
                printScore(score, depth);
                // make sure to enter here if loss imminent
                best_column = column;
                if (bAccurateLog)
                {
                    print("found possible win for " + nOpponentNo);
                }
                //print("BOTLOOSE");
                return(score);
            }
            int nply;

            // swap playerNo
            if (currPlayer == nOpponentNo)
            {
                nply = nPlayerNo;
            }
            else
            {
                nply = nOpponentNo;
            }
            int playerFac = 0;

            if (currPlayer == nOpponentNo)
            {
                playerFac = -1;
            }
            else
            {
                playerFac = 1;
            }

            for (int i = 3; i > 1; i--)
            {
                if (LocalBoard.checkForCountDown(currPlayer, i))
                {
                    //Program.drawBoard(board);
                    // the deeper in the win is the less acceptable is a win
                    score = aSCORES_NOT_WIN[i] * depth * currPlayer;
                    printScore(score, depth);
                    //print("BOTWIN");
                    i = 1;
                }
                if (LocalBoard.checkForCountDiagonal(currPlayer, i))
                {
                    //Program.drawBoard(board);
                    // the deeper in the win is the less acceptable is a win
                    score = aSCORES_NOT_WIN[i] * depth * currPlayer;
                    printScore(score, depth);
                    //print("BOTWIN");
                    i = 1;
                }
                if (LocalBoard.checkForCountSideways(currPlayer, i))
                {
                    //Program.drawBoard(board);
                    // the deeper in the win is the less acceptable is a win
                    score = aSCORES_NOT_WIN[i] * depth * currPlayer;
                    printScore(score, depth);
                    //print("BOTWIN");
                    i = 1;
                }
            }
            int[] scores       = { 0, 0, 0, 0, 0, 0, 0 };
            int   lDeeperScore = 0;

            // play the other variants
            for (int i = 0; i < 7; i++)
            {
                // check the score of the different plays
                // TODO if depth > threshold, run in async in different thread to speed up the process
                scores[i] = checkBest(virtBoard, i, depth - 1, nply) * depth;
            }
            if (nply == nOpponentNo)
            {
                lDeeperScore = scores.Min() * depth;
            }
            if (nply == nPlayerNo)
            {
                lDeeperScore = scores.Max() * depth;
            }

            score = lDeeperScore + score;
            // log
            if (bAccurateLog)
            {
                print(indent(depth) + "CB: p= " + currPlayer + "; x= " + column + "; d= " + depth + "; score= " + score + "; deep= " + lDeeperScore);
            }
            //          Program.print("p "+ currPlayer,false,true);
            //          Program.print(depth + ": " + scores[0] + "|" + scores[1] + "|" + scores[2] + "|" + scores[3] + "|" + scores[4] + "|" + scores[5] + "|" + scores[6] + "|", false, true);
            // reset board
            board      = new Board(preBoard);
            currPlayer = prePlayer;
            printScore(score, depth);
            // return score of node
            return(score);
        }