diff --git a/source/Trek-12/ConsoleApp/ConsoleApp.csproj b/source/Trek-12/ConsoleApp/ConsoleApp.csproj index 229387b..5d6a28e 100644 --- a/source/Trek-12/ConsoleApp/ConsoleApp.csproj +++ b/source/Trek-12/ConsoleApp/ConsoleApp.csproj @@ -8,6 +8,7 @@ + diff --git a/source/Trek-12/ConsoleApp/Program.cs b/source/Trek-12/ConsoleApp/Program.cs index 117e7cb..13ca4b4 100644 --- a/source/Trek-12/ConsoleApp/Program.cs +++ b/source/Trek-12/ConsoleApp/Program.cs @@ -1,246 +1,416 @@ -// See https://aka.ms/new-console-template for more information - -using Models; -using Models.Events; -using Models.Exceptions; -using Models.Game; - -namespace ConsoleApp; - -class Program -{ - /// - /// Main function of the console app - /// - /// - static void Main(string[] args) - { - Console.WriteLine("Enter your pseudo:"); - string? pseudo = Console.ReadLine(); - if (pseudo != null) - { - Player player = new Player(pseudo); - - Map map = new Map("background"); - Game game = new Game(player, map); - - // Abonnement aux événements - game.GameStarted += OnGameStarted!; - game.GameEnded += OnGameEnded!; - game.BoardUpdated += OnBoardUpdated!; - game.DiceRolled += OnDiceRolled!; - game.OperationChosen += OnOperationChosen!; - game.CellChosen += OnCellChosen!; - - // Initialisation - game.InitializeGame(); - } - } - - /// - /// Handles the event when the game has started. - /// - /// - /// - static void OnGameStarted(object sender, GameStartedEventArgs e) - { - Console.WriteLine($"The game has started! Player: {e.CurrentPlayer.Pseudo}"); - } - - /// - /// Handles the event when the game has ended. - /// - /// - /// - static void OnGameEnded(object sender, GameEndedEventArgs e) - { - Console.WriteLine($"The game has ended! Player: {e.CurrentPlayer.Pseudo}"); - } - - /// - /// Handles the event when the board is updated. - /// - /// - /// - static void OnBoardUpdated(object sender, EventArgs e) - { - DisplayBoard(((Game)sender).UsedMap); - DisplayOperationTable(((Game)sender).UsedMap.OperationGrid); - } - - /// - /// Handles the event when the dice are rolled. - /// - /// - /// - static void OnDiceRolled(object sender, DiceRolledEventArgs e) - { - Console.WriteLine($"Dice 1: {e.Dice1Value} | Dice 2: {e.Dice2Value}"); - Operation playerOperation = GetPlayerOperation(); - ((Game)sender).HandlePlayerOperation(playerOperation); - } - - /// - /// Handles the event when an operation is chosen by the player. - /// - /// - /// - static void OnOperationChosen(object sender, OperationChosenEventArgs e) - { - Console.WriteLine($"Operation: {e.Operation}, Result: {e.Result}"); - DisplayOperationTable(((Game)sender).UsedMap.OperationGrid); - Cell playerChoice = GetPlayerChoice(); - try - { - ((Game)sender).HandlePlayerChoice(playerChoice, e.Result); - } - catch (InvalidCellCoordinatesException err) - { - Console.WriteLine(err.Message); - playerChoice = GetPlayerChoice(); - ((Game)sender).HandlePlayerChoice(playerChoice, e.Result); - } - catch (InvalidCellException err) - { - Console.WriteLine(err.Message); - playerChoice = GetPlayerChoice(); - ((Game)sender).HandlePlayerChoice(playerChoice, e.Result); - } - } - - /// - /// Handles the event when a cell is chosen by the player. - /// - /// - /// - static void OnCellChosen(object sender, CellChosenEventArgs e) - { - Console.WriteLine($"Cell chosen: ({e.Cell.X}, {e.Cell.Y}) with result: {e.Result}"); - DisplayBoard(((Game)sender).UsedMap); - } - - /// - /// Displays the game board. - /// - /// Used map to display - static void DisplayBoard(Map map) - { - int cpt = 0; - for (int i = 0; i < map.Boards.Count; i++) - { - if (cpt % 6 == 0) - { - Console.Write("| "); - } - - if (map.Boards[i].Value.HasValue) - { - Console.Write(map.Boards[i].Value?.ToString().PadLeft(2)); - } - else - { - Console.Write(" O"); - } - - cpt++; - if (cpt % 6 == 0) - { - Console.Write(" |"); - Console.WriteLine(); - } - } - } - - /// - /// Displays the operation table. - /// - /// The operation table to display. - static void DisplayOperationTable(List operationTable) - { - Console.WriteLine("Operation Table:"); - string[] operations = { "Addition (+)", "Subtraction (-)", "Multiplication (*)", "Lower Dice (less)", "Higher Dice (high)" }; - - for (int i = 0; i < operations.Length; i++) - { - Console.Write(operations[i].PadRight(18)); - - for (int j = 0; j < 4; j++) - { - int index = i * 4 + j; - if (index < operationTable.Count) - { - string status = operationTable[index].IsChecked ? "X" : " "; - Console.Write($" | {status}"); - } - } - Console.WriteLine(); - } - } - - /// - /// Gets the cell chosen by the player. - /// - /// The cell chosen by the player. - static Cell GetPlayerChoice() - { - int row, column; - while (true) - { - Console.WriteLine("Enter the position of the cell you want to play"); - Console.WriteLine("Enter the row number (0-5)"); - if (!int.TryParse(Console.ReadLine(), out row) || row < 0 || row >= 6) - { - Console.WriteLine("Invalid row number. Please enter a number between 0 and 5."); - continue; - } - - Console.WriteLine("Enter the column number (0-5)"); - if (!int.TryParse(Console.ReadLine(), out column) || column < 0 || column >= 6) - { - Console.WriteLine("Invalid column number. Please enter a number between 0 and 5."); - continue; - } - - return new Cell(row, column); - } - } - - /// - /// Gets the operation chosen by the player. - /// - /// - /// - static Operation GetPlayerOperation() - { - DisplayOperationOptions(); - string? op = Console.ReadLine(); - while (op != "1" && op != "2" && op != "3" && op != "4" && op != "5") - { - Console.WriteLine("Invalid operation. Please choose again."); - op = Console.ReadLine(); - } - - return op switch - { - "1" => Operation.ADDITION, - "2" => Operation.SUBTRACTION, - "3" => Operation.MULTIPLICATION, - "4" => Operation.LOWER, - "5" => Operation.HIGHER, - _ => throw new ArgumentOutOfRangeException() - }; - } - - /// - /// Displays the operation options for the player to choose from. - /// - static void DisplayOperationOptions() - { - Console.WriteLine("Choose an operation:"); - Console.WriteLine("1: Addition (+)"); - Console.WriteLine("2: Subtraction (-)"); - Console.WriteLine("3: Multiplication (*)"); - Console.WriteLine("4: Lower Dice (less)"); - Console.WriteLine("5: Higher Dice (high)"); - } +// See https://aka.ms/new-console-template for more information + +using Models; +using Models.Events; +using Models.Game; +using Models.Interfaces; +using DataContractPersistence; +using Microsoft.Extensions.Logging; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace ConsoleApp; + +class Program +{ + + static Game Game { get; set; } + + /// + /// Main function of the console app + /// + /// + static void Main(string[] args) + { + Console.WriteLine("Enter your pseudo:"); + string? pseudo = Console.ReadLine(); + if (pseudo != null) + { + IPersistence persistence = new DataContractXml(); + Player player = new Player(pseudo, "test.png"); + + Map map = new Map("Dunai","background"); + Game = new Game(persistence); + + // Abonnement aux événements + Game.GameStarted += OnGameStarted!; + Game.GameEnded += OnGameEnded!; + Game.BoardUpdated += OnBoardUpdated!; + Game.DiceRolled += OnDiceRolled!; + Game.OperationChosen += OnOperationChosen!; + Game.CellChosen += OnCellChosen!; + Game.PlayerChooseOp += OnPlayerSelectionOp!; + Game.PlayerOption += OnPlayerOption!; + Game.PlayerChooseCell += OnPlayerSelectionCell!; + + // Initialisation + Game.InitializeGame(map, player); + Game.GameLoop(); + } + + + } + + static void OnPlayerSelectionCell(Object sender, PlayerChooseCellEventArgs e) + { + int row, column; + while (true) + { + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine("Enter the position of the cell you want to play"); + Console.WriteLine("Enter the row number (0-6)"); + Console.ResetColor(); + if (!int.TryParse(Console.ReadLine(), out row) || row < 0 || row >= 7) + { + Console.ForegroundColor= ConsoleColor.Red; + Console.WriteLine("Invalid row number. Please enter a number between 0 and 6."); + Console.ResetColor(); + continue; + } + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine("Enter the column number (0-6)"); + Console.ResetColor(); + if (!int.TryParse(Console.ReadLine(), out column) || column < 0 || column >= 7) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Invalid column number. Please enter a number between 0 and 6."); + Console.ResetColor(); + continue; + } + + Game.PlayerCell = new Cell(row, column); + break; + } + } + + static void OnPlayerOption(object sender, PlayerOptionEventArgs e) + { + Console.WriteLine(); + if (e.Turn != 1) + { + IEnumerable PlayedCellsQuery = + from cell in e.Board + where cell.Valid == true + where cell.Value != null + select cell; + foreach (var item in e.Board) + { + if (item.X == 6) + Console.WriteLine(); + if (!item.Valid) + Console.Write(" "); + else if (item.Value != null) + Console.Write($"{item.Value}"); + else + { + foreach (var item1 in PlayedCellsQuery) + { + if (Math.Abs(item.X - item1.X) <= 1 && Math.Abs(item.Y - item1.Y) <= 1) + { + Console.ForegroundColor = ConsoleColor.Cyan; + Console.Write($"{e.Resultat}"); + Console.ResetColor(); + } + + } + } + } + return; + } + foreach (var item in e.Board) + { + if (!item.Valid) + Console.Write(" "); + else + { + Console.ForegroundColor = ConsoleColor.Cyan; + Console.Write($"{e.Resultat}"); + Console.ResetColor(); + + } + if (item.X == 6) + Console.WriteLine(); + } + Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine("Choose an Available cell."); + Console.ResetColor(); + } + + static void OnPlayerSelectionOp(object sender, PlayerChooseOperationEventArgs e) + { + Console.WriteLine(); + DisplayOperationTable(((Game)sender).UsedMap.OperationGrid.ToList()); + Console.WriteLine(); + Console.WriteLine("0. Lower | 1. Higher | 2. Substraction | 3. Addition | 4. Multiplication"); + string? op = Console.ReadLine(); + while (op != "0" && op != "1" && op != "2" && op != "3" && op != "4") + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Invalid operation. Please choose again."); + Console.ResetColor(); + op = Console.ReadLine(); + } + int test = Convert.ToInt32(op); + Game.PlayerOperation = (Operation)test; + + } + + + /// + /// Handles the event when the game has started. + /// + /// + /// + static void OnGameStarted(object sender, GameStartedEventArgs e) + { + Console.WriteLine($"The game has started! Player: {e.CurrentPlayer.Pseudo}"); + } + + /// + /// Handles the event when the game has ended. + /// + /// + /// + static void OnGameEnded(object sender, GameEndedEventArgs e) + { + Console.WriteLine($"The game has ended! Player: {e.CurrentPlayer.Pseudo}"); + Console.WriteLine($"Points: {e.Point}"); + } + + /// + /// Handles the event when the board is updated. + /// + /// + /// + static void OnBoardUpdated(object sender, BoardsUpdateEventArgs e) + { + foreach (var item in e.Boards) + { + if (!item.Valid) + Console.Write(" "); + else if (item.Value != null) + Console.Write($"{item.Value}"); + else Console.Write("O"); + if (item.X == 6) + Console.WriteLine(); + } + } + + /// + /// Handles the event when the dice are rolled. + /// + /// + /// + static void OnDiceRolled(object sender, DiceRolledEventArgs e) + { + // Console.Clear(); + Console.WriteLine($"Dice 1: {e.Dice1Value} | Dice 2: {e.Dice2Value}"); + Console.WriteLine(); + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine("Choose an operation."); + Console.ResetColor(); + } + + /// + /// Handles the event when an operation is chosen by the player. + /// + /// + /// + static void OnOperationChosen(object sender, OperationChosenEventArgs e) + { + Console.WriteLine($"Operation: {e.Operation}, Result: {e.Result}"); + DisplayOperationTable(((Game)sender).UsedMap.OperationGrid.ToList()); + Cell playerChoice = GetPlayerChoice(); + bool test = ((Game)sender).HandlePlayerChoice(playerChoice, e.Result); + if(!test) + { + Console.WriteLine("Invalid cell. Please choose again."); + Console.WriteLine(); + Console.WriteLine(); + DisplayBoard(((Game)sender).UsedMap); + OnOperationChosen(sender, e); + } + + + + /* + try + { + ((Game)sender).HandlePlayerChoice(playerChoice, e.Result); + } + catch (InvalidCellCoordinatesException err) + { + Console.WriteLine(err.Message); + playerChoice = GetPlayerChoice(); + ((Game)sender).HandlePlayerChoice(playerChoice, e.Result); + } + catch (InvalidCellException err) + { + Console.WriteLine(err.Message); + playerChoice = GetPlayerChoice(); + ((Game)sender).HandlePlayerChoice(playerChoice, e.Result); + } + catch (InvalidPlaceResultException err) + { + Console.WriteLine(err.Message); + playerChoice = GetPlayerChoice(); + ((Game)sender).HandlePlayerChoice(playerChoice, e.Result); + } + */ + } + + /// + /// Handles the event when a cell is chosen by the player. + /// + /// + /// + static void OnCellChosen(object sender, CellChosenEventArgs e) + { + Console.WriteLine($"Cell chosen: ({e.Cell.X}, {e.Cell.Y}) with result: {e.Result}"); + DisplayBoard(((Game)sender).UsedMap); + } + + /// + /// Displays the game board. + /// + /// Used map to display + static void DisplayBoard(Map map) + { + int cpt = 0; + for (int i = 0; i < map.Boards.Count; i++) + { + if (cpt % 6 == 0) + { + Console.Write("| "); + } + + if (map.Boards[i].Value.HasValue) + { + Console.Write(map.Boards[i].Value?.ToString().PadLeft(2)); + } + else + { + Console.Write(" O"); + } + + cpt++; + if (cpt % 6 == 0) + { + Console.Write(" |"); + Console.WriteLine(); + } + } + } + + /// + /// Displays the operation table. + /// + /// The operation table to display. + static void DisplayOperationTable(List operationTable) + { + Console.ForegroundColor = ConsoleColor.Yellow; + foreach ( var cell in operationTable) + { + + if (cell.X == 0 && cell.Y == 0) + Console.Write("Lower => "); + if (cell.X == 0 && cell.Y == 1) + Console.Write("Higher => "); + if (cell.X == 0 && cell.Y == 2) + Console.Write("Substraction => "); + if (cell.X == 0 && cell.Y == 3) + Console.Write("Addition => "); + if (cell.X == 0 && cell.Y == 4) + Console.Write("Multiplication => "); + if (cell.IsChecked) + Console.Write("X | "); + if (!cell.IsChecked) + Console.Write(" | "); + if (cell.X == 3) + Console.WriteLine(); + } + Console.ResetColor(); + } + + /// + /// Gets the cell chosen by the player. + /// + /// The cell chosen by the player. + static Cell GetPlayerChoice() + { + int row, column; + while (true) + { + Console.WriteLine("Enter the position of the cell you want to play"); + Console.WriteLine("Enter the row number (0-5)"); + if (!int.TryParse(Console.ReadLine(), out row) || row < 0 || row >= 6) + { + Console.WriteLine("Invalid row number. Please enter a number between 0 and 5."); + continue; + } + + Console.WriteLine("Enter the column number (0-5)"); + if (!int.TryParse(Console.ReadLine(), out column) || column < 0 || column >= 6) + { + Console.WriteLine("Invalid column number. Please enter a number between 0 and 5."); + continue; + } + + return new Cell(row, column); + } + } + + /// + /// Gets the operation chosen by the player. + /// + /// + /// + static Operation GetPlayerOperation(object? sender) + { + DisplayOperationOptions(); + string? op = Console.ReadLine(); + while (op != "1" && op != "2" && op != "3" && op != "4" && op != "5") + { + Console.WriteLine("Invalid operation. Please choose again."); + op = Console.ReadLine(); + } + int test = Convert.ToInt32(op); + + while(((Game)sender).UsedMap.CheckOperationPossible(test-1)) + { + Console.WriteLine("Invalid operation. Please choose again."); + Console.WriteLine(); + op = Console.ReadLine(); + while (op != "1" && op != "2" && op != "3" && op != "4" && op != "5") + { + Console.WriteLine("Invalid operation. Please choose again."); + op = Console.ReadLine(); + } + test = Convert.ToInt32(op); + } + + return op switch + { + "1" => Operation.ADDITION, + "2" => Operation.SUBTRACTION, + "3" => Operation.MULTIPLICATION, + "4" => Operation.LOWER, + "5" => Operation.HIGHER, + _ => throw new ArgumentOutOfRangeException() + }; + } + + /// + /// Displays the operation options for the player to choose from. + /// + static void DisplayOperationOptions() + { + Console.WriteLine("Choose an operation:"); + Console.WriteLine("1: Addition (+)"); + Console.WriteLine("2: Subtraction (-)"); + Console.WriteLine("3: Multiplication (*)"); + Console.WriteLine("4: Lower Dice (less)"); + Console.WriteLine("5: Higher Dice (high)"); + } } \ No newline at end of file diff --git a/source/Trek-12/DataContractPersistence/DataContractJson.cs b/source/Trek-12/DataContractPersistence/DataContractJson.cs new file mode 100644 index 0000000..d53d6fb --- /dev/null +++ b/source/Trek-12/DataContractPersistence/DataContractJson.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using System.Runtime.Serialization.Json; +using System.IO; +using System.Xml.Serialization; +using System.Collections.ObjectModel; +using System.Text.Json; +using Models.Game; +using Models.Interfaces; + +namespace DataContractPersistence +{ + public class DataContractJson : IPersistence + { + /// + /// Name of the file where the data will be saved + /// + public string FileName { get; set; } = "data.json"; + + /// + /// Path (relative to the project) + /// + public string FilePath { get; set; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Trek_12"); + + /// + /// Load all the data from JSON file + /// + /// A tuple with the lists of players, games, maps and bestScores + public (ObservableCollection, ObservableCollection, ObservableCollection, ObservableCollection) LoadData() + { + var JsonSerializer = new DataContractJsonSerializer(typeof(DataToPersist)); + DataToPersist? data = new DataToPersist(); + + using (Stream s = File.OpenRead(Path.Combine(FilePath, FileName))) + { + data = JsonSerializer.ReadObject(s) as DataToPersist; + } + Console.WriteLine("Data loaded: " + Path.Combine(FilePath, FileName)); + return (data.Players, data.Games, data.Maps, data.BestScores); + } + + /// + /// Save all the data to a JSON file + /// + /// + /// + /// + /// + public void SaveData(ObservableCollection players, ObservableCollection games, ObservableCollection maps, ObservableCollection bestScores) + { + Debug.WriteLine("Saving data at " + Path.Combine(FilePath, FileName)); + if (!Directory.Exists(FilePath)) + { + Debug.WriteLine("Directory created"); + Debug.WriteLine(Directory.GetDirectoryRoot(FilePath)); + Debug.WriteLine(FilePath); + Directory.CreateDirectory(FilePath); + } + + var JsonSerializer = new DataContractJsonSerializer(typeof(DataToPersist)); + DataToPersist? data = new DataToPersist(); + + data.Players = players; + data.Games = games; + data.Maps = maps; + data.BestScores = bestScores; + + var settings = new XmlWriterSettings() { Indent = true }; + using (FileStream stream = File.Create(Path.Combine(FilePath, FileName))) + { + using (var writer = JsonReaderWriterFactory.CreateJsonWriter( + stream, + Encoding.UTF8, + false, + true)) + { + JsonSerializer.WriteObject(writer, data); + writer.Flush(); + } + } + } + } +} diff --git a/source/Trek-12/DataContractPersistence/DataContractPersistence.csproj b/source/Trek-12/DataContractPersistence/DataContractPersistence.csproj new file mode 100644 index 0000000..f70f862 --- /dev/null +++ b/source/Trek-12/DataContractPersistence/DataContractPersistence.csproj @@ -0,0 +1,17 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + diff --git a/source/Trek-12/DataContractPersistence/DataContractXml.cs b/source/Trek-12/DataContractPersistence/DataContractXml.cs new file mode 100644 index 0000000..9ffa396 --- /dev/null +++ b/source/Trek-12/DataContractPersistence/DataContractXml.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using System.Runtime.Serialization; +using System.Xml; +using System.Xml.Serialization; +using Models.Game; +using Models.Interfaces; + +namespace DataContractPersistence +{ + public class DataContractXml : IPersistence + { + /// + /// Name of the file where the data will be saved + /// + public string FileName { get; set; } = "data.xml"; + + /// + /// Path (relative to the project) + /// + public string FilePath { get; set; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Trek_12"); + + /// + /// Load all the data from XML file + /// + /// A tuple with the lists of players, games, maps and bestScores + public (ObservableCollection, ObservableCollection, ObservableCollection, ObservableCollection) LoadData() + { + var serializer = new DataContractSerializer(typeof(DataToPersist)); + DataToPersist? data = new DataToPersist(); + + using (Stream s = File.OpenRead(Path.Combine(FilePath, FileName))) + { + data = serializer.ReadObject(s) as DataToPersist; + } + Console.WriteLine("Data loaded: " + Path.Combine(FilePath, FileName)); + return (data.Players, data.Games, data.Maps, data.BestScores); + } + + /// + /// Save all the data to a XML file + /// + /// + /// + /// + /// + public void SaveData(ObservableCollection players, ObservableCollection games, ObservableCollection maps, ObservableCollection bestScores) + { + if(!Directory.Exists(FilePath)) + { + Debug.WriteLine("Directory created"); + Debug.WriteLine(Directory.GetDirectoryRoot(FilePath)); + Debug.WriteLine(FilePath); + Directory.CreateDirectory(FilePath); + } + + var serializer = new DataContractSerializer(typeof(DataToPersist)); + DataToPersist? data = new DataToPersist(); + + data.Players = players; + data.Games = games; + data.Maps = maps; + data.BestScores = bestScores; + + var settings = new XmlWriterSettings() { Indent = true }; + using (TextWriter tw = File.CreateText(Path.Combine(FilePath, FileName))) + { + using (XmlWriter writer = XmlWriter.Create(tw, settings)) + { + serializer.WriteObject(writer, data); + Console.WriteLine("Data saved: " + Path.Combine(FilePath, FileName)); + } + } + } + } +} \ No newline at end of file diff --git a/source/Trek-12/DataContractPersistence/DataToPersist.cs b/source/Trek-12/DataContractPersistence/DataToPersist.cs new file mode 100644 index 0000000..9c72c68 --- /dev/null +++ b/source/Trek-12/DataContractPersistence/DataToPersist.cs @@ -0,0 +1,28 @@ +using System.Collections.ObjectModel; +using Models.Game; + +namespace DataContractPersistence +{ + public class DataToPersist + { + /// + /// List of players + /// + public ObservableCollection Players { get; set; } + + /// + /// List of games (with all the data in it to be able to recreate the game) + /// + public ObservableCollection Games { get; set; } + + /// + /// List of maps with their boards + /// + public ObservableCollection Maps { get; set; } + + /// + /// List of best scores + /// + public ObservableCollection BestScores { get; set; } + } +} \ No newline at end of file diff --git a/source/Trek-12/DataContractPersistence/SqLitePersistence.cs b/source/Trek-12/DataContractPersistence/SqLitePersistence.cs new file mode 100644 index 0000000..f48c0d6 --- /dev/null +++ b/source/Trek-12/DataContractPersistence/SqLitePersistence.cs @@ -0,0 +1,69 @@ +using SQLite; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.IO; +using System.Threading.Tasks; + +namespace DataContractPersistence +{ + using Models.Game; + using Models.Interfaces; + + public class SqLitePersistence : IPersistence + { + private readonly SQLiteConnection _database; + private readonly string _databasePath; + + public SqLitePersistence() + { + _databasePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Trek_12.db"); + _database = new SQLiteConnection(_databasePath); + _database.CreateTable(); + _database.CreateTable(); + _database.CreateTable(); + _database.CreateTable(); + } + + public (ObservableCollection, ObservableCollection, ObservableCollection, ObservableCollection) LoadData() + { + var players = new ObservableCollection(_database.Table()); + var games = new ObservableCollection(_database.Table()); + var maps = new ObservableCollection(_database.Table()); + var bestScores = new ObservableCollection(_database.Table()); + + return (players, games, maps, bestScores); + } + + public void SaveData(ObservableCollection players, ObservableCollection games, ObservableCollection maps, ObservableCollection bestScores) + { + _database.RunInTransaction(() => + { + _database.DeleteAll(); + _database.DeleteAll(); + _database.DeleteAll(); + _database.DeleteAll(); + }); + + foreach (var player in players) + { + _database.Insert(player); + } + + foreach (var game in games) + { + _database.Insert(game); + } + + foreach (var map in maps) + { + _database.Insert(map); + } + + foreach (var bestScore in bestScores) + { + _database.Insert(bestScore); + } + } + } +} diff --git a/source/Trek-12/Models/Events/BoardsUpdateEventArgs.cs b/source/Trek-12/Models/Events/BoardsUpdateEventArgs.cs new file mode 100644 index 0000000..1526db6 --- /dev/null +++ b/source/Trek-12/Models/Events/BoardsUpdateEventArgs.cs @@ -0,0 +1,17 @@ +using Models.Game; + +namespace Models.Events +{ + /// + /// Event arguments for when the board change. + /// + public class BoardsUpdateEventArgs : EventArgs + { + public List Boards { get; set; } + + public BoardsUpdateEventArgs(List board) + { + Boards = board; + } + } +} diff --git a/source/Trek-12/Models/Events/GameEndedEventArgs.cs b/source/Trek-12/Models/Events/GameEndedEventArgs.cs index 7148eeb..fd6ce0c 100644 --- a/source/Trek-12/Models/Events/GameEndedEventArgs.cs +++ b/source/Trek-12/Models/Events/GameEndedEventArgs.cs @@ -9,9 +9,12 @@ namespace Models.Events { public Player CurrentPlayer { get; } - public GameEndedEventArgs(Player winner) + public int? Point { get; } + + public GameEndedEventArgs(Player winner, int? point) { CurrentPlayer = winner; + Point = point; } } } diff --git a/source/Trek-12/Models/Events/PlayerChooseCellEventArgs.cs b/source/Trek-12/Models/Events/PlayerChooseCellEventArgs.cs new file mode 100644 index 0000000..cf51950 --- /dev/null +++ b/source/Trek-12/Models/Events/PlayerChooseCellEventArgs.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Models.Game; + +namespace Models.Events +{ + public class PlayerChooseCellEventArgs : EventArgs + { + public Cell Cell { get; set; } + public PlayerChooseCellEventArgs(Cell cell) + { + Cell = cell; + } + } +} diff --git a/source/Trek-12/Models/Events/PlayerChooseOperationEventArgs.cs b/source/Trek-12/Models/Events/PlayerChooseOperationEventArgs.cs new file mode 100644 index 0000000..ccbcd6b --- /dev/null +++ b/source/Trek-12/Models/Events/PlayerChooseOperationEventArgs.cs @@ -0,0 +1,19 @@ +using Models.Game; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Models.Events +{ + public class PlayerChooseOperationEventArgs : EventArgs + { + public Operation PlayerOp { get; set; } + + public PlayerChooseOperationEventArgs(Operation op) + { + PlayerOp = op; + } + } +} diff --git a/source/Trek-12/Models/Events/PlayerOptionEventArgs.cs b/source/Trek-12/Models/Events/PlayerOptionEventArgs.cs new file mode 100644 index 0000000..036370b --- /dev/null +++ b/source/Trek-12/Models/Events/PlayerOptionEventArgs.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Models.Game; + +namespace Models.Events +{ + public class PlayerOptionEventArgs : EventArgs + { + public List Board { get; set; } + public int Resultat { get; set; } + public int Turn { get; set; } + + public PlayerOptionEventArgs(List boards, int resultat, int turn) + { + Board = boards; + Resultat = resultat; + Turn = turn; + } + } +} diff --git a/source/Trek-12/Models/Exceptions/InvalidCellCoordinatesException.cs b/source/Trek-12/Models/Exceptions/InvalidCellCoordinatesException.cs deleted file mode 100644 index 4f4e53d..0000000 --- a/source/Trek-12/Models/Exceptions/InvalidCellCoordinatesException.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Models.Exceptions -{ - /// - /// Exception for when the cell coordinates are invalid. - /// - public class InvalidCellCoordinatesException : Exception - { - public InvalidCellCoordinatesException(string message) : base(message) { } - } -} - diff --git a/source/Trek-12/Models/Exceptions/InvalidCellException.cs b/source/Trek-12/Models/Exceptions/InvalidCellException.cs deleted file mode 100644 index 7556c26..0000000 --- a/source/Trek-12/Models/Exceptions/InvalidCellException.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Models.Exceptions -{ - /// - /// Exception for when the cell is invalid. - /// - public class InvalidCellException : Exception - { - public InvalidCellException(string message) : base(message) { } - } -} - diff --git a/source/Trek-12/Models/Game/Base64Converter.cs b/source/Trek-12/Models/Game/Base64Converter.cs new file mode 100644 index 0000000..9d535d9 --- /dev/null +++ b/source/Trek-12/Models/Game/Base64Converter.cs @@ -0,0 +1,41 @@ +using System; +using Microsoft.Maui.Controls; +using Models.Interfaces; + +namespace Models.Game +{ + /// + /// Converter to Base64 + /// + public class Base64Converter : IImageConverter + { + /// + /// Converts an image to a base64 string + /// + /// The path to access the image + /// The base64 string representation of the image + /// Native .NET exception + public string ConvertImage(string imagePath) + { + if (!File.Exists(imagePath)) + { + // native .NET exception + throw new FileNotFoundException("Image file not found", imagePath); + } + + byte[] imageBytes = File.ReadAllBytes(imagePath); + return Convert.ToBase64String(imageBytes); + } + + /// + /// Retrieve an image from a string encoded in base64 + /// + /// + /// + public ImageSource RetrieveImage(string imageString) + { + byte[] imageBytes = Convert.FromBase64String(imageString); + return ImageSource.FromStream(() => new MemoryStream(imageBytes)); + } + } +} diff --git a/source/Trek-12/Models/Game/BestScore.cs b/source/Trek-12/Models/Game/BestScore.cs index c2c5ca4..aba67ca 100644 --- a/source/Trek-12/Models/Game/BestScore.cs +++ b/source/Trek-12/Models/Game/BestScore.cs @@ -2,53 +2,83 @@ using System.Collections.Generic; using System.Data; using System.Linq; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; +using SQLite; namespace Models.Game { /// /// This class represents the best score of a player. /// + [DataContract, SQLite.Table("BestScores")] public class BestScore { - /// - /// Initialize a new instance of the BestScore class. - /// - /// Number of games played by the new user - /// Best score - public BestScore(int gamesPlayed, int score) - { - GamesPlayed = gamesPlayed; - Score = score; - if (GamesPlayed < 0) - GamesPlayed = 0; - if (Score < 0) - Score = 0; - } + + [PrimaryKey, AutoIncrement] + public int Id { get; set; } /// - /// Number of games played by the user. + /// Name of the map. /// - public int GamesPlayed { get; private set; } + [DataMember] + public string MapName { get; private set; } + + [DataMember] + public Player ThePlayer { get; private set; } /// - /// Best score of the player. + /// Number of games played by the user (on a specific map). /// - private int _score; - public int Score - { - get + private int _gamesPlayed; + [DataMember] + public int GamesPlayed + { + get => _gamesPlayed; + private set { - return _score; + if (value >= 0) + _gamesPlayed = value; + else _gamesPlayed = 0; } + } + + /// + /// Best score of the player (on a specific map). + /// + private int _score; + [DataMember] + public int Score + { + get => _score; private set { - if (value > _score) + if (value >= 0) _score = value; + else _score = 0; } } + /// + /// Initialize a new instance of the BestScore class. + /// + /// Number of games played by the new user + /// Best score + /// The name of the map + public BestScore(string map, Player player, int gamesPlayed, int score) + { + MapName = map; + ThePlayer = player; + GamesPlayed = gamesPlayed; + Score = score; + } + + /// + /// SQLite constructor + /// + public BestScore() { } + /// /// Increment the number of games played by the user. /// @@ -63,7 +93,31 @@ namespace Models.Game /// New best score public void UpdateScore(int newScore) { - Score = newScore; + Score += newScore; + } + + /// + /// Redefine the equal operation between BestScore. + /// + /// The object to compare with the current BestScore. + /// true if the specified object is equal to the current BestScore; otherwise, false. + public override bool Equals(object? obj) + { + if (obj == null || GetType() != obj.GetType()) + { + return false; + } + BestScore c = (BestScore)obj; + return (MapName == c.MapName && ThePlayer == c.ThePlayer); + } + + /// + /// Returns the hash code for the current BestScore, in order for the Equals operation to work + /// + /// The hash code for the current BestScore. + public override int GetHashCode() + { + return MapName.GetHashCode() ^ ThePlayer.GetHashCode(); } } } diff --git a/source/Trek-12/Models/Game/Cell.cs b/source/Trek-12/Models/Game/Cell.cs index 49fe4bb..0bfe98a 100644 --- a/source/Trek-12/Models/Game/Cell.cs +++ b/source/Trek-12/Models/Game/Cell.cs @@ -1,14 +1,20 @@ -namespace Models.Game +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization; + +namespace Models.Game { /// /// The Cell class represents a cell in the application. /// - public class Cell : Position, IEquatable + [DataContract] + public class Cell : Position, IEquatable, INotifyPropertyChanged { /// /// The value of the cell. /// private int? _value; + [DataMember] public int? Value { get => _value; set @@ -18,18 +24,31 @@ throw new Exception("La valeur doit être supérieure à 0"); } this._value = value; + + OnPropertyChanged(); } } /// /// The fact that the cell is dangerous or not. /// - private bool IsDangerous { get; set; } + [DataMember] + public bool IsDangerous { get; set; } + + [DataMember] + public bool Valid { get; set; } + /// /// Atribute to know if the cell is a penalty cell. /// - private bool Penalty { get; set; } + [DataMember] + public bool Penalty { get; private set; } + + public void SetPenalty() + { + Penalty = true; + } /// /// Constructor of the Cell class. @@ -41,6 +60,7 @@ { IsDangerous = isDangerous; Penalty = false; + Valid = false; } /// @@ -60,5 +80,13 @@ if (this.X == other.X && this.Y == other.Y) return true; return false; } + + + public event PropertyChangedEventHandler? PropertyChanged; + + protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } } } \ No newline at end of file diff --git a/source/Trek-12/Models/Game/Dice.cs b/source/Trek-12/Models/Game/Dice.cs index 2d47fe3..9b7ddaf 100644 --- a/source/Trek-12/Models/Game/Dice.cs +++ b/source/Trek-12/Models/Game/Dice.cs @@ -14,12 +14,12 @@ namespace Models.Game /// /// Lowest number on the dice. /// - public int NbMin { get; private set; } + public int MinVal { get; private set; } /// /// Highest number on the dice. /// - public int NbMax { get; private set; } + public int MaxVal { get; private set; } /// /// Value of the dice. @@ -29,9 +29,9 @@ namespace Models.Game get => _value; private set { - if (value < NbMin || value > NbMax) + if (value < MinVal || value > MaxVal) { - value = NbMin; + value = MinVal; } _value = value; } @@ -40,13 +40,13 @@ namespace Models.Game /// /// Initializes a new instance of the class. /// - /// The lowest number on the dice, on which the highest number is set - public Dice(int nbmin) + /// The lowest number on the dice, on which the highest number is set + public Dice(int minval) { - if (nbmin < 0) nbmin = 0; - if (nbmin > 1) nbmin = 1; - NbMin = nbmin; - NbMax = nbmin + 5; + if (minval < 0) minval = 0; + if (minval > 1) minval = 1; + MinVal = minval; + MaxVal = minval + 5; } /// @@ -54,13 +54,8 @@ namespace Models.Game /// public Dice() { - NbMin = 0; - NbMax = 5; - } - - public override string ToString() - { - return $"Ce dé a pour valeur {Value} et est entre {NbMin} et {NbMax}"; + MinVal = 0; + MaxVal = 5; } /// @@ -68,7 +63,7 @@ namespace Models.Game /// public void Roll() { - Value = new Random().Next(NbMin, NbMax + 1); + Value = new Random().Next(MinVal, MaxVal + 1); } /// diff --git a/source/Trek-12/Models/Game/Game.cs b/source/Trek-12/Models/Game/Game.cs index ca6ede7..dceb686 100644 --- a/source/Trek-12/Models/Game/Game.cs +++ b/source/Trek-12/Models/Game/Game.cs @@ -1,12 +1,19 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Diagnostics; using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; using System.Threading.Tasks.Dataflow; using Models.Events; -using Models.Exceptions; +using Models.Interfaces; using Models.Rules; +using SQLite; namespace Models.Game { @@ -14,54 +21,326 @@ namespace Models.Game /// The Game class represents a game session in the application. /// It contains all the necessary properties and methods to manage a game, including the game loop, dice rolling, and use of the game rules. /// - public class Game + [DataContract, SQLite.Table("Games")] + public class Game : INotifyPropertyChanged { + public bool IsPreviousGameNotFinished { get; private set; } + + [PrimaryKey, AutoIncrement] + public int Id { get; set; } + + /* Persistence Interface */ + [Ignore] + public IPersistence PersistenceManager { get; set; } + + /* List for the game and persistence */ + private ObservableCollection _players; + [Ignore] + public ObservableCollection Players + { + get => _players; + set + { + _players = value; + OnPropertyChanged(nameof(Players)); + } + } + + private ObservableCollection _games; + [Ignore] + public ObservableCollection Games + { + get => _games; + set + { + _games = value; + OnPropertyChanged(nameof(Games)); + } + } + + private ObservableCollection _maps; + [Ignore] + public ObservableCollection Maps + { + get => _maps; + set + { + _maps = value; + OnPropertyChanged(nameof(Maps)); + } + } + + private ObservableCollection _bestScores; + [Ignore] + public ObservableCollection BestScores + { + get => _bestScores; + set + { + _bestScores = value; + OnPropertyChanged(nameof(BestScores)); + } + } + private bool _isRunning; - public Player CurrentPlayer { get; private set; } + [DataMember] + public bool IsRunning + { + get => _isRunning; + private set => _isRunning = value; + } - public Map UsedMap { get; private set; } + [DataMember] + public Player? CurrentPlayer { get; private set; } - private Dice Dice1 { get; } - private Dice Dice2 { get; } + private Map? _usedMap; + [DataMember] + public Map? UsedMap + { + get => _usedMap; + set + { + _usedMap = value; + OnPropertyChanged(nameof(UsedMap)); + } + } + + [Ignore] + public Dice Dice1 { get; private set;} + + [Ignore] + public Dice Dice2 { get; private set; } + + [DataMember] + public int Turn { get; set; } + + [Ignore] + public Operation PlayerOperation { get; set; } + + private Cell _playerCell; + [Ignore] + public Cell PlayerCell { + get => _playerCell; + set + { + _playerCell = value; + OnPropertyChanged(nameof(PlayerCell)); + } + } + + private int _resultat; + public int Resultat { + get => _resultat; + set + { + _resultat = value; + OnPropertyChanged(nameof(Resultat)); + } + } - private int Turn { get; set; } + public bool DiceRolledFlag { get; private set; } + public bool OperationChosenFlag { get; private set; } + [Ignore] public Rules.Rules GameRules { get; } // == Events == public event EventHandler GameStarted; public event EventHandler GameEnded; - public event EventHandler BoardUpdated; + public event EventHandler BoardUpdated; public event EventHandler DiceRolled; public event EventHandler OperationChosen; public event EventHandler CellChosen; - + public event EventHandler PlayerChooseOp; + public event EventHandler PlayerOption; + public event EventHandler PlayerChooseCell; + + + public void AddPlayer(Player player) + { + Players.Add(player); + } + + public void AddGame(Game game) + { + Games.Add(game); + } + + public void AddMap(Map map) + { + Maps.Add(map); + } /// - /// Initializes a new instance of the class. + /// Adds a new best score to the list of best scores. Or updates it if it already exists. /// - /// The player who play the game. - /// The map to be used in the game. - public Game(Player player, Map map) + /// The final score of the game. + public void AddBestScore(int finalScore) { - _isRunning = false; - UsedMap = map; - CurrentPlayer = player; - Dice1 = new Dice(); - Dice2 = new Dice(1); - Turn = 1; + BestScore bs = new BestScore(UsedMap.Name, CurrentPlayer, 1, finalScore); + var existingScore = BestScores.FirstOrDefault(score => score.Equals(bs)); + + if (existingScore != null) + { + existingScore.IncrGamesPlayed(); + existingScore.UpdateScore(finalScore); + } + else + { + BestScores.Add(bs); + } + + // Sorting the best scores + List sortedScores = BestScores.OrderByDescending(score => score.Score).ToList(); + + for (int i = 0; i < sortedScores.Count; i++) + { + if (!BestScores[i].Equals(sortedScores[i])) + { + BestScores.Move(BestScores.IndexOf(sortedScores[i]), i); + } + } + } + + /// + /// Removes a player from the list of players. + /// + /// + /// True if the player was removed successfully, false otherwise. + public bool RemovePlayer(string playerName) + { + Player? player = Players.FirstOrDefault(p => p.Pseudo == playerName); + if (player == null) + { + return false; + } + Players.Remove(player); + CheckAndRemoveBestScoresDependencies(player.Pseudo); + return true; + } + + /// + /// Modifies the pseudo of a player. + /// + /// + /// + /// + public bool ModifyPlayer(string pseudo, string newpseudo) + { + foreach (var index in Players) + { + if (index.Pseudo == pseudo) + { + CheckAndChangeBestScoresDependencies(index.Pseudo, newpseudo); + index.Pseudo = newpseudo; + return true; + } + } + + return false; + } + + /// + /// Removes a game from the list of games. + /// + /// + public void CheckAndRemoveBestScoresDependencies(string playerName) + { + List bs = new List(); + foreach (var bestScore in BestScores) + { + if (!bestScore.ThePlayer.Pseudo.Equals(playerName)) continue; + + bs.Add(bestScore); + } + + foreach (var score in bs) + { + BestScores.Remove(score); + } + } + + /// + /// Modifies the pseudo of a player in the best scores. + /// + /// + /// + public void CheckAndChangeBestScoresDependencies(string playerName, string newPlayerName) + { + foreach (var bestScore in BestScores) + { + if (!bestScore.ThePlayer.Pseudo.Equals(playerName)) continue; + + bestScore.ThePlayer.Pseudo = newPlayerName; + } + } + + public void LoadData() + { + var data = PersistenceManager.LoadData(); + foreach (var player in data.Item1) + { + Players.Add(player); + } + foreach (var game in data.Item2) + { + if (game.IsRunning) + { + IsPreviousGameNotFinished = true; + } + Games.Add(game); + } + foreach (var map in data.Item3) + { + Maps.Add(map); + } + foreach (var bestScore in data.Item4) + { + BestScores.Add(bestScore); + } + } + + public void SaveData() => PersistenceManager.SaveData(Players, Games, Maps, BestScores); + + public Game(IPersistence persistenceManager) + { + PersistenceManager = persistenceManager; + + Players = new ObservableCollection(); + Games = new ObservableCollection(); + Maps = new ObservableCollection(); + BestScores = new ObservableCollection(); + GameRules = new Rules.Rules(); + + IsRunning = false; + } + + public Game() + { + Players = new ObservableCollection(); + Games = new ObservableCollection(); + Maps = new ObservableCollection(); + BestScores = new ObservableCollection(); + + GameRules = new Rules.Rules(); + UsedMap = new Map("temp","test"); + IsRunning = false; } /// /// Rolls all the dice. /// - private void RollAllDice() + public void RollAllDice() { Dice1.Roll(); Dice2.Roll(); + DiceRolledFlag = true; + OperationChosenFlag = false; DiceRolled?.Invoke(this, new DiceRolledEventArgs(Dice1.Value, Dice2.Value)); + OnPropertyChanged(nameof(Dice1)); + OnPropertyChanged(nameof(Dice2)); } /// @@ -71,13 +350,16 @@ namespace Models.Game private void MarkOperationAsChecked(Operation operation) { int operationIndex = (int)operation; - int operationsPerType = 4; // Chaque type d'opération peut être fait 4 fois + IEnumerable sortPaths = + from cell in UsedMap.OperationGrid + where cell.Y == operationIndex + select cell; - for (int i = operationIndex * operationsPerType; i < (operationIndex + 1) * operationsPerType; i++) + foreach (var item in sortPaths) { - if (!UsedMap.OperationGrid[i].IsChecked) + if (!item.IsChecked) { - UsedMap.OperationGrid[i].Check(); + item.Check(); break; } } @@ -94,7 +376,7 @@ namespace Models.Game /// If the operation is MULTIPLICATION, it returns the product of the values of the two dice. /// If the operation is not one of the operations, it throws an ArgumentOutOfRangeException. /// - private int ResultOperation(Operation o) + public int ResultOperation(Operation o) { int result = o switch { @@ -105,8 +387,6 @@ namespace Models.Game Operation.MULTIPLICATION => Dice2.Value * Dice1.Value, _ => throw new ArgumentOutOfRangeException() }; - - MarkOperationAsChecked(o); return result; } @@ -119,10 +399,26 @@ namespace Models.Game /// The result of the dice operation to be placed in the cell. private void PlaceResult(Cell playerChoice, int result) { - if (Turn == 1 || GameRules.NearCellIsValid(playerChoice, UsedMap.Boards)) + IEnumerable ValidCell = + from cell in UsedMap.Boards + where cell.Value == null + where cell.Valid == true + select cell; + foreach (var item in ValidCell) { - playerChoice.Value = result; - BoardUpdated?.Invoke(this, EventArgs.Empty); + if (item.X == playerChoice.X && item.Y == playerChoice.Y) + { + if (result > 12 || (result > 6 && item.IsDangerous == true)) + { + item.SetPenalty(); + PlayerCell.SetPenalty(); + } + item.Value = result; + OnPropertyChanged(nameof(UsedMap.Boards)); + return; + } + + } } @@ -131,87 +427,126 @@ namespace Models.Game /// /// /// - private void AddToRopePath(Cell playerChoice,List adjacentes) + private void AddToRopePath(Cell playerChoice) { - int index =0; - - foreach (var cells in adjacentes) - { - // La cellule choisi peut creer/s'ajouter a un chemin de corde - if (cells.Value - playerChoice.Value == 1 || cells.Value - playerChoice.Value == -1) - { - // Le cas si il n'existe aucun chemin de corde - if (UsedMap.RopePaths.Count == 0) - { - // Creer un nouveau chemin de corde avec la cellule choisi par le joueur et celle adjacente - UsedMap.RopePaths.Add(new List {playerChoice, cells}); - } + if(Turn==1) return; + int index = 0; - // A modifier dans le cas ou il est possible de fusionner deux chemins de corde - if (GameRules.IsInRopePaths(playerChoice, UsedMap.RopePaths, index)) break; + IEnumerable ValidCell = + from cell in UsedMap.Boards + where cell.Value != null && cell.Valid == true && cell != playerChoice + select cell; - // Le cas si il existe des chemins de corde + foreach (var item in ValidCell) + { + if (!GameRules.IsCellAdjacent(playerChoice, item)) + continue; + if (!((playerChoice.Value - item.Value) == 1 || (playerChoice.Value - item.Value) == -1)) + continue; + if (!GameRules.IsInRopePaths(item,UsedMap.RopePaths,index)) + { + UsedMap.RopePaths.Add(new List { playerChoice, item }); + return; + } + if (!GameRules.AsValue(playerChoice, UsedMap.RopePaths, index)) + { + UsedMap.RopePaths[index].Add(playerChoice); + return; + } + } + } - // Est-ce que la cellule adjacentes fait parti d'un chemin de corde - if (!GameRules.IsInRopePaths(cells,UsedMap.RopePaths,index)) - { - UsedMap.RopePaths.Add(new List { playerChoice, cells }); - continue; - } + /// + /// Initializes the game. + /// + public void InitializeGame(Map map, Player player, bool startImmediately = true) + { + var runningGames = Games.Where(g => g.IsRunning).ToList(); + foreach (var game in runningGames) + { + Games.Remove(game); + } + OnPropertyChanged(nameof(Games)); - if (!GameRules.AsValue(playerChoice,UsedMap.RopePaths,index)) - { - UsedMap.RopePaths[index].Add(playerChoice); - } + UsedMap = map; + CurrentPlayer = player; + Turn = 1; + Dice1 = new Dice(); + Dice2 = new Dice(1); - // Si oui, est-ce que le chemin possede deja la valeur correspondante a la valeur de la cellule du joueur choisi - // {playerChoice.Value} n'est pas dans le chemin de corde - // Ajouter au chemin - // {playerChoice.Value} existe dans le chemin de corde pas possible + IsPreviousGameNotFinished = false; + OnPropertyChanged(nameof(UsedMap)); + OnPropertyChanged(nameof(CurrentPlayer)); + OnPropertyChanged(nameof(Turn)); - } + if (startImmediately) + { + StartGame(); } - + + SaveData(); } - + /// - /// Initializes the game. + /// Starts the game. /// - public void InitializeGame() + private void StartGame() { - _isRunning = true; + IsRunning = true; GameStarted?.Invoke(this, new GameStartedEventArgs(CurrentPlayer)); - GameLoop(); + + SaveData(); } /// /// Ends the game. /// - private void EndGame() + private void EndGame(int? pts) { - _isRunning = false; - GameEnded?.Invoke(this, new GameEndedEventArgs(CurrentPlayer)); + IsRunning = false; + GameEnded?.Invoke(this, new GameEndedEventArgs(CurrentPlayer, pts)); } /// /// The main game loop that runs while the game is active. /// - private void GameLoop() + public void GameLoop() { - while (_isRunning) + while (IsRunning) { - if (Turn == 20) - { - EndGame(); - break; - } - RollAllDice(); - + Resultat = PlayerChooseOperation(); + PlayerSelectionCell(); + BoardUpdated?.Invoke(this, new BoardsUpdateEventArgs(UsedMap.Boards.ToList())); Turn++; } } + + public int PlayerChooseOperation() + { + PlayerChooseOp?.Invoke(this, new PlayerChooseOperationEventArgs(PlayerOperation)); + while(!GameRules.OperationAvailable(PlayerOperation,UsedMap.OperationGrid.ToList())) + { + PlayerChooseOp?.Invoke(this, new PlayerChooseOperationEventArgs(PlayerOperation)); + } + PlayerOption?.Invoke(this, new PlayerOptionEventArgs(UsedMap.Boards.ToList(), ResultOperation(PlayerOperation), Turn)); + OperationChosenFlag = true; + return ResultOperation(PlayerOperation); + } + + public void PlayerSelectionCell() + { + PlayerChooseCell?.Invoke(this,new PlayerChooseCellEventArgs(PlayerCell)); + while(!GameRules.NearCellIsValid(PlayerCell,UsedMap.Boards.ToList())) + { + PlayerChooseCell?.Invoke(this, new PlayerChooseCellEventArgs(PlayerCell)); + } + MarkOperationAsChecked(PlayerOperation); + PlaceResult(PlayerCell, Resultat); + DiceRolledFlag = false; + OperationChosenFlag = false; + } /// /// Handles the player's choice of an operation based on the dice values.s @@ -220,6 +555,7 @@ namespace Models.Game public void HandlePlayerOperation(Operation operation) { int result = ResultOperation(operation); + OperationChosenFlag = true; OperationChosen?.Invoke(this, new OperationChosenEventArgs(operation, result)); } @@ -230,23 +566,72 @@ namespace Models.Game /// /// /// - public void HandlePlayerChoice(Cell cell, int result) + public bool HandlePlayerChoice(Cell cell, int result) { if (cell.X < 0 || cell.X >= UsedMap.Boards.Count / 6 || cell.Y < 0 || cell.Y >= 6) { - throw new InvalidCellCoordinatesException("Invalid cell coordinates. Please choose again."); + return false; } - if (!GameRules.IsCellValid(cell, UsedMap.Boards)) + if (!GameRules.IsCellValid(cell, UsedMap.Boards.ToList())) { - throw new InvalidCellException("Cell is not valid. Please choose again."); + return false; } - PlaceResult(cell, result); GameRules.IsZoneValidAndAddToZones(cell, UsedMap); - AddToRopePath(cell, GameRules.EveryAdjacentCells(cell, UsedMap.Boards)); + AddToRopePath(cell); CellChosen?.Invoke(this, new CellChosenEventArgs(cell, result)); - BoardUpdated?.Invoke(this, EventArgs.Empty); + return true; } + + /// + /// Event raised when a property is changed to notify the view. + /// + public event PropertyChangedEventHandler? PropertyChanged; + + /// + /// Trigger the PropertyChanged event for a specific property. + /// + /// Name of the property that changed. + public virtual void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + public int CalculusOfPenalty(ReadOnlyCollection Boards) + { + int result = 0; + foreach (var cells in Boards) + if (cells.Penalty) + { + if (!cells.Valid || cells.Value == null) + continue; + result += 3; + } + return result; + } + + public void PutPenaltyForLostCells(ReadOnlyCollection Boards) + { + foreach (var cells in Boards) + { + if (cells == null || cells.Value == null || !cells.Valid) + continue; + if (!UsedMap.IsCellInZones(cells) && !UsedMap.IsCellInRopePath(cells)) + cells.SetPenalty(); + } + } + + public int FinalCalculusOfPoints() + { + int? points = GameRules.FinalCalculusOfZones(UsedMap.Zones); + for (int i = 0; i < UsedMap.RopePaths.Count; i++) + { + points += GameRules.ScoreRopePaths(UsedMap.RopePaths[i]); + } + points -= CalculusOfPenalty(UsedMap.Boards); + return points ?? 0; + } + } } diff --git a/source/Trek-12/Models/Game/Map.cs b/source/Trek-12/Models/Game/Map.cs index 56dbb69..cfb2956 100644 --- a/source/Trek-12/Models/Game/Map.cs +++ b/source/Trek-12/Models/Game/Map.cs @@ -1,78 +1,152 @@ -namespace Models.Game +using System.Collections.ObjectModel; +using System.Runtime.Serialization; +using SQLite; + +namespace Models.Game { /// /// The Map class is the representation of the game map with the board and the operations table. /// + [DataContract, SQLite.Table("Maps")] public class Map { + /// + /// The displaying name of the map + /// + [DataMember, PrimaryKey] + public string Name { get; private set; } + /// /// It is the list of cells on the map. /// - public List Boards { get; private set; } - + [DataMember] + [Ignore] + public ReadOnlyObservableCollection Boards { get; private set; } + + private readonly ObservableCollection _board = new ObservableCollection(); + /// /// It is the backgrond image of the map /// + [DataMember] public string Background { get; private set; } /// /// It is the grid of the possible operation in the game /// - public List OperationGrid { get; private set; } + [DataMember] + public ReadOnlyObservableCollection OperationGrid { get; private set; } + + private readonly ObservableCollection _operationGrid = new ObservableCollection(); /// /// It is a list of a list containing user's rope paths in the current game /// + [DataMember] public List> RopePaths { get; private set; } /// /// It is a list of a list containing user's zones in the current game /// + [DataMember] public List> Zones { get; private set; } /// /// Initializes a new instance of the Map class. /// + /// /// The background of the map. - public Map(string background) + public Map(string name, string background) { - Boards = InitializeBoards(); + Name = name; Background = background; - OperationGrid = InitializeOperationGrid(); + Boards = new ReadOnlyObservableCollection(_board); + InitializeBoards(_board); + OperationGrid = new ReadOnlyObservableCollection(_operationGrid); + InitializeOperationGrid(_operationGrid); RopePaths = new List>(); Zones = new List>(); } + + /// + /// SQLite constructor + /// + public Map() { } + + /// + /// Clone the map to avoid reference problems. + /// + /// + public Map Clone() + { + Map map = new Map(Name, Background); + return map; + } /// /// Initializes the boards of the map. /// /// Return the boards - private List InitializeBoards() + private void InitializeBoards(ObservableCollection board) { - var boards = new List(); - for (int i = 0; i < 36; i++) // 6x6 board + for (int i = 0; i < 49; i++) // 7x7 board { - boards.Add(new Cell(i / 6, i % 6)); + board.Add(new Cell(i % 7, i / 7)); } - return boards; + board[1].Valid = true; + board[3].Valid = true; + board[4].Valid = true; + board[5].Valid = true; + board[9].Valid = true; + board[12].Valid = true; + board[15].Valid = true; + board[16].Valid = true; + board[17].Valid = true; + board[21].Valid = true; + board[24].Valid = true; + board[25].Valid = true; + board[28].Valid = true; + board[30].Valid = true; + board[31].Valid = true; + board[32].Valid = true; + board[40].Valid = true; + board[41].Valid = true; + board[48].Valid = true; + + board[3].IsDangerous = true; + board[15].IsDangerous = true; + board[16].IsDangerous = true; } /// /// Initializes the operation grid of the map. /// /// Return the operation grid - private List InitializeOperationGrid() + private void InitializeOperationGrid(ObservableCollectionoperationGrid) { - var operationGrid = new List(); for (int i = 0; i < 5; i++) // 5 operations { for (int j = 0; j < 4; j++) // 4 cells per operation { - operationGrid.Add(new OperationCell(i, j)); + operationGrid.Add(new OperationCell(j, i)); } } - return operationGrid; + } + + public bool CheckOperationPossible(int x) + { + return OperationGrid[x * 4 + 3].IsChecked; + } + + public bool IsCellInZones(Cell cell) + { + return Zones.Any(zone => zone.Contains(cell)); + } + + public bool IsCellInRopePath(Cell cell) + { + return RopePaths.Any(path => path.Contains(cell)); } } } \ No newline at end of file diff --git a/source/Trek-12/Models/Game/Operation.cs b/source/Trek-12/Models/Game/Operation.cs index 2eca1fe..833181f 100644 --- a/source/Trek-12/Models/Game/Operation.cs +++ b/source/Trek-12/Models/Game/Operation.cs @@ -16,5 +16,7 @@ namespace Models.Game SUBTRACTION, ADDITION, MULTIPLICATION + + } } diff --git a/source/Trek-12/Models/Game/OperationCell.cs b/source/Trek-12/Models/Game/OperationCell.cs index d8ac6da..fd53a81 100644 --- a/source/Trek-12/Models/Game/OperationCell.cs +++ b/source/Trek-12/Models/Game/OperationCell.cs @@ -1,14 +1,30 @@ +using System.ComponentModel; +using System.Runtime.Serialization; + namespace Models.Game { /// /// Represents a cell in the operation grid of the game. /// - public class OperationCell : Position + [DataContract] + public class OperationCell : Position, INotifyPropertyChanged { /// /// It tells if the operation is checked or not in the operation grid of the game. /// - public bool IsChecked { get; private set; } + [DataMember] + private bool isChecked; + public bool IsChecked + { + get => isChecked; + set + { + if (isChecked == value) + return; + isChecked = value; + OnPropertyChanged(nameof(IsChecked)); + } + } /// /// Constructor of the OperationCell class. @@ -17,6 +33,17 @@ namespace Models.Game /// public OperationCell(int x, int y) : base(x, y) { + IsChecked = false; + } + + public event PropertyChangedEventHandler? PropertyChanged; + + void OnPropertyChanged(string propertyName) + { + if (PropertyChanged != null) + { + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } } /// diff --git a/source/Trek-12/Models/Game/Player.cs b/source/Trek-12/Models/Game/Player.cs index f363eb4..d0fa8d7 100644 --- a/source/Trek-12/Models/Game/Player.cs +++ b/source/Trek-12/Models/Game/Player.cs @@ -1,59 +1,77 @@ -namespace Models.Game +using SQLite; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations.Schema; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization; +using Models.Interfaces; + +namespace Models.Game { /// /// Represents a player in the game. /// - public class Player + [DataContract, SQLite.Table("Players")] + public class Player : INotifyPropertyChanged { + public event PropertyChangedEventHandler? PropertyChanged; + + void OnPropertyChanged([CallerMemberName] string? propertyName = null) + => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + + /// /// It is he pseudo of the player. /// - public string Pseudo { get; private set; } + private string _pseudo; + [DataMember, PrimaryKey] + public string Pseudo + { + get => _pseudo; + set + { + if (_pseudo == value) + return; + _pseudo = value; + OnPropertyChanged(); + } + } /// /// It is the profile picture of the player. /// + [DataMember] public string ProfilePicture { get; private set; } /// /// It is the creation date of the player. /// - public string? CreationDate { get; private set; } + [DataMember] + public string CreationDate { get; private set; } /// /// It tells when was the last time the player played. /// + [DataMember] public string? LastPlayed { get; private set; } - /// - /// Constructor with default values. - /// - public Player() - { - Pseudo = "Player"; - ProfilePicture = "DefaultProfilePicture"; - } - /// /// Construct a new instance of Player with specified pseudo and profile picture. /// /// The pseudo of the player. /// The profile picture of the player. - public Player(string pseudo, string profilePicture = "DefaultProfilePicture") + public Player(string pseudo, string profilePicture) { Pseudo = pseudo; ProfilePicture = profilePicture; + CreationDate = DateTime.Now.ToString("dd/MM/yyyy"); } /// - /// Chooses the operation for the player. + /// SQLite constructor /// - /// The chosen operation. - public Operation ChooseOperation() - { - return Operation.LOWER; - } + public Player() { } /// /// Redefine the equal operation between player. @@ -78,5 +96,13 @@ { return Pseudo.GetHashCode(); } + + /// + /// Actualize the last time the player played. + /// + public void UpdateLastPlayed() + { + LastPlayed = DateTime.Now.ToString("dd/MM/yyyy"); + } } } \ No newline at end of file diff --git a/source/Trek-12/Models/Game/Position.cs b/source/Trek-12/Models/Game/Position.cs index c1b75da..e6edc7a 100644 --- a/source/Trek-12/Models/Game/Position.cs +++ b/source/Trek-12/Models/Game/Position.cs @@ -1,19 +1,26 @@ -namespace Models.Game +using System.ComponentModel; +using System.Runtime.CompilerServices; +using System.Runtime.Serialization; + +namespace Models.Game { /// /// The Position (x,y) of a cell in the game. /// + [DataContract] public class Position { /// /// The X coordinate. /// + [DataMember] public int X { get; set; } /// /// The Y coordinate. /// + [DataMember] public int Y { get; set; } /// diff --git a/source/Trek-12/Models/Interfaces/IImageConverter.cs b/source/Trek-12/Models/Interfaces/IImageConverter.cs new file mode 100644 index 0000000..8d02931 --- /dev/null +++ b/source/Trek-12/Models/Interfaces/IImageConverter.cs @@ -0,0 +1,24 @@ +using Microsoft.Maui.Controls; + +namespace Models.Interfaces +{ + /// + /// Interface for image converters + /// + public interface IImageConverter + { + /// + /// Converter to any type that can be converted to a string (ex: Base64) + /// + /// + /// + string ConvertImage(string imagePath); + + /// + /// Retrieve an image from a string encoded + /// + /// + /// + ImageSource RetrieveImage(string imageString); + } +} diff --git a/source/Trek-12/Models/Interfaces/IPersistence.cs b/source/Trek-12/Models/Interfaces/IPersistence.cs new file mode 100644 index 0000000..3a5c55b --- /dev/null +++ b/source/Trek-12/Models/Interfaces/IPersistence.cs @@ -0,0 +1,12 @@ +using System.Collections.ObjectModel; + +namespace Models.Interfaces +{ + using Models.Game; + public interface IPersistence + { + (ObservableCollection, ObservableCollection, ObservableCollection, ObservableCollection) LoadData(); + + void SaveData(ObservableCollection players, ObservableCollection games, ObservableCollection maps, ObservableCollection bestScores); + } +} \ No newline at end of file diff --git a/source/Trek-12/Models/Interfaces/IRules.cs b/source/Trek-12/Models/Interfaces/IRules.cs index 1b9cb8d..c2dbd70 100644 --- a/source/Trek-12/Models/Interfaces/IRules.cs +++ b/source/Trek-12/Models/Interfaces/IRules.cs @@ -8,8 +8,6 @@ namespace Models.Interfaces /// public interface IRules { - //public bool NearCellIsValid(Position playerChoicePosition, SortedDictionary cells); - /// /// Return true if the cell is empty, otherwise false. /// @@ -25,15 +23,6 @@ namespace Models.Interfaces /// true if the cell is valid; otherwise, false public bool IsCellValid(Cell playerChoicePosition, List cells); - //public bool IsRopePath(Cell playerChoice, HashSet ropePaths); - - //public bool IsAdjacent(Cell cell1, Cell cell2, List cells); - - //public int HowMany(Cell playerChoice, List cells); - - //public void SetValueAndPenalty(int valueChoice, Cell playerChoice, List cells); - - /// /// Check if the given cell is adjacent to the target cell. /// diff --git a/source/Trek-12/Models/Models.csproj b/source/Trek-12/Models/Models.csproj index 0119668..2506c52 100644 --- a/source/Trek-12/Models/Models.csproj +++ b/source/Trek-12/Models/Models.csproj @@ -7,9 +7,14 @@ - - + + + + + + + diff --git a/source/Trek-12/Models/Rules/Rules.cs b/source/Trek-12/Models/Rules/Rules.cs index 8a7dc43..91a595d 100644 --- a/source/Trek-12/Models/Rules/Rules.cs +++ b/source/Trek-12/Models/Rules/Rules.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -24,40 +25,32 @@ namespace Models.Rules { if (!IsCellEmpty(playerChoicePosition)) return false; + if (!playerChoicePosition.Valid) return false; + if (EveryAdjacentCells(playerChoicePosition, cells).Count == 1) return false; return true; } + public bool IsCellAdjacent(Cell choosenCell, Cell targetCell) { - if (Math.Abs(choosenCell.X - targetCell.X) > 1 || Math.Abs(choosenCell.Y - targetCell.Y) > 1) - return false; - if (Math.Abs(choosenCell.X - targetCell.X) > 1 && Math.Abs(choosenCell.Y - targetCell.Y) > 1) - return false; - if (choosenCell.X == 0 && targetCell.X == 4) - return false; - if (choosenCell.Y == 0 && targetCell.Y == 4) - return false; - if (choosenCell.X == 4 && targetCell.X == 0) - return false; - if (choosenCell.Y == 4 && targetCell.Y == 0) - return false; - if (choosenCell.X == targetCell.X && choosenCell.Y == targetCell.Y) - return false; + if (Math.Abs(choosenCell.X - targetCell.X) <= 1 && Math.Abs(choosenCell.Y - targetCell.Y) <= 1) + { + return true; + } + + return false; + } - return true; - } - public bool IsInRopePaths (Cell adjacente,List> ropePaths,int index) + public bool IsInRopePaths (Cell adjacente,List> ropePaths, int index) { foreach (List path in ropePaths) { - if (path.Contains(adjacente)) - { - index=ropePaths.IndexOf(path); - return true; - } + if (!path.Contains(adjacente)) continue; + index=ropePaths.IndexOf(path); + return true; } return false; } @@ -70,32 +63,36 @@ namespace Models.Rules } return false; } + public bool NearCellIsValid(Cell choosenCell, List cells) { if (choosenCell == null || cells == null) return false; - + IEnumerable PlayedCellsQuery = from cell in cells - where cell.Value != null + where cell.Valid select cell; foreach (var cell in PlayedCellsQuery) { - if(!IsCellAdjacent(choosenCell, cell)) continue; - - return true; + if (choosenCell.X == cell.X && choosenCell.Y == cell.Y && cell.Value == null) + return true; + if (IsCellAdjacent(choosenCell, cell)) + return true; + } return false; } + public void IsZoneValidAndAddToZones(Cell chosenCell, Map map) { if (chosenCell == null ||chosenCell.Value == null) return; - List adjacentCells = new List(); + List adjacentCells; - adjacentCells = EveryAdjacentCells(chosenCell, map.Boards); + adjacentCells = EveryAdjacentCells(chosenCell, map.Boards.ToList()); foreach(var cells in adjacentCells) { @@ -109,12 +106,8 @@ namespace Models.Rules { NewZoneIsCreated(chosenCell, cells, map); } - //return true; // Il y a une cellule adjacente avec la même valeur donc une zone est créée si elle n'est pas déjà existante - // Si il return true, tout c'est bien passer } } - - return; } public bool IsValueInZones(Cell chosenCell, List> zones) @@ -159,7 +152,6 @@ namespace Models.Rules return; } } - return; } public void NewZoneIsCreated(Cell firstCell, Cell secondCell, Map map) @@ -171,9 +163,11 @@ namespace Models.Rules map.Zones.Add(newZone); } - public List EveryAdjacentCells(Cell choosenCell, List cells) + public List EveryAdjacentCells(Cell? choosenCell, List cells) { List adjacentCells = new List(); + + if (choosenCell == null || cells == null) return adjacentCells; foreach (var cell in cells) { @@ -195,11 +189,42 @@ namespace Models.Rules calculus += zones[i].Count - 1 + zones[i][0].Value; if (zones[i].Count > 9) { - calculus += (zones[i].Count - 9) * 5; + calculus += (zones[i].Count - 9) * 5 - (zones[i].Count - 9); } } return calculus; } + public int? ScoreRopePaths(List paths) + { + int? score = 0; + IEnumerable sortPaths = + from cell in paths + orderby cell.Value descending + select cell; + foreach (var item in sortPaths) + { + if (score == 0) + score += item.Value; + else + score++; + } + return score; + } + + public bool OperationAvailable(Operation operation,List operationGrid) + { + IEnumerable row = + from cell in operationGrid + where cell.Y == (int)operation + select cell; + foreach (var item in row) + { + if (!item.IsChecked) + return true; + } + return false; + } + } } \ No newline at end of file diff --git a/source/Trek-12/Stub/Stub.cs b/source/Trek-12/Stub/Stub.cs new file mode 100644 index 0000000..6d45f51 --- /dev/null +++ b/source/Trek-12/Stub/Stub.cs @@ -0,0 +1,88 @@ +using System.Collections.ObjectModel; +using System.Data; +using System.Numerics; +using Models.Game; +using Models.Interfaces; +using static Microsoft.Maui.ApplicationModel.Permissions; + +namespace Stub +{ + public class Stub : IPersistence + { + public ReadOnlyObservableCollection ListPlayer { get; private set; } + private readonly ObservableCollection listplayer = new ObservableCollection(); + public ReadOnlyObservableCollection ListMap { get; private set; } + private readonly ObservableCollection listmap = new ObservableCollection(); + + public Game game { get; private set; } + + public Game ThePartie { get; private set; } + + public Stub() + { + ListPlayer = new ReadOnlyObservableCollection(listplayer); + ListMap = new ReadOnlyObservableCollection(listmap); + ThePartie = new Game(); + LoadPlayer(); + LoadMap(); + } + + public void LoadPlayer() + { + listplayer.Add(new Player("luduflot", "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")); + listplayer.Add(new Player("relavergne", "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")); + listplayer.Add(new Player("reneveu", "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")); + + } + + public void LoadMap() + { + + listmap.Add(new Map("Dunai","profile.jpg")); + listmap.Add(new Map("Kagkot","montagne1.png")); + listmap.Add(new Map("Dhaulagiri","tmp1.jpeg")); + } + + public void Add(string pseudo, string profilePicture) + { + listplayer.Add(new Player(pseudo, profilePicture)); + } + + public void Pop(string pseudo, string profilePicture) + { + listplayer.Remove(new Player(pseudo, profilePicture)); + } + + public bool Modify(string pseudo, string newpseudo) + { + foreach (var index in listplayer) + { + if (index.Pseudo == pseudo) + { + index.Pseudo = newpseudo; + return true; + } + } + + return false; + } + + public (ObservableCollection, ObservableCollection, ObservableCollection, ObservableCollection) LoadData() + { + foreach(var item in ThePartie.Players) + { + listplayer.Add(item); + } + foreach(var item in ThePartie.Maps) + { + listmap.Add(item); + } + return (listplayer, ThePartie.Games, listmap, ThePartie.BestScores); + } + + public void SaveData(ObservableCollection players, ObservableCollection games, ObservableCollection maps, ObservableCollection bestScores) + { + throw new NotImplementedException(); + } + } +} diff --git a/source/Trek-12/Stub/Stub.csproj b/source/Trek-12/Stub/Stub.csproj new file mode 100644 index 0000000..8dcc508 --- /dev/null +++ b/source/Trek-12/Stub/Stub.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/source/Trek-12/Tests/Base64ConverterTests.cs b/source/Trek-12/Tests/Base64ConverterTests.cs new file mode 100644 index 0000000..e0f0560 --- /dev/null +++ b/source/Trek-12/Tests/Base64ConverterTests.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Models.Game; +using Models.Interfaces; +using Moq; + +namespace Tests +{ + public class Base64ConverterTests + { + /* + public interface IImageConverter + { + /// + /// Converter to any type that can be converted to a string (ex: Base64) + /// + /// + /// + string ConvertImage(string imagePath); + + /// + /// Retrieve an image from a string encoded + /// + /// + /// + ImageSource RetrieveImage(string imageString); + } + */ + + /* + public class Base64Converter : IImageConverter + { + /// + /// Converts an image to a base64 string + /// + /// The path to access the image + /// The base64 string representation of the image + /// Native .NET exception + public string ConvertImage(string imagePath) + { + if (!File.Exists(imagePath)) + { + // native .NET exception + throw new FileNotFoundException("Image file not found", imagePath); + } + + byte[] imageBytes = File.ReadAllBytes(imagePath); + return Convert.ToBase64String(imageBytes); + } + + /// + /// Retrieve an image from a string encoded in base64 + /// + /// + /// + public ImageSource RetrieveImage(string imageString) + { + byte[] imageBytes = Convert.FromBase64String(imageString); + return ImageSource.FromStream(() => new MemoryStream(imageBytes)); + } + } + */ + + // Create a mock + private Mock _imageConverterMock; + + public Base64ConverterTests() + { + _imageConverterMock = new Mock(); + } + + [Fact] + public void ConvertImage_WithNonExistentPath_ThrowsFileNotFoundException() + { + var base64Converter = new Base64Converter(); + Assert.Throws(() => base64Converter.ConvertImage("nonexistent.jpg")); + } + + [Fact] + public void RetrieveImage_WithInvalidBase64_ThrowsFormatException() + { + var base64Converter = new Base64Converter(); + Assert.Throws(() => base64Converter.RetrieveImage("////invalidBase64//!!///")); + } + } +} diff --git a/source/Trek-12/Tests/BestScoreTests.cs b/source/Trek-12/Tests/BestScoreTests.cs index 951989c..6e0b215 100644 --- a/source/Trek-12/Tests/BestScoreTests.cs +++ b/source/Trek-12/Tests/BestScoreTests.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection.Emit; using System.Text; using System.Threading.Tasks; using Models.Game; @@ -12,7 +13,11 @@ namespace Tests [Fact] public void Constructor_WithNegativeInputs_SetsPropertiesToZero() { - var bestScore = new BestScore(-5, -10); + var myMap = new Map("Dunai", "Dunai.png"); + var myPlayer = new Player("John", "pp.png"); + + var bestScore = new BestScore(myMap.Name, myPlayer, -5, -10); + Assert.Equal(0, bestScore.GamesPlayed); Assert.Equal(0, bestScore.Score); } @@ -20,7 +25,11 @@ namespace Tests [Fact] public void Constructor_WithPositiveInputs_SetsPropertiesCorrectly() { - var bestScore = new BestScore(5, 10); + var myMap = new Map("Dunai", "Dunai.png"); + var myPlayer = new Player("John", "pp.png"); + + var bestScore = new BestScore(myMap.Name, myPlayer, 5, 10); + Assert.Equal(5, bestScore.GamesPlayed); Assert.Equal(10, bestScore.Score); } @@ -28,25 +37,99 @@ namespace Tests [Fact] public void IncrGamesPlayed_IncrementsGamesPlayed() { - var bestScore = new BestScore(0, 0); + var myMap = new Map("Dunai", "Dunai.png"); + var myPlayer = new Player("John", "pp.png"); + + var bestScore = new BestScore(myMap.Name, myPlayer, 0, 0); bestScore.IncrGamesPlayed(); + Assert.Equal(1, bestScore.GamesPlayed); } [Fact] public void ScoreSetter_WithLowerValue_DoesNotChangeScore() { - var bestScore = new BestScore(0, 10); + var myMap = new Map("Dunai", "Dunai.png"); + var myPlayer = new Player("John", "pp.png"); + + var bestScore = new BestScore(myMap.Name, myPlayer, 0, 10); bestScore.UpdateScore(5); - Assert.Equal(10, bestScore.Score); + + Assert.Equal(15, bestScore.Score); } [Fact] public void ScoreSetter_WithHigherValue_ChangesScore() { - var bestScore = new BestScore(0, 5); + var myMap = new Map("Dunai", "Dunai.png"); + var myPlayer = new Player("John", "pp.png"); + + var bestScore = new BestScore(myMap.Name, myPlayer, 0, 5); bestScore.UpdateScore(10); - Assert.Equal(10, bestScore.Score); + + Assert.Equal(15, bestScore.Score); + } + + [Fact] + public void IdGetter_ReturnsCorrectId() + { + var myMap = new Map("Dunai", "Dunai.png"); + var myPlayer = new Player("John", "pp.png"); + + var bestScore = new BestScore(myMap.Name, myPlayer, 5, 10); + bestScore.Id = 1; + + Assert.Equal(1, bestScore.Id); + } + + [Fact] + public void Equals_WithEqualBestScores_ReturnsTrue() + { + var myMap = new Map("Dunai", "Dunai.png"); + var myPlayer = new Player("John", "pp.png"); + + var bestScore1 = new BestScore(myMap.Name, myPlayer, 5, 10); + var bestScore2 = new BestScore(myMap.Name, myPlayer, 5, 10); + + Assert.True(bestScore1.Equals(bestScore2)); + } + + [Fact] + public void Equals_WithDifferentBestScores_ReturnsFalse() + { + var myMap1 = new Map("Dunai", "Dunai.png"); + var myMap2 = new Map("Amazon", "Amazon.png"); + var myPlayer = new Player("John", "pp.png"); + + var bestScore1 = new BestScore(myMap1.Name, myPlayer, 5, 10); + var bestScore2 = new BestScore(myMap2.Name, myPlayer, 5, 10); + + Assert.False(bestScore1.Equals(bestScore2)); + } + + [Fact] + public void GetHashCode_WithEqualBestScores_ReturnsSameHashCode() + { + var myMap = new Map("Dunai", "Dunai.png"); + var myPlayer = new Player("John", "pp.png"); + + var bestScore1 = new BestScore(myMap.Name, myPlayer, 5, 10); + var bestScore2 = new BestScore(myMap.Name, myPlayer, 5, 10); + + Assert.Equal(bestScore1.GetHashCode(), bestScore2.GetHashCode()); + } + + [Fact] + public void GetHashCode_WithDifferentBestScores_ReturnsDifferentHashCodes() + { + var myMap1 = new Map("Dunai", "Dunai.png"); + var myMap2 = new Map("Amazon", "Amazon.png"); + var myPlayer = new Player("John", "pp.png"); + + var bestScore1 = new BestScore(myMap1.Name, myPlayer, 5, 10); + var bestScore2 = new BestScore(myMap2.Name, myPlayer, 5, 10); + + Assert.NotEqual(bestScore1.GetHashCode(), bestScore2.GetHashCode()); } } } diff --git a/source/Trek-12/Tests/DiceTests.cs b/source/Trek-12/Tests/DiceTests.cs index 7831db6..51b3ea0 100644 --- a/source/Trek-12/Tests/DiceTests.cs +++ b/source/Trek-12/Tests/DiceTests.cs @@ -13,30 +13,37 @@ public class DiceTests public void Constructor_WithNegativeNbMin_SetsNbMinToZero() { Dice dice = new Dice(-1); - Assert.Equal(0, dice.NbMin); + Assert.Equal(0, dice.MinVal); + } + + [Fact] + public void Constructor_WithValueMoreThan5_SetsValueTo0() + { + Dice dice = new Dice(6); + Assert.Equal(0, dice.Value); } [Fact] public void Constructor_WithNbMinGreaterThanOne_SetsNbMinToOne() { Dice dice = new Dice(2); - Assert.Equal(1, dice.NbMin); + Assert.Equal(1, dice.MinVal); } [Fact] public void Constructor_WithValidNbMin_SetsNbMinAndNbMaxCorrectly() { Dice dice = new Dice(1); - Assert.Equal(1, dice.NbMin); - Assert.Equal(6, dice.NbMax); + Assert.Equal(1, dice.MinVal); + Assert.Equal(6, dice.MaxVal); } [Fact] public void DefaultConstructor_SetsNbMinToZeroAndNbMaxToFive() { Dice dice = new Dice(); - Assert.Equal(0, dice.NbMin); - Assert.Equal(5, dice.NbMax); + Assert.Equal(0, dice.MinVal); + Assert.Equal(5, dice.MaxVal); } [Fact] @@ -44,6 +51,6 @@ public class DiceTests { Dice dice = new Dice(); dice.Roll(); - Assert.True(dice.Value >= dice.NbMin && dice.Value <= dice.NbMax); + Assert.True(dice.Value >= dice.MinVal && dice.Value <= dice.MaxVal); } } diff --git a/source/Trek-12/Tests/GameTests.cs b/source/Trek-12/Tests/GameTests.cs new file mode 100644 index 0000000..7397e82 --- /dev/null +++ b/source/Trek-12/Tests/GameTests.cs @@ -0,0 +1,694 @@ +using System.Collections.ObjectModel; +using Moq; +using Models.Game; +using Models.Interfaces; +using System.Reflection; +using static System.Type; +using Xunit.Abstractions; + +namespace Tests; + +public class GameTests +{ + private readonly Mock _mockPersistence; // Mocking (faking) the persistence layer to allow for testing without a persistent connection + private readonly Game _game; + + public GameTests() + { + _mockPersistence = new Mock(); + _game = new Game(_mockPersistence.Object); + } + + private void SetDiceValues(Game game, int value1, int value2) + { + var dice1Field = typeof(Game).GetProperty("Dice1", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + var dice2Field = typeof(Game).GetProperty("Dice2", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + + if (dice1Field != null && dice2Field != null) + { + var dice1 = (Dice)dice1Field?.GetValue(game)!; + var dice2 = (Dice)dice2Field?.GetValue(game)!; + + var valueField = typeof(Dice).GetField("_value", BindingFlags.Instance | BindingFlags.NonPublic); + valueField?.SetValue(dice1, value1); + valueField?.SetValue(dice2, value2); + } + } + + [Fact] + public void DefaultConstructor_ShouldInitializeLists() + { + Assert.NotNull(_game.Players); + Assert.NotNull(_game.Games); + Assert.NotNull(_game.Maps); + Assert.NotNull(_game.BestScores); + Assert.NotNull(_game.GameRules); + Assert.False(_game.IsRunning); + } + + [Fact] + public void AddPlayer_ShouldAddPlayerToList() + { + var player = new Player("test_player", "DefaultProfilePicture"); + + _game.AddPlayer(player); + + Assert.Contains(player, _game.Players); + } + + [Fact] + public void AddGame_ShouldAddGameToList() + { + var game = new Game(_mockPersistence.Object); + + _game.AddGame(game); + + Assert.Contains(game, _game.Games); + } + + [Fact] + public void AddMap_ShouldAddMapToList() + { + var map = new Map("test_name", "test_background.png"); + + _game.AddMap(map); + + Assert.Contains(map, _game.Maps); + } + + [Fact] + public void AddBestScore_ShouldAddBestScoreToList() + { + var bestScore = new BestScore("test", new Player("John", "Picture.png"), 3, 127); + + _game.BestScores.Add(bestScore); + + Assert.Contains(bestScore, _game.BestScores); + } + + [Fact] + public void LoadData_ShouldLoadDataFromPersistence() + { + var myGame = new Game(_mockPersistence.Object); + var myPlayer = new Player("test", "DefaultProfilePicture"); + var myMap = new Map("test_name", "test_background.png"); + + var players = new ObservableCollection { myPlayer }; + var games = new ObservableCollection { myGame }; + var maps = new ObservableCollection { myMap }; + var bestScores = new ObservableCollection { new BestScore(myMap.Name, myPlayer, 1, 45) }; + + _mockPersistence.Setup(p => p.LoadData()).Returns((players, games, maps, bestScores)); + + _game.LoadData(); + + Assert.Equal(players, _game.Players); + Assert.Equal(games, _game.Games); + Assert.Equal(maps, _game.Maps); + Assert.Equal(bestScores, _game.BestScores); + } + + [Fact] + public void SaveData_ShouldCallPersistenceSaveData() + { + _game.SaveData(); + + _mockPersistence.Verify(p => p.SaveData(_game.Players, _game.Games, _game.Maps, _game.BestScores), Times.Once); // Times.Once is to verify if the method is called exactly one time + } + + [Fact] + public void InitializeGame_ShouldInitializeGameAndNotTriggerEventWhenNotStarted() + { + var player = new Player("test_player", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + bool eventTriggered = false; + + _game.GameStarted += (sender, args) => + { + eventTriggered = true; + }; + + _game.InitializeGame(map, player, false); + Assert.False(eventTriggered); + Assert.False(_game.IsRunning); + Assert.Equal(map, _game.UsedMap); + Assert.Equal(player, _game.CurrentPlayer); + } + + [Theory] + [InlineData(Operation.ADDITION, 3, 4, 7)] + [InlineData(Operation.SUBTRACTION, 6, 4, 2)] + [InlineData(Operation.MULTIPLICATION, 2, 3, 6)] + [InlineData(Operation.LOWER, 1, 4, 1)] + [InlineData(Operation.HIGHER, 2, 5, 5)] + public void HandlePlayerOperation_ShouldPerformCorrectOperationAndTriggerEvent(Operation operation, int value1, int value2, int expectedResult) + { + var player = new Player("test_player", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + _game.InitializeGame(map, player, false); + + bool eventTriggered = false; + int actualResult = 0; + + _game.OperationChosen += (sender, args) => + { + eventTriggered = true; + actualResult = args.Result; + }; + + SetDiceValues(_game, value1, value2); + + + _game.HandlePlayerOperation(operation); + + + Assert.True(eventTriggered); + Assert.Equal(expectedResult, actualResult); + } + + [Fact] + public void Game_Initialization_SetsMap() + { + var player = new Player("test_player", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + + _game.InitializeGame(map, player, false); + + Assert.Equal(map, _game.UsedMap); + } + + [Fact] + public void Game_Initialization_SetsPlayer() + { + var player = new Player("test_player", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + + _game.InitializeGame(map, player, false); + + Assert.Equal(player, _game.CurrentPlayer); + } + + [Fact] + public void Game_Initialization_SetsDice() + { + Player player = new Player("test_player", "DefaultProfilePicture"); + Map map = new Map("test_name", "test_background.png"); + + _game.InitializeGame(map, player, false); + + Assert.NotNull(_game.Dice1); + Assert.NotNull(_game.Dice2); + } + + [Fact] + public void Game_Initialization_SetsGameRules() + { + var game = new Game(_mockPersistence.Object); + + Assert.NotNull(game.GameRules); + } + + [Fact] + public void MarkOperationAsChecked_Check_Well() + { + var player = new Player("test_player", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + + _game.InitializeGame(map, player, false); + + // Use of reflection to call private method + var methodInfo = typeof(Game).GetMethod("MarkOperationAsChecked", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(methodInfo); + + var operation = Operation.ADDITION; + + + methodInfo.Invoke(_game, new object[] { operation }); + + int operationIndex = (int)operation; + int operationsPerType = 4; + bool isChecked = false; + + for (int i = operationIndex * operationsPerType; i < (operationIndex + 1) * operationsPerType; i++) + { + if (_game.UsedMap.OperationGrid[i].IsChecked) + { + isChecked = true; + break; + } + } + + Assert.True(isChecked); + } + + [Fact] + public void IsPlaceOperationCorrect() + { + var player = new Player("test_player", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + + _game.InitializeGame(map, player, false); + Assert.NotNull(_game.GameRules); + _game.UsedMap.Boards[0].Value = 1; + _game.UsedMap.Boards[1].Value = 2; + _game.UsedMap.Boards[0].Valid = true; + _game.UsedMap.Boards[1].Valid = true; + _game.UsedMap.Boards[2].Valid = true; + + var methodInfo = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(methodInfo); + + _game.PlayerCell = new Cell(2, 0); + _game.PlayerCell.Value = 3; + methodInfo.Invoke(_game, new object[] { _game.PlayerCell, 3 }); + //_game.UsedMap.Boards[2].Value = _game.PlayerCell.Value; + + Assert.Equal(3, _game.UsedMap.Boards[2].Value); + } + + [Fact] + public void IsHandlePlayerChoice_Handling() + { + var player = new Player("test_player", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + + _game.InitializeGame(map, player, false); + + var cell = new Cell(1, 0); + cell.Valid = true; + _game.UsedMap.Boards[0].Valid = true; + _game.UsedMap.Boards[0].Value = 1; + _game.UsedMap.Boards[1].Valid = true; + bool result = _game.HandlePlayerChoice(cell, 1); + Assert.True(result); + } + + [Fact] + public void IsHandlePlayerChoice_InvalidCell() + { + var player = new Player("test_player", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + + _game.InitializeGame(map, player, false); + + var cell = new Cell(0, 7); + cell.Value = 1; + bool result = _game.HandlePlayerChoice(cell, 1); + Assert.False(result); + } + + [Fact] + public void IsHandlePlayerChoice_InvalidPlace() + { + var player = new Player("test_player", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + + _game.InitializeGame(map, player, false); + + var cell = new Cell(0, 0); + cell.Value = 1; + var othercell = new Cell(3, 3); + bool result = _game.HandlePlayerChoice(othercell, 1); + Assert.False(result); + } + + [Fact] + public void RemovePlayerTest_ShouldRemovePlayer() + { + Game game = new Game(); + Player player = new Player("test", "DefaultProfilePicture"); + game.AddPlayer(player); + Assert.True(game.RemovePlayer("test")); + } + + [Fact] + public void RemovePlayerTest_ShouldNotRemovePlayer() + { + Game game = new Game(); + Player player = new Player("test", "DefaultProfilePicture"); + game.AddPlayer(player); + Assert.False(game.RemovePlayer("otherName")); + } + + [Fact] + public void PutPenalty_ShouldPutPenalty() + { + var player = new Player("test_player", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + _game.InitializeGame(map, player, false); + _game.UsedMap.Boards[1].Valid = true; + _game.UsedMap.Boards[2].Valid = true; + _game.UsedMap.Boards[1].Value = 5; + + var methodInfo = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(methodInfo); + + _game.PlayerCell = new Cell(2, 0); + _game.PlayerCell.Value = 14; + methodInfo.Invoke(_game, new object[] { _game.PlayerCell, 14 }); + + Assert.True(_game.UsedMap.Boards[2].Penalty); + } + + [Fact] + public void PutPenalty_ShouldPutPenalty_ForDangerous() + { + var player = new Player("test_player", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + _game.InitializeGame(map, player, false); + + _game.UsedMap.Boards[1].Valid = true; + _game.UsedMap.Boards[2].Valid = true; + + _game.UsedMap.Boards[1].Value = 5; + _game.UsedMap.Boards[2].IsDangerous = true; + + var methodInfo = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(methodInfo); + + _game.PlayerCell = new Cell(2, 0); + _game.PlayerCell.Value = 7; + methodInfo.Invoke(_game, new object[] { _game.PlayerCell, 7 }); + + Assert.True(_game.UsedMap.Boards[2].Penalty); + } + + [Fact] + public void PutPenaltyForLostCells_ReallyPutPenalty_ForZones() + { + var player = new Player("test_player", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + _game.InitializeGame(map, player, false); + + _game.UsedMap.Boards[0].Valid = true; + _game.UsedMap.Boards[3].Valid = true; + _game.UsedMap.Boards[2].Valid = true; + _game.UsedMap.Boards[1].Valid = true; + + _game.UsedMap.Boards[1].Value = 5; + _game.UsedMap.Boards[2].Value = 5; + _game.UsedMap.Boards[3].Value = 5; + _game.UsedMap.Boards[0].Value = 0; + + foreach (var cells in _game.UsedMap.Boards.ToList()) + { + _game.GameRules.IsZoneValidAndAddToZones(cells, _game.UsedMap); + } + + _game.PutPenaltyForLostCells(_game.UsedMap.Boards); + + Assert.True(_game.UsedMap.Boards[0].Penalty); + + } + + [Fact] + public void PutPenaltyForLostCells_ReallyPutPenalty_ForRopePathes() + { + var player = new Player("test_player", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + _game.InitializeGame(map, player, false); + + _game.UsedMap.Boards[1].Value = 1; + _game.UsedMap.Boards[2].Value = 2; + _game.UsedMap.Boards[3].Value = 5; + _game.UsedMap.Boards[0].Value = 0; + + var methodInfo = typeof(Game).GetMethod("AddToRopePath", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(methodInfo); + + foreach (var cells in _game.UsedMap.Boards.ToList()) + { + methodInfo.Invoke(_game, new object[] { cells }); + } + + _game.PutPenaltyForLostCells(_game.UsedMap.Boards); + + Assert.True(_game.UsedMap.Boards[3].Penalty); + + } + + [Fact] + public void CalculusOfPenalty_ReallyCalculusPenalty_ForZonesAndDangerousCellsAndOverTwelve() + { + var player = new Player("test_player", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + _game.InitializeGame(map, player, false); + + _game.UsedMap.Boards[7].Valid = true; + _game.UsedMap.Boards[8].Valid = true; + _game.UsedMap.Boards[9].Valid = true; + _game.UsedMap.Boards[10].Valid = true; + _game.UsedMap.Boards[11].Valid = true; + _game.UsedMap.Boards[12].Valid = true; + + _game.UsedMap.Boards[10].Value = 2; // 1,3 // penalty + _game.UsedMap.Boards[7].Value = 5; // 1,0 + _game.UsedMap.Boards[8].Value = 5; // 1,1 + _game.UsedMap.Boards[9].Value = 5; // 1,2 + + var place = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(place); + + _game.PlayerCell = new Cell(4, 1); + _game.PlayerCell.Value = 7; + _game.PlayerCell.Valid = true; + _game.PlayerCell.IsDangerous = true; + place.Invoke(_game, new object[] { _game.PlayerCell, 7 }); //One penalty + + _game.PlayerCell = new Cell(5, 1); + _game.PlayerCell.Value = 14; + _game.PlayerCell.Valid = true; + place.Invoke(_game, new object[] { _game.PlayerCell, 14 }); + + + foreach (var cells in _game.UsedMap.Boards.ToList()) + { + _game.GameRules.IsZoneValidAndAddToZones(cells, _game.UsedMap); + } + + _game.PutPenaltyForLostCells(_game.UsedMap.Boards); + + Assert.True(_game.UsedMap.Boards[11].Penalty); + Assert.Equal(9, _game.CalculusOfPenalty(_game.UsedMap.Boards)); + + } + + [Fact] + public void CanIModifyAPlayer() + { + Game game = new Game(); + Player player = new Player("test", "DefaultProfilePicture"); + game.AddPlayer(player); + game.ModifyPlayer("test", "newName"); + Assert.Equal("newName", game.Players[0].Pseudo); + } + + [Fact] + public void CanIModifyANonExistentPlayer() + { + Game game = new Game(); + var res = game.ModifyPlayer("nope", "newName"); + Assert.False(res); + } + + [Fact] + public void CanIRollDice() + { + _game.InitializeGame(new Map("test", "test.png"), new Player("test", "test.png"), false); + _game.RollAllDice(); + Assert.NotNull(_game.Dice1); + Assert.NotNull(_game.Dice2); + Assert.True(_game.Dice1.Value >= 0 && _game.Dice1.Value <= 5 ); + Assert.True(_game.Dice2.Value >= 1 && _game.Dice2.Value <= 6 ); + } + + [Fact] + public void CanIStartGame() + { + _game.InitializeGame(new Map("test", "test.png"), new Player("test", "test.png"), false); + + var start = typeof(Game).GetMethod("StartGame", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(start); + + start.Invoke(_game, null); + + Assert.True(_game.IsRunning); + } + + [Fact] + public void CanIEndGame() + { + _game.InitializeGame(new Map("test", "test.png"), new Player("test", "test.png"), false); + + var start = typeof(Game).GetMethod("StartGame", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(start); + + start.Invoke(_game, null); + var end = typeof(Game).GetMethod("EndGame", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(end); + + end.Invoke(_game, new object[] { 14 } ); + + Assert.False(_game.IsRunning); + } + + [Fact] + public void CalculusOfPointsWorksWellOrNot() + { + _game.InitializeGame(new Map("test", "test.png"), new Player("test", "test.png"), false); + + _game.UsedMap.Boards[7].Valid = true; + _game.UsedMap.Boards[8].Valid = true; + _game.UsedMap.Boards[9].Valid = true; + _game.UsedMap.Boards[10].Valid = true; + _game.UsedMap.Boards[11].Valid = true; + _game.UsedMap.Boards[12].Valid = true; + + _game.UsedMap.Boards[10].Value = 2; // penalty (- 3) + _game.UsedMap.Boards[7].Value = 5; //5 + 2 = 7 + _game.UsedMap.Boards[8].Value = 5; + _game.UsedMap.Boards[9].Value = 5; + + var place = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(place); + + _game.PlayerCell = new Cell(4, 1); + _game.PlayerCell.Value = 7; + _game.PlayerCell.Valid = true; + _game.PlayerCell.IsDangerous = true; + place.Invoke(_game, new object[] { _game.PlayerCell, 7 }); //One penalty + + + + foreach (var cells in _game.UsedMap.Boards.ToList()) + { + _game.GameRules.IsZoneValidAndAddToZones(cells, _game.UsedMap); + } + + _game.PutPenaltyForLostCells(_game.UsedMap.Boards); + + Assert.True(_game.UsedMap.Boards[11].Penalty); + + Assert.Equal(1, _game.FinalCalculusOfPoints()); + } + + [Fact] + public void CalculusOfPointsWorksWellOrNotForRopePathes() + { + _game.InitializeGame(new Map("test", "test.png"), new Player("test", "test.png"), false); + + var methodInfo = typeof(Game).GetMethod("AddToRopePath", BindingFlags.NonPublic | BindingFlags.Instance); + Assert.NotNull(methodInfo); + _game.Turn = 2; + _game.UsedMap.Boards[7].Valid = true; + _game.UsedMap.Boards[8].Valid = true; + _game.UsedMap.Boards[9].Valid = true; + _game.UsedMap.Boards[10].Valid = true; + + _game.UsedMap.Boards[7].Value = 5; //7 + 2 = 9 + methodInfo.Invoke(_game, new object[] { _game.UsedMap.Boards[7] }); + _game.UsedMap.Boards[8].Value = 6; + methodInfo.Invoke(_game, new object[] { _game.UsedMap.Boards[8] }); + _game.UsedMap.Boards[9].Value = 7; + methodInfo.Invoke(_game, new object[] { _game.UsedMap.Boards[9] }); + _game.UsedMap.Boards[10].Value = 2; // penalty (- 3) + methodInfo.Invoke(_game, new object[] { _game.UsedMap.Boards[10] }); + + + _game.PutPenaltyForLostCells(_game.UsedMap.Boards); + + + Assert.True(_game.UsedMap.Boards[10].Penalty); + + Assert.Equal(6, _game.FinalCalculusOfPoints()); + } + + [Fact] + public void AddBestScore_AddsNewBestScoreToList() + { + var game = new Game(_mockPersistence.Object); + var player = new Player("John Doe", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + + game.InitializeGame(map, player, false); + + game.AddBestScore(100); + + Assert.Single(game.BestScores); + Assert.Equal(100, game.BestScores[0].Score); + Assert.Equal(player, game.BestScores[0].ThePlayer); + Assert.Equal(map.Name, game.BestScores[0].MapName); + } + + [Fact] + public void AddBestScore_UpdatesExistingBestScoreAndIncrementsGamesPlayed() + { + var game = new Game(_mockPersistence.Object); + var player = new Player("John Doe", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + + game.InitializeGame(map, player, false); + + game.AddBestScore(100); + game.AddBestScore(200); + + Assert.Single(game.BestScores); + Assert.Equal(300, game.BestScores[0].Score); + Assert.Equal(2, game.BestScores[0].GamesPlayed); + Assert.Equal(player, game.BestScores[0].ThePlayer); + Assert.Equal(map.Name, game.BestScores[0].MapName); + } + + [Fact] + public void AddBestScore_SortsBestScoresCorrectly() + { + var game = new Game(_mockPersistence.Object); + var player1 = new Player("John Doe", "DefaultProfilePicture"); + var player2 = new Player("John Does", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + + game.InitializeGame(map, player1, false); + + game.AddBestScore(100); + game.InitializeGame(map, player2, false); + game.AddBestScore(200); + + Assert.Equal(2, game.BestScores.Count); + Assert.Equal(200, game.BestScores[0].Score); + Assert.Equal(player2, game.BestScores[0].ThePlayer); + Assert.Equal(100, game.BestScores[1].Score); + Assert.Equal(player1, game.BestScores[1].ThePlayer); + } + + [Fact] + public void CheckAndRemoveBestScoresDependencies_RemovesDependenciesCorrectly() + { + var game = new Game(_mockPersistence.Object); + var player = new Player("John Doe", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + + game.InitializeGame(map, player, false); + game.AddBestScore(100); + + game.CheckAndRemoveBestScoresDependencies(player.Pseudo); + + Assert.DoesNotContain(game.BestScores, bs => bs.ThePlayer.Pseudo == player.Pseudo); + } + + [Fact] + public void CheckAndChangeBestScoresDependencies_ChangesDependenciesCorrectly() + { + var game = new Game(_mockPersistence.Object); + var player = new Player("John Doe", "DefaultProfilePicture"); + var map = new Map("test_name", "test_background.png"); + + game.InitializeGame(map, player, false); + game.AddBestScore(100); + + game.CheckAndChangeBestScoresDependencies(player.Pseudo, "John Does"); + + Assert.All(game.BestScores, bs => Assert.NotEqual("John Doe", bs.ThePlayer.Pseudo)); + Assert.Contains(game.BestScores, bs => bs.ThePlayer.Pseudo == "John Does"); + } + +} diff --git a/source/Trek-12/Tests/MapTests.cs b/source/Trek-12/Tests/MapTests.cs index 027ed94..9858d86 100644 --- a/source/Trek-12/Tests/MapTests.cs +++ b/source/Trek-12/Tests/MapTests.cs @@ -8,37 +8,101 @@ public class MapTests [Fact] public void Map_Initialization_SetsBackground() { + string name = "test_name"; string background = "test_background"; - - var map = new Map(background); - + + var map = new Map(name, background); + Assert.Equal(background, map.Background); } [Fact] public void Map_Initialization_InitializesBoards() { + string name = "test_name"; string background = "test_background"; - - var map = new Map(background); - - Assert.Equal(36, map.Boards.Count); + + var map = new Map(name, background); + + Assert.Equal(49, map.Boards.Count); for (int i = 0; i < 36; i++) { - Assert.Equal(new Cell(i / 6, i % 6), map.Boards[i]); + Assert.Equal(new Cell(i % 7, i / 7), map.Boards[i]); } } [Fact] public void Map_Initialization_InitializesRopePathsAndZones() { + string name = "test_name"; string background = "test_background"; - - var map = new Map(background); - + + var map = new Map(name, background); + Assert.NotNull(map.RopePaths); Assert.NotNull(map.Zones); Assert.Empty(map.RopePaths); Assert.Empty(map.Zones); } + + [Fact] + public void IsCellInZones_FoundTheCell() + { + var map = new Map("test_name", "test_background.png"); + + var cell = new Cell(0, 0); + var zone = new List { cell }; + map.Zones.Add(zone); + Assert.True(map.IsCellInZones(cell)); + + } + + [Fact] + public void IsCellInZones_DoNotFoundTheCell() + { + var map = new Map("test_name", "test_background.png"); + + var cell = new Cell(0, 0); + var othercell = new Cell(1, 1); + var zone = new List { cell }; + map.Zones.Add(zone); + Assert.False(map.IsCellInZones(othercell)); + + } + + [Fact] + public void IsCellInRopePath_FoundTheCell() + { + var map = new Map("test_name", "test_background.png"); + + var cell = new Cell(0, 0); + var paths = new List { cell }; + map.RopePaths.Add(paths); + Assert.True(map.IsCellInRopePath(cell)); + + } + + [Fact] + public void IsCellInRopePath_DoNotFoundTheCell() + { + var map = new Map("test_name", "test_background.png"); + + var cell = new Cell(0, 0); + var othercell = new Cell(1, 1); + var paths = new List { cell }; + map.RopePaths.Add(paths); + Assert.False(map.IsCellInRopePath(othercell)); + } + + [Fact] + public void Clone_ReturnsNewMap() + { + var map = new Map("test_name", "test_background.png"); + + var clone = map.Clone(); + + Assert.NotEqual(map, clone); + Assert.Equal(map.Name, clone.Name); + Assert.Equal(map.Background, clone.Background); + } } diff --git a/source/Trek-12/Tests/PlayerTests.cs b/source/Trek-12/Tests/PlayerTests.cs index 194fa85..5da5ee0 100644 --- a/source/Trek-12/Tests/PlayerTests.cs +++ b/source/Trek-12/Tests/PlayerTests.cs @@ -11,14 +11,7 @@ public class PlayerTests var player = new Player(pseudo, profilePicture); Assert.Equal(pseudo, player.Pseudo); Assert.Equal(profilePicture, player.ProfilePicture); - } - - [Fact] - public void Constructor_WithPseudoAndWithoutProfilePicture_SetsPseudoAndDefaultProfilePicture() - { - var player = new Player("MyPlayer"); - Assert.Equal("MyPlayer", player.Pseudo); - Assert.Equal("DefaultProfilePicture", player.ProfilePicture); + Assert.Null(player.LastPlayed); } [Theory] @@ -26,8 +19,8 @@ public class PlayerTests [InlineData("John Doe", "Jane Doe", false)] public void Equals_WithSameOrDifferentPseudo_ReturnsExpectedResult(string pseudo1, string pseudo2, bool expectedResult) { - var player1 = new Player(pseudo1); - var player2 = new Player(pseudo2); + var player1 = new Player(pseudo1, "DefaultProfilePicture"); + var player2 = new Player(pseudo2, "DefaultProfilePicture"); Assert.Equal(expectedResult, player1.Equals(player2)); } @@ -36,8 +29,33 @@ public class PlayerTests [InlineData("John Doe", "Jane Doe", false)] public void GetHashCode_ReturnsSameOrDifferentHashCodeForPseudo(string pseudo1, string pseudo2, bool expectedResult) { - var player1 = new Player(pseudo1); - var player2 = new Player(pseudo2); + var player1 = new Player(pseudo1, "DefaultProfilePicture"); + var player2 = new Player(pseudo2, "DefaultProfilePicture"); Assert.Equal(expectedResult, player1.GetHashCode() == player2.GetHashCode()); } + + [Fact] + public void Equals_WithNull_ReturnsFalse() + { + Player player = new Player(null, null); + Assert.False(player.Equals(null)); + } + + [Fact] + public void Equals_WithDifferentType_ReturnsFalse() + { + Player player = new Player("test_pseudo", "DefaultProfilePicture"); + Assert.False(player.Equals(new Cell(0, 0))); + } + + [Fact] + public void UpdateLastPlayed_UpdatesLastPlayedDate() + { + var player = new Player("John Doe", "DefaultProfilePicture"); + + player.UpdateLastPlayed(); + + Assert.NotNull(player.LastPlayed); + Assert.Equal(DateTime.Now.ToString("dd/MM/yyyy"), player.LastPlayed); + } } \ No newline at end of file diff --git a/source/Trek-12/Tests/RulesTests.cs b/source/Trek-12/Tests/RulesTests.cs new file mode 100644 index 0000000..ee82959 --- /dev/null +++ b/source/Trek-12/Tests/RulesTests.cs @@ -0,0 +1,571 @@ +namespace Tests; +using Models.Game; +using Models.Rules; +using System.Diagnostics; + +public class RulesTests +{ + [Fact] + public void IsCellEmpty_ReturnsTrue_WhenCellIsNull() + { + Rules rules = new Rules(); + Assert.True(rules.IsCellEmpty(null)); + } + + [Fact] + public void IsCellEmpty_ReturnsTrue_WhenCellValueIsNull() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + Assert.True(rules.IsCellEmpty(cell)); + } + + [Fact] + public void IsCellEmpty_ReturnsFalse_WhenCellValueIsNotNull() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + cell.Value = 1; + Assert.False(rules.IsCellEmpty(cell)); + } + + [Fact] + public void IsCellValid_ReturnsFalse_WhenCellIsNotEmptyAndHasAdjacentCells() + { + Rules rules = new Rules(); + Map map = new Map("test", "background"); + Cell selectedCell = map.Boards[0]; + selectedCell.Value = 5; + Assert.False(rules.IsCellValid(selectedCell, map.Boards.ToList())); + } + + [Fact] + public void IsCellValid_ReturnsTrue_WhenCellIsEmptyAndHasAdjacentCells() + { + Rules rules = new Rules(); + Map map = new Map("test", "background"); + map.Boards[0].Valid = true; + Cell selectedCell = map.Boards[0]; + Assert.True(rules.IsCellValid(selectedCell, map.Boards.ToList())); + } + + [Fact] + public void IsCellAdjacent_ReturnsFalse_WhenCellsAreNotAdjacent() + { + Rules rules = new Rules(); + Cell cell1 = new Cell(0, 0); + Cell cell2 = new Cell(2, 2); + Assert.False(rules.IsCellAdjacent(cell1, cell2)); + } + + [Fact] + public void IsCellAdjacent_ReturnsTrue_WhenCellsAreSideBySide() + { + Rules rules = new Rules(); + Cell cell1 = new Cell(0, 0); + Cell cell2 = new Cell(0, 1); + Assert.True(rules.IsCellAdjacent(cell1, cell2)); + } + + [Fact] + public void IsCellAdjacent_ReturnsTrue_WhenCellsAreDiagonal() + { + Rules rules = new Rules(); + Cell cell1 = new Cell(0, 0); + Cell cell2 = new Cell(1, 1); + Assert.True(rules.IsCellAdjacent(cell1, cell2)); + } + + [Fact] + public void IsInRopePaths_ReturnsTrue_WhenCellsAreInRopePaths() + { + Rules rules = new Rules(); + Cell cell1 = new Cell(0, 0); + Cell cell2 = new Cell(0, 1); + Map map = new Map("test", "background"); + map.RopePaths.Add(new List { cell1, cell2 }); + Assert.True(rules.IsInRopePaths(cell2, map.RopePaths, 0)); + } + + [Fact] + public void IsInRopePaths_ReturnsFalse_WhenCellsAreNotInRopePaths() + { + Rules rules = new Rules(); + Cell cell1 = new Cell(0, 0); + Cell cell2 = new Cell(0, 1); + Map map = new Map("test", "background"); + map.RopePaths.Add(new List { cell1 }); + Assert.False(rules.IsInRopePaths(cell2, map.RopePaths, 0)); + } + + [Fact] + public void IsInRopePaths_ReturnsTrue_WhenCellsAreInRopePathsButNotInTheSamePath() + { + Rules rules = new Rules(); + Cell cell1 = new Cell(0, 0); + Cell cell2 = new Cell(0, 1); + Map map = new Map("test", "background"); + map.RopePaths.Add(new List { cell1 }); + map.RopePaths.Add(new List { cell2 }); + Assert.True(rules.IsInRopePaths(cell2, map.RopePaths, 0)); + } + + [Fact] + public void AsValue_ReturnsTrue_WhenCellHasTheSameValue() + { + Rules rules = new Rules(); + Cell cell1 = new Cell(0, 0); + Cell cell2 = new Cell(0, 1); + cell1.Value = 5; + cell2.Value = 5; + Map map = new Map("test", "background"); + map.RopePaths.Add(new List { cell1, cell2 }); + Assert.True(rules.AsValue(cell2, map.RopePaths, 0)); + } + + [Fact] + public void AsValue_ReturnsTrue_WhenCellValueIsAlreadyInRopePaths() + { + Rules rules = new Rules(); + Cell cell1 = new Cell(0, 0); + Cell cell2 = new Cell(0, 1); + cell1.Value = 5; + cell2.Value = 5; + Map map = new Map("test", "background"); + map.RopePaths.Add(new List { cell1 }); + Assert.True(rules.AsValue(cell2, map.RopePaths, 0)); + } + + [Fact] + public void AsValue_ReturnsFalse_WhenCellHasDifferentValue() + { + Rules rules = new Rules(); + Cell cell1 = new Cell(0, 0); + Cell cell2 = new Cell(0, 1); + cell1.Value = 5; + cell2.Value = 6; + Map map = new Map("test", "background"); + map.RopePaths.Add(new List { cell1 }); + Assert.False(rules.AsValue(cell2, map.RopePaths, 0)); + } + + [Fact] + public void NearCellIsValid_ReturnsFalse_WhenChosenCellIsNull() + { + Rules rules = new Rules(); + Assert.False(rules.NearCellIsValid(null, new List())); + } + + [Fact] + public void NearCellIsValid_ReturnsFalse_WhenCellsIsNull() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + Assert.False(rules.NearCellIsValid(cell, null)); + } + + [Fact] + public void NearCellIsValid_ReturnsFalse_WhenNoAdjacentCells() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + List cells = new List { new Cell(2, 0) }; + Assert.False(rules.NearCellIsValid(cell, cells)); + } + + [Fact] + public void NearCellIsValid_ReturnsTrue_WhenAdjacentCellExists() + { + Rules rules = new Rules(); + Cell cell1 = new Cell(0, 0); + Cell cell2 = new Cell(0, 1); + cell2.Value = 12; + cell2.Valid = true; + List cells = new List { cell2 }; + Assert.True(rules.NearCellIsValid(cell1, cells)); + } + + [Fact] + public void IsZoneValidAndAddToZones_DoesNothing_WhenCellIsNull() + { + Rules rules = new Rules(); + Map map = new Map("test", "background"); + rules.IsZoneValidAndAddToZones(null, map); + Assert.Empty(map.Zones); + } + + [Fact] + public void IsZoneValidAndAddToZones_DoesNothing_WhenCellValueIsNull() + { + Rules rules = new Rules(); + Map map = new Map("test", "background"); + Cell cell = new Cell(0, 0); + rules.IsZoneValidAndAddToZones(cell, map); + Assert.Empty(map.Zones); + } + + + [Fact] + public void IsZoneValidAndAddToZones_AddsToExistingZone_WhenAdjacentCellWithSameValueExists() + { + Rules rules = new Rules(); + Map map = new Map("Dunai", "background"); + Cell cell = new Cell(0, 0); + cell.Value = 1; + Cell adjacentCell = new Cell(0, 1); + adjacentCell.Value = 1; + Cell finalCell = new Cell(0, 2); + + map.Boards.ToList().Add(cell); + map.Boards.ToList().Add(adjacentCell); + rules.NewZoneIsCreated(cell, adjacentCell, map); + + rules.IsZoneValidAndAddToZones(finalCell, map); + Assert.Contains(cell, map.Zones[0]); + } + + [Fact] + public void IsZoneValidAndAddToZones_CreatesNewZone_WhenAdjacentCellWithSameValueExistsButNoExistingZone() + { + Rules rules = new Rules(); + Map map = new Map("Dunai", "background"); + Cell cell = new Cell(0, 0); + cell.Value = 1; + Cell adjacentCell = new Cell(0, 1); + adjacentCell.Value = 1; + + map.Boards[0].Value = 1; + map.Boards[1].Value = 1; + + rules.IsZoneValidAndAddToZones(cell, map); + Assert.Contains(cell, map.Zones[0]); + } + + [Fact] + public void IsValueInZones_ReturnsFalse_WhenCellIsNull() + { + Rules rules = new Rules(); + Assert.False(rules.IsValueInZones(null, new List>())); + } + + [Fact] + public void IsValueInZones_ReturnsFalse_WhenZonesAreEmpty() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + cell.Value = 1; + Assert.False(rules.IsValueInZones(cell, new List>())); + } + + [Fact] + public void IsValueInZones_ReturnsFalse_WhenNoZoneContainsCellWithSameValue() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + cell.Value = 1; + List> zones = new List> + { + new List { new Cell(0, 1) { Value = 2 } }, + new List { new Cell(1, 0) { Value = 3 } } + }; + Assert.False(rules.IsValueInZones(cell, zones)); + } + + [Fact] + public void IsValueInZones_ReturnsTrue_WhenZoneContainsCellWithSameValue() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + cell.Value = 1; + List> zones = new List> + { + new List { new Cell(0, 1) { Value = 1 } }, + new List { new Cell(1, 0) { Value = 3 } } + }; + Assert.True(rules.IsValueInZones(cell, zones)); + } + + [Fact] + public void IsCellInZone_ReturnsFalse_WhenCellIsNull() + { + Rules rules = new Rules(); + Assert.False(rules.IsCellInZone(null, new List>())); + } + + [Fact] + public void IsCellInZone_ReturnsFalse_WhenZonesAreEmpty() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + Assert.False(rules.IsCellInZone(cell, new List>())); + } + + [Fact] + public void IsCellInZone_ReturnsFalse_WhenNoZoneContainsCell() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + List> zones = new List> + { + new List { new Cell(0, 1) }, + new List { new Cell(1, 0) } + }; + Assert.False(rules.IsCellInZone(cell, zones)); + } + + [Fact] + public void IsCellInZone_ReturnsTrue_WhenZoneContainsCell() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + List> zones = new List> + { + new List { new Cell(0, 1) }, + new List { cell } + }; + Assert.True(rules.IsCellInZone(cell, zones)); + } + + [Fact] + public void AddToZone_DoesNothing_WhenCellIsNull() + { + Rules rules = new Rules(); + List> zones = new List>(); + rules.AddToZone(null, zones); + Assert.Empty(zones); + } + + [Fact] + public void AddToZone_DoesNothing_WhenCellValueIsNull() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + List> zones = new List>(); + rules.AddToZone(cell, zones); + Assert.Empty(zones); + } + + [Fact] + public void AddToZone_DoesNothing_WhenCellIsAlreadyInZone() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + cell.Value = 1; + List> zones = new List> + { + new List { cell } + }; + rules.AddToZone(cell, zones); + Assert.Single(zones[0]); // Verify if the List has still only one element + } + + [Fact] + public void AddToZone_AddsCellToExistingZone_WhenCellHasSameValueAsZone() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + cell.Value = 1; + List> zones = new List> + { + new List { new Cell(0, 1) { Value = 1 } } + }; + rules.AddToZone(cell, zones); + Assert.Contains(cell, zones[0]); + } + + [Fact] + public void NewZoneIsCreated_DoesNothing_WhenFirstCellIsNull() + { + Rules rules = new Rules(); + Map map = new Map("test", "background"); + rules.NewZoneIsCreated(null, new Cell(0, 0), map); + Assert.Empty(map.Zones); + } + + [Fact] + public void NewZoneIsCreated_DoesNothing_WhenSecondCellIsNull() + { + Rules rules = new Rules(); + Map map = new Map("test", "background"); + rules.NewZoneIsCreated(new Cell(0, 0), null, map); + Assert.Empty(map.Zones); + } + + [Fact] + public void NewZoneIsCreated_DoesNothing_WhenFirstCellValueIsNull() + { + Rules rules = new Rules(); + Map map = new Map("test", "background"); + Cell firstCell = new Cell(0, 0); + rules.NewZoneIsCreated(firstCell, new Cell(0, 1), map); + Assert.Empty(map.Zones); + } + + [Fact] + public void NewZoneIsCreated_DoesNothing_WhenSecondCellValueIsNull() + { + Rules rules = new Rules(); + Map map = new Map("test", "background"); + Cell secondCell = new Cell(0, 0); + rules.NewZoneIsCreated(new Cell(0, 1), secondCell, map); + Assert.Empty(map.Zones); + } + + [Fact] + public void NewZoneIsCreated_CreatesNewZone_WhenBothCellsAreNotNullAndHaveValues() + { + Rules rules = new Rules(); + Map map = new Map("test", "background"); + Cell firstCell = new Cell(0, 0); + firstCell.Value = 1; + Cell secondCell = new Cell(0, 1); + secondCell.Value = 1; + rules.NewZoneIsCreated(firstCell, secondCell, map); + Assert.Single(map.Zones); + Assert.Contains(firstCell, map.Zones[0]); + Assert.Contains(secondCell, map.Zones[0]); + } + + [Fact] + public void EveryAdjacentCells_ReturnsEmptyList_WhenCellIsNull() + { + Rules rules = new Rules(); + List cells = new List { new Cell(0, 0), new Cell(0, 1) }; + Assert.Empty(rules.EveryAdjacentCells(null, cells)); + } + + [Fact] + public void EveryAdjacentCells_ReturnsEmptyList_WhenCellsAreEmpty() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + Assert.Empty(rules.EveryAdjacentCells(cell, new List())); + } + + [Fact] + public void EveryAdjacentCells_ReturnsEmptyList_WhenNoAdjacentCells() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + List cells = new List { new Cell(2, 2), new Cell(3, 3) }; + Assert.Empty(rules.EveryAdjacentCells(cell, cells)); + } + + [Fact] + public void EveryAdjacentCells_ReturnsListWithAdjacentCells_WhenAdjacentCellsExist() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + List cells = new List { new Cell(0, 1), new Cell(1, 0), new Cell(2, 2) }; + List result = rules.EveryAdjacentCells(cell, cells); + Assert.Equal(2, result.Count); + Assert.Contains(new Cell(0, 1), result); + Assert.Contains(new Cell(1, 0), result); + } + + [Fact] + public void FinalCalculusOfZones_ReturnsZero_WhenZonesAreEmpty() + { + Rules rules = new Rules(); + Assert.Equal(0, rules.FinalCalculusOfZones(new List>())); + } + + [Fact] + public void FinalCalculusOfZones_ReturnsCorrectValue_WhenZonesAreNotEmpty() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + cell.Value = 1; + Cell cell1 = new Cell(0, 1); + cell1.Value = 1; + Cell cell2 = new Cell(0, 2); + cell2.Value = 1; + Cell uncell = new Cell(0, 0); + uncell.Value = 4; + Cell deuxcell = new Cell(0, 1); + deuxcell.Value = 4; + Cell troiscell = new Cell(0, 2); + troiscell.Value = 4; + List> zones = new List> + { + new List { cell, cell1, cell2 }, + new List { uncell, deuxcell, troiscell } + }; + + Assert.Equal(9, rules.FinalCalculusOfZones(zones)); + } + + [Fact] + public void FinalCalculusOfZones_ReturnsCorrectValue_WhenZoneCountIsGreaterThanNine() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + cell.Value = 5; + Cell cell1 = new Cell(0, 1); + cell1.Value = 5; + Cell cell2 = new Cell(0, 2); + cell2.Value = 5; + Cell cell3 = new Cell(0, 3); + cell3.Value = 5; + Cell cell4 = new Cell(0, 4); + cell4.Value = 5; + Cell cell5 = new Cell(0, 5); + cell5.Value = 5; + Cell cell6 = new Cell(1, 0); + cell6.Value = 5; + Cell cell7 = new Cell(1, 1); + cell7.Value = 5; + Cell cell8 = new Cell(1, 2); + cell8.Value = 5; + Cell cell9 = new Cell(1, 3); + cell9.Value = 5; + Cell cell10 = new Cell(1, 4); + cell10.Value = 5; + + List> zones = new List> + { + new List { cell, cell1, cell2, cell3, cell4, cell5, cell6, cell7, cell8, cell9, cell10 } + }; + + Assert.Equal(23, rules.FinalCalculusOfZones(zones)); + } + + [Fact] + public void ScoreRopePaths_ReturnsZero_WhenPathsAreEmpty() + { + Rules rules = new Rules(); + Assert.Equal(0, rules.ScoreRopePaths(new List())); + } + + [Fact] + public void ScoreRopePaths_ReturnsCorrectValue_WhenPathsAreNotEmpty() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + cell.Value = 5; + Cell cell1 = new Cell(0, 1); + cell1.Value = 6; + Cell cell2 = new Cell(0, 2); + cell2.Value = 4; + + List ropePath = new List { cell, cell1, cell2 }; + + Assert.Equal(8, rules.ScoreRopePaths(ropePath)); + } + + [Fact] + public void ScoreRopePaths_ReturnsCorrectValue_WhenPathsAreNotEmptyAndSorted() + { + Rules rules = new Rules(); + Cell cell = new Cell(0, 0); + cell.Value = 5; + Cell cell1 = new Cell(0, 1); + cell1.Value = 6; + Cell cell2 = new Cell(0, 2); + cell2.Value = 4; + + List ropePath = new List { cell1, cell, cell2 }; + + Assert.Equal(8, rules.ScoreRopePaths(ropePath)); + } +} \ No newline at end of file diff --git a/source/Trek-12/Tests/Tests.csproj b/source/Trek-12/Tests/Tests.csproj index 2fea905..4ea534a 100644 --- a/source/Trek-12/Tests/Tests.csproj +++ b/source/Trek-12/Tests/Tests.csproj @@ -10,8 +10,9 @@ - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/source/Trek-12/Trek-12.sln b/source/Trek-12/Trek-12.sln index 23e752e..2c7ceca 100644 --- a/source/Trek-12/Trek-12.sln +++ b/source/Trek-12/Trek-12.sln @@ -5,11 +5,15 @@ VisualStudioVersion = 17.8.34408.163 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Trek-12", "Trek-12\Trek-12.csproj", "{41EE7BF8-DDE6-4B00-9434-076589C0B419}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Models", "Models\Models.csproj", "{807AB723-7AD3-42DD-9DA6-7AA5B0A9AAB4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Models", "Models\Models.csproj", "{807AB723-7AD3-42DD-9DA6-7AA5B0A9AAB4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApp", "ConsoleApp\ConsoleApp.csproj", "{795F2C88-3C43-4795-9764-E52F7330888D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp", "ConsoleApp\ConsoleApp.csproj", "{795F2C88-3C43-4795-9764-E52F7330888D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{383C4215-C680-4C2E-BC7E-B62F0B164370}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tests", "Tests\Tests.csproj", "{383C4215-C680-4C2E-BC7E-B62F0B164370}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataContractPersistence", "DataContractPersistence\DataContractPersistence.csproj", "{FC6A23C3-A1E3-4BF4-85B0-404D8574E190}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stub", "Stub\Stub.csproj", "{49360F7D-C59D-4B4F-AF5A-73FF61D9EF9B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -35,6 +39,14 @@ Global {383C4215-C680-4C2E-BC7E-B62F0B164370}.Debug|Any CPU.Build.0 = Debug|Any CPU {383C4215-C680-4C2E-BC7E-B62F0B164370}.Release|Any CPU.ActiveCfg = Release|Any CPU {383C4215-C680-4C2E-BC7E-B62F0B164370}.Release|Any CPU.Build.0 = Release|Any CPU + {FC6A23C3-A1E3-4BF4-85B0-404D8574E190}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC6A23C3-A1E3-4BF4-85B0-404D8574E190}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC6A23C3-A1E3-4BF4-85B0-404D8574E190}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC6A23C3-A1E3-4BF4-85B0-404D8574E190}.Release|Any CPU.Build.0 = Release|Any CPU + {49360F7D-C59D-4B4F-AF5A-73FF61D9EF9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {49360F7D-C59D-4B4F-AF5A-73FF61D9EF9B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {49360F7D-C59D-4B4F-AF5A-73FF61D9EF9B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {49360F7D-C59D-4B4F-AF5A-73FF61D9EF9B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/source/Trek-12/Trek-12/App.xaml.cs b/source/Trek-12/Trek-12/App.xaml.cs index 08757e4..5059279 100644 --- a/source/Trek-12/Trek-12/App.xaml.cs +++ b/source/Trek-12/Trek-12/App.xaml.cs @@ -1,12 +1,69 @@ -namespace Trek_12 +using System.Diagnostics; +using System.Runtime.Serialization.DataContracts; + + +namespace Trek_12 { + using Stub; + using Models.Game; + using Models.Interfaces; + using DataContractPersistence; + public partial class App : Application { + public string FileName { get; set; } = "data.json"; + + public string FilePath { get; set; } = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Trek_12"); + + public Game Manager { get; private set; } + public App() { InitializeComponent(); + Manager = new Game(new DataContractJson()); + //Manager = new Game(new Stub()); + + if (!Directory.Exists(FilePath)) + { + Directory.CreateDirectory(FilePath); + } + + //File.Delete(Path.Combine(FilePath, FileName)); + + string fullPath = Path.Combine(FilePath, FileName); + if (File.Exists(fullPath)) + { + Debug.WriteLine("Data loaded from " + fullPath); + Manager.LoadData(); + } + /* Add the permanent maps if they are not already in the game */ + if (Manager.Maps.Count == 0) + { + Manager.AddMap(new Map("Dunai","montagne2.png")); + Manager.AddMap(new Map("Kagkot", "montagne3.png")); + Manager.AddMap(new Map("Dhaulagiri", "montagne4.png")); + } + + MainPage = new AppShell(); + + // If the MainPage is closed, we save the data + MainPage.Disappearing += (sender, e) => + { + Debug.WriteLine("Saving data..."); + Manager.SaveData(); + }; + + } + + /// + /// Save the data when the app is in background + /// + protected override void OnSleep() + { + Debug.WriteLine("Zzz Secure save..."); + Manager.SaveData(); } } } diff --git a/source/Trek-12/Trek-12/AppShell.xaml b/source/Trek-12/Trek-12/AppShell.xaml index 4eda938..c66ddf6 100644 --- a/source/Trek-12/Trek-12/AppShell.xaml +++ b/source/Trek-12/Trek-12/AppShell.xaml @@ -5,38 +5,11 @@ xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:Trek_12" xmlns:views="clr-namespace:Trek_12.Views" - Shell.FlyoutBehavior="Flyout" + Shell.FlyoutBehavior="Disabled" Title="Trek_12" - Shell.NavBarIsVisible="False"> - - - - - - - - - - - - + Shell.NavBarIsVisible="False" + Shell.FlyoutItemIsVisible="False" + Shell.TabBarIsVisible="False"> + diff --git a/source/Trek-12/Trek-12/AppShell.xaml.cs b/source/Trek-12/Trek-12/AppShell.xaml.cs index ad8d368..eba8dbd 100644 --- a/source/Trek-12/Trek-12/AppShell.xaml.cs +++ b/source/Trek-12/Trek-12/AppShell.xaml.cs @@ -1,10 +1,22 @@ -namespace Trek_12 +using Trek_12.Views; + +namespace Trek_12 { + /// + /// Class for the route of the views and the navigation of the app. + /// public partial class AppShell : Shell { public AppShell() { InitializeComponent(); + + Routing.RegisterRoute(nameof(PageMenuPrincipal), typeof(PageMenuPrincipal)); + Routing.RegisterRoute(nameof(PageProfiles), typeof(PageProfiles)); + Routing.RegisterRoute(nameof(PageSelectMap), typeof(PageSelectMap)); + Routing.RegisterRoute(nameof(PageRegles), typeof(PageRegles)); + Routing.RegisterRoute(nameof(PageLeaderBoard), typeof(PageLeaderBoard)); + Routing.RegisterRoute(nameof(PageBoard), typeof(PageBoard)); } } } diff --git a/source/Trek-12/Trek-12/Resources/AppIcon/app_icon.png b/source/Trek-12/Trek-12/Resources/AppIcon/app_icon.png new file mode 100644 index 0000000..c9df929 Binary files /dev/null and b/source/Trek-12/Trek-12/Resources/AppIcon/app_icon.png differ diff --git a/source/Trek-12/Trek-12/Resources/AppIcon/appicon.svg b/source/Trek-12/Trek-12/Resources/AppIcon/appicon.svg deleted file mode 100644 index 9d63b65..0000000 --- a/source/Trek-12/Trek-12/Resources/AppIcon/appicon.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/source/Trek-12/Trek-12/Resources/AppIcon/appiconfg.svg b/source/Trek-12/Trek-12/Resources/AppIcon/appiconfg.svg deleted file mode 100644 index 21dfb25..0000000 --- a/source/Trek-12/Trek-12/Resources/AppIcon/appiconfg.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/source/Trek-12/Trek-12/Resources/Images/back_arrow.png b/source/Trek-12/Trek-12/Resources/Images/back_arrow.png new file mode 100644 index 0000000..fcc3d87 Binary files /dev/null and b/source/Trek-12/Trek-12/Resources/Images/back_arrow.png differ diff --git a/source/Trek-12/Trek-12/Resources/Images/checked.png b/source/Trek-12/Trek-12/Resources/Images/checked.png new file mode 100644 index 0000000..fdac7db Binary files /dev/null and b/source/Trek-12/Trek-12/Resources/Images/checked.png differ diff --git a/source/Trek-12/Trek-12/Resources/Images/dotnet_bot.png b/source/Trek-12/Trek-12/Resources/Images/dotnet_bot.png deleted file mode 100644 index f93ce02..0000000 Binary files a/source/Trek-12/Trek-12/Resources/Images/dotnet_bot.png and /dev/null differ diff --git a/source/Trek-12/Trek-12/Resources/Images/maptest.png b/source/Trek-12/Trek-12/Resources/Images/maptest.png new file mode 100644 index 0000000..03dd7c4 Binary files /dev/null and b/source/Trek-12/Trek-12/Resources/Images/maptest.png differ diff --git a/source/Trek-12/Trek-12/Resources/Images/montagne2.png b/source/Trek-12/Trek-12/Resources/Images/montagne2.png new file mode 100644 index 0000000..08ef213 Binary files /dev/null and b/source/Trek-12/Trek-12/Resources/Images/montagne2.png differ diff --git a/source/Trek-12/Trek-12/Resources/Images/montagne3.png b/source/Trek-12/Trek-12/Resources/Images/montagne3.png new file mode 100644 index 0000000..2fe46a7 Binary files /dev/null and b/source/Trek-12/Trek-12/Resources/Images/montagne3.png differ diff --git a/source/Trek-12/Trek-12/Resources/Images/montagne4.png b/source/Trek-12/Trek-12/Resources/Images/montagne4.png new file mode 100644 index 0000000..9e3b0b0 Binary files /dev/null and b/source/Trek-12/Trek-12/Resources/Images/montagne4.png differ diff --git a/source/Trek-12/Trek-12/Resources/Images/tmp1.jpeg b/source/Trek-12/Trek-12/Resources/Images/tmp1.jpeg deleted file mode 100644 index 36b1bdd..0000000 Binary files a/source/Trek-12/Trek-12/Resources/Images/tmp1.jpeg and /dev/null differ diff --git a/source/Trek-12/Trek-12/Resources/Images/tmp2.jpeg b/source/Trek-12/Trek-12/Resources/Images/tmp2.jpeg deleted file mode 100644 index b17bea2..0000000 Binary files a/source/Trek-12/Trek-12/Resources/Images/tmp2.jpeg and /dev/null differ diff --git a/source/Trek-12/Trek-12/Resources/Images/tmp3.jpeg b/source/Trek-12/Trek-12/Resources/Images/tmp3.jpeg deleted file mode 100644 index 2b14897..0000000 Binary files a/source/Trek-12/Trek-12/Resources/Images/tmp3.jpeg and /dev/null differ diff --git a/source/Trek-12/Trek-12/Resources/Images/user.png b/source/Trek-12/Trek-12/Resources/Images/user.png new file mode 100644 index 0000000..9c4f84d Binary files /dev/null and b/source/Trek-12/Trek-12/Resources/Images/user.png differ diff --git a/source/Trek-12/Trek-12/Trek-12.csproj b/source/Trek-12/Trek-12/Trek-12.csproj index 51d65e3..bb2dfcb 100644 --- a/source/Trek-12/Trek-12/Trek-12.csproj +++ b/source/Trek-12/Trek-12/Trek-12.csproj @@ -2,7 +2,7 @@ net8.0-android;net8.0-ios;net8.0-maccatalyst - $(TargetFrameworks);net8.0-windows10.0.19041.0 + @@ -38,16 +38,23 @@ 6.5 + + $(TargetFrameworks);net8.0-windows10.0.19041.0 + MSIX + 404032fa5d4dc4c8bbf036505d2409963f355ebd + + + + - + - @@ -56,6 +63,17 @@ + + + + + + + + + + + @@ -63,26 +81,32 @@ - - - PageLeaderBoard.xaml - - - PageProfils.xaml - - - PageRegles.xaml - + + + + + + + + + PageLeaderBoard.xaml + + + pageProfiles.xaml + + + PageRegles.xaml + - - MSBuild:Compile + + MSBuild:Compile - - MSBuild:Compile + + MSBuild:Compile - + MSBuild:Compile diff --git a/source/Trek-12/Trek-12/Views/Components/ContentLeaderBoard.xaml b/source/Trek-12/Trek-12/Views/Components/ContentLeaderBoard.xaml index 639b6f3..3ec0052 100644 --- a/source/Trek-12/Trek-12/Views/Components/ContentLeaderBoard.xaml +++ b/source/Trek-12/Trek-12/Views/Components/ContentLeaderBoard.xaml @@ -1,7 +1,9 @@ + x:Class="Trek_12.Views.Components.ContentLeaderBoard" + x:Name="this"> + @@ -12,31 +14,31 @@ WidthRequest="60" IsClippedToBounds="True" HasShadow="True"> - -