Compare commits

..

No commits in common. 'master' and 'old_branch_remy' have entirely different histories.

File diff suppressed because one or more lines are too long

@ -53,16 +53,16 @@ namespace QwirkleClassLibrary.Boards
{ {
for (int b = 0; b < Columns; b++) for (int b = 0; b < Columns; b++)
{ {
Cell localcell = new(b, a); Cell localcell = new(a, b);
cells.Add(localcell); cells.Add(localcell);
} }
} }
} }
/// <summary> /// <summary>
/// This method is used to check if a cell in the board whether already contains a tile or not. /// This method is used to check if a cell in the board whether it already contains a tile or not.
/// </summary> /// </summary>
/// <returns>Returns a boolean : true if the cell doesn't contain any tile, false if already contains a tile.</returns> /// <returns>Returns a boolean : true if the cell doesn't contain any tile, false if it already contains a tile.</returns>
public bool HasOccupiedCase() public bool HasOccupiedCase()
{ {
foreach (var cell in cells) foreach (var cell in cells)

@ -4,15 +4,11 @@ using System.Runtime.CompilerServices;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using QwirkleClassLibrary.Tiles; using QwirkleClassLibrary.Tiles;
namespace QwirkleClassLibrary.Boards namespace QwirkleClassLibrary.Boards;
{
/// <summary> [DataContract]
/// Our board is made with a list of this class. It can stock infos such as its position on the board and the tile it contains. public class Cell : INotifyPropertyChanged
/// </summary> {
[DataContract]
public class Cell : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged; public event PropertyChangedEventHandler? PropertyChanged;
[DataMember] [DataMember]
@ -22,7 +18,7 @@ namespace QwirkleClassLibrary.Boards
private readonly int y; private readonly int y;
[DataMember] [DataMember]
public Tile? Tile { get; private set; } public Tile? Tile { get; private set;}
/// <summary> /// <summary>
/// This is the constructor for a Cell. /// This is the constructor for a Cell.
@ -60,12 +56,12 @@ namespace QwirkleClassLibrary.Boards
} }
/// <summary> /// <summary>
/// Checks if the Cell whether is empty or contains a tile. /// Check if the Cell whether is empty or contains a tile.
/// </summary> /// </summary>
/// <returns>True if the cell is empty, false if the cell contains a tile.</returns> /// <returns>True if the cell is empty, false if the cell contains a tile.</returns>
public bool IsFree public bool IsFree
{ {
get { return Tile! == null!; } get { return Tile == null; }
} }
@ -76,7 +72,7 @@ namespace QwirkleClassLibrary.Boards
/// <returns>True if added succefully (if the cell didn't already contain a tile), false if there already was a tile in this cell.</returns> /// <returns>True if added succefully (if the cell didn't already contain a tile), false if there already was a tile in this cell.</returns>
public bool SetTile(Tile addedTile) public bool SetTile(Tile addedTile)
{ {
if (Tile! == null!) if (Tile == null)
{ {
Tile = addedTile; Tile = addedTile;
@ -93,5 +89,4 @@ namespace QwirkleClassLibrary.Boards
{ {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
} }
}
} }

@ -7,37 +7,43 @@ using QwirkleClassLibrary.Events;
using QwirkleClassLibrary.Players; using QwirkleClassLibrary.Players;
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using static System.Formats.Asn1.AsnWriter;
namespace QwirkleClassLibrary.Games namespace QwirkleClassLibrary.Games
{ {
/// <summary>
/// This is our main class for the Qwirkle application, taking care of the good efficiency of the game.
/// </summary>
[DataContract] [DataContract]
public class Game : IPlayer, IRules, INotifyPropertyChanged public class Game : IPlayer, IRules, INotifyPropertyChanged
{ {
[DataMember] private TileBag? bag = null; [DataMember]
private TileBag? bag = null;
[DataMember] public bool GameRunning { get; set; } [DataMember]
public bool GameRunning { get; set; }
[DataMember] private Board board = new(17, 14); [DataMember]
private Board board = new(17, 14);
public bool PlayerSwapping { get; set; } public bool PlayerSwapping { get; set; }
public Board Board => board; public Board Board => board;
public ReadOnlyCollection<Player> PlayerList => players.AsReadOnly(); public ReadOnlyCollection<Player> PlayerList => players.AsReadOnly();
[DataMember] private readonly List<Player> players = []; [DataMember]
private readonly List<Player> players = [];
[DataMember] private readonly Dictionary<string, int> scoreBoard = new Dictionary<string, int>(); [DataMember]
private readonly Dictionary<string, int> scoreBoard = new Dictionary<string, int>();
public ReadOnlyDictionary<string, int> ScoreBoard => scoreBoard.AsReadOnly(); public ReadOnlyDictionary<string, int> ScoreBoard => scoreBoard.AsReadOnly();
[DataMember] private readonly ObservableCollection<KeyValuePair<string, int>> observableScoreBoard = []; [DataMember]
private readonly ObservableCollection<KeyValuePair<string, int>> observableScoreBoard = [];
public ReadOnlyObservableCollection<KeyValuePair<string, int>> ObservableScoreBoard => public ReadOnlyObservableCollection<KeyValuePair<string, int>> ObservableScoreBoard =>
new(observableScoreBoard); new(observableScoreBoard);
[DataMember] private readonly List<Cell> cellUsed = []; [DataMember]
private readonly List<Cell> cellUsed = [];
public ReadOnlyCollection<Cell> CellsUsed => cellUsed.AsReadOnly(); public ReadOnlyCollection<Cell> CellsUsed => cellUsed.AsReadOnly();
@ -98,11 +104,9 @@ namespace QwirkleClassLibrary.Games
if (playersTag.Count <= 1 || playersTag.Count > 4) if (playersTag.Count <= 1 || playersTag.Count > 4)
{ {
playersTag.Clear(); playersTag.Clear();
OnPlayerNotified(new AddPlayerNotifiedEventArgs( OnPlayerNotified(new AddPlayerNotifiedEventArgs("ERROR : It takes a minimum of 2 players and a maximum of 4 players to start a game."));
"ERROR : It takes a minimum of 2 players and a maximum of 4 players to start a game."));
return false; return false;
} }
for (int i = playersTag.Count - 1; i >= 0; i--) for (int i = playersTag.Count - 1; i >= 0; i--)
{ {
if (!CheckPlayerTag(playersTag, i)) if (!CheckPlayerTag(playersTag, i))
@ -122,18 +126,12 @@ namespace QwirkleClassLibrary.Games
OnPlayerNotified(new AddPlayerNotifiedEventArgs("Players were correctly added.")); OnPlayerNotified(new AddPlayerNotifiedEventArgs("Players were correctly added."));
return true; return true;
} }
/// <summary>
/// This function is used to check if the player name that the user has entered meets the criteria set by the application.
/// </summary>
/// <param name="playersTag">A list that contains all the names entered when the game was started.</param>
/// <param name="pos">The position of the name we want to check in this list.</param>
/// <returns>boolean true if everything is okay, false if there was a problem in the player name.</returns>
public bool CheckPlayerTag(List<string> playersTag, int pos) public bool CheckPlayerTag(List<string> playersTag, int pos)
{ {
if (string.IsNullOrWhiteSpace(playersTag[pos])) if (string.IsNullOrWhiteSpace(playersTag[pos]))
{ {
OnPlayerNotified(new AddPlayerNotifiedEventArgs("ERROR with " + (pos + 1) + OnPlayerNotified(new AddPlayerNotifiedEventArgs("ERROR with " + (pos + 1) + " entry : The name is null or white space."));
" entry : The name is null or white space."));
return false; return false;
} }
@ -150,6 +148,7 @@ namespace QwirkleClassLibrary.Games
new AddPlayerNotifiedEventArgs("ERROR with " + (pos + 1) + " entry : Name alreay taken")); new AddPlayerNotifiedEventArgs("ERROR with " + (pos + 1) + " entry : Name alreay taken"));
return false; return false;
} }
} }
return true; return true;
@ -171,19 +170,13 @@ namespace QwirkleClassLibrary.Games
/// Returns the Board of the game /// Returns the Board of the game
/// </summary> /// </summary>
/// <returns>Board</returns> /// <returns>Board</returns>
public Board GetBoard() public Board? GetBoard() { return board; }
{
return board;
}
/// <summary> /// <summary>
/// Returns the tile bag of the game /// Returns the tile bag of the game
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public TileBag? GetTileBag() public TileBag? GetTileBag() { return bag; }
{
return bag;
}
/// <summary> /// <summary>
/// Creates a Board with a number of columns and rows /// Creates a Board with a number of columns and rows
@ -245,7 +238,6 @@ namespace QwirkleClassLibrary.Games
{ {
throw new ArgumentException("No player currently playing !"); throw new ArgumentException("No player currently playing !");
} }
return players[GetPlayingPlayerPosition()]; return players[GetPlayingPlayerPosition()];
} }
@ -262,7 +254,6 @@ namespace QwirkleClassLibrary.Games
return i; return i;
} }
} }
return -1; return -1;
} }
@ -325,6 +316,7 @@ namespace QwirkleClassLibrary.Games
startingPlayer!.IsPlaying = true; startingPlayer!.IsPlaying = true;
OnNextPlayer(new NextPlayerNotifiedEventArgs(players[0])); OnNextPlayer(new NextPlayerNotifiedEventArgs(players[0]));
return startingPlayer.NameTag; return startingPlayer.NameTag;
} }
/// <summary> /// <summary>
@ -362,15 +354,13 @@ namespace QwirkleClassLibrary.Games
OnPlaceTile(new PlaceTileNotifiedEventArgs(tile, "you are swapping, you can't place tile !")); OnPlaceTile(new PlaceTileNotifiedEventArgs(tile, "you are swapping, you can't place tile !"));
return false; return false;
} }
if (!TileInbag(player, tile)) if (!TileInbag(player, tile))
{ {
OnPlaceTile(new PlaceTileNotifiedEventArgs(tile, "you can't play")); OnPlaceTile(new PlaceTileNotifiedEventArgs(tile, "you can't play"));
return false; return false;
} }
if (!IsMoveCorrect(tile, x, y, board!)) return false;
if (!IsMoveCorrect(tile, x, y, board)) return false; if (board!.AddTileInCell(x, y, tile))
if (board.AddTileInCell(x, y, tile))
{ {
AddCellUsed(board.GetCell(x, y)); AddCellUsed(board.GetCell(x, y));
return player.RemoveTileToPlayer(tile); return player.RemoveTileToPlayer(tile);
@ -456,12 +446,12 @@ namespace QwirkleClassLibrary.Games
{ {
players[GetPlayingPlayerPosition()].AddTileToPlayer(t); players[GetPlayingPlayerPosition()].AddTileToPlayer(t);
} }
} }
/// <summary> /// <summary>
/// Extension of IsMoveCorrect to check beyond the surrounding cells of the cell where the tile is placed /// Extension of IsMoveCorrect to check beyond the surrounding cells of the cell where the tile is placed
/// </summary> /// </summary>
/// <param name="previousTilesFound"></param>
/// <param name="tile"></param> /// <param name="tile"></param>
/// <param name="x"></param> /// <param name="x"></param>
/// <param name="y"></param> /// <param name="y"></param>
@ -469,39 +459,26 @@ namespace QwirkleClassLibrary.Games
/// <param name="dy">used to get the direction on the y axis</param> /// <param name="dy">used to get the direction on the y axis</param>
/// <param name="b"></param> /// <param name="b"></param>
/// <returns>bool</returns> /// <returns>bool</returns>
public bool CheckExtendedSurroundingCells(ref bool previousTilesFound, Tile tile, int x, int y, int dx, int dy, public bool CheckExtendedSurroundingCells(Tile tile, int x, int y, int dx, int dy, Board b)
Board b)
{ {
for (int i = 1; i < 7; i++) for (int i = 1; i < 7; i++)
{ {
var extendedCell = b.GetCell(x + i * dx, y + i * dy); var extendedCell = b.GetCell(x + i * dx, y + i * dy);
if (cellUsed.Count == 0) if (extendedCell?.Tile == null)
{
previousTilesFound = true;
}
if (cellUsed.Contains(extendedCell!))
{
previousTilesFound = true;
}
if (extendedCell?.Tile! == null!)
{ {
break; break;
} }
if (extendedCell.Tile.GetColor != tile.GetColor && extendedCell.Tile.GetShape != tile.GetShape) if (extendedCell.Tile.GetColor != tile.GetColor && extendedCell.Tile.GetShape != tile.GetShape)
{ {
OnPlaceTile(new PlaceTileNotifiedEventArgs(tile, OnPlaceTile(new PlaceTileNotifiedEventArgs(tile, " : Color / Shape does not match with the surrounding tiles !"));
" : Color / Shape does not match with the surrounding tiles !"));
return false; return false;
} }
if (extendedCell.Tile.GetColor == tile.GetColor && extendedCell.Tile.GetShape == tile.GetShape) if (extendedCell.Tile.GetColor == tile.GetColor && extendedCell.Tile.GetShape == tile.GetShape)
{ {
OnPlaceTile(new PlaceTileNotifiedEventArgs(tile, OnPlaceTile(new PlaceTileNotifiedEventArgs(tile, " : Tile already placed on the same line / column !"));
" : Tile already placed on the same line / column !"));
return false; return false;
} }
@ -550,7 +527,6 @@ namespace QwirkleClassLibrary.Games
{ {
return x == x1; return x == x1;
} }
if (y1 == y2) if (y1 == y2)
{ {
return y == y1; return y == y1;
@ -560,62 +536,13 @@ namespace QwirkleClassLibrary.Games
} }
/// <summary> /// <summary>
/// Check that there isn't any same tile on a said line when a tile is forming a line /// Main method to check if the move the player is trying to make is correct
/// </summary> /// </summary>
/// <param name="t1"></param> /// <param name="t"></param>
/// <param name="nbTiles"></param>
/// <param name="checkdoubles"></param>
/// <returns></returns>
public static bool CheckTileInCompletedLines(Tile? t1, ref int nbTiles, ref List<Tile> checkdoubles)
{
if (t1! != null!)
{
nbTiles++;
if (checkdoubles.Any(t => t.CompareTo(t1) == 0))
{
return false;
}
checkdoubles.Add(t1);
}
return true;
}
/// <summary>
/// Check if the line is completed with the tile placed
/// </summary>
/// <param name="tile"></param>
/// <param name="x"></param> /// <param name="x"></param>
/// <param name="y"></param> /// <param name="y"></param>
/// <param name="dx"></param>
/// <param name="dy"></param>
/// <param name="b"></param> /// <param name="b"></param>
/// <param name="checkdoubles"></param> /// <returns>bool</returns>
/// <returns></returns>
public static bool CheckWrongCompletedLines(int x, int y, int dx, int dy, Board b, ref List<Tile> checkdoubles)
{
int nbTiles = 1;
for (int i = 1; i < 7; i++)
{
var extendedCell = b.GetCell(x + i * dx, y + i * dy);
var extendedCell2 = b.GetCell(x - i * dx, y - i * dy);
if (extendedCell?.Tile! == null! && extendedCell2?.Tile! == null!)
{
break;
}
if(!CheckTileInCompletedLines(extendedCell?.Tile, ref nbTiles, ref checkdoubles)) return false;
if(!CheckTileInCompletedLines(extendedCell2?.Tile, ref nbTiles, ref checkdoubles)) return false;
}
return nbTiles <= 6;
}
public bool IsMoveCorrect(Tile t, int x, int y, Board b) public bool IsMoveCorrect(Tile t, int x, int y, Board b)
{ {
if (!b.HasOccupiedCase()) if (!b.HasOccupiedCase())
@ -623,10 +550,9 @@ namespace QwirkleClassLibrary.Games
return true; return true;
} }
if (b.GetCell(x, y)!.Tile! != null!) if (b.GetCell(x, y)!.Tile != null)
{ {
OnPlaceTile(new PlaceTileNotifiedEventArgs(t, " : Cell already used !")); OnPlaceTile(new PlaceTileNotifiedEventArgs(t, " : Cell already used !"));
return false;
} }
var surroundingCells = new List<Cell?> var surroundingCells = new List<Cell?>
@ -637,69 +563,51 @@ namespace QwirkleClassLibrary.Games
b.GetCell(x, y - 1) b.GetCell(x, y - 1)
}; };
if (surroundingCells.All(cell => cell?.Tile! == null!))
{
OnPlaceTile(new PlaceTileNotifiedEventArgs(t,
" : You can't place a tile that isn't adjacent to another one !"));
return false;
}
return IsTilePlacementCorrect(t, x, y, b, surroundingCells);
}
public bool IsTilePlacementCorrect(Tile t, int x, int y, Board b, List<Cell?> surroundingCells)
{
bool previousTilesFound = false;
var checkDoubles = new List<Tile>();
foreach (var cell in surroundingCells) foreach (var cell in surroundingCells)
{ {
if (cell?.Tile! == null!) if (cell?.Tile == null)
{ {
continue; continue;
} }
if (cell.Tile.GetColor != t.GetColor && cell.Tile.GetShape != t.GetShape) if (cell.Tile.GetColor != t.GetColor && cell.Tile.GetShape != t.GetShape)
{ {
OnPlaceTile(new PlaceTileNotifiedEventArgs(t, OnPlaceTile(new PlaceTileNotifiedEventArgs(t, " : Colors / Shapes do not match with the surrounding tiles !"));
" : Colors / Shapes do not match with the surrounding tiles !"));
return false; return false;
} }
if (cell.Tile.GetColor == t.GetColor && cell.Tile.GetShape == t.GetShape) if (cell.Tile.GetColor == t.GetColor && cell.Tile.GetShape == t.GetShape)
{ {
OnPlaceTile(new PlaceTileNotifiedEventArgs(t, " is already placed on the same line / column !")); OnPlaceTile(new PlaceTileNotifiedEventArgs(t, " is already placed on the same line / column !"));
return false; return false;
} }
var dx = cell.GetX - x; var dx = cell.GetX - x;
var dy = cell.GetY - y; var dy = cell.GetY - y;
if (!CheckExtendedSurroundingCells(ref previousTilesFound, t, x, y, dx, dy, b)) if (!CheckExtendedSurroundingCells(t, x, y, dx, dy, b))
{ {
return false; return false;
} }
if (CheckWrongCompletedLines(x, y, dx, dy, b, ref checkDoubles)) continue;
OnPlaceTile(new PlaceTileNotifiedEventArgs(t,
" : You can't complete this line ! (More than 6 tiles / same tiles on the line)"));
return false;
} }
if (!CheckTilesInLine(cellUsed, b, x, y)) if (!CheckTilesInLine(cellUsed, b, x, y))
{ {
OnPlaceTile(new PlaceTileNotifiedEventArgs(t, OnPlaceTile(new PlaceTileNotifiedEventArgs(t, "isn't on the same line as the ones previously placed !"));
"isn't on the same line as the ones previously placed !"));
return false; return false;
} }
if (previousTilesFound) return true; if (surroundingCells.All(cell => cell?.Tile == null))
OnPlaceTile(new PlaceTileNotifiedEventArgs(t, {
" : You must place your tile next / on the same line as the ones previously placed !")); OnPlaceTile(new PlaceTileNotifiedEventArgs(t, " : You can't place a tile that isn't adjacent to another one !"));
return false; return false;
} }
return true;
}
/// <summary> /// <summary>
/// Main method to get the score of the player after he played his turn /// Main method to get the score of the player after he played his turn
@ -717,9 +625,6 @@ namespace QwirkleClassLibrary.Games
int score = cellsPlayed.Count; int score = cellsPlayed.Count;
int nbCellsInLine = cellsPlayed.Count; int nbCellsInLine = cellsPlayed.Count;
int nbCellsInPerpLine = 1;
var checkedCells = new List<Cell>();
if (cellsPlayed.Count == 6) if (cellsPlayed.Count == 6)
{ {
@ -749,16 +654,16 @@ namespace QwirkleClassLibrary.Games
cellsX = cellsY = -1; cellsX = cellsY = -1;
} }
score += cellsPlayed.Sum(cell => score += cellsPlayed.Sum(cell => CalculateAdjacentScore(cell, b, cellsPlayed, cellsX, cellsY, ref nbCellsInLine));
CalculateAdjacentScore(cell, b, cellsPlayed, new Tuple<int, int>(cellsX, cellsY), ref nbCellsInLine, ref nbCellsInPerpLine, ref checkedCells));
if (nbCellsInLine == 6 || nbCellsInPerpLine == 6) if (nbCellsInLine == 6)
{ {
score += 6; score += 6;
} }
if (!scoreBoard.TryAdd(player.NameTag, score)) if (!scoreBoard.TryAdd(player.NameTag, score))
{ {
scoreBoard.TryGetValue(player.NameTag, out int scoreold); scoreBoard.TryGetValue(player.NameTag, out int scoreold);
SetScoreBoard(player.NameTag, score + scoreold); SetScoreBoard(player.NameTag, score + scoreold);
} }
@ -772,12 +677,11 @@ namespace QwirkleClassLibrary.Games
/// <param name="cell"></param> /// <param name="cell"></param>
/// <param name="b"></param> /// <param name="b"></param>
/// <param name="cellsPlayed"></param> /// <param name="cellsPlayed"></param>
/// <param name="orientation"></param> /// <param name="cellsX"></param>
/// <param name="nbCellsInPerpLine"></param> /// <param name="cellsY"></param>
/// <param name="checkedCells"></param>
/// <param name="nbCellsInLine"></param> /// <param name="nbCellsInLine"></param>
/// <returns>int</returns> /// <returns>int</returns>
public int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection<Cell> cellsPlayed, Tuple<int, int> orientation, ref int nbCellsInLine, ref int nbCellsInPerpLine, ref List<Cell> checkedCells) public int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection<Cell> cellsPlayed, int cellsX, int cellsY, ref int nbCellsInLine)
{ {
int score = 0; int score = 0;
@ -789,10 +693,11 @@ namespace QwirkleClassLibrary.Games
b.GetCell(cell.GetX, cell.GetY - 1) b.GetCell(cell.GetX, cell.GetY - 1)
}; };
var checkedSurroundingCells = new List<Cell>();
foreach (var adjacentCell in surroundingCells) foreach (var adjacentCell in surroundingCells)
{ {
if (adjacentCell?.Tile! == null! || cellsPlayed.Contains(adjacentCell) || if (adjacentCell?.Tile == null || cellsPlayed.Contains(adjacentCell) || checkedSurroundingCells.Contains(adjacentCell))
checkedCells.Contains(adjacentCell))
{ {
continue; continue;
} }
@ -800,10 +705,9 @@ namespace QwirkleClassLibrary.Games
int dx = adjacentCell.GetX - cell.GetX; int dx = adjacentCell.GetX - cell.GetX;
int dy = adjacentCell.GetY - cell.GetY; int dy = adjacentCell.GetY - cell.GetY;
score += CalculateLineScore(cellsPlayed, cell, new Tuple<int, int>(dx, dy), score += CalculateLineScore(cellsPlayed, cell, new Tuple<int, int>(dx, dy), b, new Tuple<int, int>(cellsX, cellsY), ref nbCellsInLine);
new Tuple<int, int>(orientation.Item1, orientation.Item2), ref nbCellsInLine, ref nbCellsInPerpLine, ref checkedCells);
checkedCells.Add(adjacentCell); checkedSurroundingCells.Add(adjacentCell);
} }
return score; return score;
@ -815,20 +719,19 @@ namespace QwirkleClassLibrary.Games
/// <param name="cellsPlayed"></param> /// <param name="cellsPlayed"></param>
/// <param name="cell"></param> /// <param name="cell"></param>
/// <param name="direction"></param> /// <param name="direction"></param>
/// <param name="b"></param>
/// <param name="orientation"></param> /// <param name="orientation"></param>
/// <param name="nbCellsInLine"></param> /// <param name="nbCellsInLine"></param>
/// <param name="nbCellsInPerpLine"></param>
/// <param name="checkedCells"></param>
/// <returns>int</returns> /// <returns>int</returns>
public int CalculateLineScore(ReadOnlyCollection<Cell> cellsPlayed, Cell cell, Tuple<int, int> direction, Tuple<int, int> orientation, ref int nbCellsInLine, ref int nbCellsInPerpLine, ref List<Cell> checkedCells) public int CalculateLineScore(ReadOnlyCollection<Cell> cellsPlayed, Cell cell, Tuple<int, int> direction, Board b, Tuple<int, int> orientation, ref int nbCellsInLine)
{ {
int score = 0; int score = 0;
for (int i = 1; i < 6; i++) for (int i = 1; i < 6; i++)
{ {
var extendedCell = board.GetCell(cell.GetX + i * direction.Item1, cell.GetY + i * direction.Item2); var extendedCell = b.GetCell(cell.GetX + i * direction.Item1, cell.GetY + i * direction.Item2);
if (extendedCell?.Tile! == null! || cellsPlayed.Contains(extendedCell) || checkedCells.Contains(extendedCell)) if (extendedCell?.Tile == null || cellsPlayed.Contains(extendedCell))
{ {
break; break;
} }
@ -838,16 +741,10 @@ namespace QwirkleClassLibrary.Games
nbCellsInLine++; nbCellsInLine++;
} }
if (direction.Item1 != 0 && orientation.Item1 != -1 || direction.Item2 != 0 && orientation.Item2 != -1)
{
nbCellsInPerpLine++;
}
checkedCells.Add(extendedCell);
score++; score++;
} }
if (ShouldIncreaseScore(direction, orientation)) if (direction.Item1 == 0 && orientation.Item1 == -1 && orientation.Item2 != -1 || direction.Item2 == 0 && orientation.Item2 == -1 && orientation.Item1 != -1)
{ {
score += 1; score += 1;
} }
@ -855,11 +752,6 @@ namespace QwirkleClassLibrary.Games
return score; return score;
} }
public static bool ShouldIncreaseScore(Tuple<int, int> direction, Tuple<int, int> orientation)
{
return direction.Item1 == 0 && orientation.Item1 == -1 && orientation.Item2 != -1 ||
direction.Item2 == 0 && orientation.Item2 == -1 && orientation.Item1 != -1;
}
/// <summary> /// <summary>
/// Returns the list of the positions of the players who still have tiles in their bag /// Returns the list of the positions of the players who still have tiles in their bag
@ -878,6 +770,7 @@ namespace QwirkleClassLibrary.Games
playerTilesBagPos.Add(i); playerTilesBagPos.Add(i);
} }
} }
} }
return playerTilesBagPos; return playerTilesBagPos;
@ -894,7 +787,7 @@ namespace QwirkleClassLibrary.Games
{ {
foreach (var t in players[t1].Tiles) foreach (var t in players[t1].Tiles)
{ {
for (int b = 0; b < board.ReadCells.Count; b++) for (int b = 0; b < board!.ReadCells.Count; b++)
{ {
int x = board.ReadCells[b].GetX; int x = board.ReadCells[b].GetX;
int y = board.ReadCells[b].GetY; int y = board.ReadCells[b].GetY;
@ -920,8 +813,7 @@ namespace QwirkleClassLibrary.Games
{ {
List<int> playerTilesBagPos = CheckTilesBag(); List<int> playerTilesBagPos = CheckTilesBag();
if (playerTilesBagPos.Count != 0 && !CheckPlacementPossibilities(playerTilesBagPos) || if (playerTilesBagPos.Count != 0 && !CheckPlacementPossibilities(playerTilesBagPos) || bag!.TilesBag!.Count == 0 && players[GetPlayingPlayerPosition()].Tiles.Count == 0)
bag!.TilesBag!.Count == 0 && players[GetPlayingPlayerPosition()].Tiles.Count == 0)
{ {
OnEndOfGame(new EndOfGameNotifiedEventArgs(player)); OnEndOfGame(new EndOfGameNotifiedEventArgs(player));
GameRunning = false; GameRunning = false;
@ -946,6 +838,7 @@ namespace QwirkleClassLibrary.Games
public void SetScoreBoard(string name, int score) public void SetScoreBoard(string name, int score)
{ {
if (!scoreBoard.TryAdd(name, score)) if (!scoreBoard.TryAdd(name, score))
{ {
scoreBoard[name] = score; scoreBoard[name] = score;
@ -956,7 +849,6 @@ namespace QwirkleClassLibrary.Games
{ {
observableScoreBoard.Add(item); observableScoreBoard.Add(item);
} }
OnPropertyChanged(nameof(ObservableScoreBoard)); OnPropertyChanged(nameof(ObservableScoreBoard));
} }
} }

@ -3,14 +3,10 @@ using QwirkleClassLibrary.Boards;
using QwirkleClassLibrary.Players; using QwirkleClassLibrary.Players;
using QwirkleClassLibrary.Tiles; using QwirkleClassLibrary.Tiles;
namespace QwirkleClassLibrary.Games namespace QwirkleClassLibrary.Games;
{
/// <summary> public interface IPlayer
/// This interface is used for all methods related to the player, such as the moves he can make. {
/// </summary>
public interface IPlayer
{
public Player CreatePlayer(string playerTag); public Player CreatePlayer(string playerTag);
public string SetNextPlayer(); public string SetNextPlayer();
@ -25,10 +21,7 @@ namespace QwirkleClassLibrary.Games
public int GetPlayerScore(Player player, ReadOnlyCollection<Cell> cellsPlayed, Board b); public int GetPlayerScore(Player player, ReadOnlyCollection<Cell> cellsPlayed, Board b);
int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection<Cell> cellsPlayed, Tuple<int, int> orientation, int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection<Cell> cellsPlayed, int cellsX, int cellsY, ref int nbCellsInLine);
ref int nbCellsInLine, ref int nbCellsInPerpLine, ref List<Cell> checkedCells);
int CalculateLineScore(ReadOnlyCollection<Cell> cellsPlayed, Cell cell, Tuple<int, int> direction, int CalculateLineScore(ReadOnlyCollection<Cell> cellsPlayed, Cell cell, Tuple<int, int> direction, Board b, Tuple<int, int> orientation, ref int nbCellsInLine);
Tuple<int, int> orientation, ref int nbCellsInLine, ref int nbCellsInPerpLine, ref List<Cell> checkedCells);
}
} }

@ -9,9 +9,6 @@ using QwirkleClassLibrary.Tiles;
namespace QwirkleClassLibrary.Games namespace QwirkleClassLibrary.Games
{ {
/// <summary>
/// This interface is used to define the functions used in the game. It is mainly about all the rules of the games, checking if the player moves are correct.
/// </summary>
public interface IRules public interface IRules
{ {
Board CreateBoard(); Board CreateBoard();
@ -20,7 +17,7 @@ namespace QwirkleClassLibrary.Games
bool IsMoveCorrect(Tile t, int x, int y, Board b); bool IsMoveCorrect(Tile t, int x, int y, Board b);
bool CheckExtendedSurroundingCells(ref bool previousTilesFound, Tile tile, int x, int y, int dx, int dy, Board b); bool CheckExtendedSurroundingCells(Tile tile, int x, int y, int dx, int dy, Board b);
bool CheckTilesInLine(List<Cell> cells, Board b, int x, int y); bool CheckTilesInLine(List<Cell> cells, Board b, int x, int y);

@ -1,17 +1,10 @@
using System.Runtime.Serialization; using System.Runtime.Serialization;
using QwirkleClassLibrary.Games; using QwirkleClassLibrary.Games;
namespace QwirkleClassLibrary.Persistences namespace QwirkleClassLibrary.Persistences;
public class GamePersistenceXml : IGamePersistence
{ {
/// <summary>
/// This class takes care of managing persistence with regard to the information of the current game, allowing the last game played to be resumed even when returning to the menu or exiting the application.
/// </summary>
public class GamePersistenceXml : IGamePersistence
{
/// <summary>
/// The main purpose of this method is to save the data from the game when the user quits the app, so players can continue it later.
/// </summary>
/// <param name="game"></param>
public void SaveGame(Game game) public void SaveGame(Game game)
{ {
var serializer = new DataContractSerializer(typeof(Game), var serializer = new DataContractSerializer(typeof(Game),
@ -22,10 +15,7 @@ namespace QwirkleClassLibrary.Persistences
serializer.WriteObject(writer, game); serializer.WriteObject(writer, game);
} }
} }
/// <summary>
/// This method is used to retrieve the information needed to resume the last game launched on the application.
/// </summary>
/// <returns>A Game.</returns>
public Game LoadGame() public Game LoadGame()
{ {
var serializer = new DataContractSerializer(typeof(Game)); var serializer = new DataContractSerializer(typeof(Game));
@ -43,5 +33,4 @@ namespace QwirkleClassLibrary.Persistences
return new Game(); return new Game();
} }
} }
}
} }

@ -1,17 +1,10 @@
using System.Runtime.Serialization.Json; using System.Runtime.Serialization.Json;
using QwirkleClassLibrary.Players; using QwirkleClassLibrary.Players;
namespace QwirkleClassLibrary.Persistences namespace QwirkleClassLibrary.Persistences;
public class LeaderboardPersistenceJson : ILeaderboardPersistence
{ {
/// <summary>
/// This is the persistence class for the leaderboard : it is in charge of managing all the parameters necessary for the backup and recovery of data concerning the leaderboard.
/// </summary>
public class LeaderboardPersistenceJson : ILeaderboardPersistence
{
/// <summary>
/// As the name suggest, this class is used to save the data from the leaderboard.
/// </summary>
/// <param name="leaderboard">The current leaderboard we want to save data from.</param>
public void SaveLeaderboard(Leaderboard leaderboard) public void SaveLeaderboard(Leaderboard leaderboard)
{ {
var serializer = new DataContractJsonSerializer(typeof(Leaderboard)); var serializer = new DataContractJsonSerializer(typeof(Leaderboard));
@ -21,11 +14,7 @@ namespace QwirkleClassLibrary.Persistences
serializer.WriteObject(writer, leaderboard); serializer.WriteObject(writer, leaderboard);
} }
} }
/// <summary>
/// This method is used to load the leaderboard into the app when the application starts.
/// </summary>
/// <returns>Leaderboard</returns>
/// <exception cref="InvalidOperationException"></exception>
public Leaderboard LoadLeaderboard() public Leaderboard LoadLeaderboard()
{ {
var serializer = new DataContractJsonSerializer(typeof(Leaderboard)); var serializer = new DataContractJsonSerializer(typeof(Leaderboard));
@ -35,5 +24,4 @@ namespace QwirkleClassLibrary.Persistences
return serializer.ReadObject(reader) as Leaderboard ?? throw new InvalidOperationException(); return serializer.ReadObject(reader) as Leaderboard ?? throw new InvalidOperationException();
} }
} }
}
} }

@ -12,9 +12,6 @@ using System.Threading.Tasks;
namespace QwirkleClassLibrary.Players namespace QwirkleClassLibrary.Players
{ {
/// <summary>
/// The purpose of this class is to save data at the end of a game so players can consult it later, comparing their best scores along their games.
/// </summary>
[DataContract] [DataContract]
public class Leaderboard : INotifyPropertyChanged public class Leaderboard : INotifyPropertyChanged
{ {

@ -12,9 +12,6 @@ using QwirkleClassLibrary.Tiles;
namespace QwirkleClassLibrary.Players namespace QwirkleClassLibrary.Players
{ {
/// <summary>
/// This class is mainly used to manage the sets of tiles of players during the game.
/// </summary>
[DataContract] [DataContract]
public class Player : INotifyPropertyChanged public class Player : INotifyPropertyChanged
{ {

@ -9,9 +9,6 @@ using System.Threading.Tasks;
namespace QwirkleClassLibrary.Players namespace QwirkleClassLibrary.Players
{ {
/// <summary>
/// The main purpose of this class is to save the data of the scores during the games, allowing the app to back up data.
/// </summary>
[DataContract] [DataContract]
public class Score public class Score
{ {

@ -8,11 +8,8 @@ using System.Threading.Tasks;
namespace QwirkleClassLibrary.Tiles namespace QwirkleClassLibrary.Tiles
{ {
/// <summary>
/// This is the class for the Tile, it defines what it is and what can be done with it.
/// </summary>
[DataContract] [DataContract]
public class Tile : IComparable public class Tile
{ {
[DataMember] [DataMember]
private readonly Shape shape; private readonly Shape shape;
@ -44,13 +41,19 @@ namespace QwirkleClassLibrary.Tiles
/// A getter for the shape of the Tile. /// A getter for the shape of the Tile.
/// </summary> /// </summary>
/// <returns>The shape attribute of the Tile.</returns> /// <returns>The shape attribute of the Tile.</returns>
public Shape GetShape => shape; public Shape GetShape
{
get { return shape; }
}
/// <summary> /// <summary>
/// A getter for the color of the Tile. /// A getter for the color of the Tile.
/// </summary> /// </summary>
/// <returns>The color attribute of the Tile.</returns> /// <returns>The color attribute of the Tile.</returns>
public Color GetColor => color; public Color GetColor
{
get { return color; }
}
/// <summary> /// <summary>
/// This method is used to override the ToString() method. It is simply a tool to facilitate the development. /// This method is used to override the ToString() method. It is simply a tool to facilitate the development.
@ -60,69 +63,5 @@ namespace QwirkleClassLibrary.Tiles
{ {
return color.ToString() + " " + shape.ToString(); return color.ToString() + " " + shape.ToString();
} }
public int CompareTo(object? obj)
{
if (obj == null)
{
return 1;
}
var otherTile = obj as Tile;
if (color == otherTile!.color)
{
return shape.CompareTo(otherTile.shape);
}
return color.CompareTo(otherTile.color);
}
public override bool Equals(object? obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
var otherTile = obj as Tile;
return color == otherTile!.color && shape == otherTile.shape;
}
public override int GetHashCode()
{
return HashCode.Combine(color, shape);
}
public static bool operator ==(Tile tile1, Tile tile2)
{
return EqualityComparer<Tile>.Default.Equals(tile1, tile2);
}
public static bool operator !=(Tile tile1, Tile tile2)
{
return !(tile1 == tile2);
}
public static bool operator <(Tile tile1, Tile tile2)
{
return tile1.CompareTo(tile2) < 0;
}
public static bool operator >(Tile tile1, Tile tile2)
{
return tile1.CompareTo(tile2) > 0;
}
public static bool operator <=(Tile tile1, Tile tile2)
{
return tile1.CompareTo(tile2) <= 0;
}
public static bool operator >=(Tile tile1, Tile tile2)
{
return tile1.CompareTo(tile2) >= 0;
}
} }
} }

@ -8,9 +8,6 @@ using System.Threading.Tasks;
namespace QwirkleClassLibrary.Tiles namespace QwirkleClassLibrary.Tiles
{ {
/// <summary>
/// This class is used during the game for the tile redistribution system.
/// </summary>
[DataContract] [DataContract]
public class TileBag public class TileBag
{ {

@ -19,10 +19,10 @@ namespace Qwirkle
InitializeComponent(); InitializeComponent();
//MainPage = new NavigationPage(new MainPage());
MainPage = new AppShell(); MainPage = new AppShell();
Routing.RegisterRoute(nameof(SetPlayers), typeof(SetPlayers)); Routing.RegisterRoute(nameof(SetPlayers), typeof(SetPlayers));
Routing.RegisterRoute(nameof(Settings), typeof(Settings));
Routing.RegisterRoute(nameof(Gameboard), typeof(Gameboard)); Routing.RegisterRoute(nameof(Gameboard), typeof(Gameboard));
Routing.RegisterRoute(nameof(Rules), typeof(Rules)); Routing.RegisterRoute(nameof(Rules), typeof(Rules));
Routing.RegisterRoute(nameof(MainPage), typeof(MainPage)); Routing.RegisterRoute(nameof(MainPage), typeof(MainPage));

@ -21,7 +21,6 @@ namespace Qwirkle
DisplayAlert("Game notification", "Enter minimun 2 player and max 4 player !", "Ok ! Lets's go !"); DisplayAlert("Game notification", "Enter minimun 2 player and max 4 player !", "Ok ! Lets's go !");
Shell.Current.GoToAsync("SetPlayers"); Shell.Current.GoToAsync("SetPlayers");
//Navigation.PushAsync(new SetPlayers());
} }
public async void OnContinueClicked(object sender, EventArgs e) public async void OnContinueClicked(object sender, EventArgs e)
@ -30,8 +29,7 @@ namespace Qwirkle
try try
{ {
((App)Application.Current!).Game = gameLoad.LoadGame(); ((App)Application.Current!).Game = gameLoad.LoadGame();
await Shell.Current.GoToAsync("Gameboard"); await Navigation.PushAsync(new Gameboard());
//await Navigation.PushAsync(new Gameboard());
} }
catch catch
{ {

@ -1,7 +1,5 @@
using CommunityToolkit.Maui; using CommunityToolkit.Maui;
using CommunityToolkit.Maui.Views;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Maui;
namespace Qwirkle namespace Qwirkle
{ {
@ -13,7 +11,6 @@ namespace Qwirkle
builder builder
.UseMauiApp<App>() .UseMauiApp<App>()
.UseMauiCommunityToolkit() .UseMauiCommunityToolkit()
.UseMauiCommunityToolkitMediaElement()
.ConfigureFonts(fonts => .ConfigureFonts(fonts =>
{ {
fonts.AddFont("DiloWorld.ttf", "DiloWorld"); fonts.AddFont("DiloWorld.ttf", "DiloWorld");

@ -11,7 +11,6 @@ using Color = Microsoft.Maui.Graphics.Color;
using System.Drawing; using System.Drawing;
using QwirkleClassLibrary.Persistences; using QwirkleClassLibrary.Persistences;
using CommunityToolkit.Maui.Views; using CommunityToolkit.Maui.Views;
using System.Diagnostics;
namespace Qwirkle.Pages; namespace Qwirkle.Pages;
@ -109,6 +108,8 @@ public partial class Gameboard : ContentPage
{ {
var x = game.GetPlayerScore(game.GetPlayingPlayer(), game.CellsUsed, game.GetBoard()!); var x = game.GetPlayerScore(game.GetPlayingPlayer(), game.CellsUsed, game.GetBoard()!);
DisplayAlert("TEMP ALERT FOR DEBUG", game.GetPlayingPlayer().ToString() + " win : " + x, "Copy !");
game.EmptyCellUsed(); game.EmptyCellUsed();
game.DrawTiles(game.GetPlayingPlayer()); game.DrawTiles(game.GetPlayingPlayer());
} }
@ -190,7 +191,7 @@ public partial class Gameboard : ContentPage
private void Game_NextPlayerNotified(object? sender, NextPlayerNotifiedEventArgs args) private void Game_NextPlayerNotified(object? sender, NextPlayerNotifiedEventArgs args)
{ {
Debug.WriteLine(args.Player.NameTag); DisplayAlert("Player switch !", "It's your turn : " + args.Player.NameTag, "<3");
} }
private void OnButtonSwapClicked(object sender, EventArgs e) private void OnButtonSwapClicked(object sender, EventArgs e)
@ -201,17 +202,13 @@ public partial class Gameboard : ContentPage
{ {
_ = AnswerSwap(); _ = AnswerSwap();
} }
else
{
DisplayAlert("Swap system", "You cannot place tiles and swap in the same turn.", "Ok !");
}
game.PlaceTileNotified -= Game_PlaceTileNotified; game.PlaceTileNotified -= Game_PlaceTileNotified;
} }
private async Task AnswerSwap() private async Task AnswerSwap()
{ {
bool answer = await DisplayAlert("Swap System", "Are you sure you want to swap your tiles? Attention, if you swap you can not play", "Yes", "No"); bool answer = await DisplayAlert("Swap System", "Etes vous sur de vouloir swap vos tuiles ? Attention, si vous swapez vous ne pouvez pu jouer", "Yes", "No");
if (answer) if (answer)
{ {
@ -239,24 +236,17 @@ public partial class Gameboard : ContentPage
if (answer) if (answer)
{ {
IGamePersistence gameIntermediateSave = new GamePersistenceXml();
gameIntermediateSave.SaveGame(game);
game.ClearGame();
await Navigation.PopToRootAsync(); await Navigation.PopToRootAsync();
} }
} }
private void OnButtonBookClicked(object? sender, EventArgs e) private void OnButtonBookClicked(object? sender, EventArgs e)
{ {
Navigation.PushAsync(new Rules()); Shell.Current.GoToAsync("Rules");
} }
private void OnButtonSettingsClicked(object? sender, EventArgs e) private void OnButtonSettingsClicked(object? sender, EventArgs e)
{ {
Navigation.PushAsync(new Settings()); Shell.Current.GoToAsync("Settings");
} }

@ -4,15 +4,7 @@
xmlns:controls="clr-namespace:Qwirkle.Views" xmlns:controls="clr-namespace:Qwirkle.Views"
Title="Gameboard" Title="Gameboard"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Name="root" x:Name="root">
>
<Shell.BackButtonBehavior>
<BackButtonBehavior IsVisible="False" IsEnabled="False"></BackButtonBehavior>
</Shell.BackButtonBehavior>
<ContentPage.Resources> <ContentPage.Resources>
<x:Double x:Key="CellWidth">75</x:Double> <x:Double x:Key="CellWidth">75</x:Double>
@ -34,6 +26,7 @@
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Border WidthRequest="80" HeightRequest="80" <Border WidthRequest="80" HeightRequest="80"
BackgroundColor="Transparent" BackgroundColor="Transparent"
Margin="0"> Margin="0">
@ -42,7 +35,7 @@
DropCommand="{Binding OnDropB, Source={x:Reference root}}" /> DropCommand="{Binding OnDropB, Source={x:Reference root}}" />
</Border.GestureRecognizers> </Border.GestureRecognizers>
<Image Source="bag.png" <Image Source="bag.png"
ToolTipProperties.Text="To use me, you need to click the swap button first ^^"> ToolTipProperties.Text="Pour m'utiliser il faut cliquer sur le boutton swap avant ^^">
</Image> </Image>
</Border> </Border>
@ -80,7 +73,7 @@
ToolTipProperties.Text="Click here to exit ;)" ToolTipProperties.Text="Click here to exit ;)"
Style="{StaticResource GameButton}" /> Style="{StaticResource GameButton}" />
<Label HorizontalOptions="Center" Grid.Row="0" Grid.Column="1" FontSize="Medium" Text="{Binding PlayerList[0].NameTag}"></Label> <Label HorizontalOptions="Center" Grid.Row="0" Grid.Column="1" Text="{Binding PlayerList[0].NameTag}"></Label>
<CollectionView Grid.Row="0" Grid.Column="1" ItemsSource="{Binding PlayerList[0].Tiles}" <CollectionView Grid.Row="0" Grid.Column="1" ItemsSource="{Binding PlayerList[0].Tiles}"
HorizontalOptions="Center" HorizontalOptions="Center"
VerticalOptions="Center"> VerticalOptions="Center">
@ -104,7 +97,7 @@
</CollectionView> </CollectionView>
<Label HorizontalOptions="Center" Grid.Row="1" Grid.Column="0" FontSize="Medium" Text="{Binding PlayerList[2].NameTag}"></Label> <Label HorizontalOptions="Center" Grid.Row="1" Grid.Column="0" Text="{Binding PlayerList[2].NameTag}"></Label>
<CollectionView Grid.Row="1" Grid.Column="0" ItemsSource="{Binding PlayerList[2].Tiles}" <CollectionView Grid.Row="1" Grid.Column="0" ItemsSource="{Binding PlayerList[2].Tiles}"
HorizontalOptions="Center" HorizontalOptions="Center"
VerticalOptions="Center"> VerticalOptions="Center">
@ -125,7 +118,7 @@
</CollectionView.ItemTemplate> </CollectionView.ItemTemplate>
</CollectionView> </CollectionView>
<Label HorizontalOptions="Center" Grid.Row="1" Grid.Column="2" FontSize="Medium" Text="{Binding PlayerList[3].NameTag}"></Label> <Label HorizontalOptions="Center" Grid.Row="1" Grid.Column="2" Text="{Binding PlayerList[3].NameTag}"></Label>
<CollectionView Grid.Row="1" Grid.Column="2" ItemsSource="{Binding PlayerList[3].Tiles}" <CollectionView Grid.Row="1" Grid.Column="2" ItemsSource="{Binding PlayerList[3].Tiles}"
HorizontalOptions="Center" HorizontalOptions="Center"
VerticalOptions="Center"> VerticalOptions="Center">
@ -146,7 +139,7 @@
</CollectionView.ItemTemplate> </CollectionView.ItemTemplate>
</CollectionView> </CollectionView>
<Label HorizontalOptions="Center" VerticalOptions="End" Grid.Row="2" Grid.Column="1" FontSize="Medium" Text="{Binding PlayerList[1].NameTag}"></Label> <Label HorizontalOptions="Center" VerticalOptions="End" Grid.Row="2" Grid.Column="1" Text="{Binding PlayerList[1].NameTag}"></Label>
<CollectionView Grid.Row="2" Grid.Column="1" ItemsSource="{Binding PlayerList[1].Tiles}" <CollectionView Grid.Row="2" Grid.Column="1" ItemsSource="{Binding PlayerList[1].Tiles}"
HorizontalOptions="Center" HorizontalOptions="Center"
VerticalOptions="Start"> VerticalOptions="Start">

@ -55,7 +55,6 @@ public partial class SetPlayers : ContentPage
game.SetNextPlayer(); game.SetNextPlayer();
Shell.Current.GoToAsync("Gameboard"); Shell.Current.GoToAsync("Gameboard");
} }
game.PlayerAddNotified -= Game_PlayerAddNotified; game.PlayerAddNotified -= Game_PlayerAddNotified;

@ -6,4 +6,9 @@ public partial class Settings : ContentPage
{ {
InitializeComponent(); InitializeComponent();
} }
public void OnGoBackClicked(object sender, EventArgs e)
{
Navigation.PopAsync();
}
} }

@ -5,7 +5,6 @@
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Name="root" x:Name="root"
CanBeDismissedByTappingOutsideOfPopup="False" CanBeDismissedByTappingOutsideOfPopup="False"
xmlns:controls="clr-namespace:Qwirkle.Views"
> >
<VerticalStackLayout HeightRequest="400" WidthRequest="500"> <VerticalStackLayout HeightRequest="400" WidthRequest="500">
@ -20,7 +19,35 @@
<Label Text="{Binding ScoreboardList[0].Key, Source={x:Reference root}}" Style="{StaticResource SuperTitle}" TextColor="HotPink" FontSize="Medium"></Label> <Label Text="{Binding ScoreboardList[0].Key, Source={x:Reference root}}" Style="{StaticResource SuperTitle}" TextColor="HotPink" FontSize="Medium"></Label>
<controls:Scoreboard></controls:Scoreboard> <CollectionView ItemsSource="{Binding ScoreboardList}" BindingContext="{x:Reference root}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Grid ColumnDefinitions="4*, auto, 2*"
RowDefinitions="50">
<Label
Grid.Column="0"
Text="{Binding Key}"
Style="{StaticResource ContentTab}"/>
<Rectangle
Style="{StaticResource RectangleTab}"
Grid.Column="1"/>
<Label
Grid.Column="2"
Text="{Binding Value}"
Style="{StaticResource ContentTab}"/>
</Grid>
<Rectangle/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Button Text="Skip" Style="{StaticResource GameButton}" Clicked="OnButtonNextClick"></Button> <Button Text="Skip" Style="{StaticResource GameButton}" Clicked="OnButtonNextClick"></Button>

@ -1,5 +1,4 @@
using CommunityToolkit.Maui.Views; using CommunityToolkit.Maui.Views;
using Microsoft.Maui.Controls;
using QwirkleClassLibrary.Games; using QwirkleClassLibrary.Games;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
@ -33,8 +32,7 @@ public partial class PopUpEndGame : Popup
public async void OnButtonNextClick(object sender, EventArgs e) public async void OnButtonNextClick(object sender, EventArgs e)
{ {
Close(); await CloseAsync();
await Shell.Current.GoToAsync("MainPage");
} }
} }

@ -1,7 +1,7 @@
{ {
"profiles": { "profiles": {
"Windows Machine": { "Windows Machine": {
"commandName": "Project", "commandName": "MsixPackage",
"nativeDebugging": false "nativeDebugging": false
} }
} }

@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net8.0-windows10.0.19041.0</TargetFrameworks> <TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET --> <!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> --> <!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
@ -29,9 +30,6 @@
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion> <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<ApplicationVersion>1</ApplicationVersion> <ApplicationVersion>1</ApplicationVersion>
<WindowsPackageType Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">None</WindowsPackageType>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion> <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">13.1</SupportedOSPlatformVersion> <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">13.1</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion> <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
@ -43,7 +41,7 @@
<ItemGroup> <ItemGroup>
<!-- App Icon --> <!-- App Icon -->
<!-- <MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />--> <!-- <MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />-->
<MauiIcon Include="Resources\AppIcon\appicon.svg" /> <MauiIcon Include="Resources\AppIcon\appicon.svg"/>
<!-- Splash Screen --> <!-- Splash Screen -->
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" /> <MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
@ -67,11 +65,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CommunityToolkit.Maui" Version="9.0.1" /> <PackageReference Include="CommunityToolkit.Maui" Version="9.0.0" />
<PackageReference Include="CommunityToolkit.Maui.MediaElement" Version="3.1.1" />
<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.40" /> <PackageReference Include="Microsoft.Maui.Controls" Version="8.0.40" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.40" /> <PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.40" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="9.0.0-preview.4.24266.19" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -1,5 +1,3 @@
using Qwirkle.Pages;
namespace Qwirkle.Views; namespace Qwirkle.Views;
public partial class GoBack : ContentView public partial class GoBack : ContentView

@ -287,6 +287,25 @@ public class TestGame
Assert.False(game.PlaceTile(game.GetPlayingPlayer(), game.PlayerList[game.GetPlayingPlayerPosition()].Tiles[0], -5, 1)); Assert.False(game.PlaceTile(game.GetPlayingPlayer(), game.PlayerList[game.GetPlayingPlayerPosition()].Tiles[0], -5, 1));
} }
// [Fact]
// public void Test_DrawTile()
// {
// Game game = new Game();
// game.AddPlayerInGame("Test1");
// game.AddPlayerInGame(playerstest);
//
// game.StartGame();
// game.SetNextPlayer();
//
// Assert.True(game.DrawTiles(game.GetPlayingPlayer()));
//
// /*test*/
// TileBag bag = new TileBag(0);
// Assert.False(game.DrawTiles(game.GetPlayingPlayer()));
// return;
//
// }
[Theory] [Theory]
[InlineData(true)] [InlineData(true)]
[InlineData(false)] [InlineData(false)]
@ -323,48 +342,6 @@ public class TestGame
Assert.Equal(p, events.Player); Assert.Equal(p, events.Player);
} }
[Fact]
public void Test_IsTilePlacementCorrect()
{
var game = new Game();
var board = new Board(17, 14);
var tile = new Tile(Shape.Club, Color.Red);
board.AddTileInCell(0, 1, new Tile(Shape.Club, Color.Blue));
var x = 1;
var y = 1;
var surroundingCells = new List<Cell?>
{
board.GetCell(x + 1, y),
board.GetCell(x - 1, y),
board.GetCell(x, y + 1),
board.GetCell(x, y - 1)
};
bool result = game.IsTilePlacementCorrect(tile, x, y, board, surroundingCells);
Assert.True(result);
}
[Fact]
public void Test_IsMoveCorrect()
{
var game = new Game();
var board = new Board(17, 14);
var tile = new Tile(Shape.Club, Color.Red);
board.AddTileInCell(0, 1, new Tile(Shape.Club, Color.Blue));
var x = 2;
var y = 1;
bool result = game.IsMoveCorrect(tile, x, y, board);
Assert.False(result);
}
[Fact] [Fact]
public void Test_IsMoveCorrectSixLine() public void Test_IsMoveCorrectSixLine()
{ {
@ -404,41 +381,6 @@ public class TestGame
} }
[Fact]
public void Test_CheckTileInCompletedLines()
{
int nbTiles = 0;
var checkdoubles = new List<Tile>()
{
new(Shape.Club, Color.Blue),
new(Shape.Club, Color.Red),
new(Shape.Club, Color.Green),
};
var t1 = new Tile(Shape.Club, Color.Green);
Assert.False(Game.CheckTileInCompletedLines(t1, ref nbTiles, ref checkdoubles));
}
[Fact]
public void Test_CheckWrongCompletedLines()
{
var board = new Board(17, 14);
var checkDoubles = new List<Tile>();
int x = 4, y = 1, dx = 1, dy = 0;
board.AddTileInCell(1, 1, new Tile(Shape.Club, Color.Red));
board.AddTileInCell(2, 1, new Tile(Shape.Square, Color.Red));
board.AddTileInCell(3, 1, new Tile(Shape.Star, Color.Red));
board.AddTileInCell(5, 1, new Tile(Shape.Round, Color.Red));
board.AddTileInCell(6, 1, new Tile(Shape.Shuriken, Color.Red));
board.AddTileInCell(7, 1, new Tile(Shape.Rhombus, Color.Red));
bool result = Game.CheckWrongCompletedLines(x, y, dx, dy, board, ref checkDoubles);
Assert.False(result);
}
[Theory] [Theory]
[InlineData(3, 1, 4, 1, 5, 1, 5)] [InlineData(3, 1, 4, 1, 5, 1, 5)]
[InlineData(2, 2, 3, 2, 4, 2, 5)] [InlineData(2, 2, 3, 2, 4, 2, 5)]
@ -447,7 +389,7 @@ public class TestGame
{ {
var game = new Game(); var game = new Game();
var player = new Player("TestPlayer"); var player = new Player("TestPlayer");
var board = game.GetBoard(); var board = new Board(8, 8);
board.AddTileInCell(1, 1, new Tile(Shape.Club, Color.Red)); board.AddTileInCell(1, 1, new Tile(Shape.Club, Color.Red));
board.AddTileInCell(2, 1, new Tile(Shape.Square, Color.Red)); board.AddTileInCell(2, 1, new Tile(Shape.Square, Color.Red));
@ -472,14 +414,6 @@ public class TestGame
Assert.Equal(expectedScore, score); Assert.Equal(expectedScore, score);
} }
[Theory]
[InlineData(0, -1, -1, 6)]
[InlineData(1, 0, 4, -1)]
public void Test_ShouldIncreaseScore(int dx, int dy, int cellsX, int cellsY)
{
Assert.True(Game.ShouldIncreaseScore(new Tuple<int, int>(dx, dy), new Tuple<int, int>(cellsX, cellsY)));
}
[Fact] [Fact]
public void Test_EndOfGame() public void Test_EndOfGame()
{ {

Binary file not shown.

@ -1,3 +1,4 @@
[![Build Status](https://codefirst.iut.uca.fr/api/badges/jeremy.mouyon/sae201_qwirkle/status.svg)](https://codefirst.iut.uca.fr/jeremy.mouyon/sae201_qwirkle) [![Build Status](https://codefirst.iut.uca.fr/api/badges/jeremy.mouyon/sae201_qwirkle/status.svg)](https://codefirst.iut.uca.fr/jeremy.mouyon/sae201_qwirkle)
# Notre QWIRKLE # Notre QWIRKLE
@ -8,11 +9,7 @@ Projet .NET MAUI portant sur la conception d'un jeu vidéo en reprenant un jeu d
## Présentation de notre jeu ## Présentation de notre jeu
Notre présentation est consutable sur ce [lien](https://codefirst.iut.uca.fr/git/jeremy.mouyon/sae201_qwirkle/wiki/Pr%C3%A9sentation-du-jeu). Notré présentation est consutable sur ce [lien](https://codefirst.iut.uca.fr/git/jeremy.mouyon/sae201_qwirkle/wiki/Pr%C3%A9sentation-du-jeu).
### Vidéo de présentation
Voici le [lien](https://opencast.dsi.uca.fr/paella/ui/watch.html?id=4c3f5f66-69e8-4700-878e-3ec700e14640) de notre vidéo de présentation du jeu
## Composition du groupe ## Composition du groupe
@ -23,17 +20,6 @@ Voici le [lien](https://opencast.dsi.uca.fr/paella/ui/watch.html?id=4c3f5f66-69e
## *Comment utiliser notre application ?* ## *Comment utiliser notre application ?*
### Executable
Semé d'embûches, le chemin pour vous fournir un exécutable a finalement été trouvé. Il se trouve à la racine de notre projet.
Vous pourrez via celui-ci, utiliser notre application de A à Z !
*Nous ne sommes malheureusement pas en mesure de vous fournir un fichier .msix!*
### Via un IDE
Tout d'abord, récupérez notre projet en tapant dans votre terminal : Tout d'abord, récupérez notre projet en tapant dans votre terminal :
```sh ```sh
git clone https://codefirst.iut.uca.fr/git/jeremy.mouyon/sae201_qwirkle.git git clone https://codefirst.iut.uca.fr/git/jeremy.mouyon/sae201_qwirkle.git
@ -67,10 +53,9 @@ Après cela, vous pourrez continuer à placer d'autres tuiles, si vous le souhai
Si vous souhaitez échanger des des tuiles de votre main, vous pouvez choisir de les échanger avec des tuiles de la pioche. Entrez simplement les numéros correspondants des tuiles que vous voulez échanger. Si vous souhaitez échanger des des tuiles de votre main, vous pouvez choisir de les échanger avec des tuiles de la pioche. Entrez simplement les numéros correspondants des tuiles que vous voulez échanger.
Attention, gardez à l'esprit que si vous choisissez cette option, vous ne pourrez pas jouer durant ce tour. Attention, gardez à l'esprit que si vous choisissez cette option, vous ne pourrez pas jouer durant ce tour.
## Where is the sound ? ### Et voilà !
Vous vous demandez probablement où est passé le son ? Il n'y en a finalement pas eu. Le temps d'implémenter un système sonore avec un réglage était impossible dans les délais fixés. Nous avons quand même fait la page, conformément à notre conception !
## Et voilà ! Votre partie est lancée ! Amusez-vous bien avec ce jeu de Qwirkle !
Votre partie est lancée ! Amusez-vous bien avec ce jeu de Qwirkle ! :) *PS pour Mr Chargueraud : Promesse faite, promesse tenue ! Mon problème de score est en grande partie réglé (non sans peine) !*
*Le seul problème restant étant que sur certains cas, le +6 de la complétion de ligne peut s'effectuer 2 fois.*
Loading…
Cancel
Save