diff --git a/Qwirkle/Files/LeaderBoard.json b/Qwirkle/Files/LeaderBoard.json new file mode 100644 index 0000000..176dc08 --- /dev/null +++ b/Qwirkle/Files/LeaderBoard.json @@ -0,0 +1 @@ +2024-05-31T00:00:00+02:00Jérémy012024-05-31T00:00:00+02:00Jules00 \ No newline at end of file diff --git a/Qwirkle/Files/game.json b/Qwirkle/Files/game.json new file mode 100644 index 0000000..9f0bf08 --- /dev/null +++ b/Qwirkle/Files/game.json @@ -0,0 +1 @@ +true000102030405060708090100110120130141011121314151617181911011111211311420212223242526272829210211212213214303132333435363738393103113123133144041424344454647484941041141241341450515253545556575859510511512513514606162636465666768696106116126136147071727374757677787971071171271371480818283848586878889810811812813814909192939495969798999109119129139141001011021031041051061071081091010101110121013101411011111211311411511611711811911101111111211131114falseJulesPurpleClubRedClubRedRhombusPurpleRoundPurpleStarPurpleStartrueJérémyGreenClubBlueShurikenGreenSquareOrangeStarOrangeClubBlueClubfalseJulesPurpleClubRedClubRedRhombusPurpleRoundPurpleStarPurpleStar0trueJérémyGreenClubBlueShurikenGreenSquareOrangeStarOrangeClubBlueClub0 \ No newline at end of file diff --git a/Qwirkle/QwirkleClassLibrary/Boards/Board.cs b/Qwirkle/QwirkleClassLibrary/Boards/Board.cs index b13c4f8..2f0df94 100644 --- a/Qwirkle/QwirkleClassLibrary/Boards/Board.cs +++ b/Qwirkle/QwirkleClassLibrary/Boards/Board.cs @@ -122,7 +122,7 @@ namespace QwirkleClassLibrary.Boards return null; } - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } diff --git a/Qwirkle/QwirkleClassLibrary/Boards/Cell.cs b/Qwirkle/QwirkleClassLibrary/Boards/Cell.cs index ea9353b..0f470dc 100644 --- a/Qwirkle/QwirkleClassLibrary/Boards/Cell.cs +++ b/Qwirkle/QwirkleClassLibrary/Boards/Cell.cs @@ -85,7 +85,7 @@ public class Cell : INotifyPropertyChanged } } - protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } diff --git a/Qwirkle/QwirkleClassLibrary/Events/SwapTilesNotifiedEventArgs.cs b/Qwirkle/QwirkleClassLibrary/Events/SwapTilesNotifiedEventArgs.cs index e59c3c1..0fefb18 100644 --- a/Qwirkle/QwirkleClassLibrary/Events/SwapTilesNotifiedEventArgs.cs +++ b/Qwirkle/QwirkleClassLibrary/Events/SwapTilesNotifiedEventArgs.cs @@ -1,7 +1,12 @@ namespace QwirkleClassLibrary.Events { - public class SwapTilesNotifiedEventArgs(string reason) + public class SwapTilesNotifiedEventArgs { - public string Reason { get; private set; } = reason; + public string Reason { get; private set; } + + public SwapTilesNotifiedEventArgs(string reason) + { + Reason = reason; + } } } \ No newline at end of file diff --git a/Qwirkle/QwirkleClassLibrary/Games/Game.cs b/Qwirkle/QwirkleClassLibrary/Games/Game.cs index 2c32d3b..6eee4f6 100644 --- a/Qwirkle/QwirkleClassLibrary/Games/Game.cs +++ b/Qwirkle/QwirkleClassLibrary/Games/Game.cs @@ -20,20 +20,24 @@ namespace QwirkleClassLibrary.Games [DataContract] public class Game : IPlayer, IRules { - public ReadOnlyDictionary ScoreBoard => scoreBoard.AsReadOnly(); - private readonly Dictionary scoreBoard = new(); - private TileBag? bag = null; [DataMember] - public bool GameRunning { get; private set; } + public bool GameRunning { get; set; } [DataMember] private Board board = new Board(15, 12); public Board Board => board; - + public ReadOnlyCollection PlayerList => players.AsReadOnly(); + + [DataMember] private readonly List players = new(); + + [DataMember] + private readonly Dictionary scoreBoard = new(); + + public ReadOnlyDictionary ScoreBoard => scoreBoard.AsReadOnly(); public ReadOnlyCollection CellsUsed => cellUsed.AsReadOnly(); private readonly List cellUsed = new(); @@ -259,7 +263,7 @@ namespace QwirkleClassLibrary.Games { for (int j = 0; j < 6; j++) { - if (bag != null) + if (bag != null && p.Tiles.Count < 6) { int val = RandomNumberGenerator.GetInt32(0, bag.TilesBag.Count); @@ -333,16 +337,14 @@ namespace QwirkleClassLibrary.Games return false; } - public bool TileInbag(Player player, Tile tile) + private bool TileInbag(Player player, Tile tile) { - for (int i = 0; i < player.Tiles.Count; i++) + foreach (var t in player.Tiles) { - Tile? t = player.Tiles[i]; - if (Object.ReferenceEquals(t, tile)) return true; - + if (ReferenceEquals(t, tile)) return true; } - return false; + return false; } diff --git a/Qwirkle/QwirkleClassLibrary/Persistences/GamePersistenceJson.cs b/Qwirkle/QwirkleClassLibrary/Persistences/GamePersistenceJson.cs new file mode 100644 index 0000000..da90959 --- /dev/null +++ b/Qwirkle/QwirkleClassLibrary/Persistences/GamePersistenceJson.cs @@ -0,0 +1,27 @@ +using System.Runtime.Serialization; +using QwirkleClassLibrary.Games; + +namespace QwirkleClassLibrary.Persistences; + +public class GamePersistenceJson : IGamePersistence +{ + public void SaveGame(Game game) + { + var serializer = new DataContractSerializer(typeof(Game)); + + using (Stream writer = File.Create("Game.json")) + { + serializer.WriteObject(writer, game); + } + } + + public Game LoadGame() + { + var serializer = new DataContractSerializer(typeof(Game)); + + using (Stream reader = File.OpenRead("Game.json")) + { + return serializer.ReadObject(reader) as Game ?? throw new InvalidOperationException(); + } + } +} \ No newline at end of file diff --git a/Qwirkle/QwirkleClassLibrary/Persistences/IGamePersistence.cs b/Qwirkle/QwirkleClassLibrary/Persistences/IGamePersistence.cs new file mode 100644 index 0000000..3eaa63a --- /dev/null +++ b/Qwirkle/QwirkleClassLibrary/Persistences/IGamePersistence.cs @@ -0,0 +1,10 @@ +using QwirkleClassLibrary.Games; + +namespace QwirkleClassLibrary.Persistences; + +public interface IGamePersistence +{ + void SaveGame(Game game); + + Game LoadGame(); +} \ No newline at end of file diff --git a/Qwirkle/QwirkleClassLibrary/Persistences/ILeaderboardPersistence.cs b/Qwirkle/QwirkleClassLibrary/Persistences/ILeaderboardPersistence.cs new file mode 100644 index 0000000..e63ece0 --- /dev/null +++ b/Qwirkle/QwirkleClassLibrary/Persistences/ILeaderboardPersistence.cs @@ -0,0 +1,10 @@ +using QwirkleClassLibrary.Players; + +namespace QwirkleClassLibrary.Persistences; + +public interface ILeaderboardPersistence +{ + void SaveLeaderboard(Leaderboard leaderboard); + + Leaderboard LoadLeaderboard(); +} \ No newline at end of file diff --git a/Qwirkle/QwirkleClassLibrary/Persistences/LeaderboardPersistenceJson.cs b/Qwirkle/QwirkleClassLibrary/Persistences/LeaderboardPersistenceJson.cs new file mode 100644 index 0000000..decb648 --- /dev/null +++ b/Qwirkle/QwirkleClassLibrary/Persistences/LeaderboardPersistenceJson.cs @@ -0,0 +1,27 @@ +using System.Runtime.Serialization; +using QwirkleClassLibrary.Players; + +namespace QwirkleClassLibrary.Persistences; + +public class LeaderboardPersistenceJson : ILeaderboardPersistence +{ + public void SaveLeaderboard(Leaderboard leaderboard) + { + var serializer = new DataContractSerializer(typeof(Leaderboard)); + + using (Stream writer = File.Create("Leaderboard.json")) + { + serializer.WriteObject(writer, leaderboard); + } + } + + public Leaderboard LoadLeaderboard() + { + var serializer = new DataContractSerializer(typeof(Leaderboard)); + + using (Stream reader = File.OpenRead("Leaderboard.json")) + { + return serializer.ReadObject(reader) as Leaderboard ?? throw new InvalidOperationException(); + } + } +} \ No newline at end of file diff --git a/Qwirkle/QwirkleClassLibrary/Players/Leaderboard.cs b/Qwirkle/QwirkleClassLibrary/Players/Leaderboard.cs index 2971291..3a06518 100644 --- a/Qwirkle/QwirkleClassLibrary/Players/Leaderboard.cs +++ b/Qwirkle/QwirkleClassLibrary/Players/Leaderboard.cs @@ -3,14 +3,18 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Runtime.ExceptionServices; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; namespace QwirkleClassLibrary.Players { + [DataContract] public class Leaderboard { public ReadOnlyCollection Lb => leaderboard.AsReadOnly(); + + [DataMember] private readonly List leaderboard = new(); diff --git a/Qwirkle/QwirkleClassLibrary/Players/Player.cs b/Qwirkle/QwirkleClassLibrary/Players/Player.cs index 7533147..2f7ae77 100644 --- a/Qwirkle/QwirkleClassLibrary/Players/Player.cs +++ b/Qwirkle/QwirkleClassLibrary/Players/Player.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; +using System.Runtime.Serialization; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; @@ -11,20 +12,15 @@ using QwirkleClassLibrary.Tiles; namespace QwirkleClassLibrary.Players { + [DataContract] public class Player : INotifyPropertyChanged { - private ObservableCollection playerTiles = new ObservableCollection(); - public ObservableCollection Tiles - { - get { return playerTiles; } - set - { - playerTiles = value; - OnPropertyChanged(nameof(Tiles)); - } - } + [DataMember] + public ObservableCollection Tiles { get; private set; } + public event PropertyChangedEventHandler? PropertyChanged; + void OnPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); @@ -41,10 +37,13 @@ namespace QwirkleClassLibrary.Players } NameTag = name; + Tiles = new ObservableCollection(); } - public string NameTag { get; } + [DataMember] + public string NameTag { get; set; } + [DataMember] public bool IsPlaying { get; set; } = false; /// @@ -53,7 +52,7 @@ namespace QwirkleClassLibrary.Players /// public void AddTileToPlayer(Tile tile) { - playerTiles.Add(tile); + Tiles.Add(tile); OnPropertyChanged(nameof(Tiles)); } @@ -64,7 +63,7 @@ namespace QwirkleClassLibrary.Players /// bool public bool RemoveTileToPlayer(Tile tile) { - if (playerTiles.Remove(tile)) + if (Tiles.Remove(tile)) { OnPropertyChanged(nameof(Tiles)); return true; diff --git a/Qwirkle/QwirkleClassLibrary/Players/Score.cs b/Qwirkle/QwirkleClassLibrary/Players/Score.cs index cb02b98..d8f193b 100644 --- a/Qwirkle/QwirkleClassLibrary/Players/Score.cs +++ b/Qwirkle/QwirkleClassLibrary/Players/Score.cs @@ -3,16 +3,25 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; namespace QwirkleClassLibrary.Players { + [DataContract] public class Score { + [DataMember] public string PlayerName { get; private set; } + + [DataMember] public DateTime Date { get; set; } + + [DataMember] public int Points { get; set; } + + [DataMember] public int Victories { get; set; } /// diff --git a/Qwirkle/QwirkleClassLibrary/Tiles/Color.cs b/Qwirkle/QwirkleClassLibrary/Tiles/Color.cs index 780d96c..e7e526d 100644 --- a/Qwirkle/QwirkleClassLibrary/Tiles/Color.cs +++ b/Qwirkle/QwirkleClassLibrary/Tiles/Color.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; diff --git a/Qwirkle/QwirkleClassLibrary/Tiles/TileBag.cs b/Qwirkle/QwirkleClassLibrary/Tiles/TileBag.cs index 57cf565..c8f70d3 100644 --- a/Qwirkle/QwirkleClassLibrary/Tiles/TileBag.cs +++ b/Qwirkle/QwirkleClassLibrary/Tiles/TileBag.cs @@ -35,8 +35,7 @@ namespace QwirkleClassLibrary.Tiles } } } - - + TilesBag = tiles.AsReadOnly(); } diff --git a/Qwirkle/QwirkleConsoleApp/Program.cs b/Qwirkle/QwirkleConsoleApp/Program.cs index 4754c99..49137d9 100644 --- a/Qwirkle/QwirkleConsoleApp/Program.cs +++ b/Qwirkle/QwirkleConsoleApp/Program.cs @@ -12,6 +12,7 @@ using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Text; using System.Transactions; +using QwirkleClassLibrary.Persistences; using static System.Console; @@ -173,7 +174,7 @@ static void MenuSwitch(Game game) { int enter = 0; - while (enter != 3) + while (enter != 3 && game.GameRunning) { ShowBoard(game); @@ -186,6 +187,7 @@ static void MenuSwitch(Game game) WriteLine("[1] Place your tiles"); WriteLine("[2] Swap your tiles"); WriteLine("[3] End your turn / Skip your turn"); + WriteLine("[4] Save the game"); Write("Enter your choice : "); try @@ -215,7 +217,17 @@ static void MenuSwitch(Game game) game.EmptyCellUsed(); game.DrawTiles(game.GetPlayingPlayer()); game.CheckGameOver(game.GetPlayingPlayer()); + + IGamePersistence gameSave = new GamePersistenceJson(); + gameSave.SaveGame(game); + return; + case 4: + IGamePersistence endGameSave = new GamePersistenceJson(); + endGameSave.SaveGame(game); + + game.GameRunning = false; + break; } } } @@ -231,20 +243,20 @@ static void ShowBoard(Game game) Cell? cell = board.GetCell(y, i); if (cell != null && !cell.IsFree) { - Tile? tile = cell.GetTile; + Tile? tile = cell.Tile; if (tile != null) { - Console.Write("| " + tile.GetShape.ToString()[0] + tile.GetShape.ToString()[1] + + Write("| " + tile.GetShape.ToString()[0] + tile.GetShape.ToString()[1] + tile.GetColor.ToString()[0] + " |"); } } else { - Console.Write("| |"); + Write("| |"); } } - Console.WriteLine(); + WriteLine(); } } @@ -281,9 +293,9 @@ static void MainMenu(Game game) { game.GiveTilesToPlayers(); - Console.ForegroundColor = ConsoleColor.Green; + ForegroundColor = ConsoleColor.Green; WriteLine("Game is starting !"); - Console.ResetColor(); + ResetColor(); NotificationClass nc = new NotificationClass(); @@ -309,12 +321,40 @@ static void MainMenu(Game game) ShowScoreBoard(game); } +static void MainMenuContinue(Game game) +{ + ForegroundColor = ConsoleColor.Green; + WriteLine("Game loaded ! You can continue the game !"); + ResetColor(); + + NotificationClass nc = new NotificationClass(); + + do + { + game.NextPlayerNotified += nc.NotificationNextPlayer; + game.EndOfGameNotified += nc.NotificationEndOfGame; + + game.SetNextPlayer(); + + WriteLine(" --------------------- GAME ! ------------------------"); + + MenuSwitch(game); + + game.NextPlayerNotified -= nc.NotificationNextPlayer; + game.EndOfGameNotified -= nc.NotificationEndOfGame; + + } while (game.GameRunning); +} + static void MainGame() { + Directory.SetCurrentDirectory(Path.Combine(Directory.GetCurrentDirectory(), "..\\..\\..\\..\\Files")); + Leaderboard leaderboard = new Leaderboard(); - Console.ForegroundColor = ConsoleColor.DarkGray; + + ForegroundColor = ConsoleColor.DarkGray; WriteLine(" ===================== WELCOME TO QWIRKLE ! ====================="); - Console.ResetColor(); + ResetColor(); int enter = 0; @@ -322,8 +362,9 @@ static void MainGame() { ForegroundColor = ConsoleColor.DarkCyan; WriteLine("[1] Create game"); - WriteLine("[2] Show leaderboard"); - WriteLine("[3] Exit"); + WriteLine("[2] Load game"); + WriteLine("[3] Show leaderboard"); + WriteLine("[4] Exit"); WriteLine(); ResetColor(); WriteLine("Enter your choice : "); @@ -347,47 +388,43 @@ static void MainGame() ForegroundColor = ConsoleColor.DarkYellow; WriteLine("Enter minimun 2 player and max 4 player !\n"); ResetColor(); + Game game = new Game(); AddPlayers(game); + game.StartGame(); MainMenu(game); + leaderboard.AddScoreInLead(game.ScoreBoard); + + ILeaderboardPersistence leaderboardSave = new LeaderboardPersistenceJson(); + leaderboardSave.SaveLeaderboard(leaderboard); + break; case 2: - ShowLeaderboard(leaderboard); + Game loadedGame; + + IGamePersistence gameLoad = new GamePersistenceJson(); + loadedGame = gameLoad.LoadGame(); + + ILeaderboardPersistence leaderboardLoad = new LeaderboardPersistenceJson(); + leaderboard = leaderboardLoad.LoadLeaderboard(); + + MainMenuContinue(loadedGame); + leaderboard.AddScoreInLead(loadedGame.ScoreBoard); + break; case 3: + ShowLeaderboard(leaderboard); + break; + + case 4: return; } } } -// MainGame(); - -var game = new Game(); -game.AddPlayerInGame(["Player1", "Player2", "Player3", "Player4"]); - -game.StartGame(); -game.SetNextPlayer(); - -game.PlaceTile(game.GetPlayingPlayer(), new Tile(Shape.Round, Color.Blue), 0, 0); -game.PlaceTile(game.GetPlayingPlayer(), new Tile(Shape.Square, Color.Blue), 0, 1); - -Directory.SetCurrentDirectory(Path.Combine(Directory.GetCurrentDirectory(), "..\\..\\..\\..\\Files")); - -var serializer = new DataContractJsonSerializer(typeof(Game)); -using (Stream s = File.Create("game.json")) -{ - serializer.WriteObject(s, game); -} - -Game game2; -using (Stream s = File.OpenRead("game.json")) -{ - game2 = (serializer.ReadObject(s) as Game)!; -} - -WriteLine(game2.GetBoard()!.GetCell(0, 0)!.GetTile); \ No newline at end of file +MainGame(); \ No newline at end of file diff --git a/Qwirkle/TestBase/TestGame.cs b/Qwirkle/TestBase/TestGame.cs index 7ba4293..7a3f615 100644 --- a/Qwirkle/TestBase/TestGame.cs +++ b/Qwirkle/TestBase/TestGame.cs @@ -319,16 +319,20 @@ public class TestGame Tile t1 = new Tile(Shape.Square, Color.Red); Tile t2 = new Tile(Shape.Club, Color.Purple); Tile t3 = new Tile(Shape.Round, Color.Red); + + game.GetPlayingPlayer().Tiles.Add(t1); + game.GetPlayingPlayer().Tiles.Add(t2); + game.GetPlayingPlayer().Tiles.Add(t3); - game.PlaceTile(game.GetPlayingPlayer(), t1, 0, 0); + game.PlaceTile(game.GetPlayingPlayer(), game.GetPlayingPlayer().Tiles[0], 0, 0); if (except) { - Assert.True(game.IsMoveCorrect(t3, 0, 1, game.GetBoard()!)); + Assert.True(game.IsMoveCorrect(game.GetPlayingPlayer().Tiles[1], 0, 1, game.GetBoard()!)); } else { - Assert.False(game.IsMoveCorrect(t2, 0, 1, game.GetBoard()!)); + Assert.False(game.IsMoveCorrect(game.GetPlayingPlayer().Tiles[0], 0, 1, game.GetBoard()!)); } } @@ -350,6 +354,12 @@ public class TestGame Tile t6 = new Tile(Shape.Rhombus, Color.Red); Tile t7 = new Tile(Shape.Round, Color.Red); + game.GetPlayingPlayer().Tiles.Add(t1); + game.GetPlayingPlayer().Tiles.Add(t2); + game.GetPlayingPlayer().Tiles.Add(t3); + game.GetPlayingPlayer().Tiles.Add(t4); + game.GetPlayingPlayer().Tiles.Add(t5); + game.GetPlayingPlayer().Tiles.Add(t6); game.PlaceTile(game.GetPlayingPlayer(), t1, 0, 0); game.PlaceTile(game.GetPlayingPlayer(), t2, 1, 0); @@ -358,7 +368,8 @@ public class TestGame game.PlaceTile(game.GetPlayingPlayer(), t5, 4, 0); game.PlaceTile(game.GetPlayingPlayer(), t6, 5, 0); - + game.GetPlayingPlayer().Tiles.Add(t7); + Assert.False(game.IsMoveCorrect(t7, 6, 0, game.GetBoard()!)); }