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++)
{
Cell localcell = new(b, a);
Cell localcell = new(a, b);
cells.Add(localcell);
}
}
}
/// <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>
/// <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()
{
foreach (var cell in cells)

@ -4,15 +4,11 @@ using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using QwirkleClassLibrary.Tiles;
namespace QwirkleClassLibrary.Boards
{
namespace QwirkleClassLibrary.Boards;
/// <summary>
/// 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.
/// </summary>
[DataContract]
public class Cell : INotifyPropertyChanged
{
[DataContract]
public class Cell : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
[DataMember]
@ -22,7 +18,7 @@ namespace QwirkleClassLibrary.Boards
private readonly int y;
[DataMember]
public Tile? Tile { get; private set; }
public Tile? Tile { get; private set;}
/// <summary>
/// This is the constructor for a Cell.
@ -60,12 +56,12 @@ namespace QwirkleClassLibrary.Boards
}
/// <summary>
/// Checks if the Cell whether is empty or contains a tile.
/// Check if the Cell whether is empty or contains a tile.
/// </summary>
/// <returns>True if the cell is empty, false if the cell contains a tile.</returns>
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>
public bool SetTile(Tile addedTile)
{
if (Tile! == null!)
if (Tile == null)
{
Tile = addedTile;
@ -93,5 +89,4 @@ namespace QwirkleClassLibrary.Boards
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

@ -7,37 +7,43 @@ using QwirkleClassLibrary.Events;
using QwirkleClassLibrary.Players;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using static System.Formats.Asn1.AsnWriter;
namespace QwirkleClassLibrary.Games
{
/// <summary>
/// This is our main class for the Qwirkle application, taking care of the good efficiency of the game.
/// </summary>
[DataContract]
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 Board Board => board;
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();
[DataMember] private readonly ObservableCollection<KeyValuePair<string, int>> observableScoreBoard = [];
[DataMember]
private readonly ObservableCollection<KeyValuePair<string, int>> observableScoreBoard = [];
public ReadOnlyObservableCollection<KeyValuePair<string, int>> ObservableScoreBoard =>
new(observableScoreBoard);
[DataMember] private readonly List<Cell> cellUsed = [];
[DataMember]
private readonly List<Cell> cellUsed = [];
public ReadOnlyCollection<Cell> CellsUsed => cellUsed.AsReadOnly();
@ -98,11 +104,9 @@ namespace QwirkleClassLibrary.Games
if (playersTag.Count <= 1 || playersTag.Count > 4)
{
playersTag.Clear();
OnPlayerNotified(new AddPlayerNotifiedEventArgs(
"ERROR : It takes a minimum of 2 players and a maximum of 4 players to start a game."));
OnPlayerNotified(new AddPlayerNotifiedEventArgs("ERROR : It takes a minimum of 2 players and a maximum of 4 players to start a game."));
return false;
}
for (int i = playersTag.Count - 1; i >= 0; i--)
{
if (!CheckPlayerTag(playersTag, i))
@ -122,18 +126,12 @@ namespace QwirkleClassLibrary.Games
OnPlayerNotified(new AddPlayerNotifiedEventArgs("Players were correctly added."));
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)
{
if (string.IsNullOrWhiteSpace(playersTag[pos]))
{
OnPlayerNotified(new AddPlayerNotifiedEventArgs("ERROR with " + (pos + 1) +
" entry : The name is null or white space."));
OnPlayerNotified(new AddPlayerNotifiedEventArgs("ERROR with " + (pos + 1) + " entry : The name is null or white space."));
return false;
}
@ -150,6 +148,7 @@ namespace QwirkleClassLibrary.Games
new AddPlayerNotifiedEventArgs("ERROR with " + (pos + 1) + " entry : Name alreay taken"));
return false;
}
}
return true;
@ -171,19 +170,13 @@ namespace QwirkleClassLibrary.Games
/// Returns the Board of the game
/// </summary>
/// <returns>Board</returns>
public Board GetBoard()
{
return board;
}
public Board? GetBoard() { return board; }
/// <summary>
/// Returns the tile bag of the game
/// </summary>
/// <returns></returns>
public TileBag? GetTileBag()
{
return bag;
}
public TileBag? GetTileBag() { return bag; }
/// <summary>
/// Creates a Board with a number of columns and rows
@ -245,7 +238,6 @@ namespace QwirkleClassLibrary.Games
{
throw new ArgumentException("No player currently playing !");
}
return players[GetPlayingPlayerPosition()];
}
@ -262,7 +254,6 @@ namespace QwirkleClassLibrary.Games
return i;
}
}
return -1;
}
@ -325,6 +316,7 @@ namespace QwirkleClassLibrary.Games
startingPlayer!.IsPlaying = true;
OnNextPlayer(new NextPlayerNotifiedEventArgs(players[0]));
return startingPlayer.NameTag;
}
/// <summary>
@ -362,15 +354,13 @@ namespace QwirkleClassLibrary.Games
OnPlaceTile(new PlaceTileNotifiedEventArgs(tile, "you are swapping, you can't place tile !"));
return false;
}
if (!TileInbag(player, tile))
{
OnPlaceTile(new PlaceTileNotifiedEventArgs(tile, "you can't play"));
return false;
}
if (!IsMoveCorrect(tile, x, y, board)) return false;
if (board.AddTileInCell(x, y, tile))
if (!IsMoveCorrect(tile, x, y, board!)) return false;
if (board!.AddTileInCell(x, y, tile))
{
AddCellUsed(board.GetCell(x, y));
return player.RemoveTileToPlayer(tile);
@ -456,12 +446,12 @@ namespace QwirkleClassLibrary.Games
{
players[GetPlayingPlayerPosition()].AddTileToPlayer(t);
}
}
/// <summary>
/// Extension of IsMoveCorrect to check beyond the surrounding cells of the cell where the tile is placed
/// </summary>
/// <param name="previousTilesFound"></param>
/// <param name="tile"></param>
/// <param name="x"></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="b"></param>
/// <returns>bool</returns>
public bool CheckExtendedSurroundingCells(ref bool previousTilesFound, Tile tile, int x, int y, int dx, int dy,
Board b)
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 (cellUsed.Count == 0)
{
previousTilesFound = true;
}
if (cellUsed.Contains(extendedCell!))
{
previousTilesFound = true;
}
if (extendedCell?.Tile! == null!)
if (extendedCell?.Tile == null)
{
break;
}
if (extendedCell.Tile.GetColor != tile.GetColor && extendedCell.Tile.GetShape != tile.GetShape)
{
OnPlaceTile(new PlaceTileNotifiedEventArgs(tile,
" : Color / Shape does not match with the surrounding tiles !"));
OnPlaceTile(new PlaceTileNotifiedEventArgs(tile, " : Color / Shape does not match with the surrounding tiles !"));
return false;
}
if (extendedCell.Tile.GetColor == tile.GetColor && extendedCell.Tile.GetShape == tile.GetShape)
{
OnPlaceTile(new PlaceTileNotifiedEventArgs(tile,
" : Tile already placed on the same line / column !"));
OnPlaceTile(new PlaceTileNotifiedEventArgs(tile, " : Tile already placed on the same line / column !"));
return false;
}
@ -550,7 +527,6 @@ namespace QwirkleClassLibrary.Games
{
return x == x1;
}
if (y1 == y2)
{
return y == y1;
@ -560,62 +536,13 @@ namespace QwirkleClassLibrary.Games
}
/// <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>
/// <param name="t1"></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="t"></param>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="dx"></param>
/// <param name="dy"></param>
/// <param name="b"></param>
/// <param name="checkdoubles"></param>
/// <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;
}
/// <returns>bool</returns>
public bool IsMoveCorrect(Tile t, int x, int y, Board b)
{
if (!b.HasOccupiedCase())
@ -623,10 +550,9 @@ namespace QwirkleClassLibrary.Games
return true;
}
if (b.GetCell(x, y)!.Tile! != null!)
if (b.GetCell(x, y)!.Tile != null)
{
OnPlaceTile(new PlaceTileNotifiedEventArgs(t, " : Cell already used !"));
return false;
}
var surroundingCells = new List<Cell?>
@ -637,69 +563,51 @@ namespace QwirkleClassLibrary.Games
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)
{
if (cell?.Tile! == null!)
if (cell?.Tile == null)
{
continue;
}
if (cell.Tile.GetColor != t.GetColor && cell.Tile.GetShape != t.GetShape)
{
OnPlaceTile(new PlaceTileNotifiedEventArgs(t,
" : Colors / Shapes do not match with the surrounding tiles !"));
OnPlaceTile(new PlaceTileNotifiedEventArgs(t, " : Colors / Shapes do not match with the surrounding tiles !"));
return false;
}
if (cell.Tile.GetColor == t.GetColor && cell.Tile.GetShape == t.GetShape)
{
OnPlaceTile(new PlaceTileNotifiedEventArgs(t, " is already placed on the same line / column !"));
return false;
}
var dx = cell.GetX - x;
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;
}
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))
{
OnPlaceTile(new PlaceTileNotifiedEventArgs(t,
"isn't on the same line as the ones previously placed !"));
OnPlaceTile(new PlaceTileNotifiedEventArgs(t, "isn't on the same line as the ones previously placed !"));
return false;
}
if (previousTilesFound) return true;
OnPlaceTile(new PlaceTileNotifiedEventArgs(t,
" : You must place your tile next / on the same line as the ones previously placed !"));
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 true;
}
/// <summary>
/// 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 nbCellsInLine = cellsPlayed.Count;
int nbCellsInPerpLine = 1;
var checkedCells = new List<Cell>();
if (cellsPlayed.Count == 6)
{
@ -749,16 +654,16 @@ namespace QwirkleClassLibrary.Games
cellsX = cellsY = -1;
}
score += cellsPlayed.Sum(cell =>
CalculateAdjacentScore(cell, b, cellsPlayed, new Tuple<int, int>(cellsX, cellsY), ref nbCellsInLine, ref nbCellsInPerpLine, ref checkedCells));
score += cellsPlayed.Sum(cell => CalculateAdjacentScore(cell, b, cellsPlayed, cellsX, cellsY, ref nbCellsInLine));
if (nbCellsInLine == 6 || nbCellsInPerpLine == 6)
if (nbCellsInLine == 6)
{
score += 6;
}
if (!scoreBoard.TryAdd(player.NameTag, score))
{
scoreBoard.TryGetValue(player.NameTag, out int scoreold);
SetScoreBoard(player.NameTag, score + scoreold);
}
@ -772,12 +677,11 @@ namespace QwirkleClassLibrary.Games
/// <param name="cell"></param>
/// <param name="b"></param>
/// <param name="cellsPlayed"></param>
/// <param name="orientation"></param>
/// <param name="nbCellsInPerpLine"></param>
/// <param name="checkedCells"></param>
/// <param name="cellsX"></param>
/// <param name="cellsY"></param>
/// <param name="nbCellsInLine"></param>
/// <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;
@ -789,10 +693,11 @@ namespace QwirkleClassLibrary.Games
b.GetCell(cell.GetX, cell.GetY - 1)
};
var checkedSurroundingCells = new List<Cell>();
foreach (var adjacentCell in surroundingCells)
{
if (adjacentCell?.Tile! == null! || cellsPlayed.Contains(adjacentCell) ||
checkedCells.Contains(adjacentCell))
if (adjacentCell?.Tile == null || cellsPlayed.Contains(adjacentCell) || checkedSurroundingCells.Contains(adjacentCell))
{
continue;
}
@ -800,10 +705,9 @@ namespace QwirkleClassLibrary.Games
int dx = adjacentCell.GetX - cell.GetX;
int dy = adjacentCell.GetY - cell.GetY;
score += CalculateLineScore(cellsPlayed, cell, new Tuple<int, int>(dx, dy),
new Tuple<int, int>(orientation.Item1, orientation.Item2), ref nbCellsInLine, ref nbCellsInPerpLine, ref checkedCells);
score += CalculateLineScore(cellsPlayed, cell, new Tuple<int, int>(dx, dy), b, new Tuple<int, int>(cellsX, cellsY), ref nbCellsInLine);
checkedCells.Add(adjacentCell);
checkedSurroundingCells.Add(adjacentCell);
}
return score;
@ -815,20 +719,19 @@ namespace QwirkleClassLibrary.Games
/// <param name="cellsPlayed"></param>
/// <param name="cell"></param>
/// <param name="direction"></param>
/// <param name="b"></param>
/// <param name="orientation"></param>
/// <param name="nbCellsInLine"></param>
/// <param name="nbCellsInPerpLine"></param>
/// <param name="checkedCells"></param>
/// <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;
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;
}
@ -838,16 +741,10 @@ namespace QwirkleClassLibrary.Games
nbCellsInLine++;
}
if (direction.Item1 != 0 && orientation.Item1 != -1 || direction.Item2 != 0 && orientation.Item2 != -1)
{
nbCellsInPerpLine++;
}
checkedCells.Add(extendedCell);
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;
}
@ -855,11 +752,6 @@ namespace QwirkleClassLibrary.Games
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>
/// 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);
}
}
}
return playerTilesBagPos;
@ -894,7 +787,7 @@ namespace QwirkleClassLibrary.Games
{
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 y = board.ReadCells[b].GetY;
@ -920,8 +813,7 @@ namespace QwirkleClassLibrary.Games
{
List<int> playerTilesBagPos = CheckTilesBag();
if (playerTilesBagPos.Count != 0 && !CheckPlacementPossibilities(playerTilesBagPos) ||
bag!.TilesBag!.Count == 0 && players[GetPlayingPlayerPosition()].Tiles.Count == 0)
if (playerTilesBagPos.Count != 0 && !CheckPlacementPossibilities(playerTilesBagPos) || bag!.TilesBag!.Count == 0 && players[GetPlayingPlayerPosition()].Tiles.Count == 0)
{
OnEndOfGame(new EndOfGameNotifiedEventArgs(player));
GameRunning = false;
@ -946,6 +838,7 @@ namespace QwirkleClassLibrary.Games
public void SetScoreBoard(string name, int score)
{
if (!scoreBoard.TryAdd(name, score))
{
scoreBoard[name] = score;
@ -956,7 +849,6 @@ namespace QwirkleClassLibrary.Games
{
observableScoreBoard.Add(item);
}
OnPropertyChanged(nameof(ObservableScoreBoard));
}
}

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

@ -9,9 +9,6 @@ using QwirkleClassLibrary.Tiles;
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
{
Board CreateBoard();
@ -20,7 +17,7 @@ namespace QwirkleClassLibrary.Games
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);

@ -1,17 +1,10 @@
using System.Runtime.Serialization;
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)
{
var serializer = new DataContractSerializer(typeof(Game),
@ -22,10 +15,7 @@ namespace QwirkleClassLibrary.Persistences
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()
{
var serializer = new DataContractSerializer(typeof(Game));
@ -43,5 +33,4 @@ namespace QwirkleClassLibrary.Persistences
return new Game();
}
}
}
}

@ -1,17 +1,10 @@
using System.Runtime.Serialization.Json;
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)
{
var serializer = new DataContractJsonSerializer(typeof(Leaderboard));
@ -21,11 +14,7 @@ namespace QwirkleClassLibrary.Persistences
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()
{
var serializer = new DataContractJsonSerializer(typeof(Leaderboard));
@ -35,5 +24,4 @@ namespace QwirkleClassLibrary.Persistences
return serializer.ReadObject(reader) as Leaderboard ?? throw new InvalidOperationException();
}
}
}
}

@ -12,9 +12,6 @@ using System.Threading.Tasks;
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]
public class Leaderboard : INotifyPropertyChanged
{

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

@ -9,9 +9,6 @@ using System.Threading.Tasks;
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]
public class Score
{

@ -8,11 +8,8 @@ using System.Threading.Tasks;
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]
public class Tile : IComparable
public class Tile
{
[DataMember]
private readonly Shape shape;
@ -44,13 +41,19 @@ namespace QwirkleClassLibrary.Tiles
/// A getter for the shape of the Tile.
/// </summary>
/// <returns>The shape attribute of the Tile.</returns>
public Shape GetShape => shape;
public Shape GetShape
{
get { return shape; }
}
/// <summary>
/// A getter for the color of the Tile.
/// </summary>
/// <returns>The color attribute of the Tile.</returns>
public Color GetColor => color;
public Color GetColor
{
get { return color; }
}
/// <summary>
/// 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();
}
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
{
/// <summary>
/// This class is used during the game for the tile redistribution system.
/// </summary>
[DataContract]
public class TileBag
{

@ -19,10 +19,10 @@ namespace Qwirkle
InitializeComponent();
//MainPage = new NavigationPage(new MainPage());
MainPage = new AppShell();
Routing.RegisterRoute(nameof(SetPlayers), typeof(SetPlayers));
Routing.RegisterRoute(nameof(Settings), typeof(Settings));
Routing.RegisterRoute(nameof(Gameboard), typeof(Gameboard));
Routing.RegisterRoute(nameof(Rules), typeof(Rules));
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 !");
Shell.Current.GoToAsync("SetPlayers");
//Navigation.PushAsync(new SetPlayers());
}
public async void OnContinueClicked(object sender, EventArgs e)
@ -30,8 +29,7 @@ namespace Qwirkle
try
{
((App)Application.Current!).Game = gameLoad.LoadGame();
await Shell.Current.GoToAsync("Gameboard");
//await Navigation.PushAsync(new Gameboard());
await Navigation.PushAsync(new Gameboard());
}
catch
{

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

@ -11,7 +11,6 @@ using Color = Microsoft.Maui.Graphics.Color;
using System.Drawing;
using QwirkleClassLibrary.Persistences;
using CommunityToolkit.Maui.Views;
using System.Diagnostics;
namespace Qwirkle.Pages;
@ -109,6 +108,8 @@ public partial class Gameboard : ContentPage
{
var x = game.GetPlayerScore(game.GetPlayingPlayer(), game.CellsUsed, game.GetBoard()!);
DisplayAlert("TEMP ALERT FOR DEBUG", game.GetPlayingPlayer().ToString() + " win : " + x, "Copy !");
game.EmptyCellUsed();
game.DrawTiles(game.GetPlayingPlayer());
}
@ -190,7 +191,7 @@ public partial class Gameboard : ContentPage
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)
@ -201,17 +202,13 @@ public partial class Gameboard : ContentPage
{
_ = AnswerSwap();
}
else
{
DisplayAlert("Swap system", "You cannot place tiles and swap in the same turn.", "Ok !");
}
game.PlaceTileNotified -= Game_PlaceTileNotified;
}
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)
{
@ -239,24 +236,17 @@ public partial class Gameboard : ContentPage
if (answer)
{
IGamePersistence gameIntermediateSave = new GamePersistenceXml();
gameIntermediateSave.SaveGame(game);
game.ClearGame();
await Navigation.PopToRootAsync();
}
}
private void OnButtonBookClicked(object? sender, EventArgs e)
{
Navigation.PushAsync(new Rules());
Shell.Current.GoToAsync("Rules");
}
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"
Title="Gameboard"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Name="root"
>
<Shell.BackButtonBehavior>
<BackButtonBehavior IsVisible="False" IsEnabled="False"></BackButtonBehavior>
</Shell.BackButtonBehavior>
x:Name="root">
<ContentPage.Resources>
<x:Double x:Key="CellWidth">75</x:Double>
@ -34,6 +26,7 @@
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border WidthRequest="80" HeightRequest="80"
BackgroundColor="Transparent"
Margin="0">
@ -42,7 +35,7 @@
DropCommand="{Binding OnDropB, Source={x:Reference root}}" />
</Border.GestureRecognizers>
<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>
</Border>
@ -80,7 +73,7 @@
ToolTipProperties.Text="Click here to exit ;)"
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}"
HorizontalOptions="Center"
VerticalOptions="Center">
@ -104,7 +97,7 @@
</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}"
HorizontalOptions="Center"
VerticalOptions="Center">
@ -125,7 +118,7 @@
</CollectionView.ItemTemplate>
</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}"
HorizontalOptions="Center"
VerticalOptions="Center">
@ -146,7 +139,7 @@
</CollectionView.ItemTemplate>
</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}"
HorizontalOptions="Center"
VerticalOptions="Start">

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

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

@ -5,7 +5,6 @@
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Name="root"
CanBeDismissedByTappingOutsideOfPopup="False"
xmlns:controls="clr-namespace:Qwirkle.Views"
>
<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>
<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>

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

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

@ -1,7 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<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 -->
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
@ -29,9 +30,6 @@
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<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)')) == 'maccatalyst'">13.1</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
@ -43,7 +41,7 @@
<ItemGroup>
<!-- App Icon -->
<!-- <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 -->
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
@ -67,11 +65,10 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Maui" Version="9.0.1" />
<PackageReference Include="CommunityToolkit.Maui.MediaElement" Version="3.1.1" />
<PackageReference Include="CommunityToolkit.Maui" Version="9.0.0" />
<PackageReference Include="Microsoft.Maui.Controls" 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>

@ -1,5 +1,3 @@
using Qwirkle.Pages;
namespace Qwirkle.Views;
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));
}
// [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]
[InlineData(true)]
[InlineData(false)]
@ -323,48 +342,6 @@ public class TestGame
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]
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]
[InlineData(3, 1, 4, 1, 5, 1, 5)]
[InlineData(2, 2, 3, 2, 4, 2, 5)]
@ -447,7 +389,7 @@ public class TestGame
{
var game = new Game();
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(2, 1, new Tile(Shape.Square, Color.Red));
@ -472,14 +414,6 @@ public class TestGame
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]
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)
# 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
Notre 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
Notré présentation est consutable sur ce [lien](https://codefirst.iut.uca.fr/git/jeremy.mouyon/sae201_qwirkle/wiki/Pr%C3%A9sentation-du-jeu).
## 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 ?*
### 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 :
```sh
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.
Attention, gardez à l'esprit que si vous choisissez cette option, vous ne pourrez pas jouer durant ce tour.
## Where is the sound ?
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à !
## 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