/// <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; } }
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()); }
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()); }
//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; }
/// <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; }
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; }
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; }
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());} }
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; }