|
|
|
@ -51,13 +51,20 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
protected virtual void OnEndOfGame(EndOfGameNotifiedEventArgs args)
|
|
|
|
|
=> EndOfGameNotified?.Invoke(this, args);
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates a game with a board and a tile bag
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Game()
|
|
|
|
|
{
|
|
|
|
|
bag = CreateTileBag(3);
|
|
|
|
|
board = CreateBoard();
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Adds a player in the game if the game is not running, if the name is correct, if the game is not full and if the name is not already taken.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="playerTag"></param>
|
|
|
|
|
/// <returns>boolean to check it</returns>
|
|
|
|
|
public bool AddPlayerInGame(string? playerTag)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(playerTag))
|
|
|
|
@ -96,6 +103,11 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates a player with a name
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="playerTag"></param>
|
|
|
|
|
/// <returns>Player</returns>
|
|
|
|
|
public Player CreatePlayer(string playerTag)
|
|
|
|
|
{
|
|
|
|
|
var player = new Player(playerTag);
|
|
|
|
@ -103,36 +115,64 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
return player;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns the board of the game
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>Board</returns>
|
|
|
|
|
public Board GetBoard() { return board; }
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates a board with a number of columns and rows
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>Board</returns>
|
|
|
|
|
public Board CreateBoard()
|
|
|
|
|
{
|
|
|
|
|
board = new Board(15, 12);
|
|
|
|
|
return board;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates a bag of tiles with a number of sets of 36 tiles
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="nbSet"></param>
|
|
|
|
|
/// <returns>TileBag</returns>
|
|
|
|
|
public TileBag CreateTileBag(int nbSet)
|
|
|
|
|
{
|
|
|
|
|
bag = new TileBag(nbSet);
|
|
|
|
|
return bag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Starts the game if there are at least 2 players and at most 4 players
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void StartGame()
|
|
|
|
|
{
|
|
|
|
|
if (players.Count < 2 || players.Count >= 5) return;
|
|
|
|
|
GameRunning = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Adds a cell to the list of cells used by the player in his turn if the cell is not null
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="c"></param>
|
|
|
|
|
public void AddCellUsed(Cell? c)
|
|
|
|
|
{
|
|
|
|
|
if (c != null) cellUsed.Add(c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Empty the list of cells used by the player at the end of his turn
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void EmptyCellUsed()
|
|
|
|
|
{
|
|
|
|
|
cellUsed.Clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the player who is currently playing
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>Player</returns>
|
|
|
|
|
/// <exception cref="ArgumentException"></exception>
|
|
|
|
|
public Player GetPlayingPlayer()
|
|
|
|
|
{
|
|
|
|
|
if (GetPlayingPlayerPosition() == -1)
|
|
|
|
@ -142,6 +182,10 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
return players[GetPlayingPlayerPosition()];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the position of the player who is currently playing
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>int</returns>
|
|
|
|
|
public int GetPlayingPlayerPosition()
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < players.Count; i++)
|
|
|
|
@ -154,11 +198,19 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns the tile of the player who is currently playing at the position postile
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="postile"></param>
|
|
|
|
|
/// <returns>Tile</returns>
|
|
|
|
|
public Tile TileOfPlayerWithPos(int postile)
|
|
|
|
|
{
|
|
|
|
|
return players[GetPlayingPlayerPosition()].Tiles[postile];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gives random picked tiles to the players at the beginning of the game
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void GiveTilesToPlayers()
|
|
|
|
|
{
|
|
|
|
|
foreach (var p in players)
|
|
|
|
@ -173,6 +225,11 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sets the first player of the game at the beginning of the game
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>string</returns>
|
|
|
|
|
/// <exception cref="ArgumentException"></exception>
|
|
|
|
|
public string SetFirstPlayer()
|
|
|
|
|
{
|
|
|
|
|
if (GameRunning)
|
|
|
|
@ -181,13 +238,13 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
OnNextPlayer(new NextPlayerNotifiedEventArgs(players[0]));
|
|
|
|
|
return players[0].NameTag;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException("Game is not running");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Sets the next player of the game. If there's no current player, it sets the first player
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public string SetNextPlayer()
|
|
|
|
|
{
|
|
|
|
|
int i = GetPlayingPlayerPosition();
|
|
|
|
@ -204,6 +261,14 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
return players[GetPlayingPlayerPosition()].NameTag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Allows the player to place a tile on the board at a (x, y) position
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="player"></param>
|
|
|
|
|
/// <param name="tile"></param>
|
|
|
|
|
/// <param name="x"></param>
|
|
|
|
|
/// <param name="y"></param>
|
|
|
|
|
/// <returns>bool</returns>
|
|
|
|
|
public bool PlaceTile(Player player, Tile tile, int x, int y)
|
|
|
|
|
{
|
|
|
|
|
if (!IsMoveCorrect(tile, x, y, board)) return false;
|
|
|
|
@ -242,6 +307,12 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Allows a player to swap some of his tile with the ones in the bag if he can't play them
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="player"></param>
|
|
|
|
|
/// <param name="tilesToSwap"></param>
|
|
|
|
|
/// <returns>bool</returns>
|
|
|
|
|
public bool SwapTiles(Player player, List<Tile> tilesToSwap)
|
|
|
|
|
{
|
|
|
|
|
if (tilesToSwap.Count == 0)
|
|
|
|
@ -270,6 +341,16 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Extension of IsMoveCorrect to check beyond the surrounding cells of the cell where the tile is placed
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="tile"></param>
|
|
|
|
|
/// <param name="x"></param>
|
|
|
|
|
/// <param name="y"></param>
|
|
|
|
|
/// <param name="dx">used to get the direction on the x axis</param>
|
|
|
|
|
/// <param name="dy">used to get the direction on the y axis</param>
|
|
|
|
|
/// <param name="b"></param>
|
|
|
|
|
/// <returns>bool</returns>
|
|
|
|
|
public bool CheckExtendedSurroundingCells(Tile tile, int x, int y, int dx, int dy, Board b)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 1; i < 7; i++)
|
|
|
|
@ -302,7 +383,15 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Extension of IsMoveCorrect to check if the tiles are on the same line
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="cells"></param>
|
|
|
|
|
/// <param name="b"></param>
|
|
|
|
|
/// <param name="x"></param>
|
|
|
|
|
/// <param name="y"></param>
|
|
|
|
|
/// <returns>bool</returns>
|
|
|
|
|
public bool CheckTilesInLine(List<Cell> cells, Board b, int x, int y)
|
|
|
|
|
{
|
|
|
|
|
if (cells.Count == 0)
|
|
|
|
@ -338,6 +427,14 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Main method to check if the move the player is trying to make is correct
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="t"></param>
|
|
|
|
|
/// <param name="x"></param>
|
|
|
|
|
/// <param name="y"></param>
|
|
|
|
|
/// <param name="b"></param>
|
|
|
|
|
/// <returns>bool</returns>
|
|
|
|
|
public bool IsMoveCorrect(Tile t, int x, int y, Board b)
|
|
|
|
|
{
|
|
|
|
|
if (!b.HasOccupiedCase())
|
|
|
|
@ -398,8 +495,14 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Main method to get the score of the player after he played his turn
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="player"></param>
|
|
|
|
|
/// <param name="cellsPlayed"></param>
|
|
|
|
|
/// <param name="b"></param>
|
|
|
|
|
/// <returns>int</returns>
|
|
|
|
|
public int GetPlayerScore(Player player, ReadOnlyCollection<Cell> cellsPlayed, Board b)
|
|
|
|
|
{
|
|
|
|
|
if (cellsPlayed.Count == 0)
|
|
|
|
@ -441,6 +544,15 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
return score;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Extension of GetPlayerScore to calculate the score of the player based on the adjacent cells
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="cell"></param>
|
|
|
|
|
/// <param name="b"></param>
|
|
|
|
|
/// <param name="cellsPlayed"></param>
|
|
|
|
|
/// <param name="cellsX"></param>
|
|
|
|
|
/// <param name="cellsY"></param>
|
|
|
|
|
/// <returns>int</returns>
|
|
|
|
|
public int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection<Cell> cellsPlayed, int cellsX, int cellsY)
|
|
|
|
|
{
|
|
|
|
|
int score = 0;
|
|
|
|
@ -469,6 +581,17 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
return score;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Extension of GetPlayerScore to calculate the score of the player based on the line/column of the adjacent cells
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="cell"></param>
|
|
|
|
|
/// <param name="dx"></param>
|
|
|
|
|
/// <param name="dy"></param>
|
|
|
|
|
/// <param name="b"></param>
|
|
|
|
|
/// <param name="cellsX"></param>
|
|
|
|
|
/// <param name="cellsY"></param>
|
|
|
|
|
/// <param name="nbCellsPlayed"></param>
|
|
|
|
|
/// <returns>int</returns>
|
|
|
|
|
public int CalculateLineScore(Cell cell, int dx, int dy, Board b, int cellsX, int cellsY, int nbCellsPlayed)
|
|
|
|
|
{
|
|
|
|
|
int score = 0;
|
|
|
|
@ -499,6 +622,10 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns the list of the positions of the players who still have tiles in their bag
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>List<int></returns>
|
|
|
|
|
public List<int> CheckTilesBag()
|
|
|
|
|
{
|
|
|
|
|
List<int> playerTilesBagPos = [];
|
|
|
|
@ -518,6 +645,11 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
return playerTilesBagPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns a boolean to check if the player can play a tile on the board
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="playerTilesBagPos"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public bool CheckBoardTile(List<int> playerTilesBagPos)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < playerTilesBagPos.Count; i++)
|
|
|
|
@ -541,6 +673,11 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Main method to check if the game is over
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="player"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public bool CheckGameOver(Player player)
|
|
|
|
|
{
|
|
|
|
|
List<int> playerTilesBagPos = CheckTilesBag();
|
|
|
|
|