public int GetMove(BoardModel boardModel)
        {
            var openIndicies = boardModel.GetOpenIndicies();
            if (openIndicies.Count == 0)
            {
                return -1;
            }

            HypotheticalBoard best = null;
            //Generate a tree of HypotheticalBoards for each open spot to determine which move is the best.
            foreach (var index in openIndicies)
            {
                var board = new HypotheticalBoard(new BoardModel(boardModel), Player.Computer, index);
                if ((best == null) || board.GetScore() > best.GetScore())
                {
                    best = board;
                } else if (best.GetScore() == board.GetScore())
                {
                    //Randomly decide whether to use the new board, or the existing best board.
                    //This will make the game a bit more random, while still using strategy.
                    if (_random == null)
                    {
                        _random = new Random();
                    }
                    if (_random.NextDouble() < 0.25)
                    {
                        best = board;
                    }
                }
            }
            //best can never be null, it will be set in the first pass of the for loop.
            return best.Index;
        }
        /// <summary>
        /// Keeping depth private, because external uses do not need to worry about it. 
        /// </summary>
        /// <param name="depth"></param>
        /// <param name="board"></param>
        /// <param name="player"></param>
        /// <param name="index"></param>
        private HypotheticalBoard(int depth, BoardModel board, Player player, int index)
        {
            _depth = depth;
            _board = board;
            _player = player;
            Index = index;

            _board.UpdatePositionAtIndex(Index, _player);

            // Continue to fill the tree of next possible moves
            // Stop the recursion when there are no open spots left,
            // or we have reached the max depth of recursion.
            if (_depth < maxDepth)
            {
                // Get the open indicies for the board where there are moves are still available
                var openIndicies = _board.GetOpenIndicies();
                if (openIndicies.Count > 0)
                {
                    ChildBoards = new List<HypotheticalBoard>();
                    foreach (var openIndex in openIndicies)
                    {
                        ChildBoards.Add(new HypotheticalBoard(depth + 1, new BoardModel(board),
                                                               Utilities.SwitchPlayer(_player), openIndex));
                    }
                }
            }
        }
 public int GetMove(BoardModel boardModel)
 {
     var openIndicies = boardModel.GetOpenIndicies();
     if(_randomMove == null)
     {
         _randomMove = new Random();
     }
     return openIndicies[_randomMove.Next(openIndicies.Count)];
 }
 /// <summary>
 /// Construct a BoardModel copy of the given baseBoardModel
 /// </summary>
 /// <param name="baseBoardModel">The BoardModel to copy.</param>
 public BoardModel(BoardModel baseBoardModel)
 {
     _board = new List<Player>(baseBoardModel._board);
 }
 /// <summary>
 /// Creates a board using the given BoardModel in which the given player
 /// will take the given index. 
 /// </summary>
 /// <param name="board"></param>
 /// <param name="player"></param>
 /// <param name="index"></param>
 public HypotheticalBoard(BoardModel board, Player player, int index)
     : this(0, board, player, index)
 {
 }
        /// <summary>
        /// Begin new game. 
        /// </summary>
        /// <param name="userInterface">Instance of form that the controller will send various game state updates to</param>
        /// <param name="startingPlayer">Who begins the game, must be Human or Computer</param>
        /// <param name="difficulty">The level of difficulty</param>
        public void StartNewGame(TicTacToeForm userInterface, Player startingPlayer = Player.Human, Difficulty difficulty=Difficulty.Easy)
        {
            if (startingPlayer == Player.None)
            {
                throw new ArgumentException("Player must be either human or computer.");
            }
            _boardModel = new BoardModel();
            _userInterface = userInterface;
            _playerTurn = startingPlayer;

            //If the difficulty is easy, then the computer will choose indicies at random.
            //If the diffuculty is hard, the computer uses a min-max algorithm to choose the optimal index.
            switch(difficulty)
            {
                case Difficulty.Easy:
                    _moveChooser = new RandomComputerMoveChooser();
                    break;
                case Difficulty.Hard:
                    _moveChooser = new MinMaxComputerMoveChooser();
                    break;
            }

            if(_playerTurn == Player.Computer)
            {
                DoComputerTurn();
            }
        }