Compare commits

...

39 Commits

Author SHA1 Message Date
Jérémy Mouyon 70825b1093 Mise à jour de 'README.md'
continuous-integration/drone/push Build is passing Details
3 weeks ago
Jules LASCRET d3fc957213 Mise à jour de 'README.md'
continuous-integration/drone/push Build is passing Details
10 months ago
Jérémy Mouyon d9e8a536a3 Merge branch 'master' of https://codefirst.iut.uca.fr/git/jeremy.mouyon/sae201_qwirkle
continuous-integration/drone/push Build is passing Details
10 months ago
Jérémy Mouyon 440a329a92 back button
10 months ago
Jérémy Mouyon a09e25bca4 Mise à jour de 'README.md'
continuous-integration/drone/push Build is passing Details
11 months ago
Jérémy Mouyon c4e5cc09a3 push of zip exe
continuous-integration/drone/push Build is passing Details
11 months ago
Jérémy Mouyon 1edf1d7374 Mise à jour de 'README.md'
continuous-integration/drone/push Build is passing Details
11 months ago
Jérémy Mouyon fcfaf6ee5a Merge branch 'master' of https://codefirst.iut.uca.fr/git/jeremy.mouyon/sae201_qwirkle
continuous-integration/drone/push Build is passing Details
11 months ago
Jérémy Mouyon 4bef870bd6 trad + new message / delete message
11 months ago
Jérémy Mouyon af69cba848 good smile :)
continuous-integration/drone/push Build is passing Details
11 months ago
rportet d24b19e757 more and more documentation, again
continuous-integration/drone/push Build is passing Details
11 months ago
rportet ffbd8aba48 adding a lil more doc again
continuous-integration/drone/push Build is passing Details
11 months ago
rportet d9afae006d Merge branch 'master' of https://codefirst.iut.uca.fr/git/jeremy.mouyon/sae201_qwirkle
continuous-integration/drone/push Build is passing Details
11 months ago
rportet 2026228b71 adding a lil doc
11 months ago
Jules LASCRET 08ed17959b Split methods + new test
continuous-integration/drone/push Build is passing Details
11 months ago
Jules LASCRET 77054e7c3d Merge remote-tracking branch 'origin/master'
continuous-integration/drone/push Build is passing Details
11 months ago
Jules LASCRET 897bc547d7 Scores bloody working now, I hope otherwise I might quit
11 months ago
Jérémy Mouyon 76d047595a label meduim
continuous-integration/drone/push Build is passing Details
11 months ago
Jérémy Mouyon 019307e893 Merge branch 'master' of https://codefirst.iut.uca.fr/git/jeremy.mouyon/sae201_qwirkle
continuous-integration/drone/push Build is passing Details
11 months ago
Jérémy Mouyon 73f1fd91ea end of game / build edit
11 months ago
Jules LASCRET b0afa799ae Test issue #3, normally back at 0 code smells & +80% coverage
continuous-integration/drone/push Build is passing Details
11 months ago
Jules LASCRET f0a3185b4b Test issue #2
continuous-integration/drone/push Build is passing Details
11 months ago
Jules LASCRET 4cc3b3361d test issue #1
continuous-integration/drone/push Build is passing Details
11 months ago
Jules LASCRET 20323c92b5 More tests and code smell fix (starting to feel bored)
continuous-integration/drone/push Build is passing Details
11 months ago
Jules LASCRET 9ea98eaa90 Fixed code smell + added test
continuous-integration/drone/push Build is passing Details
11 months ago
Jules LASCRET 3455682073 fixed all code smells normally now
continuous-integration/drone/push Build is passing Details
11 months ago
Jules LASCRET c45e859e83 fix some code smells
continuous-integration/drone/push Build is passing Details
11 months ago
Jérémy Mouyon e85e47ab26 delete sound / update framework
11 months ago
Jules LASCRET ecfcc1cb37 Fix 1 minor code smell (normally)
continuous-integration/drone/push Build is passing Details
11 months ago
Jules LASCRET 317dbeaa83 reduce complexity for CheckWrongCompletedLines
continuous-integration/drone/push Build is passing Details
11 months ago
Jules LASCRET 35134c2bbc Merge remote-tracking branch 'origin/master'
continuous-integration/drone/push Build is passing Details
11 months ago
Jules LASCRET 1073b2d802 Boum le bibi
11 months ago
rportet 0a34f4bc43 now goBack fucking works ! better dirty than not working
continuous-integration/drone/push Build is passing Details
11 months ago
rportet 6ea1bdc7f0 j'ai push le mauvais truc mdrr
continuous-integration/drone/push Build is passing Details
11 months ago
rportet ad0e5be725 test for the app.xaml
continuous-integration/drone/push Build is passing Details
11 months ago
Jérémy Mouyon 1009c742f8 push
continuous-integration/drone/push Build is passing Details
11 months ago
Jérémy Mouyon d16d488477 revert branch by remy without sound
continuous-integration/drone/push Build is passing Details
11 months ago
Jérémy Mouyon 448a44386b Merge branch 'master' of https://codefirst.iut.uca.fr/git/jeremy.mouyon/sae201_qwirkle
continuous-integration/drone/push Build is passing Details
11 months ago
Jérémy Mouyon 332ac4979a sound + up end game
11 months ago

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(a, b);
Cell localcell = new(b, a);
cells.Add(localcell);
}
}
}
/// <summary>
/// This method is used to check if a cell in the board whether it already contains a tile or not.
/// This method is used to check if a cell in the board whether already contains a tile or not.
/// </summary>
/// <returns>Returns a boolean : true if the cell doesn't contain any tile, false if it already contains a tile.</returns>
/// <returns>Returns a boolean : true if the cell doesn't contain any tile, false if already contains a tile.</returns>
public bool HasOccupiedCase()
{
foreach (var cell in cells)

@ -4,8 +4,12 @@ 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
{
@ -56,12 +60,12 @@ public class Cell : INotifyPropertyChanged
}
/// <summary>
/// Check if the Cell whether is empty or contains a tile.
/// Checks 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!; }
}
@ -72,7 +76,7 @@ public class Cell : INotifyPropertyChanged
/// <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;
@ -90,3 +94,4 @@ public class Cell : INotifyPropertyChanged
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

@ -7,43 +7,37 @@ 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();
@ -104,9 +98,11 @@ 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))
@ -126,12 +122,18 @@ 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;
}
@ -148,7 +150,6 @@ namespace QwirkleClassLibrary.Games
new AddPlayerNotifiedEventArgs("ERROR with " + (pos + 1) + " entry : Name alreay taken"));
return false;
}
}
return true;
@ -170,13 +171,19 @@ 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
@ -238,6 +245,7 @@ namespace QwirkleClassLibrary.Games
{
throw new ArgumentException("No player currently playing !");
}
return players[GetPlayingPlayerPosition()];
}
@ -254,6 +262,7 @@ namespace QwirkleClassLibrary.Games
return i;
}
}
return -1;
}
@ -316,7 +325,6 @@ namespace QwirkleClassLibrary.Games
startingPlayer!.IsPlaying = true;
OnNextPlayer(new NextPlayerNotifiedEventArgs(players[0]));
return startingPlayer.NameTag;
}
/// <summary>
@ -354,13 +362,15 @@ 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);
@ -446,12 +456,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>
@ -459,26 +469,39 @@ 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(Tile tile, int x, int y, int dx, int dy, Board b)
public bool CheckExtendedSurroundingCells(ref bool previousTilesFound, Tile tile, int x, int y, int dx, int dy,
Board b)
{
for (int i = 1; i < 7; i++)
{
var extendedCell = b.GetCell(x + i * dx, y + i * dy);
if (extendedCell?.Tile == null)
if (cellUsed.Count == 0)
{
previousTilesFound = true;
}
if (cellUsed.Contains(extendedCell!))
{
previousTilesFound = true;
}
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;
}
@ -527,6 +550,7 @@ namespace QwirkleClassLibrary.Games
{
return x == x1;
}
if (y1 == y2)
{
return y == y1;
@ -536,13 +560,62 @@ namespace QwirkleClassLibrary.Games
}
/// <summary>
/// Main method to check if the move the player is trying to make is correct
/// Check that there isn't any same tile on a said line when a tile is forming a line
/// </summary>
/// <param name="t"></param>
/// <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="x"></param>
/// <param name="y"></param>
/// <param name="dx"></param>
/// <param name="dy"></param>
/// <param name="b"></param>
/// <returns>bool</returns>
/// <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;
}
public bool IsMoveCorrect(Tile t, int x, int y, Board b)
{
if (!b.HasOccupiedCase())
@ -550,9 +623,10 @@ 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?>
@ -563,49 +637,67 @@ 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(t, x, y, dx, dy, b))
if (!CheckExtendedSurroundingCells(ref previousTilesFound, t, x, y, dx, dy, b))
{
return false;
}
}
if (!CheckTilesInLine(cellUsed, b, x, y))
{
OnPlaceTile(new PlaceTileNotifiedEventArgs(t, "isn't on the same line as the ones previously placed !"));
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 (surroundingCells.All(cell => cell?.Tile == null))
if (!CheckTilesInLine(cellUsed, b, x, y))
{
OnPlaceTile(new PlaceTileNotifiedEventArgs(t, " : You can't place a tile that isn't adjacent to another one !"));
OnPlaceTile(new PlaceTileNotifiedEventArgs(t,
"isn't on the same line as the ones previously placed !"));
return false;
}
return true;
if (previousTilesFound) return true;
OnPlaceTile(new PlaceTileNotifiedEventArgs(t,
" : You must place your tile next / on the same line as the ones previously placed !"));
return false;
}
@ -625,6 +717,9 @@ namespace QwirkleClassLibrary.Games
int score = cellsPlayed.Count;
int nbCellsInLine = cellsPlayed.Count;
int nbCellsInPerpLine = 1;
var checkedCells = new List<Cell>();
if (cellsPlayed.Count == 6)
{
@ -654,16 +749,16 @@ namespace QwirkleClassLibrary.Games
cellsX = cellsY = -1;
}
score += cellsPlayed.Sum(cell => CalculateAdjacentScore(cell, b, cellsPlayed, cellsX, cellsY, ref nbCellsInLine));
score += cellsPlayed.Sum(cell =>
CalculateAdjacentScore(cell, b, cellsPlayed, new Tuple<int, int>(cellsX, cellsY), ref nbCellsInLine, ref nbCellsInPerpLine, ref checkedCells));
if (nbCellsInLine == 6)
if (nbCellsInLine == 6 || nbCellsInPerpLine == 6)
{
score += 6;
}
if (!scoreBoard.TryAdd(player.NameTag, score))
{
scoreBoard.TryGetValue(player.NameTag, out int scoreold);
SetScoreBoard(player.NameTag, score + scoreold);
}
@ -677,11 +772,12 @@ namespace QwirkleClassLibrary.Games
/// <param name="cell"></param>
/// <param name="b"></param>
/// <param name="cellsPlayed"></param>
/// <param name="cellsX"></param>
/// <param name="cellsY"></param>
/// <param name="orientation"></param>
/// <param name="nbCellsInPerpLine"></param>
/// <param name="checkedCells"></param>
/// <param name="nbCellsInLine"></param>
/// <returns>int</returns>
public int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection<Cell> cellsPlayed, int cellsX, int cellsY, ref int nbCellsInLine)
public int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection<Cell> cellsPlayed, Tuple<int, int> orientation, ref int nbCellsInLine, ref int nbCellsInPerpLine, ref List<Cell> checkedCells)
{
int score = 0;
@ -693,11 +789,10 @@ 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) || checkedSurroundingCells.Contains(adjacentCell))
if (adjacentCell?.Tile! == null! || cellsPlayed.Contains(adjacentCell) ||
checkedCells.Contains(adjacentCell))
{
continue;
}
@ -705,9 +800,10 @@ 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), b, new Tuple<int, int>(cellsX, cellsY), ref nbCellsInLine);
score += CalculateLineScore(cellsPlayed, cell, new Tuple<int, int>(dx, dy),
new Tuple<int, int>(orientation.Item1, orientation.Item2), ref nbCellsInLine, ref nbCellsInPerpLine, ref checkedCells);
checkedSurroundingCells.Add(adjacentCell);
checkedCells.Add(adjacentCell);
}
return score;
@ -719,19 +815,20 @@ 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, Board b, Tuple<int, int> orientation, ref int nbCellsInLine)
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)
{
int score = 0;
for (int i = 1; i < 6; i++)
{
var extendedCell = b.GetCell(cell.GetX + i * direction.Item1, cell.GetY + i * direction.Item2);
var extendedCell = board.GetCell(cell.GetX + i * direction.Item1, cell.GetY + i * direction.Item2);
if (extendedCell?.Tile == null || cellsPlayed.Contains(extendedCell))
if (extendedCell?.Tile! == null! || cellsPlayed.Contains(extendedCell) || checkedCells.Contains(extendedCell))
{
break;
}
@ -741,10 +838,16 @@ namespace QwirkleClassLibrary.Games
nbCellsInLine++;
}
if (direction.Item1 != 0 && orientation.Item1 != -1 || direction.Item2 != 0 && orientation.Item2 != -1)
{
nbCellsInPerpLine++;
}
checkedCells.Add(extendedCell);
score++;
}
if (direction.Item1 == 0 && orientation.Item1 == -1 && orientation.Item2 != -1 || direction.Item2 == 0 && orientation.Item2 == -1 && orientation.Item1 != -1)
if (ShouldIncreaseScore(direction, orientation))
{
score += 1;
}
@ -752,6 +855,11 @@ 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
@ -770,7 +878,6 @@ namespace QwirkleClassLibrary.Games
playerTilesBagPos.Add(i);
}
}
}
return playerTilesBagPos;
@ -787,7 +894,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;
@ -813,7 +920,8 @@ 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;
@ -838,7 +946,6 @@ namespace QwirkleClassLibrary.Games
public void SetScoreBoard(string name, int score)
{
if (!scoreBoard.TryAdd(name, score))
{
scoreBoard[name] = score;
@ -849,6 +956,7 @@ namespace QwirkleClassLibrary.Games
{
observableScoreBoard.Add(item);
}
OnPropertyChanged(nameof(ObservableScoreBoard));
}
}

@ -3,8 +3,12 @@ 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 Player CreatePlayer(string playerTag);
@ -21,7 +25,10 @@ public interface IPlayer
public int GetPlayerScore(Player player, ReadOnlyCollection<Cell> cellsPlayed, Board b);
int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection<Cell> cellsPlayed, int cellsX, int cellsY, ref int nbCellsInLine);
int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection<Cell> cellsPlayed, 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);
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);
}
}

@ -9,6 +9,9 @@ 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();
@ -17,7 +20,7 @@ namespace QwirkleClassLibrary.Games
bool IsMoveCorrect(Tile t, int x, int y, Board b);
bool CheckExtendedSurroundingCells(Tile tile, int x, int y, int dx, int dy, Board b);
bool CheckExtendedSurroundingCells(ref bool previousTilesFound, Tile tile, int x, int y, int dx, int dy, Board b);
bool CheckTilesInLine(List<Cell> cells, Board b, int x, int y);

@ -1,10 +1,17 @@
using System.Runtime.Serialization;
using QwirkleClassLibrary.Games;
namespace QwirkleClassLibrary.Persistences;
namespace QwirkleClassLibrary.Persistences
{
/// <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),
@ -15,7 +22,10 @@ public class GamePersistenceXml : IGamePersistence
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));
@ -34,3 +44,4 @@ public class GamePersistenceXml : IGamePersistence
}
}
}
}

@ -1,10 +1,17 @@
using System.Runtime.Serialization.Json;
using QwirkleClassLibrary.Players;
namespace QwirkleClassLibrary.Persistences;
namespace QwirkleClassLibrary.Persistences
{
/// <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));
@ -14,7 +21,11 @@ public class LeaderboardPersistenceJson : ILeaderboardPersistence
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));
@ -25,3 +36,4 @@ public class LeaderboardPersistenceJson : ILeaderboardPersistence
}
}
}
}

@ -12,6 +12,9 @@ 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,6 +12,9 @@ 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,6 +9,9 @@ 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,8 +8,11 @@ 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
public class Tile : IComparable
{
[DataMember]
private readonly Shape shape;
@ -41,19 +44,13 @@ namespace QwirkleClassLibrary.Tiles
/// A getter for the shape of the Tile.
/// </summary>
/// <returns>The shape attribute of the Tile.</returns>
public Shape GetShape
{
get { return shape; }
}
public Shape GetShape => shape;
/// <summary>
/// A getter for the color of the Tile.
/// </summary>
/// <returns>The color attribute of the Tile.</returns>
public Color GetColor
{
get { return color; }
}
public Color GetColor => color;
/// <summary>
/// This method is used to override the ToString() method. It is simply a tool to facilitate the development.
@ -63,5 +60,69 @@ 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,6 +8,9 @@ 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,6 +21,7 @@ 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)
@ -29,7 +30,8 @@ namespace Qwirkle
try
{
((App)Application.Current!).Game = gameLoad.LoadGame();
await Navigation.PushAsync(new Gameboard());
await Shell.Current.GoToAsync("Gameboard");
//await Navigation.PushAsync(new Gameboard());
}
catch
{

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

@ -11,6 +11,7 @@ using Color = Microsoft.Maui.Graphics.Color;
using System.Drawing;
using QwirkleClassLibrary.Persistences;
using CommunityToolkit.Maui.Views;
using System.Diagnostics;
namespace Qwirkle.Pages;
@ -108,8 +109,6 @@ 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());
}
@ -191,7 +190,7 @@ public partial class Gameboard : ContentPage
private void Game_NextPlayerNotified(object? sender, NextPlayerNotifiedEventArgs args)
{
DisplayAlert("Player switch !", "It's your turn : " + args.Player.NameTag, "<3");
Debug.WriteLine(args.Player.NameTag);
}
private void OnButtonSwapClicked(object sender, EventArgs e)
@ -202,13 +201,17 @@ 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", "Etes vous sur de vouloir swap vos tuiles ? Attention, si vous swapez vous ne pouvez pu jouer", "Yes", "No");
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");
if (answer)
{
@ -236,17 +239,24 @@ 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)
{
Shell.Current.GoToAsync("Rules");
Navigation.PushAsync(new Rules());
}
private void OnButtonSettingsClicked(object? sender, EventArgs e)
{
Shell.Current.GoToAsync("Settings");
Navigation.PushAsync(new Settings());
}

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

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

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

@ -5,6 +5,7 @@
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">
@ -19,35 +20,7 @@
<Label Text="{Binding ScoreboardList[0].Key, Source={x:Reference root}}" Style="{StaticResource SuperTitle}" TextColor="HotPink" FontSize="Medium"></Label>
<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>
<controls:Scoreboard></controls:Scoreboard>
<Button Text="Skip" Style="{StaticResource GameButton}" Clicked="OnButtonNextClick"></Button>

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

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

@ -1,8 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
<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> -->
@ -30,6 +29,9 @@
<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>
@ -65,10 +67,11 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Maui" Version="9.0.0" />
<PackageReference Include="CommunityToolkit.Maui" Version="9.0.1" />
<PackageReference Include="CommunityToolkit.Maui.MediaElement" Version="3.1.1" />
<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="9.0.0-preview.4.24266.19" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
</ItemGroup>
<ItemGroup>

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

@ -287,25 +287,6 @@ 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)]
@ -342,6 +323,48 @@ 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()
{
@ -381,6 +404,41 @@ 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)]
@ -389,7 +447,7 @@ public class TestGame
{
var game = new Game();
var player = new Player("TestPlayer");
var board = new Board(8, 8);
var board = game.GetBoard();
board.AddTileInCell(1, 1, new Tile(Shape.Club, Color.Red));
board.AddTileInCell(2, 1, new Tile(Shape.Square, Color.Red));
@ -414,6 +472,14 @@ 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,4 +1,3 @@
[![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
@ -9,7 +8,11 @@ Projet .NET MAUI portant sur la conception d'un jeu vidéo en reprenant un jeu d
## Présentation de notre 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).
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
## Composition du groupe
@ -20,6 +23,17 @@ Notré présentation est consutable sur ce [lien](https://codefirst.iut.uca.fr/g
## *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
@ -53,9 +67,10 @@ 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.
### Et voilà !
## 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 !
Votre partie est lancée ! Amusez-vous bien avec ce jeu de Qwirkle !
## Et voilà !
*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.*
Votre partie est lancée ! Amusez-vous bien avec ce jeu de Qwirkle ! :)
Loading…
Cancel
Save