using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; using System.Security.Cryptography; using System.Collections; namespace QwirkleClassLibrary { public class Game : IPlayer, IRules { public Dictionary ScoreBoard = new(); private TileBag bag; public bool GameRunning { get; private set; } private Board board; public ReadOnlyCollection PlayerList => players.AsReadOnly(); private readonly List players = new(); public ReadOnlyCollection CellsUsed => cellUsed.AsReadOnly(); private readonly List cellUsed = new(); public event EventHandler? PlayerAddNotified; protected virtual void OnPlayerNotified(AddPlayerNotifiedEventArgs args) => PlayerAddNotified?.Invoke(this, args); public event EventHandler? NextPlayerNotified; protected virtual void OnNextPlayer(NextPlayerNotifiedEventArgs args) => NextPlayerNotified?.Invoke(this, args); public event EventHandler? PlaceTileNotified; protected virtual void OnPlaceTile(PlaceTileNotifiedEventArgs args) => PlaceTileNotified?.Invoke(this, args); public Game() { bag = CreateTileBag(3); board = CreateBoard(); } public bool AddPlayerInGame(string? playerTag) { if (string.IsNullOrWhiteSpace(playerTag) == true) { OnPlayerNotified(new AddPlayerNotifiedEventArgs("ERROR : The name is null or white space.")); return false; } if(this.GameRunning == true) { OnPlayerNotified(new AddPlayerNotifiedEventArgs("ERROR : The game is running.")); return false; } if (players.Count >= 4) { OnPlayerNotified(new AddPlayerNotifiedEventArgs("ERROR : The game is full.")); return false; } foreach (var p in players) { if (p.NameTag == playerTag) { OnPlayerNotified(new AddPlayerNotifiedEventArgs("ERROR : Name alreay taken")); return false; } } players.Add(CreatePlayer(playerTag)); //scores.Add(new Score(players[players.Count-1])); OnPlayerNotified(new AddPlayerNotifiedEventArgs("Player was correctly added")); return true; } public Player CreatePlayer(string playerTag) { var player = new Player(playerTag); return player; } public Board GetBoard() { return board; } public Board CreateBoard() { board = new Board(8, 8); return board; } public TileBag CreateTileBag(int nbSet) { bag = new TileBag(nbSet); return bag; } public bool StartGame() { if (players.Count < 2 || players.Count >= 5) return false; this.GameRunning = true; return true; } public void AddCellUsed(Cell? c) { if (c != null) cellUsed.Add(c); } public void EmptyCellUsed() { cellUsed.Clear(); } public Player GetPlayingPlayer() { if(GetPlayingPlayerPosition() == -1) { throw new ArgumentException(); } return players[GetPlayingPlayerPosition()]; } public int GetPlayingPlayerPosition() { for (int i = 0; i < players.Count; i++) { if (players[i].IsPlaying == true) { return i; } } return -1; } public Tile TileOfPlayerWithPos(int postile) { return players[GetPlayingPlayerPosition()].Tiles[postile]; } public void GiveTilesToPlayers() { foreach (var p in players) { for (int j = 0; j < 6; j++) { int val = RandomNumberGenerator.GetInt32(0, bag.TilesBag.Count); p.AddTileToPlayer(bag.TilesBag[val]); bag.RemoveTileInBag(bag.TilesBag[val]); } } } public string SetFirstPlayer() { if (GameRunning == true) { players[0].IsPlaying = true; //OnNextPlayer(new NextPlayerNotifiedEventArgs(players[0])); return players[0].NameTag; } else { throw new ArgumentException("Game is not running"); } } public string SetNextPlayer() { int i = GetPlayingPlayerPosition(); if (i == -1) { return SetFirstPlayer(); } players[i].IsPlaying = false; players[(i + 1) % players.Count].IsPlaying = true; OnNextPlayer(new NextPlayerNotifiedEventArgs(players[i])); return players[GetPlayingPlayerPosition()].NameTag; } public bool PlaceTile(Player player, Tile tile, int x, int y) { if (board.AddTileInCell(x, y, tile) == true) { return player.RemoveTileToPlayer(tile) == true; } else { return false; } } /// /// Allows a player to draw tiles from the bag as soon as he has less than 6 tiles /// /// /// public bool DrawTiles(Player player) { while(player.Tiles.Count < 6) { if (bag.TilesBag.Count == 0) { return false; } int val = RandomNumberGenerator.GetInt32(0, bag.TilesBag.Count + 1); player.AddTileToPlayer(bag.TilesBag[val]); bag.RemoveTileInBag(bag.TilesBag[val]); } return true; } public bool SwapTiles(Player player, List tilesToSwap) { if (tilesToSwap.Count == 0) { return false; } foreach (var t in tilesToSwap) { if (player.RemoveTileToPlayer(t) == false) { return false; } } if (DrawTiles(player) == false) { return false; } foreach (var t in tilesToSwap) { bag.AddTileInBag(t); } return true; } public bool CheckExtendedSurroundingCells(Tile tile, int x, int y, int dx, int dy, Board b) { for (int i = 1; i < 7; i++) { var extendedCell = b.GetCell(x + i * dx, y + i * dy); if (extendedCell?.GetTile == null) { break; } if (extendedCell.GetTile.GetColor != tile.GetColor && extendedCell.GetTile.GetShape != tile.GetShape) { OnPlaceTile(new PlaceTileNotifiedEventArgs(tile, "Les couleurs/formes adjacentes ne correspondes pas")); return false; } if (i == 6) { OnPlaceTile(new PlaceTileNotifiedEventArgs(tile, "La ligne ou colonne fait deja 6 tuiles !")); return false; } } return true; } public bool CheckTilesInLine(List cells, Board b, int x, int y) { if(cells.Count < 2) { return true; } var x1 = cells[0].GetX; var y1 = cells[0].GetY; var x2 = cells[1].GetX; var y2 = cells[1].GetY; if (x1 == x2) { return x == x1; } if (y1 == y2) { return y == y1; } return false; } public bool IsMoveCorrect(Tile t, int x, int y, Board b) { if (!b.HasOccupiedCase()) { if (this.PlaceTile(this.GetPlayingPlayer(), t, x, y) == true) { this.AddCellUsed(this.GetBoard().GetCell(x, y)); OnPlaceTile(new PlaceTileNotifiedEventArgs(t, "Tile correctement placé")); return true; } } var surroundingCells = new List { b.GetCell(x + 1, y), b.GetCell(x - 1, y), b.GetCell(x, y + 1), b.GetCell(x, y - 1) }; foreach (var cell in surroundingCells) { if (cell?.GetTile == null) { continue; } if (cell.GetTile.GetColor != t.GetColor && cell.GetTile.GetShape != t.GetShape) { OnPlaceTile(new PlaceTileNotifiedEventArgs(t, "Tile ne correspond pas au bonne couleur des tiles a coté")); return false; } var dx = cell.GetX - x; var dy = cell.GetY - y; if (CheckExtendedSurroundingCells(t, x, y, dx, dy, b) == false) { return false; } } if (CheckTilesInLine(this.cellUsed, b, x, y) && surroundingCells.Any(cell => cell?.GetTile != null)) { if(this.PlaceTile(this.GetPlayingPlayer(), t, x, y) == true) { this.AddCellUsed(this.GetBoard().GetCell(x, y)); OnPlaceTile(new PlaceTileNotifiedEventArgs(t, "Tile correctement placé")); return true; } OnPlaceTile(new PlaceTileNotifiedEventArgs(t, "Cell Already use")); } OnPlaceTile(new PlaceTileNotifiedEventArgs(t, "La tuile n'a pu etre placé")); return false; } // public int GetPlayerScore(Player player, List cellsPlayed, Board b) // { // // Compte le nombre de tuiles et ajoute ce nombre au score // int score = cellsPlayed.Count; // // // Check les lignes / colonnes adjacentes aux tuiles placées // for(int i= 0; i < cellsPlayed.Count; i++) // { // // A chaque tour, crée la liste des 4 cellules adjacentes à la cellule sélectionnée // var surroundingCells = new[] // { // b.GetCell(cellsPlayed[i].GetX + 1, cellsPlayed[i].GetY), // b.GetCell(cellsPlayed[i].GetX - 1, cellsPlayed[i].GetY), // b.GetCell(cellsPlayed[i].GetX, cellsPlayed[i].GetY + 1), // b.GetCell(cellsPlayed[i].GetX, cellsPlayed[i].GetY - 1) // }; // // // Parcourt le tableau dans la direction par rapport à ces cellules adjacentes // foreach (var cell in surroundingCells) // { // // Si la cellule adjacente ne contient pas de tuile, on passe à la cellule adjacente suivante // if (cell?.GetTile == null) break; // // if (cellsPlayed.Contains(cell) != true) // { // // var dx = cell.GetX - cellsPlayed[i].GetX; // var dy = cell.GetY - cellsPlayed[i].GetY; // // for (int j = 1; j < b.Rows; j++) // { // var extendedCell = b.GetCell(cellsPlayed[i].GetX + j * dx, cellsPlayed[i].GetY + j * dy); // // if (extendedCell?.GetTile == null) // { // break; // } // // score += 1; // // } // } // } // // } // // ScoreBoard.Add(player, score); // // return score; // } public int GetPlayerScore(Player player, ReadOnlyCollection cellsPlayed, Board b) { int score = cellsPlayed.Count; foreach (var cell in cellsPlayed) { score += CalculateAdjacentScore(cell, b, cellsPlayed); } if(ScoreBoard.TryAdd(player, score) == false) { ScoreBoard[player] += score; } return score; } private int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection cellsPlayed) { int score = 0; var surroundingCells = new[] { b.GetCell(cell.GetX + 1, cell.GetY), b.GetCell(cell.GetX - 1, cell.GetY), b.GetCell(cell.GetX, cell.GetY + 1), b.GetCell(cell.GetX, cell.GetY - 1) }; foreach (var adjacentCell in surroundingCells) { if (adjacentCell?.GetTile == null || cellsPlayed.Contains(adjacentCell)) { continue; } int dx = adjacentCell.GetX - cell.GetX; int dy = adjacentCell.GetY - cell.GetY; score += CalculateLineScore(cell, dx, dy, b); } return score; } private int CalculateLineScore(Cell cell, int dx, int dy, Board b) { int score = 0; for (int i = 1; i < b.Rows; i++) { var extendedCell = b.GetCell(cell.GetX + i * dx, cell.GetY + i * dy); if (extendedCell?.GetTile == null) { break; } score++; } return score; } public bool IsGameOver() { return true; } } }