// [2016.12.01] protected bool endTurn() { // [SC] reset board position resetSelected(); Player activePlayer = players[activePlayerIndex]; // [SC] reset player's variables that are persistent only for a turn activePlayer.resetTurnVars(); // [SC] refill player's tile array with new tiles from bag fillPlayerTiles(activePlayer); // [SC] if player has no tiles then end the game if (activePlayer.getPlayerTileCount() == 0) { return(true); } // [SC] make the next player in a queue as a current player if (++activePlayerIndex >= players.Count) { activePlayerIndex = 0; } // [SC] set a flag to start a next turn startTurnFlag = true; Cfg.log(getVirtualBoard().ToString()); return(false); }
// [2016.12.01] // [SC] place active player's tile on a board public void placePlayerTileOnBoard(int playerIndex) { if (!activeGameFlag) { return; } if (playerIndex != activePlayerIndex) { Cfg.log("It is not your turn!"); return; } Player activePlayer = players[activePlayerIndex]; // [SC] check if player can put tiles on a board if (!activePlayer.getCanMove()) { Cfg.log("Cannot move a tile after dropping a tile!"); // [TODO] return; } // [SC] check if board position is selected if (!isSelected()) { Cfg.log("Select a board position at first!"); // [TODO] return; } // [SC] check if player tile is selected if (!activePlayer.isTileSelected()) { Cfg.log("Select a tile at first!"); // [TODO] return; } TileZeroTile tile = activePlayer.getSelectedTile(); int result = putTileOnBoard(selectedRowIndex, selectedColIndex, tile, true); if (result != Cfg.NONE) { Cfg.log(String.Format(" Put tile {0} at position {1}-{2} for {3} points.", tile.ToString(), selectedRowIndex, selectedColIndex, result)); // [SC] increase player's score activePlayer.increaseScore(result); // [SC] remove the tile from the player and reset player selection activePlayer.removeSelectedTile(); // [SC] disable mismatching tiles activePlayer.disableMismatchedTiles(tile.getColorIndex(), tile.getShapeIndex()); // [SC] prevent the player from dropping tiles in the same turn activePlayer.setCanDrop(false); // [SC] reset board selection resetSelected(); } }
// [2016.12.01] // [TODO] end the game protected bool verifyPlayableTileCount(int tileCount, int aiPlayerCount) { int minTileCount = Cfg.START_TILE_COUNT + (aiPlayerCount + 1) * Cfg.MAX_PLAYER_TILE_COUNT; if (tileCount < minTileCount) { Cfg.log(String.Format("The minimum umber of playable tiles should be {0}. Using default bag size.", minTileCount)); return(false); } return(true); }
// [2016.12.01] public void endTurn(int playerIndex) { if (!activeGameFlag) { Cfg.log("No active game."); } else if (playerIndex != activePlayerIndex) { Cfg.log("Not your turn!" + playerIndex); } else { endTurnFlag = true; } }
////// END: generic functions for manipulating tiles ///////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////// ////// START: functions for manipulating a selected tile private bool setSelectedTile(TileZeroTile tile) { // [TODO] make sure the tile is one of the player's tiles if (!tile.getPlayable()) { Cfg.log(String.Format("The tile {0}{1} is not playable.", tile.getColorIndex(), tile.getShapeIndex())); } else { selectedTile = tile; return(true); } return(false); }
// [2016.12.01] protected void startTurn() { if (!activeGameFlag) { return; } Player activePlayer = players[activePlayerIndex]; Cfg.log(String.Format("{0}'s turn. Score: {1}. Tiles: {2}" , activePlayer.getPlayerName() , activePlayer.getPlayerScore() , activePlayer.PlayerTilesToString())); activePlayer.invokeAI(); endTurn(activePlayerIndex); }
///////////////////////////////////////////////////////////////// ////// START: board cell selection // [2016.12.01] public bool setSelectedCell(int rowIndex, int colIndex, int playerIndex) { if (playerIndex >= players.Count) { Cfg.log(String.Format("Unknown player with an index {0}.", playerIndex)); } else if (activePlayerIndex != playerIndex) { Cfg.log(String.Format("It is not your turn, {0}!", players[playerIndex].getPlayerName())); } else { selectedRowIndex = rowIndex; selectedColIndex = colIndex; return(true); } return(false); }
// [2016.12.01] public void endGame() { if (!activeGameFlag) { return; } Player activePlayer = players[activePlayerIndex]; activePlayer.increaseScore(Cfg.LAST_PLAYER_REWARD); int maxScore = Cfg.NONE; List <Player> maxScorePlayers = new List <Player>(); foreach (Player player in players) { int playerScore = player.getPlayerScore(); if (maxScore == Cfg.NONE || maxScore == playerScore) { maxScorePlayers.Add(player); maxScore = playerScore; } else if (maxScore < playerScore) { maxScorePlayers.Clear(); maxScorePlayers.Add(player); maxScore = playerScore; } } if (maxScorePlayers.Count > 1) { Cfg.log("It is a draw!"); } else { Cfg.log(String.Format("Player {0} won the game!", maxScorePlayers[0].getPlayerName())); maxScorePlayers[0].WinFlag = true; } activeGameFlag = false; }
// [2016.12.01] protected void putStartingTiles() { int startCol = virtualBoard.getColCount() / 2 - Cfg.START_TILE_COUNT / 2; int startRow = virtualBoard.getRowCount() / 2; for (int counter = 0; counter < Cfg.START_TILE_COUNT; counter++) { int currCol = startCol + counter; TileZeroTile tile = (TileZeroTile)tileBag.ElementAt(0); int result = putTileOnBoard(startRow, currCol, tile, false); // [TODO] need to terminate the game if (result == Cfg.NONE) { Cfg.log("Error putting starting tiles"); break; } tileBag.Remove(tile); ++playedTileCount; } }
// [2016.12.01] // [SC] a function for dropping a tile public void dropPlayerTile(int playerIndex) { if (!activeGameFlag) { return; } if (playerIndex != activePlayerIndex) { Cfg.log("It is not your turn!"); return; } Player activePlayer = players[activePlayerIndex]; // [SC] check if player drop tiles if (!activePlayer.getCanDrop()) { Cfg.log("Cannot drop a tile after putting a tile on a board!"); // [TODO] return; } // [SC] check if bag has tiles if (tileBag.Count == 0) { Cfg.log("Cannot drop a tile! The bag is empty."); // [TODO] return; } // [SC] check if player tile is selected if (!activePlayer.isTileSelected()) { Cfg.log("Select a tile at first!"); // [TODO] return; } TileZeroTile tile = activePlayer.getSelectedTile(); // [SC] make sure that the tile being dropped is not a replacement tile of previously dropped tile if (!tile.getCanDrop()) { Cfg.log("Cannot drop a replacement tile!"); return; } foreach (TileZeroTile newTile in tileBag) { // [SC] make sure that the new tile does not have the same features as the dropped tile if (newTile.getColorIndex() == tile.getColorIndex() && newTile.getShapeIndex() == tile.getShapeIndex()) { continue; } Cfg.log(String.Format(" Dropped tile {0}. Replaced with tile {1}.", tile.ToString(), newTile.ToString())); // [SC] remove the dropped tile from player's stack activePlayer.removeTile(tile); // [SC] add the dropped tile into the bag tileBag.Add(tile); // [SC] remove the new tile from the bag tileBag.Remove(newTile); // [SC] add the new tile to player's stack activePlayer.addTile(newTile); // [SC] make sure that the new tile cannot be dropped in the same turn newTile.setCanDrop(false); // [SC] shuffle the bag tileBag.Shuffle(); // [SC] prevent the player from moving tiles into the board activePlayer.setCanMove(false); break; } }
private int isValidSequence(int rowIndex, int colIndex, int orientation, TileZeroTile[,] tileArrayP, bool showMsg) { int[] uniqueColors = new int[Cfg.MAX_VAL_INDEX]; int uniqueColorCount = 0; int[] uniqueShapes = new int[Cfg.MAX_VAL_INDEX]; int uniqueShapeCount = 0; int sequenceLength = 0; int currRow = rowIndex; int currCol = colIndex; for (int currIndex = 0; currIndex < Cfg.MAX_VAL_INDEX; currIndex++) { uniqueColors[currIndex] = Cfg.NONE; uniqueShapes[currIndex] = Cfg.NONE; } // [SC] start with the left-most or top-most tile in the sequence if (orientation == Cfg.HORIZONTAL) { while (currCol > 0 && tileArrayP[currRow, currCol - 1] != null) { currCol--; } } else { while (currRow > 0 && tileArrayP[currRow - 1, currCol] != null) { currRow--; } } // [SC] checking the validity of colors and shapes, and color-shape combination of the sequence while (currRow < rowCount && currCol < colCount) { TileZeroTile currTile = tileArrayP[currRow, currCol]; if (currTile == null) { break; } // [SC] checking the validity of colors int currColorIndex = currTile.getColorIndex(); if (uniqueColors[currColorIndex] == Cfg.NONE) { uniqueColors[currColorIndex] = currColorIndex; uniqueColorCount++; } else if (uniqueColorCount == 1) { } else { if (showMsg) { Cfg.log("Invalid color sequence."); } return(Cfg.NONE); } // [SC] checking the validity of shapes int currShapeIndex = currTile.getShapeIndex(); if (uniqueShapes[currShapeIndex] == Cfg.NONE) { uniqueShapes[currShapeIndex] = currShapeIndex; uniqueShapeCount++; } else if (uniqueShapeCount == 1) { } else { if (showMsg) { Cfg.log("Invalid shape sequence."); } return(Cfg.NONE); } sequenceLength++; if (sequenceLength > 1) { if ((uniqueColorCount == 1 && uniqueShapeCount == 1) || // [SC] both shape and color are same (uniqueColorCount > 1 && uniqueShapeCount > 1) // both shape and color are different ) { if (showMsg) { Cfg.log("Invalid combination of color and shape."); } return(Cfg.NONE); } } // [TODO] update row if (orientation == Cfg.HORIZONTAL) { currCol++; } else { currRow++; } } return(sequenceLength); }
public int isValidMove(int rowIndex, int colIndex, TileZeroTile tile, bool validCheck, TileZeroTile[,] tileArrayP, bool showMsg) { if (tileArrayP == null) { tileArrayP = tileArray; } int horizScore = 0; int vertScore = 0; if (rowIndex < 0 || rowIndex >= rowCount) { if (showMsg) { Cfg.log("Invalid row index: " + rowIndex + "."); } return(Cfg.NONE); } if (colIndex < 0 || colIndex >= colCount) { if (showMsg) { Cfg.log("Invalid column index: " + colIndex + "."); } return(Cfg.NONE); } if (hasTile(rowIndex, colIndex, tileArrayP)) { if (showMsg) { Cfg.log("The cell already has a tile."); } return(Cfg.NONE); } if (validCheck) { // [SC] check if there is any tile adjacent to the destinatio position if (!hasLeftTile(rowIndex, colIndex, tileArrayP) && !hasRightTile(rowIndex, colIndex, tileArrayP) && !hasBottomTile(rowIndex, colIndex, tileArrayP) && !hasTopTile(rowIndex, colIndex, tileArrayP) ) { if (showMsg) { Cfg.log("A new tile should be placed next to the existing one."); } return(Cfg.NONE); } // [SC] temporarily put the tile tileArrayP[rowIndex, colIndex] = tile; // [SC] check validity of the horizontal sequence of tiles if (hasLeftTile(rowIndex, colIndex, tileArrayP) || hasRightTile(rowIndex, colIndex, tileArrayP)) { horizScore = isValidSequence(rowIndex, colIndex, Cfg.HORIZONTAL, tileArrayP, showMsg); if (horizScore == Cfg.NONE) { tileArrayP[rowIndex, colIndex] = null; return(Cfg.NONE); } else if (horizScore == Cfg.MAX_SEQ_SCORE) { // [SC] reward for completing a TileZero horizScore = Cfg.TILEZERO_REWARD; } } // [SC] check validity of the vertical sequence of tiles if (hasTopTile(rowIndex, colIndex, tileArrayP) || hasBottomTile(rowIndex, colIndex, tileArrayP)) { vertScore = isValidSequence(rowIndex, colIndex, Cfg.VERTICAL, tileArrayP, showMsg); if (vertScore == Cfg.NONE) { tileArrayP[rowIndex, colIndex] = null; return(Cfg.NONE); } else if (vertScore == Cfg.MAX_SEQ_SCORE) { // [SC] reward for completing a TileZero vertScore = Cfg.TILEZERO_REWARD; } } // [SC] remove the temporary tile tileArrayP[rowIndex, colIndex] = null; } return(horizScore + vertScore); }