/// <summary>
        /// Given a tile, this method checks if there is a possible
        /// eventually winnable connection around it.
        /// </summary>
        /// <param name="tile"></param>
        /// <returns></returns>
        public TileConnection GetWinnableConnectionAround(Tile tile)
        {
            var tileIndex = _tiles.IndexOf(tile);

            //Check Backwards
            int backwardsIndex = tileIndex;
            int currentIndex = tileIndex - 1;
            while (currentIndex >= 0 &&
                currentIndex >= (tileIndex - 3) && //once we pass 3 tiles away, they are no longer contributing to this tiles winnablility
                    (_tiles[currentIndex].OwningPlayer == tile.OwningPlayer ||
                    _tiles[currentIndex].OwningPlayer == null)) {
                backwardsIndex = currentIndex;
                currentIndex--;
            }

            //Count Forwards
            var forwardsIndex = tileIndex;
            currentIndex = tileIndex + 1;
            while (currentIndex < _tiles.Count &&
                currentIndex <= (tileIndex + 3) && //once we pass 3 tiles away, they are no longer contributing to this tiles winnablility
                    (_tiles[currentIndex].OwningPlayer == tile.OwningPlayer ||
                    _tiles[currentIndex].OwningPlayer == null)) {
                forwardsIndex = currentIndex;
                currentIndex++;
            }

            if ((forwardsIndex - backwardsIndex + 1) >= 4) {
                return new TileConnection(
                    _tiles.GetRange(backwardsIndex, forwardsIndex - backwardsIndex + 1));

            } else {
                return null;
            }
        }
Example #2
0
        public void TestGetPositiveDiagonalStartingRowNo()
        {
            var tile = new Tile(new Column(0), 4);
            Assert.AreEqual(4, tile.GetPositiveDiagonalStartingRowNo());

            tile = new Tile(new Column(3), 5);
            Assert.AreEqual(2, tile.GetPositiveDiagonalStartingRowNo());

            tile = new Tile(new Column(6), 5);
            Assert.AreEqual(-1, tile.GetPositiveDiagonalStartingRowNo());

            tile = new Tile(new Column(6), 0);
            Assert.AreEqual(-6, tile.GetPositiveDiagonalStartingRowNo());
        }
Example #3
0
        public void TestGetNegativeDiagonalStartingRowNo()
        {
            var tile = new Tile(new Column(0), 4);
            Assert.AreEqual(4, tile.GetNegativeDiagonalStartingRowNo());

            tile = new Tile(new Column(3), 4);
            Assert.AreEqual(7, tile.GetNegativeDiagonalStartingRowNo());

            tile = new Tile(new Column(5), 0);
            Assert.AreEqual(5, tile.GetNegativeDiagonalStartingRowNo());

            tile = new Tile(new Column(6), 2);
            Assert.AreEqual(8, tile.GetNegativeDiagonalStartingRowNo());
        }
Example #4
0
        //Test Me
        public int GetRatingForTile(GameCore gameCore, Tile tile, Object player)
        {
            int rating = 0;

            //First check if placing a tile here will force the opponent to block us, or give the
            //opponent a wining move. We shouldn't consider those tiles.
            var copy = gameCore.Copy();
            copy.DropTokenOnColumn(tile.ColumnNo);
            var otherPlayerDirectWinnable = AIHelper.FindDirectWinningPossibilities(copy.Board, gameCore.GetOtherPlayer(player));
            if (otherPlayerDirectWinnable.Count > 0) {

                //lower skilled players can miss an opponents winning move, especially if they are
                //focused on their own win
                if (_difficulty == AIDifficulty.VeryEasy) {  rating -= 2; }
                else if (_difficulty == AIDifficulty.Easy) {  rating -= 4; }
                else if (_difficulty == AIDifficulty.Medium) {  rating -= 6; }
                else {
                    //the other player can win if we play here, so don't play
                    return -1000;
                }
            }

            var usDirectWinnable = AIHelper.FindDirectWinningPossibilities(copy.Board, player);
            if (usDirectWinnable.Count > 0) {
                //we can win next turn if we place here, forcing the other player to make a blocking move.
                //It may be worth making the move anyway if it gives us a good position, and there isn't
                //anything better, so don't completley discount it.
                if (CanCreateCompulsion(copy.Board)) {
                    rating -= 3;
                } else {
                    //if the player can't create compulsions we shouldn't penalize them for
                    //trying to win

                    if (_difficulty < AIDifficulty.Medium) {
                        //lower skilled players will chase a win
                        rating += 2;
                    }
                }
            }

            //We are trying to create general opportunities to head into the end game by creating
            //potential token connections. So we want to look at where we have potential connections
            //and try to build that area up to generate a compulsion.
            rating += (FindTilesInConnection(gameCore, tile, player).Count * 2);

            //Future ToDos
            //Now check the opponents tile connections. Add points based on how many they have, sine we're
            //blocking their position
            if (_tryToBlockOpponentsGoodConnections) {
                rating += FindTilesInConnection(gameCore, tile, gameCore.GetOtherPlayer(player)).Count;
            }

            //Check what will happen once we play our tile. Does it open up any good positions?

            //Do some planning stuff now:

            //If placing a tile here will start a compulsion for us, add points
            //If placing a tile here will block an opponents compulsion then add some points.
            //Check the tile connections for the tile above this one. If the opponent would have good
            //connections then subtract points. If we would have a good connections subtract points
            //(since it alows the opponent to block us.

            return rating;
        }
Example #5
0
        /// <summary>
        /// Method finds the amount of player tokens around the tile which are in a good connection
        /// to it.
        /// </summary>
        public List<Tile> FindTilesInConnection(GameCore gameCore, Tile tile, Object player)
        {
            //To do this we get all the potential tile connections that contain this placeable tile.
            var possibleConnections = AIHelper.FindFourTokenConnectionPossibilties(gameCore.Board, player);
            var containingConnections = (from pc in possibleConnections
                                        where pc.Tiles.Contains(tile)
                                        select pc).ToList();

            //And add points based on how many of our tokens in tile connections it is part of. More
            //is better
            var playerTilesInConnection = (from tc in containingConnections
                                           from t in tc.Tiles
                                           where t.OwningPlayer == player
                                           select t).ToList();

            return playerTilesInConnection;
        }
Example #6
0
 private List<Tile> GetRowTilesForTile(Tile tile)
 {
     int rowNo = tile.RowNo;
     var tiles = new List<Tile>();
     for (int columnNo = 0; columnNo < Board.BoardWidth; columnNo++) {
         tiles.Add(_board[columnNo][rowNo]);
     }
     return tiles;
 }
Example #7
0
        private List<Tile> GetPoistiveDiagonalTilesForTile(Tile tile)
        {
            int rowNo = tile.RowNo;
            int columnNo = tile.ColumnNo;

            //work out the start point. Farthest bottom left point diagonally inline with the tile
            while (columnNo > 0 && rowNo > 0) {
                columnNo--;
                rowNo--;
            }

            //move diagonally up and rightwatds grabbing each tile
            var tiles = new List<Tile>();
            while ( columnNo < Board.BoardWidth && rowNo < Board.BoardHeight) {
                tiles.Add(_board[columnNo][rowNo]);
                columnNo++;
                rowNo++;
            }
            return tiles;
        }
Example #8
0
        private void DropTokenOnColumn(Column column)
        {
            if (column.IsFull) {
                throw new ApplicationException(string.Format("Cannot drop token on column {0} because it is full!", column.ColumnNo));
            }

            Tile tokenTile = column.GetFirstEmptyTile();
            tokenTile.OwningPlayer = _currentPlayer;

            //To-Do: We should probably check for a win condition now
            List<List<Tile>> winningSets = CheckForWin(tokenTile);
            if (winningSets.Count != 0) {
                //We have a winner
                _winningTile = tokenTile;
                _winningSets = winningSets;
                _winningPlayer = _currentPlayer;
                _currentPlayer = null;

            } else if (this.Board.GetAllPlaceableTiles().Count == 0) {
                _isStalemate = true;

            } else {
                //after a token has been dropped we update the current player
                _currentPlayer = GetNonCurrentPlayer();
            }

            //and let any subscribers know that the game state has changed
            if (GameStateChanged != null) {GameStateChanged(this, new EventArgs());}
        }
Example #9
0
        private List<List<Tile>> CheckForWin(Tile lastPlayedTile)
        {
            //Check in each of the four directions for four or more in a row.

            //To do this we could just map each directions into a linear list, and do the same check for each

               List<List<Tile>> winningSets = new List<List<Tile>>();

            //Check Horizontal
            CheckInlineTilesAndAddToWinningSetIfMatching(
                   GetRowTilesForTile(lastPlayedTile),
                   winningSets);

            //Check Vertical
            CheckInlineTilesAndAddToWinningSetIfMatching(
                   _board[lastPlayedTile.ColumnNo].Tiles,
                   winningSets);

            //Check Positive Diagonal
            CheckInlineTilesAndAddToWinningSetIfMatching(
                   GetPoistiveDiagonalTilesForTile(lastPlayedTile),
                   winningSets);

            //Check Negative Diagonal
            CheckInlineTilesAndAddToWinningSetIfMatching(
                   GetNegativeDiagonalTilesForTile(lastPlayedTile),
                   winningSets);

            return winningSets;
        }