/// <summary>
        /// Converts board to neurel net training example.  Returns example corresopnding to normalized board (current player's checker color is blue, last player is green)
        /// </summary>
        /// <param name="lastPlayerToGo">Current Player which corresponds to last checker placed on board.</param>
        public static Example ToNormalizedExample(Board board, Checker lastPlayerToGo)
        {
            Debug.Assert(lastPlayerToGo != Checker.Empty);
            List<double> boardState = board.Cells.Cast<Checker>().Select(c=>Transform.ToNormalizedValue(c, lastPlayerToGo)).ToList();
            List<int> features = new List<int>();

            // 42 Input Units - Board State Only
            // return new Example(boardState);

            foreach (Checker checker in new List<Checker> { lastPlayerToGo, Board.Toggle(lastPlayerToGo) })
            {
                features.AddRange(board.LineOfX(checker));
                features.AddRange(board.LineOfX(checker, potential: true));
                features.AddRange(board.NumbersInColumns(checker));
                features.AddRange(board.NumbersInRows(checker));
                features.Add(board.NumberOnBoard(checker));
            }
            boardState.AddRange(features.Select(e => (double)e));

            // 40 Input Units - Features Only
            //return new Example(features.Select(e => (double)e).ToList());

            // 82 Input Units - Board State and Features
            return new Example(boardState);
        }
예제 #2
0
        public override void AddCells(Board board, Cell cell, connectedCells c)
        {
            switch(c)
            {
                case connectedCells.north:
                    for (int i = 1; i < connectR; i++)
                    {
                        cells.Add(board.getCell(cell.getRow() - i, cell.getColumn()));
                    }

                    cell.AddConnectedCells((int)connectedCells.north, cells);

                    break;

                case connectedCells.south:
                    for (int i = 1; i < connectR; i++)
                    {
                        cells.Add(board.getCell(cell.getRow() + i, cell.getColumn()));
                    }

                    cell.AddConnectedCells((int)connectedCells.south, cells);

                    break;
            }
        }
예제 #3
0
        public override void Move(Board b)
        {
            {
                //Create a new game state for the root of the state space
                GameState gameState = new GameState(GameState.State.initial, b, this, null, cell, true);

                //Set the state as the root
                MiniMaxTree m = new MiniMaxTree(gameState);

                //Find children states if they exist
                m.GenerateStates(gameState, 4, true);

                //The value returned by the recursive minimax function
                int value = m.MiniMax(gameState, 4, true);

                cell = null;

                foreach(GameState child in gameState.GetChildren())
                {
                    if (child.GetHeuristicValue() == value)
                    {
                        cell = child.GetCell();
                    }
                }

                //Set the cell on the playing board
                b.getCell(cell.getRow(), cell.getColumn()).setState((int)cell.getState());

                //if a row exists above this cell, make it playable
                if (cell.getRow() != 0)
                {
                    b.getCell(cell.getRow() - 1, cell.getColumn()).isPlayable(true);
                }

                //Test if the game is over
                if(MiniMaxTree.TerminalTest(cell))
                {
                    b.printBoard();
                    Console.WriteLine("GameOver: " + this.getColorToString() + " wins");
                    b.isGameOver(true);
                }

                moveCount++;

            }
        }
        /// <summary>
        /// Parses the validation set from connect-4 8-ply database.
        /// </summary>
        /// <returns>Validation set</returns>
        public static List<Example> Parse()
        {
            ValidationSet.Clear();
            using (StringReader reader = new StringReader(Properties.Resources.connect_4))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    string[] values = line.Split(',');

                    Board board = new Board();
                    for (int i = 0; i < values.Length - 1; ++i)
                    {
                        string x = values[i].ToLower().Trim();
                        Checker checker = Checker.Empty;
                        switch (x)
                        {
                            case "x": checker = Checker.Blue; break;
                            case "o": checker = Checker.Green; break;
                            case "b": checker = Checker.Empty; break;
                        }
                        // Format of linear board data in connect-4.txt is bottom to top, left to right
                        board.AddChecker(checker, i/6);
                    }

                    // In connect-4.txt, it is X's turn to go next, which means
                    // player O has just went. Player O == Green, therefore
                    // we use Checker.Green in the following line.
                    Example example = Transform.ToNormalizedExample(board, Checker.Green);

                    string result = values[values.Length - 1].ToLower().Trim();

                    // Current values denote next player that goes will be guaranteed to win/lose/draw given he/she plays optimally...
                    //  We need to normalize this for our network... Ie, the label should instead denote if last player that went for given board position win/loses/ties if he/she plays optimally.
                    GameResult gr =
                            result == "win" ? GameResult.Loss :
                            result == "loss" ? GameResult.Win :
                            GameResult.Draw;
                    example.Labels.Add(Transform.ToValue(gr));
                    ValidationSet.Add(example);
                }
            }
            return ValidationSet;
        }
예제 #5
0
        //Copy constructor
        public Board(Board b)
        {
            length = b.GetLength();

            width = b.GetWidth();

            connectR = Board.GetConnectR();

            board = new Cell[length, width];

            for (int i = 0; i < length; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    Cell cell = new Cell(b.getCell(i, j));

                    board[i, j] = cell;
                }
            }
        }
        public void BatchAddCheckers(Checker start, List<int> columnHistory, bool updateBoard = true, bool delay = true, Board completedBoard = null)
        {
            Storyboard story = new Storyboard();
            Checker checker = start;
            int i = 0;
            foreach (int column in columnHistory)
            {
                Image image = new Image();
                image.Stretch = Stretch.Uniform;
                image.Source = (checker == Checker.Blue ? new BitmapImage(new Uri("/Icons/orbz_water.ico", UriKind.Relative)) : new BitmapImage(new Uri("/Icons/orbz_spirit.ico", UriKind.Relative)));
                image.SetValue(Grid.ColumnProperty, column);
                int? minRow = gridBoard.Children.OfType<Image>().Where(e => (int)e.GetValue(Grid.ColumnProperty) == column).Select(e => (int?)e.GetValue(Grid.RowProperty)).Min();
                if (minRow.HasValue && minRow == 0)
                    throw new Exception("Cannot add checker to full column");
                int row = (int)(minRow.HasValue ? minRow - 1 : 5);
                image.SetValue(Grid.ZIndexProperty, -1);
                image.SetValue(Grid.RowProperty, row);
                image.Opacity = 0;
                image.Height = gridBoard.RowDefinitions[0].ActualHeight;
                gridBoard.Children.Add(image);
                if (updateBoard)
                    CurrentBoard.AddChecker(checker, column);

                ThicknessAnimation animation = new ThicknessAnimation(new Thickness(0, -gridBoard.ActualHeight * 2 * Settings.Default.DropHeightRatio, 0, 0), new Thickness(0, 0, 0, 0), TimeSpan.FromMilliseconds(Settings.Default.DropSpeed));
                animation.EasingFunction = new BounceEase() { Bounces = 3, Bounciness = 5, EasingMode = System.Windows.Media.Animation.EasingMode.EaseOut };
                animation.BeginTime = TimeSpan.FromMilliseconds(i * Settings.Default.MoveDelay);
                Storyboard.SetTarget(animation, image);
                Storyboard.SetTargetProperty(animation, new PropertyPath(Image.MarginProperty));
                story.Children.Add(animation);

                DoubleAnimation fade = (completedBoard != null && !completedBoard.WinningSequence.Any(t => t.Item1 == row && t.Item2 == column) ? Fade(image, 1, Settings.Default.FadeTo, i * Settings.Default.MoveDelay, Settings.Default.FadeSpeed) : Fade(image, 0, 1, i * Settings.Default.MoveDelay, 0));
                story.Children.Add(fade);
                story.Completed += new EventHandler(story_Completed);

                checker = Board.Toggle(checker);
                ++i;
            }
            story.Begin();
        }
예제 #7
0
        public GameState(State s, Board b, Player p, GameState parent, Cell c, Boolean mp)
        {
            maxPlayer = mp;
            state = s;
            cell = c;
            board = b;
            player = p;
            this.parent = parent;
            children = new List<GameState>();
            Region.findConnectedCells(b);
            b.UpdateCellObservers();

            if(MiniMaxTree.TerminalTest(cell) && state != GameState.State.initial)
            {
                state = GameState.State.terminal;

                if (maxPlayer)
                {
                    heuristicValue = MiniMaxTree.MIN_VALUE;
                }
                else
                    heuristicValue = MiniMaxTree.MAX_VALUE;
            }
        }
예제 #8
0
        public void recSelectMove(Board board, int depth, bool max, out int column, out double score, out List<double> columnEvaluations)
        {
            int bestX = 0;
            columnEvaluations = Enumerable.Repeat(double.NegativeInfinity, board.Columns).ToList();
            double bestV = max ? Double.NegativeInfinity : Double.PositiveInfinity; ;

            for (int x = 0; x < board.Columns; x++)
            {
                if (!board.IsColumnFull(x))
                {
                    board.AddChecker(MyColor, x);
                    int col;
                    double v;
                    if (depth <= 1 || board.IsGameOver)
                    {
                        col = x;
                        v = EvaluateBoard(board);
                    }
                    else
                    {
                        List<double> ignore = (new double[board.Columns]).ToList();
                        recSelectMove(board, depth - 1, !max, out col, out v, out ignore);
                    }
                    board.RemoveChecker(x);
                    columnEvaluations[x] = v;

                    if (v > bestV && max || v < bestV && !max)
                    {
                        bestV = v;
                        bestX = col;
                    }
                }
            }
            column = bestX;
            score = bestV;
        }
예제 #9
0
        public void SelectMove(Board board, out int column, out double score, int depth = 1)
        {
            // Lambda percent of the time, select a random move.
            if (LambdaType == LambdaType.Threshold && RANDOM.NextDouble() <= Lambda)
            {
                int[] cols = Enumerable.Range(0, board.Columns).Where(x => !board.IsColumnFull(x)).ToArray();
                column = cols[RANDOM.Next(cols.Count())];
                board.AddChecker(MyColor, column);
                score = EvaluateBoard(board);
                board.RemoveChecker(column);
                return;
            }

            List<double> columnEvaluations;
            recSelectMove(board, depth, true, out column, out score, out columnEvaluations);

            //we pick a move randomly, using a probability distribution such that the moves with the "best" board positions have a
            //  higher probability of being selected higher values of Lambda mean choices will have more equal probability, even if they had different
            //  low values of Lambda will have the opposite effect Lambda should be positive number.  Otherwise, no exploration will take place.
            //  If non-positive, just return the "best" move now, to avoid divide-by-zero type issues.
            if (LambdaType == LambdaType.ProbabilityDistribution && Lambda > 0)
            {
                double sum = 0.0;
                double[] weights = new double[columnEvaluations.Count];
                for (int i = 0; i < columnEvaluations.Count; i++)
                {
                    // the closer this column's evaluation to the "best", the
                    // greater weight it will have
                    double w = 1 / (Lambda + (score - columnEvaluations[i]));
                    weights[i] = w;
                    sum += w;
                }

                double r = RANDOM.NextDouble() * sum;
                int c;
                for (c = 0; c + 1 < weights.Length; c++)
                {
                    r -= weights[c];
                    if (r <= 0)
                        break;
                }

                column = c;
                score = columnEvaluations[c];
            }
        }
예제 #10
0
        public override void Move(Board b)
        {
            if(moveCount == b.GetLength() * b.GetWidth())
            {
                Console.WriteLine("Game Over, you both lose");
            }

            Boolean moveMade = false;

            b.printBoard();

            if(this.getOpponent() != null)
            {
                Console.WriteLine(" ");
            }

            Console.WriteLine(this.getColorToString() + " player's turn");

            while(!moveMade)
            {
                Console.Write("Select a Move: " + "0 - " + (b.GetWidth() - 1) + ": ");

                int choice = Convert.ToInt32(Console.ReadLine());

                for (int i = b.GetLength() - 1; i >= 0; i--)
                {
                    if(choice < 0 || choice > b.GetWidth() - 1)
                    {
                        break;
                    }

                    cell = b.getCell(i, choice);

                    if (cell.isPlayable())
                    {
                        cell.setState((int)color);

                        cell.isPlayable(false);

                        if (i != 0)
                        {
                            b.getCell(i - 1, choice).isPlayable(true);
                        }

                        moveMade = true;

                        moveCount++;

                        if (MiniMaxTree.TerminalTest(cell))
                        {
                            b.printBoard();
                            Console.WriteLine("GameOver: " + this.getColorToString() + " wins");
                            b.isGameOver(true);
                        }

                        break;
                    }
                }

            }
        }
예제 #11
0
 public abstract void Move(Board board);
예제 #12
0
        static void Main(string[] args)
        {
            Console.Write("Board Width? ");
            colNum = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine();

            Console.Write("Board Height? ");
            rowNum = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine();

            Console.Write("Connect? ");
            r = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine();

            Console.WriteLine("1: Human vs Human");
            Console.WriteLine("2: Human vs AI");
            Console.WriteLine("3: AI vs AI");
            Console.Write("Select Players: ");
            int choice = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine();

            Board board = new Board(rowNum, colNum, r);
            Region.findConnectedCells(board);
            board.UpdateCellObservers();

            Player p1 = null;
            Player p2 = null;

            switch (choice)
            {
                case 1:
                    p1 = new HumanPlayer();
                    p1.setAsRed();
                    p2 = new HumanPlayer();
                    p2.setAsBlack();
                    break;

                case 2:
                    Console.WriteLine("1: Human 2: AI");
                    Console.Write("Who will go first? ");
                    choice = Convert.ToInt32(Console.ReadLine());
                    if(choice == 1)
                    {
                        p1 = new HumanPlayer();
                        p1.setAsRed();
                        p2 = new AIPlayer();
                        p2.setAsBlack();
                    }
                    else
                    {
                        p1 = new AIPlayer();
                        p1.setAsRed();
                        p2 = new HumanPlayer();
                        p2.setAsBlack();
                    }
                    p1.setOpponent(p2);
                    p2.setOpponent(p1);
                    break;

                case 3:
                    break;

            }

            int turn = RED;

            while(!board.isGameOver())
            {
                switch (turn)
                {
                    case RED:
                        p1.Move(board);
                        turn = BLACK;
                        break;
                    case BLACK:
                        p2.Move(board);
                        turn = RED;
                        break;
                }
            }

            Console.Read();
        }
예제 #13
0
        public static void findConnectedCells(Board board)
        {
            for(int i = length - 1; i >= 0; i--)
            {
                for(int j = 0; j < width; j++)
                {
                    Cell cell = board.getCell(i, j);

                    //has r north cells
                    if(i >= connectR - 1)
                    {
                        region = new Vertical();
                        region.AddCells(board, cell, connectedCells.north);

                        //has r northeast cells
                        if(j + connectR - 1 < width)
                        {
                            region = new Diagonal();
                            region.AddCells(board, cell, connectedCells.northEast);
                        }

                        //has r northwest cells
                        if(j >= connectR - 1)
                        {
                            region = new Diagonal();
                            region.AddCells(board, cell, connectedCells.northWest);
                        }
                    }

                    //has r south cells
                    if(i + connectR - 1 < length)
                    {
                        region = new Vertical();
                        region.AddCells(board, cell, connectedCells.south);

                        //has r southwest cells
                        if(j - connectR + 1 >= 0)
                        {
                            region = new Diagonal();
                            region.AddCells(board, cell, connectedCells.southWest);
                        }

                        //has r southeast cells
                        if(j <= connectR - 1)
                        {
                            region = new Diagonal();
                            region.AddCells(board, cell, connectedCells.southEast);
                        }
                    }

                    //has r east cells
                    if(j <= connectR - 1)
                    {
                        region = new Horizontal();
                        region.AddCells(board, cell, connectedCells.east);
                    }

                    //has r west cells
                    if(j - connectR + 1 >= 0)
                    {
                        region = new Horizontal();
                        region.AddCells(board, cell, connectedCells.west);
                    }
                }
            }
        }
예제 #14
0
 public abstract void AddCells(Board board, Cell cell, connectedCells c);
 protected override double EvaluateBoard(Board board)
 {
     Example example = MakeExample(board, MyColor);
     Network.PropogateInput(example);
     return example.Predictions[0];
 }
 public override Example MakeExample(Board board, Checker color)
 {
     return Transform.ToNormalizedExample(board, color);
 }
 public void Restart(GameMode mode, bool startup = false)
 {
     gridBoard.Children.RemoveRange(7, gridBoard.Children.Count - 7); // Don't remove the 7 borders.
     Mode = mode;
     Checker = Checker.Blue;
     CurrentBoard = new Board();
     if (!startup)
         GetValidNetwork(); // Assert valid current network be means of a messagebox.
 }
        /// <summary>
        /// Simulate a game until completion.
        /// </summary>
        /// <param name="board">Starting board that the bots will play on.  This need not be empty!</param>
        /// <param name="network">Neural network that provides the AI for gameplay.</param>
        /// <returns>Trace of game sequence, each board state stored as a Neural Net Example</returns>
        public List<Example> Play(Board board, Network network)
        {
            Bot allen = new NeuralNetBot(Checker.Blue, network); // <-- you know he will win :)
            Bot jason = new NeuralNetBot(Checker.Green, network);

            List<Example> trace = new List<Example>();

            Turns = 0;
            Bot current = allen.MyColor == board.NextPlayer ? allen : jason;
            while (!board.IsGameOver)
            {
                int column;
                double score;
                current.SelectMove(board, out column, out score);
                Log(String.Format("{0} picks column {1}   (Score: {2:f2})", (current == allen ? "Allen" : "Jason"), column, score));
                board.AddChecker(current.MyColor, column);

                Example example = Transform.ToNormalizedExample(board, current.MyColor);
                example.Predictions.Add(score);
                trace.Add(example);

                current = (current == allen ? jason : allen);
                ++Turns;
            }

            if (Viewer != null)
                Viewer.BatchAddCheckers(Checker.Blue, board.MoveHistory,completedBoard:board);

            TotalTurns += Turns;

            Checker winner;
            if (board.TryGetWinner(out winner))
            {
            //The game is over, there was a winner.
            //This means the last element of "trace" represents a won
            //board state (i.e. there is a four-in-a-row with color
            //'winner').

                if (trace.Count > 0) trace[trace.Count - 1].Predictions[0] = Transform.ToValue(GameResult.Win);
                if (trace.Count > 1) trace[trace.Count - 2].Predictions[0] = Transform.ToValue(GameResult.Loss);
                if (winner == allen.MyColor)
                {
                    Log("WINNER:  Allen");
                    ++AllenWon;
                }
                else
                {
                    Log("WINNER:  Jason");
                    ++JasonWon;
                }
            }
            else
            {
                if (trace.Count > 0) trace[trace.Count - 1].Predictions[0] = Transform.ToValue(GameResult.Draw);
                if (trace.Count > 1) trace[trace.Count - 2].Predictions[0] = Transform.ToValue(GameResult.Draw);
                Log("TIE");
                ++Ties;
            }

            ++TotalGames;
            Log(string.Format("Turns: {0} ({1:f2})", Turns, (double)TotalTurns / TotalGames));
            Log(string.Format("Allen: {0}({1:f2}) Jason: {2}({3:f2}) Ties {4}({5:f2})   TOTAL: {6}", AllenWon, (double)AllenWon / TotalGames, JasonWon, (double)JasonWon / TotalGames, Ties, (double)Ties / TotalGames, TotalGames));
            Log("");

            List<Example> trace1 = new List<Example>(), trace2 = new List<Example>();
            for (int i = 0; i < trace.Count; ++i)
            {
                if (i % 2 == 0) trace1.Add(trace[i]);
                else trace2.Add(trace[i]);
            }
            double lambda = .7;
            double alpha = .1;
            double gamma = .5;
            UpdateTraceLabels(trace1, lambda, alpha, gamma);
            UpdateTraceLabels(trace2, lambda, alpha, gamma);

            return trace1.Union(trace2).ToList();
        }
예제 #19
0
        public void FindChildrenStates(Boolean maxPlayer)
        {
            GameState gs;

            for(int i = 0; i < board.GetWidth(); i++)
            {
                for(int j = 0; j < board.GetLength(); j++)
                {
                    if(board.getCell(j,i).getState().Equals(Cell.CellState.empty))
                    {
                        if (board.getCell(j, i).isPlayable())
                        {
                            Board b = new Board(board);

                            Cell cell = b.getCell(j, i);

                            if (maxPlayer)
                            {
                                cell.setState(player.getColor());
                            }
                            else
                            {
                                cell.setState(player.getOpponent().getColor());
                            }

                            if (j != 0)
                            {
                                b.getCell(j - 1, i).isPlayable(true);
                            }

                            gs = new GameState(GameState.State.transition, b, player, this, cell, !maxPlayer);

                            children.Add(gs);
                        }
                    }
                    else
                        break;
                }

            }
        }
예제 #20
0
 public abstract Example MakeExample(Board board, Checker color);
예제 #21
0
 protected abstract double EvaluateBoard(Board board);