Compare commits

..

40 Commits

Author SHA1 Message Date
Rémi LAVERGNE a03ccb76e9 Ajout de la vidéo
continuous-integration/drone/push Build is passing Details
continuous-integration/drone Build is passing Details
11 months ago
Rémi LAVERGNE 4ea6ec094b Merge pull request 'v0.9 - Application MAUI' (#112) from dev into master
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
11 months ago
Rémi LAVERGNE bc26c9184d Mise à jour du README
continuous-integration/drone/push Build is passing Details
11 months ago
Rémi LAVERGNE 6509cbcdd1 Bug de Rules.cs
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is failing Details
11 months ago
Rémi LAVERGNE e414771027 Bug de Rules.cs
continuous-integration/drone/push Build is failing Details
11 months ago
Rémi LAVERGNE aab53a614e Bug de Rules.cs
continuous-integration/drone/push Build is failing Details
11 months ago
Rémi LAVERGNE a5ea118e4a Bug de Rules.cs
continuous-integration/drone/push Build is passing Details
11 months ago
Rémi LAVERGNE cd2c35c481 Code Smells de Map.cs
continuous-integration/drone/push Build is passing Details
11 months ago
Remi NEVEU 170e5c5a66 Suppression d'un code smell
continuous-integration/drone/push Build is passing Details
11 months ago
Rémi LAVERGNE 5a597d8323 Code Smells de Player.cs
continuous-integration/drone/push Build is passing Details
11 months ago
Rémi LAVERGNE e113ee2ac6 Code Smells de Rules.cs
continuous-integration/drone/push Build is passing Details
11 months ago
Rémi LAVERGNE 0d3c541c4b Code Smells de Rules.cs
continuous-integration/drone/push Build is failing Details
11 months ago
Rémi LAVERGNE 8b54be4818 Code Smells de Rules.cs
continuous-integration/drone/push Build is failing Details
11 months ago
Rémi LAVERGNE 66cf3c37b2 Actualisation de LastPlayed
continuous-integration/drone/push Build is passing Details
11 months ago
Rémi LAVERGNE 9d6b2af796 🛠️ Encore plus de tests
11 months ago
Remi NEVEU c11ccba67d Merge branch 'dev' of https://codefirst.iut.uca.fr/git/remi.lavergne/Trek-12 into dev
continuous-integration/drone/push Build is passing Details
11 months ago
Remi NEVEU 68d29bc5a5 Suppression de code commenter et fonction EveryAdjacentCells mit nullable pour faire baisser les codes smells
11 months ago
Remi NEVEU 3104b66a39 Changement de la méthode AddToRopePath en enlever le second paramètre, qui était inutilisé
11 months ago
Rémi LAVERGNE b98b2172ce Merge SQLite into dev (#111)
continuous-integration/drone/push Build is passing Details
11 months ago
Rémi LAVERGNE d8962f4cb1 Suppression de deux tests qui ne servaient plus
continuous-integration/drone/push Build is passing Details
11 months ago
Rémi LAVERGNE 60c8f76e01 Merge branch 'dev' of codefirst.iut.uca.fr:remi.lavergne/Trek-12 into dev
continuous-integration/drone/push Build is failing Details
11 months ago
Rémi LAVERGNE 103fd02652 ⚙️ Correction de bugs dans le jeu
11 months ago
Remi NEVEU c95295575e Ajout d'un test et suppression de quelques codes smells
continuous-integration/drone/push Build is passing Details
11 months ago
Remi NEVEU 7fe5289475 Ajout de quelques tests
continuous-integration/drone/push Build is passing Details
11 months ago
Remi NEVEU c562f9cbb5 suppression d'une mauvaise modification
continuous-integration/drone/push Build is passing Details
11 months ago
Remi NEVEU 38a9c8a8e7 Correction de tous les tests et fusion de ce qu'a fait Lucas
continuous-integration/drone/push Build is passing Details
11 months ago
Remi NEVEU 37d57b37fb première correction des tests mais je vais tout recommencer à mon git pull
11 months ago
Rémi LAVERGNE 62ff6c130f Merge PageBoard into dev (#110)
continuous-integration/drone/push Build is failing Details
11 months ago
Rémi LAVERGNE 3fbe28accf Quelques modification pour continuer une partie non terminée
continuous-integration/drone/push Build is failing Details
11 months ago
Rémi LAVERGNE 1f723b64f1 🚧 Correction de bugs et modification de la solution pour publication
continuous-integration/drone/push Build is failing Details
11 months ago
Rémi LAVERGNE d63bc44634 Merge pull request 'ConsoleApp' (#109) from ConsoleApp into dev
continuous-integration/drone/push Build is failing Details
11 months ago
Rémi LAVERGNE 70c4b9c3b2 Correction de tests
continuous-integration/drone/push Build is failing Details
11 months ago
Lucas DUFLOT 2685063b5e rien change
continuous-integration/drone/push Build was killed Details
continuous-integration/drone/pr Build was killed Details
11 months ago
Rémi LAVERGNE cfa4a18b93 Mise à jour de 'README.md'
continuous-integration/drone/push Build is passing Details
11 months ago
Rémi LAVERGNE 631fae3711 💾 Persistance avec SQLite (création et bases)
continuous-integration/drone/push Build was killed Details
continuous-integration/drone/pr Build is failing Details
11 months ago
Lucas DUFLOT 2595ac686f ✔ Chemins de corde
continuous-integration/drone/push Build was killed Details
11 months ago
Rémi LAVERGNE 6d791f4737 Ajout de la LICENCE
continuous-integration/drone/push Build is passing Details
11 months ago
Rémi LAVERGNE 9fef1b7fff Supprimer 'LICENSE'
continuous-integration/drone/push Build is passing Details
11 months ago
Rémi LAVERGNE 1323dcc53f Ajout de la licence sur le dépôt
continuous-integration/drone/push Build is passing Details
11 months ago
Rémi LAVERGNE e4e14adf45 v0.8 - Application Console
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details
12 months ago

@ -0,0 +1,15 @@
**© 2024 - Tous droits réservés.**
Les éléments de conception et de documentation regroupent:
- Les diagrammes
- Les éléments de design
- Tout écrit réalisé dans le cadre de l'application et présent sur ce même [wiki](https://codefirst.iut.uca.fr/git/remi.lavergne/Trek-12/wiki).
Le terme "code" tel que définit constitue tout ou partie de texte permettant la formation, le fonctionnement et le lancement de l'application et présent dans le [dépôt CodeFirst](https://codefirst.iut.uca.fr/git/remi.lavergne/Trek-12).
Tous les éléments de conception et de documentation, ainsi que le code dans son intégralité sont la propriété des utilisateurs enregistrés sous les comptes CodeFirst/Gitea suivants: @remi.lavergne, @remi.neveu & @lucas.duflot.
Le jeu de société du nom "Trek 12" ainsi que tous ses logos associés sont la propriété de [🪓 LUMBERJACKS [Studio]](https://lumberjacks-studio.com/fr/trek12/)
**Utilisation et distribution :** Toute reproduction, distribution, ou utilisation non autorisée des éléments protégés est strictement interdite sans l'autorisation écrite préalable des propriétaires respectifs. Les utilisateurs peuvent demander des autorisations spécifiques en contactant les propriétaires via leurs comptes mentionnés.
**Avis de non-responsabilité :** Ce copyright ne s'étend pas aux éléments tiers utilisés sous licence. Toutes les marques commerciales et logos appartiennent à leurs propriétaires respectifs. Les propriétaires des comptes mentionnés ne sauraient être tenus responsables de l'utilisation abusive des éléments protégés par des tiers.

@ -1,4 +1,4 @@
![Static Badge](https://img.shields.io/badge/Trek12-En_Production-red) ![Static Badge](https://img.shields.io/badge/Trek12-Disponible_au_public-yellow)
<details> <details>
<summary>Sonarcube Ratings</summary> <summary>Sonarcube Ratings</summary>
@ -27,4 +27,29 @@ Auteurs:
<br> <br>
> ### **📕 Toute la documentation est présente sur le [Wiki](https://codefirst.iut.uca.fr/git/remi.lavergne/Trek-12/wiki) !** > ### **📼 Vidéo de présentation sur [Opencast](https://opencast.dsi.uca.fr/paella/ui/watch.html?id=b08a0497-0fc3-420f-a98d-5f5a2b226252).**
> ### **📕 Toute la conception et le fonctionnement est présent sur le [Wiki](https://codefirst.iut.uca.fr/git/remi.lavergne/Trek-12/wiki) !**
> ### **📄 Documentation du code sur [CodeDoc](https://codefirst.iut.uca.fr/documentation/remi.lavergne/Trek-12/doxygen/index.html).**
<br>
*Persistance locale en XML ou JSON disponible. La persistance en SQLite est créée mais nécessite encore du développement pour fonctionner.*<br/>
*Pour changer de mode de persistance, se rendre dans le fichier App.xaml.cs*
<br><br>
## 📦 Générer un exécutable
Pour générer un exécutable, il suffit de lancer la commande suivante dans le terminal :
```bash
# Pour un exécutable MSIX (Windows Store):
dotnet publish -f net8.0-windows10.0.19041.0 -p:WindowsPackageType=MSIX
# Ou pour un exécutable "classique":
dotnet publish -c Release -r win-x64 --self-contained
```
<br>
***Avant de fork le projet ou autre, merci de lire attentivement la [LICENCE](LICENSE.md)***

@ -1,4 +1,4 @@
// See https://aka.ms/new-console-template for more information // See https://aka.ms/new-console-template for more information
using Models; using Models;
using Models.Events; using Models.Events;
@ -86,7 +86,7 @@ class Program
static void OnPlayerOption(object sender, PlayerOptionEventArgs e) static void OnPlayerOption(object sender, PlayerOptionEventArgs e)
{ {
Console.WriteLine(); Console.WriteLine();
if(e.Turn != 1) if (e.Turn != 1)
{ {
IEnumerable<Cell> PlayedCellsQuery = IEnumerable<Cell> PlayedCellsQuery =
from cell in e.Board from cell in e.Board
@ -111,6 +111,7 @@ class Program
Console.Write($"{e.Resultat}"); Console.Write($"{e.Resultat}");
Console.ResetColor(); Console.ResetColor();
} }
} }
} }
} }

@ -6,6 +6,10 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Models\Models.csproj" /> <ProjectReference Include="..\Models\Models.csproj" />
</ItemGroup> </ItemGroup>

@ -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<Player>();
_database.CreateTable<Map>();
_database.CreateTable<Game>();
_database.CreateTable<BestScore>();
}
public (ObservableCollection<Player>, ObservableCollection<Game>, ObservableCollection<Map>, ObservableCollection<BestScore>) LoadData()
{
var players = new ObservableCollection<Player>(_database.Table<Player>());
var games = new ObservableCollection<Game>(_database.Table<Game>());
var maps = new ObservableCollection<Map>(_database.Table<Map>());
var bestScores = new ObservableCollection<BestScore>(_database.Table<BestScore>());
return (players, games, maps, bestScores);
}
public void SaveData(ObservableCollection<Player> players, ObservableCollection<Game> games, ObservableCollection<Map> maps, ObservableCollection<BestScore> bestScores)
{
_database.RunInTransaction(() =>
{
_database.DeleteAll<Player>();
_database.DeleteAll<Game>();
_database.DeleteAll<Map>();
_database.DeleteAll<BestScore>();
});
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);
}
}
}
}

@ -5,15 +5,20 @@ using System.Linq;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using SQLite;
namespace Models.Game namespace Models.Game
{ {
/// <summary> /// <summary>
/// This class represents the best score of a player. /// This class represents the best score of a player.
/// </summary> /// </summary>
[DataContract] [DataContract, SQLite.Table("BestScores")]
public class BestScore public class BestScore
{ {
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
/// <summary> /// <summary>
/// Name of the map. /// Name of the map.
/// </summary> /// </summary>
@ -69,6 +74,11 @@ namespace Models.Game
Score = score; Score = score;
} }
/// <summary>
/// SQLite constructor
/// </summary>
public BestScore() { }
/// <summary> /// <summary>
/// Increment the number of games played by the user. /// Increment the number of games played by the user.
/// </summary> /// </summary>

@ -1,4 +1,6 @@
using System.Runtime.Serialization; using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
namespace Models.Game namespace Models.Game
{ {
@ -6,7 +8,7 @@ namespace Models.Game
/// The Cell class represents a cell in the application. /// The Cell class represents a cell in the application.
/// </summary> /// </summary>
[DataContract] [DataContract]
public class Cell : Position, IEquatable<Cell> public class Cell : Position, IEquatable<Cell>, INotifyPropertyChanged
{ {
/// <summary> /// <summary>
/// The value of the cell. /// The value of the cell.
@ -22,6 +24,8 @@ namespace Models.Game
throw new Exception("La valeur doit être supérieure à 0"); throw new Exception("La valeur doit être supérieure à 0");
} }
this._value = value; this._value = value;
OnPropertyChanged();
} }
} }
@ -76,5 +80,13 @@ namespace Models.Game
if (this.X == other.X && this.Y == other.Y) return true; if (this.X == other.X && this.Y == other.Y) return true;
return false; return false;
} }
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
} }
} }

@ -13,6 +13,7 @@ using System.Threading.Tasks.Dataflow;
using Models.Events; using Models.Events;
using Models.Interfaces; using Models.Interfaces;
using Models.Rules; using Models.Rules;
using SQLite;
namespace Models.Game namespace Models.Game
{ {
@ -20,14 +21,21 @@ namespace Models.Game
/// The Game class represents a game session in the application. /// 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. /// It contains all the necessary properties and methods to manage a game, including the game loop, dice rolling, and use of the game rules.
/// </summary> /// </summary>
[DataContract] [DataContract, SQLite.Table("Games")]
public class Game : INotifyPropertyChanged public class Game : INotifyPropertyChanged
{ {
public bool IsPreviousGameNotFinished { get; private set; }
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
/* Persistence Interface */ /* Persistence Interface */
[Ignore]
public IPersistence PersistenceManager { get; set; } public IPersistence PersistenceManager { get; set; }
/* List for the game and persistence */ /* List for the game and persistence */
private ObservableCollection<Player> _players; private ObservableCollection<Player> _players;
[Ignore]
public ObservableCollection<Player> Players public ObservableCollection<Player> Players
{ {
get => _players; get => _players;
@ -39,6 +47,7 @@ namespace Models.Game
} }
private ObservableCollection<Game> _games; private ObservableCollection<Game> _games;
[Ignore]
public ObservableCollection<Game> Games public ObservableCollection<Game> Games
{ {
get => _games; get => _games;
@ -50,6 +59,7 @@ namespace Models.Game
} }
private ObservableCollection<Map> _maps; private ObservableCollection<Map> _maps;
[Ignore]
public ObservableCollection<Map> Maps public ObservableCollection<Map> Maps
{ {
get => _maps; get => _maps;
@ -61,6 +71,7 @@ namespace Models.Game
} }
private ObservableCollection<BestScore> _bestScores; private ObservableCollection<BestScore> _bestScores;
[Ignore]
public ObservableCollection<BestScore> BestScores public ObservableCollection<BestScore> BestScores
{ {
get => _bestScores; get => _bestScores;
@ -94,18 +105,43 @@ namespace Models.Game
} }
} }
[Ignore]
public Dice Dice1 { get; private set;} public Dice Dice1 { get; private set;}
[Ignore]
public Dice Dice2 { get; private set; } public Dice Dice2 { get; private set; }
[DataMember] [DataMember]
public int Turn { get; private set; } public int Turn { get; set; }
[Ignore]
public Operation PlayerOperation { get; set; } public Operation PlayerOperation { get; set; }
public Cell PlayerCell { get; set; } private Cell _playerCell;
public int Resultat { get; set; } [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));
}
}
public bool DiceRolledFlag { get; private set; }
public bool OperationChosenFlag { get; private set; }
[Ignore]
public Rules.Rules GameRules { get; } public Rules.Rules GameRules { get; }
@ -136,25 +172,45 @@ namespace Models.Game
Maps.Add(map); Maps.Add(map);
} }
/// <summary>
/// Adds a new best score to the list of best scores. Or updates it if it already exists.
/// </summary>
/// <param name="finalScore">The final score of the game.</param>
public void AddBestScore(int finalScore) public void AddBestScore(int finalScore)
{ {
BestScore bs = new BestScore(UsedMap.Name, CurrentPlayer, 1, finalScore); BestScore bs = new BestScore(UsedMap.Name, CurrentPlayer, 1, finalScore);
foreach (var score in BestScores) var existingScore = BestScores.FirstOrDefault(score => score.Equals(bs));
{
if (!bs.Equals(score)) continue;
score.IncrGamesPlayed(); if (existingScore != null)
score.UpdateScore(finalScore); {
return; existingScore.IncrGamesPlayed();
existingScore.UpdateScore(finalScore);
} }
else
{
BestScores.Add(bs); BestScores.Add(bs);
BestScores.OrderByDescending(p => p.Score);
} }
// Sorting the best scores
List<BestScore> 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);
}
}
}
/// <summary>
/// Removes a player from the list of players.
/// </summary>
/// <param name="playerName"></param>
/// <returns>True if the player was removed successfully, false otherwise.</returns>
public bool RemovePlayer(string playerName) public bool RemovePlayer(string playerName)
{ {
Player player = Players.FirstOrDefault(p => p.Pseudo == playerName); Player? player = Players.FirstOrDefault(p => p.Pseudo == playerName);
if (player == null) if (player == null)
{ {
return false; return false;
@ -164,6 +220,12 @@ namespace Models.Game
return true; return true;
} }
/// <summary>
/// Modifies the pseudo of a player.
/// </summary>
/// <param name="pseudo"></param>
/// <param name="newpseudo"></param>
/// <returns></returns>
public bool ModifyPlayer(string pseudo, string newpseudo) public bool ModifyPlayer(string pseudo, string newpseudo)
{ {
foreach (var index in Players) foreach (var index in Players)
@ -179,6 +241,10 @@ namespace Models.Game
return false; return false;
} }
/// <summary>
/// Removes a game from the list of games.
/// </summary>
/// <param name="playerName"></param>
public void CheckAndRemoveBestScoresDependencies(string playerName) public void CheckAndRemoveBestScoresDependencies(string playerName)
{ {
List<BestScore> bs = new List<BestScore>(); List<BestScore> bs = new List<BestScore>();
@ -195,6 +261,11 @@ namespace Models.Game
} }
} }
/// <summary>
/// Modifies the pseudo of a player in the best scores.
/// </summary>
/// <param name="playerName"></param>
/// <param name="newPlayerName"></param>
public void CheckAndChangeBestScoresDependencies(string playerName, string newPlayerName) public void CheckAndChangeBestScoresDependencies(string playerName, string newPlayerName)
{ {
foreach (var bestScore in BestScores) foreach (var bestScore in BestScores)
@ -214,6 +285,10 @@ namespace Models.Game
} }
foreach (var game in data.Item2) foreach (var game in data.Item2)
{ {
if (game.IsRunning)
{
IsPreviousGameNotFinished = true;
}
Games.Add(game); Games.Add(game);
} }
foreach (var map in data.Item3) foreach (var map in data.Item3)
@ -261,7 +336,11 @@ namespace Models.Game
{ {
Dice1.Roll(); Dice1.Roll();
Dice2.Roll(); Dice2.Roll();
DiceRolledFlag = true;
OperationChosenFlag = false;
DiceRolled?.Invoke(this, new DiceRolledEventArgs(Dice1.Value, Dice2.Value)); DiceRolled?.Invoke(this, new DiceRolledEventArgs(Dice1.Value, Dice2.Value));
OnPropertyChanged(nameof(Dice1));
OnPropertyChanged(nameof(Dice2));
} }
/// <summary> /// <summary>
@ -329,7 +408,13 @@ namespace Models.Game
{ {
if (item.X == playerChoice.X && item.Y == playerChoice.Y) if (item.X == playerChoice.X && item.Y == playerChoice.Y)
{ {
if (result > 12 || (result > 6 && item.IsDangerous == true))
{
item.SetPenalty();
PlayerCell.SetPenalty();
}
item.Value = result; item.Value = result;
OnPropertyChanged(nameof(UsedMap.Boards));
return; return;
} }
@ -342,35 +427,32 @@ namespace Models.Game
/// </summary> /// </summary>
/// <param name="playerChoice"></param> /// <param name="playerChoice"></param>
/// <param name="adjacentes"></param> /// <param name="adjacentes"></param>
private void AddToRopePath(Cell playerChoice,List<Cell> adjacentes) private void AddToRopePath(Cell playerChoice)
{
int index =0;
foreach (var cells in adjacentes.Where(cells => 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<Cell> {playerChoice, cells});
}
if(Turn==1) return;
int index = 0;
// A modifier dans le cas ou il est possible de fusionner deux chemins de corde IEnumerable<Cell> ValidCell =
if (GameRules.IsInRopePaths(playerChoice, UsedMap.RopePaths, index)) break; from cell in UsedMap.Boards
where cell.Value != null && cell.Valid == true && cell != playerChoice
// Le cas si il existe des chemins de corde select cell;
// Est-ce que la cellule adjacentes fait parti d'un chemin de corde foreach (var item in ValidCell)
if (!GameRules.IsInRopePaths(cells,UsedMap.RopePaths,index))
{ {
UsedMap.RopePaths.Add(new List<Cell> { playerChoice, cells }); if (!GameRules.IsCellAdjacent(playerChoice, item))
continue;
if (!((playerChoice.Value - item.Value) == 1 || (playerChoice.Value - item.Value) == -1))
continue; continue;
if (!GameRules.IsInRopePaths(item,UsedMap.RopePaths,index))
{
UsedMap.RopePaths.Add(new List<Cell> { playerChoice, item });
return;
} }
if (!GameRules.AsValue(playerChoice, UsedMap.RopePaths, index))
if (!GameRules.AsValue(playerChoice,UsedMap.RopePaths,index))
{ {
UsedMap.RopePaths[index].Add(playerChoice); UsedMap.RopePaths[index].Add(playerChoice);
return;
} }
} }
} }
@ -380,16 +462,30 @@ namespace Models.Game
/// </summary> /// </summary>
public void InitializeGame(Map map, Player player, bool startImmediately = true) 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));
UsedMap = map; UsedMap = map;
CurrentPlayer = player; CurrentPlayer = player;
Turn = 1; Turn = 1;
Dice1 = new Dice(); Dice1 = new Dice();
Dice2 = new Dice(1); Dice2 = new Dice(1);
IsPreviousGameNotFinished = false;
OnPropertyChanged(nameof(UsedMap));
OnPropertyChanged(nameof(CurrentPlayer));
OnPropertyChanged(nameof(Turn));
if (startImmediately) if (startImmediately)
{ {
StartGame(); StartGame();
} }
SaveData();
} }
/// <summary> /// <summary>
@ -399,6 +495,8 @@ namespace Models.Game
{ {
IsRunning = true; IsRunning = true;
GameStarted?.Invoke(this, new GameStartedEventArgs(CurrentPlayer)); GameStarted?.Invoke(this, new GameStartedEventArgs(CurrentPlayer));
SaveData();
} }
/// <summary> /// <summary>
@ -433,6 +531,7 @@ namespace Models.Game
PlayerChooseOp?.Invoke(this, new PlayerChooseOperationEventArgs(PlayerOperation)); PlayerChooseOp?.Invoke(this, new PlayerChooseOperationEventArgs(PlayerOperation));
} }
PlayerOption?.Invoke(this, new PlayerOptionEventArgs(UsedMap.Boards.ToList(), ResultOperation(PlayerOperation), Turn)); PlayerOption?.Invoke(this, new PlayerOptionEventArgs(UsedMap.Boards.ToList(), ResultOperation(PlayerOperation), Turn));
OperationChosenFlag = true;
return ResultOperation(PlayerOperation); return ResultOperation(PlayerOperation);
} }
@ -445,6 +544,8 @@ namespace Models.Game
} }
MarkOperationAsChecked(PlayerOperation); MarkOperationAsChecked(PlayerOperation);
PlaceResult(PlayerCell, Resultat); PlaceResult(PlayerCell, Resultat);
DiceRolledFlag = false;
OperationChosenFlag = false;
} }
/// <summary> /// <summary>
@ -454,6 +555,7 @@ namespace Models.Game
public void HandlePlayerOperation(Operation operation) public void HandlePlayerOperation(Operation operation)
{ {
int result = ResultOperation(operation); int result = ResultOperation(operation);
OperationChosenFlag = true;
OperationChosen?.Invoke(this, new OperationChosenEventArgs(operation, result)); OperationChosen?.Invoke(this, new OperationChosenEventArgs(operation, result));
} }
@ -469,26 +571,17 @@ namespace Models.Game
if (cell.X < 0 || cell.X >= UsedMap.Boards.Count / 6 || cell.Y < 0 || cell.Y >= 6) if (cell.X < 0 || cell.X >= UsedMap.Boards.Count / 6 || cell.Y < 0 || cell.Y >= 6)
{ {
return false; return false;
//throw new InvalidCellCoordinatesException("Invalid cell coordinates. Please choose again.");
} }
if (!GameRules.IsCellValid(cell, UsedMap.Boards.ToList())) if (!GameRules.IsCellValid(cell, UsedMap.Boards.ToList()))
{ {
return false; return false;
//throw new InvalidCellException("Cell is not valid. Please choose again.");
} }
bool res = true;
if (!res)
{
return false;
//throw new InvalidPlaceResultException("Cell is not valid for place result. Please choose again.");
}
GameRules.IsZoneValidAndAddToZones(cell, UsedMap); GameRules.IsZoneValidAndAddToZones(cell, UsedMap);
AddToRopePath(cell, GameRules.EveryAdjacentCells(cell, UsedMap.Boards.ToList())); AddToRopePath(cell);
CellChosen?.Invoke(this, new CellChosenEventArgs(cell, result)); CellChosen?.Invoke(this, new CellChosenEventArgs(cell, result));
return true; return true;
//BoardUpdated?.Invoke(this, EventArgs.Empty);
} }
/// <summary> /// <summary>
@ -511,7 +604,7 @@ namespace Models.Game
foreach (var cells in Boards) foreach (var cells in Boards)
if (cells.Penalty) if (cells.Penalty)
{ {
if (cells.Valid == false || cells.Value == null) if (!cells.Valid || cells.Value == null)
continue; continue;
result += 3; result += 3;
} }
@ -522,7 +615,7 @@ namespace Models.Game
{ {
foreach (var cells in Boards) foreach (var cells in Boards)
{ {
if (cells == null || cells.Value == null || cells.Valid == false) if (cells == null || cells.Value == null || !cells.Valid)
continue; continue;
if (!UsedMap.IsCellInZones(cells) && !UsedMap.IsCellInRopePath(cells)) if (!UsedMap.IsCellInZones(cells) && !UsedMap.IsCellInRopePath(cells))
cells.SetPenalty(); cells.SetPenalty();
@ -536,7 +629,7 @@ namespace Models.Game
{ {
points += GameRules.ScoreRopePaths(UsedMap.RopePaths[i]); points += GameRules.ScoreRopePaths(UsedMap.RopePaths[i]);
} }
points += CalculusOfPenalty(UsedMap.Boards); points -= CalculusOfPenalty(UsedMap.Boards);
return points ?? 0; return points ?? 0;
} }

@ -1,5 +1,6 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using SQLite;
namespace Models.Game namespace Models.Game
{ {
@ -7,21 +8,23 @@ namespace Models.Game
/// <summary> /// <summary>
/// The Map class is the representation of the game map with the board and the operations table. /// The Map class is the representation of the game map with the board and the operations table.
/// </summary> /// </summary>
[DataContract] [DataContract, SQLite.Table("Maps")]
public class Map public class Map
{ {
/// <summary> /// <summary>
/// It is the list of cells on the map. /// The displaying name of the map
/// </summary> /// </summary>
[DataMember] [DataMember, PrimaryKey]
public ReadOnlyObservableCollection<Cell> Boards { get; private set; } public string Name { get; private set; }
ObservableCollection<Cell> board = new ObservableCollection<Cell>();
/// <summary> /// <summary>
/// The displaying name of the map /// It is the list of cells on the map.
/// </summary> /// </summary>
[DataMember] [DataMember]
public string Name { get; private set; } [Ignore]
public ReadOnlyObservableCollection<Cell> Boards { get; private set; }
private readonly ObservableCollection<Cell> _board = new ObservableCollection<Cell>();
/// <summary> /// <summary>
/// It is the backgrond image of the map /// It is the backgrond image of the map
@ -34,7 +37,8 @@ namespace Models.Game
/// </summary> /// </summary>
[DataMember] [DataMember]
public ReadOnlyObservableCollection<OperationCell> OperationGrid { get; private set; } public ReadOnlyObservableCollection<OperationCell> OperationGrid { get; private set; }
ObservableCollection<OperationCell> operationGrid = new ObservableCollection<OperationCell>();
private readonly ObservableCollection<OperationCell> _operationGrid = new ObservableCollection<OperationCell>();
/// <summary> /// <summary>
/// It is a list of a list containing user's rope paths in the current game /// It is a list of a list containing user's rope paths in the current game
@ -51,19 +55,35 @@ namespace Models.Game
/// <summary> /// <summary>
/// Initializes a new instance of the Map class. /// Initializes a new instance of the Map class.
/// </summary> /// </summary>
/// <param name="name"></param>
/// <param name="background">The background of the map.</param> /// <param name="background">The background of the map.</param>
public Map(string name, string background) public Map(string name, string background)
{ {
Name = name; Name = name;
Background = background; Background = background;
Boards = new ReadOnlyObservableCollection<Cell>(board); Boards = new ReadOnlyObservableCollection<Cell>(_board);
InitializeBoards(board); InitializeBoards(_board);
OperationGrid = new ReadOnlyObservableCollection<OperationCell>(operationGrid); OperationGrid = new ReadOnlyObservableCollection<OperationCell>(_operationGrid);
InitializeOperationGrid(operationGrid); InitializeOperationGrid(_operationGrid);
RopePaths = new List<List<Cell>>(); RopePaths = new List<List<Cell>>();
Zones = new List<List<Cell>>(); Zones = new List<List<Cell>>();
} }
/// <summary>
/// SQLite constructor
/// </summary>
public Map() { }
/// <summary>
/// Clone the map to avoid reference problems.
/// </summary>
/// <returns></returns>
public Map Clone()
{
Map map = new Map(Name, Background);
return map;
}
/// <summary> /// <summary>
/// Initializes the boards of the map. /// Initializes the boards of the map.
/// </summary> /// </summary>
@ -121,26 +141,12 @@ namespace Models.Game
public bool IsCellInZones(Cell cell) public bool IsCellInZones(Cell cell)
{ {
foreach (var zone in Zones) return Zones.Any(zone => zone.Contains(cell));
{
if (zone.Contains(cell))
{
return true;
}
}
return false;
} }
public bool IsCellInRopePath(Cell cell) public bool IsCellInRopePath(Cell cell)
{ {
foreach (var path in RopePaths) return RopePaths.Any(path => path.Contains(cell));
{
if (path.Contains(cell))
{
return true;
}
}
return false;
} }
} }
} }

@ -22,7 +22,7 @@ namespace Models.Game
if (isChecked == value) if (isChecked == value)
return; return;
isChecked = value; isChecked = value;
OnPropertyChanged("IsChecked"); OnPropertyChanged(nameof(IsChecked));
} }
} }

@ -1,5 +1,7 @@
using System.Collections.ObjectModel; using SQLite;
using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Models.Interfaces; using Models.Interfaces;
@ -10,12 +12,12 @@ namespace Models.Game
/// <summary> /// <summary>
/// Represents a player in the game. /// Represents a player in the game.
/// </summary> /// </summary>
[DataContract] [DataContract, SQLite.Table("Players")]
public class Player : INotifyPropertyChanged public class Player : INotifyPropertyChanged
{ {
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler? PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = null) void OnPropertyChanged([CallerMemberName] string? propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
@ -23,7 +25,7 @@ namespace Models.Game
/// It is he pseudo of the player. /// It is he pseudo of the player.
/// </summary> /// </summary>
private string _pseudo; private string _pseudo;
[DataMember] [DataMember, PrimaryKey]
public string Pseudo public string Pseudo
{ {
get => _pseudo; get => _pseudo;
@ -61,14 +63,16 @@ namespace Models.Game
/// <param name="profilePicture">The profile picture of the player.</param> /// <param name="profilePicture">The profile picture of the player.</param>
public Player(string pseudo, string profilePicture) public Player(string pseudo, string profilePicture)
{ {
//char[] trim = { ' ', '\n', '\t' };
//Pseudo = pseudo.Trim();
//Pseudo = Pseudo.TrimEnd(trim);
Pseudo = pseudo; Pseudo = pseudo;
ProfilePicture = profilePicture; ProfilePicture = profilePicture;
CreationDate = DateTime.Now.ToString("dd/MM/yyyy"); CreationDate = DateTime.Now.ToString("dd/MM/yyyy");
} }
/// <summary>
/// SQLite constructor
/// </summary>
public Player() { }
/// <summary> /// <summary>
/// Redefine the equal operation between player. /// Redefine the equal operation between player.
/// </summary> /// </summary>

@ -1,12 +1,12 @@
using Models.Game; using System.Collections.ObjectModel;
using System.Collections.ObjectModel;
namespace Models.Interfaces namespace Models.Interfaces
{ {
using Models.Game;
public interface IPersistence public interface IPersistence
{ {
(ObservableCollection<Player>, ObservableCollection<Game.Game>, ObservableCollection<Map>, ObservableCollection<BestScore>) LoadData(); (ObservableCollection<Player>, ObservableCollection<Game>, ObservableCollection<Map>, ObservableCollection<BestScore>) LoadData();
void SaveData(ObservableCollection<Player> players, ObservableCollection<Game.Game> games, ObservableCollection<Map> maps, ObservableCollection<BestScore> bestScores); void SaveData(ObservableCollection<Player> players, ObservableCollection<Game> games, ObservableCollection<Map> maps, ObservableCollection<BestScore> bestScores);
} }
} }

@ -14,6 +14,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls.Core" Version="8.0.3" /> <PackageReference Include="Microsoft.Maui.Controls.Core" Version="8.0.3" />
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -25,6 +25,8 @@ namespace Models.Rules
{ {
if (!IsCellEmpty(playerChoicePosition)) return false; if (!IsCellEmpty(playerChoicePosition)) return false;
if (!playerChoicePosition.Valid) return false;
if (EveryAdjacentCells(playerChoicePosition, cells).Count == 1) return false; if (EveryAdjacentCells(playerChoicePosition, cells).Count == 1) return false;
return true; return true;
@ -42,16 +44,14 @@ namespace Models.Rules
} }
public bool IsInRopePaths (Cell adjacente,List<List<Cell>> ropePaths,int index) public bool IsInRopePaths (Cell adjacente,List<List<Cell>> ropePaths, int index)
{ {
foreach (List<Cell> path in ropePaths) foreach (List<Cell> path in ropePaths)
{ {
if (path.Contains(adjacente)) if (!path.Contains(adjacente)) continue;
{
index=ropePaths.IndexOf(path); index=ropePaths.IndexOf(path);
return true; return true;
} }
}
return false; return false;
} }
@ -70,7 +70,7 @@ namespace Models.Rules
IEnumerable<Cell> PlayedCellsQuery = IEnumerable<Cell> PlayedCellsQuery =
from cell in cells from cell in cells
where cell.Valid == true where cell.Valid
select cell; select cell;
foreach (var cell in PlayedCellsQuery) foreach (var cell in PlayedCellsQuery)
@ -90,7 +90,7 @@ namespace Models.Rules
{ {
if (chosenCell == null ||chosenCell.Value == null) return; if (chosenCell == null ||chosenCell.Value == null) return;
List<Cell> adjacentCells = new List<Cell>(); List<Cell> adjacentCells;
adjacentCells = EveryAdjacentCells(chosenCell, map.Boards.ToList()); adjacentCells = EveryAdjacentCells(chosenCell, map.Boards.ToList());
@ -108,8 +108,6 @@ namespace Models.Rules
} }
} }
} }
return;
} }
public bool IsValueInZones(Cell chosenCell, List<List<Cell>> zones) public bool IsValueInZones(Cell chosenCell, List<List<Cell>> zones)
@ -154,7 +152,6 @@ namespace Models.Rules
return; return;
} }
} }
return;
} }
public void NewZoneIsCreated(Cell firstCell, Cell secondCell, Map map) public void NewZoneIsCreated(Cell firstCell, Cell secondCell, Map map)
@ -166,7 +163,7 @@ namespace Models.Rules
map.Zones.Add(newZone); map.Zones.Add(newZone);
} }
public List<Cell> EveryAdjacentCells(Cell choosenCell, List<Cell> cells) public List<Cell> EveryAdjacentCells(Cell? choosenCell, List<Cell> cells)
{ {
List<Cell> adjacentCells = new List<Cell>(); List<Cell> adjacentCells = new List<Cell>();

@ -69,5 +69,67 @@ namespace Tests
Assert.Equal(15, 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());
}
} }
} }

@ -135,25 +135,6 @@ public class GameTests
Assert.Equal(player, _game.CurrentPlayer); Assert.Equal(player, _game.CurrentPlayer);
} }
[Fact]
public void InitializeGame_ShouldInitializeGameAndTriggerEventWhenStarted()
{
var player = new Player("test_player", "DefaultProfilePicture");
var map = new Map("test_name", "test_background.png");
bool eventTriggered = false;
_game.GameEnded += (sender, args) =>
{
eventTriggered = true;
};
_game.InitializeGame(map, player, true);
Assert.True(eventTriggered);
Assert.False(_game.IsRunning);
Assert.Equal(map, _game.UsedMap);
Assert.Equal(player, _game.CurrentPlayer);
}
[Theory] [Theory]
[InlineData(Operation.ADDITION, 3, 4, 7)] [InlineData(Operation.ADDITION, 3, 4, 7)]
[InlineData(Operation.SUBTRACTION, 6, 4, 2)] [InlineData(Operation.SUBTRACTION, 6, 4, 2)]
@ -191,7 +172,7 @@ public class GameTests
var player = new Player("test_player", "DefaultProfilePicture"); var player = new Player("test_player", "DefaultProfilePicture");
var map = new Map("test_name", "test_background.png"); var map = new Map("test_name", "test_background.png");
_game.InitializeGame(map, player); _game.InitializeGame(map, player, false);
Assert.Equal(map, _game.UsedMap); Assert.Equal(map, _game.UsedMap);
} }
@ -202,7 +183,7 @@ public class GameTests
var player = new Player("test_player", "DefaultProfilePicture"); var player = new Player("test_player", "DefaultProfilePicture");
var map = new Map("test_name", "test_background.png"); var map = new Map("test_name", "test_background.png");
_game.InitializeGame(map, player); _game.InitializeGame(map, player, false);
Assert.Equal(player, _game.CurrentPlayer); Assert.Equal(player, _game.CurrentPlayer);
} }
@ -213,7 +194,7 @@ public class GameTests
Player player = new Player("test_player", "DefaultProfilePicture"); Player player = new Player("test_player", "DefaultProfilePicture");
Map map = new Map("test_name", "test_background.png"); Map map = new Map("test_name", "test_background.png");
_game.InitializeGame(map, player); _game.InitializeGame(map, player, false);
Assert.NotNull(_game.Dice1); Assert.NotNull(_game.Dice1);
Assert.NotNull(_game.Dice2); Assert.NotNull(_game.Dice2);
@ -233,7 +214,7 @@ public class GameTests
var player = new Player("test_player", "DefaultProfilePicture"); var player = new Player("test_player", "DefaultProfilePicture");
var map = new Map("test_name", "test_background.png"); var map = new Map("test_name", "test_background.png");
_game.InitializeGame(map, player); _game.InitializeGame(map, player, false);
// Use of reflection to call private method // Use of reflection to call private method
var methodInfo = typeof(Game).GetMethod("MarkOperationAsChecked", BindingFlags.NonPublic | BindingFlags.Instance); var methodInfo = typeof(Game).GetMethod("MarkOperationAsChecked", BindingFlags.NonPublic | BindingFlags.Instance);
@ -266,17 +247,21 @@ public class GameTests
var player = new Player("test_player", "DefaultProfilePicture"); var player = new Player("test_player", "DefaultProfilePicture");
var map = new Map("test_name", "test_background.png"); var map = new Map("test_name", "test_background.png");
_game.InitializeGame(map, player); _game.InitializeGame(map, player, false);
Assert.NotNull(_game.GameRules); Assert.NotNull(_game.GameRules);
_game.UsedMap.Boards[0].Value = 1; _game.UsedMap.Boards[0].Value = 1;
_game.UsedMap.Boards[1].Value = 2; _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); var methodInfo = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance);
Assert.NotNull(methodInfo); Assert.NotNull(methodInfo);
var cell = new Cell(0, 2); _game.PlayerCell = new Cell(2, 0);
cell.Value = 3; _game.PlayerCell.Value = 3;
methodInfo.Invoke(_game, new object[] { cell, 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); Assert.Equal(3, _game.UsedMap.Boards[2].Value);
} }
@ -287,10 +272,13 @@ public class GameTests
var player = new Player("test_player", "DefaultProfilePicture"); var player = new Player("test_player", "DefaultProfilePicture");
var map = new Map("test_name", "test_background.png"); var map = new Map("test_name", "test_background.png");
_game.InitializeGame(map, player); _game.InitializeGame(map, player, false);
var cell = new Cell(0, 1); var cell = new Cell(1, 0);
cell.Valid = true;
_game.UsedMap.Boards[0].Valid = true;
_game.UsedMap.Boards[0].Value = 1; _game.UsedMap.Boards[0].Value = 1;
_game.UsedMap.Boards[1].Valid = true;
bool result = _game.HandlePlayerChoice(cell, 1); bool result = _game.HandlePlayerChoice(cell, 1);
Assert.True(result); Assert.True(result);
} }
@ -301,7 +289,7 @@ public class GameTests
var player = new Player("test_player", "DefaultProfilePicture"); var player = new Player("test_player", "DefaultProfilePicture");
var map = new Map("test_name", "test_background.png"); var map = new Map("test_name", "test_background.png");
_game.InitializeGame(map, player); _game.InitializeGame(map, player, false);
var cell = new Cell(0, 7); var cell = new Cell(0, 7);
cell.Value = 1; cell.Value = 1;
@ -315,7 +303,7 @@ public class GameTests
var player = new Player("test_player", "DefaultProfilePicture"); var player = new Player("test_player", "DefaultProfilePicture");
var map = new Map("test_name", "test_background.png"); var map = new Map("test_name", "test_background.png");
_game.InitializeGame(map, player); _game.InitializeGame(map, player, false);
var cell = new Cell(0, 0); var cell = new Cell(0, 0);
cell.Value = 1; cell.Value = 1;
@ -324,25 +312,6 @@ public class GameTests
Assert.False(result); Assert.False(result);
} }
[Fact]
public void ShouldTriggerEventWhenEnded()
{
var player = new Player("test_player", "DefaultProfilePicture");
var map = new Map("test_name", "test_background.png");
bool eventTriggered = false;
_game.GameEnded += (sender, args) =>
{
eventTriggered = true;
};
_game.InitializeGame(map, player, true);
Assert.True(eventTriggered);
Assert.False(_game.IsRunning);
Assert.Equal(map, _game.UsedMap);
Assert.Equal(player, _game.CurrentPlayer);
}
[Fact] [Fact]
public void RemovePlayerTest_ShouldRemovePlayer() public void RemovePlayerTest_ShouldRemovePlayer()
{ {
@ -366,15 +335,17 @@ public class GameTests
{ {
var player = new Player("test_player", "DefaultProfilePicture"); var player = new Player("test_player", "DefaultProfilePicture");
var map = new Map("test_name", "test_background.png"); var map = new Map("test_name", "test_background.png");
_game.InitializeGame(map, player); _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[1].Value = 5;
var methodInfo = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance); var methodInfo = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance);
Assert.NotNull(methodInfo); Assert.NotNull(methodInfo);
var cell = new Cell(0, 2); _game.PlayerCell = new Cell(2, 0);
cell.Value = 14; _game.PlayerCell.Value = 14;
methodInfo.Invoke(_game, new object[] { cell, 14 }); methodInfo.Invoke(_game, new object[] { _game.PlayerCell, 14 });
Assert.True(_game.UsedMap.Boards[2].Penalty); Assert.True(_game.UsedMap.Boards[2].Penalty);
} }
@ -384,16 +355,20 @@ public class GameTests
{ {
var player = new Player("test_player", "DefaultProfilePicture"); var player = new Player("test_player", "DefaultProfilePicture");
var map = new Map("test_name", "test_background.png"); var map = new Map("test_name", "test_background.png");
_game.InitializeGame(map, player); _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[1].Value = 5;
_game.UsedMap.Boards[2].IsDangerous = true; _game.UsedMap.Boards[2].IsDangerous = true;
var methodInfo = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance); var methodInfo = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance);
Assert.NotNull(methodInfo); Assert.NotNull(methodInfo);
var cell = new Cell(0, 2); _game.PlayerCell = new Cell(2, 0);
cell.Value = 7; _game.PlayerCell.Value = 7;
methodInfo.Invoke(_game, new object[] { cell, 7 }); methodInfo.Invoke(_game, new object[] { _game.PlayerCell, 7 });
Assert.True(_game.UsedMap.Boards[2].Penalty); Assert.True(_game.UsedMap.Boards[2].Penalty);
} }
@ -403,7 +378,7 @@ public class GameTests
{ {
var player = new Player("test_player", "DefaultProfilePicture"); var player = new Player("test_player", "DefaultProfilePicture");
var map = new Map("test_name", "test_background.png"); var map = new Map("test_name", "test_background.png");
_game.InitializeGame(map, player); _game.InitializeGame(map, player, false);
_game.UsedMap.Boards[0].Valid = true; _game.UsedMap.Boards[0].Valid = true;
_game.UsedMap.Boards[3].Valid = true; _game.UsedMap.Boards[3].Valid = true;
@ -431,7 +406,7 @@ public class GameTests
{ {
var player = new Player("test_player", "DefaultProfilePicture"); var player = new Player("test_player", "DefaultProfilePicture");
var map = new Map("test_name", "test_background.png"); var map = new Map("test_name", "test_background.png");
_game.InitializeGame(map, player); _game.InitializeGame(map, player, false);
_game.UsedMap.Boards[1].Value = 1; _game.UsedMap.Boards[1].Value = 1;
_game.UsedMap.Boards[2].Value = 2; _game.UsedMap.Boards[2].Value = 2;
@ -443,7 +418,7 @@ public class GameTests
foreach (var cells in _game.UsedMap.Boards.ToList()) foreach (var cells in _game.UsedMap.Boards.ToList())
{ {
methodInfo.Invoke(_game, new object[] { cells, _game.UsedMap.Boards.ToList() }); methodInfo.Invoke(_game, new object[] { cells });
} }
_game.PutPenaltyForLostCells(_game.UsedMap.Boards); _game.PutPenaltyForLostCells(_game.UsedMap.Boards);
@ -453,42 +428,114 @@ public class GameTests
} }
[Fact] [Fact]
public void CalculusOfPenalty_ReallyCalculusPenalty() public void CalculusOfPenalty_ReallyCalculusPenalty_ForZonesAndDangerousCellsAndOverTwelve()
{ {
var player = new Player("test_player", "DefaultProfilePicture"); var player = new Player("test_player", "DefaultProfilePicture");
var map = new Map("test_name", "test_background.png"); var map = new Map("test_name", "test_background.png");
_game.InitializeGame(map, player); _game.InitializeGame(map, player, false);
var methodInfo = typeof(Game).GetMethod("AddToRopePath", BindingFlags.NonPublic | BindingFlags.Instance);
Assert.NotNull(methodInfo);
_game.UsedMap.Boards[0].Valid = true; _game.UsedMap.Boards[7].Valid = true;
_game.UsedMap.Boards[1].Valid = true; _game.UsedMap.Boards[8].Valid = true;
_game.UsedMap.Boards[2].Valid = true; _game.UsedMap.Boards[9].Valid = true;
_game.UsedMap.Boards[3].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
_game.UsedMap.Boards[0].Value = 0; var place = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance);
methodInfo.Invoke(_game, new object[] { _game.UsedMap.Boards[0], _game.GameRules.EveryAdjacentCells(_game.UsedMap.Boards[0], _game.UsedMap.Boards.ToList()) }); Assert.NotNull(place);
_game.UsedMap.Boards[1].Value = 1;
methodInfo.Invoke(_game, new object[] { _game.UsedMap.Boards[1], _game.GameRules.EveryAdjacentCells(_game.UsedMap.Boards[1], _game.UsedMap.Boards.ToList()) }); _game.PlayerCell = new Cell(4, 1);
_game.UsedMap.Boards[2].Value = 2; _game.PlayerCell.Value = 7;
methodInfo.Invoke(_game, new object[] { _game.UsedMap.Boards[2], _game.GameRules.EveryAdjacentCells(_game.UsedMap.Boards[2], _game.UsedMap.Boards.ToList()) }); _game.PlayerCell.Valid = true;
_game.UsedMap.Boards[3].Value = 5; _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); _game.PutPenaltyForLostCells(_game.UsedMap.Boards);
Assert.True(_game.UsedMap.Boards[3].Penalty); Assert.True(_game.UsedMap.Boards[11].Penalty);
Assert.Equal(9, _game.CalculusOfPenalty(_game.UsedMap.Boards));
Assert.Equal(3, _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] [Fact]
public void CalculusOfPenalty_ReallyCalculusPenalty_ForZonesAndDangerousCellsAndOverTwelve() public void CanIModifyANonExistentPlayer()
{ {
var player = new Player("test_player", "DefaultProfilePicture"); Game game = new Game();
var map = new Map("test_name", "test_background.png"); var res = game.ModifyPlayer("nope", "newName");
_game.InitializeGame(map, player); 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[7].Valid = true;
_game.UsedMap.Boards[8].Valid = true; _game.UsedMap.Boards[8].Valid = true;
@ -497,24 +544,20 @@ public class GameTests
_game.UsedMap.Boards[11].Valid = true; _game.UsedMap.Boards[11].Valid = true;
_game.UsedMap.Boards[12].Valid = true; _game.UsedMap.Boards[12].Valid = true;
_game.UsedMap.Boards[10].Value = 2; // 1,3 // penalty _game.UsedMap.Boards[10].Value = 2; // penalty (- 3)
_game.UsedMap.Boards[7].Value = 5; // 1,0 _game.UsedMap.Boards[7].Value = 5; //5 + 2 = 7
_game.UsedMap.Boards[8].Value = 5; // 1,1 _game.UsedMap.Boards[8].Value = 5;
_game.UsedMap.Boards[9].Value = 5; // 1,2 _game.UsedMap.Boards[9].Value = 5;
var place = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance); var place = typeof(Game).GetMethod("PlaceResult", BindingFlags.NonPublic | BindingFlags.Instance);
Assert.NotNull(place); Assert.NotNull(place);
var cell = new Cell(1, 4); _game.PlayerCell = new Cell(4, 1);
cell.Value = 7; _game.PlayerCell.Value = 7;
cell.Valid = true; _game.PlayerCell.Valid = true;
cell.IsDangerous = true; _game.PlayerCell.IsDangerous = true;
place.Invoke(_game, new object[] { cell, 7 }); //One penalty place.Invoke(_game, new object[] { _game.PlayerCell, 7 }); //One penalty
var othercell = new Cell(1, 5);
cell.Value = 14;
cell.Valid = true;
place.Invoke(_game, new object[] { othercell, 14 });
foreach (var cells in _game.UsedMap.Boards.ToList()) foreach (var cells in _game.UsedMap.Boards.ToList())
@ -525,7 +568,127 @@ public class GameTests
_game.PutPenaltyForLostCells(_game.UsedMap.Boards); _game.PutPenaltyForLostCells(_game.UsedMap.Boards);
Assert.True(_game.UsedMap.Boards[11].Penalty); Assert.True(_game.UsedMap.Boards[11].Penalty);
Assert.Equal(9, _game.CalculusOfPenalty(_game.UsedMap.Boards));
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");
}
} }

@ -27,7 +27,7 @@ public class MapTests
Assert.Equal(49, map.Boards.Count); Assert.Equal(49, map.Boards.Count);
for (int i = 0; i < 36; i++) for (int i = 0; i < 36; i++)
{ {
Assert.Equal(new Cell(i / 7, i % 7), map.Boards[i]); Assert.Equal(new Cell(i % 7, i / 7), map.Boards[i]);
} }
} }
@ -92,6 +92,17 @@ public class MapTests
var paths = new List<Cell> { cell }; var paths = new List<Cell> { cell };
map.RopePaths.Add(paths); map.RopePaths.Add(paths);
Assert.False(map.IsCellInRopePath(othercell)); 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);
} }
} }

@ -11,6 +11,7 @@ public class PlayerTests
var player = new Player(pseudo, profilePicture); var player = new Player(pseudo, profilePicture);
Assert.Equal(pseudo, player.Pseudo); Assert.Equal(pseudo, player.Pseudo);
Assert.Equal(profilePicture, player.ProfilePicture); Assert.Equal(profilePicture, player.ProfilePicture);
Assert.Null(player.LastPlayed);
} }
[Theory] [Theory]
@ -46,4 +47,15 @@ public class PlayerTests
Player player = new Player("test_pseudo", "DefaultProfilePicture"); Player player = new Player("test_pseudo", "DefaultProfilePicture");
Assert.False(player.Equals(new Cell(0, 0))); 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);
}
} }

@ -44,6 +44,7 @@ public class RulesTests
{ {
Rules rules = new Rules(); Rules rules = new Rules();
Map map = new Map("test", "background"); Map map = new Map("test", "background");
map.Boards[0].Valid = true;
Cell selectedCell = map.Boards[0]; Cell selectedCell = map.Boards[0];
Assert.True(rules.IsCellValid(selectedCell, map.Boards.ToList())); Assert.True(rules.IsCellValid(selectedCell, map.Boards.ToList()));
} }
@ -179,6 +180,7 @@ public class RulesTests
Cell cell1 = new Cell(0, 0); Cell cell1 = new Cell(0, 0);
Cell cell2 = new Cell(0, 1); Cell cell2 = new Cell(0, 1);
cell2.Value = 12; cell2.Value = 12;
cell2.Valid = true;
List<Cell> cells = new List<Cell> { cell2 }; List<Cell> cells = new List<Cell> { cell2 };
Assert.True(rules.NearCellIsValid(cell1, cells)); Assert.True(rules.NearCellIsValid(cell1, cells));
} }

@ -5,15 +5,15 @@ VisualStudioVersion = 17.8.34408.163
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Trek-12", "Trek-12\Trek-12.csproj", "{41EE7BF8-DDE6-4B00-9434-076589C0B419}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Trek-12", "Trek-12\Trek-12.csproj", "{41EE7BF8-DDE6-4B00-9434-076589C0B419}"
EndProject 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 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 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 EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataContractPersistence", "DataContractPersistence\DataContractPersistence.csproj", "{FC6A23C3-A1E3-4BF4-85B0-404D8574E190}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataContractPersistence", "DataContractPersistence\DataContractPersistence.csproj", "{FC6A23C3-A1E3-4BF4-85B0-404D8574E190}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stub", "Stub\Stub.csproj", "{49360F7D-C59D-4B4F-AF5A-73FF61D9EF9B}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stub", "Stub\Stub.csproj", "{49360F7D-C59D-4B4F-AF5A-73FF61D9EF9B}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution

@ -29,7 +29,7 @@ namespace Trek_12
Directory.CreateDirectory(FilePath); Directory.CreateDirectory(FilePath);
} }
File.Delete(Path.Combine(FilePath, FileName)); //File.Delete(Path.Combine(FilePath, FileName));
string fullPath = Path.Combine(FilePath, FileName); string fullPath = Path.Combine(FilePath, FileName);
if (File.Exists(fullPath)) if (File.Exists(fullPath))
@ -40,9 +40,9 @@ namespace Trek_12
/* Add the permanent maps if they are not already in the game */ /* Add the permanent maps if they are not already in the game */
if (Manager.Maps.Count == 0) if (Manager.Maps.Count == 0)
{ {
Manager.AddMap(new Map("Dunai","profile.jpg")); Manager.AddMap(new Map("Dunai","montagne2.png"));
Manager.AddMap(new Map("Kagkot","montagne1.png")); Manager.AddMap(new Map("Kagkot", "montagne3.png"));
Manager.AddMap(new Map("Dhaulagiri","tmp1.jpeg")); Manager.AddMap(new Map("Dhaulagiri", "montagne4.png"));
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 978 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 972 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks> <TargetFrameworks>net8.0-android;net8.0-ios;net8.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks> <!--<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>-->
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET --> <!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
<!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> --> <!-- <TargetFrameworks>$(TargetFrameworks);net8.0-tizen</TargetFrameworks> -->
@ -38,6 +38,14 @@
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion> <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('windows'))">
<TargetFrameworks>$(TargetFrameworks);net8.0-windows10.0.19041.0</TargetFrameworks>
<WindowsPackageType>MSIX</WindowsPackageType>
<PackageCertificateThumbprint>404032fa5d4dc4c8bbf036505d2409963f355ebd</PackageCertificateThumbprint>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<!-- App Icon --> <!-- App Icon -->
<MauiIcon Include="Resources\AppIcon\app_icon.png" /> <MauiIcon Include="Resources\AppIcon\app_icon.png" />
@ -47,7 +55,6 @@
<!-- Images --> <!-- Images -->
<MauiImage Include="Resources\Images\*" /> <MauiImage Include="Resources\Images\*" />
<MauiImage Update="Resources\Images\dotnet_bot.png" Resize="True" BaseSize="300,185" />
<!-- Custom Fonts --> <!-- Custom Fonts -->
<MauiFont Include="Resources\Fonts\*" /> <MauiFont Include="Resources\Fonts\*" />
@ -61,6 +68,9 @@
<None Remove="Resources\Images\back_arrow.png" /> <None Remove="Resources\Images\back_arrow.png" />
<None Remove="Resources\Images\checked.png" /> <None Remove="Resources\Images\checked.png" />
<None Remove="Resources\Images\maptest.png" /> <None Remove="Resources\Images\maptest.png" />
<None Remove="Resources\Images\montagne2.png" />
<None Remove="Resources\Images\montagne3.png" />
<None Remove="Resources\Images\montagne4.png" />
<None Remove="Resources\Images\user.png" /> <None Remove="Resources\Images\user.png" />
</ItemGroup> </ItemGroup>

@ -1,5 +1,6 @@
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using Microsoft.VisualBasic;
namespace Trek_12.Views; namespace Trek_12.Views;
@ -10,7 +11,7 @@ public partial class PageBoard : ContentPage
{ {
public Game GameManager => (App.Current as App).Manager; public Game GameManager => (App.Current as App).Manager;
public int Resultat { get; set; } public int Result { get; set; }
public Cell ChoosenCell { get; set; } public Cell ChoosenCell { get; set; }
@ -18,6 +19,7 @@ public partial class PageBoard : ContentPage
{ {
InitializeComponent(); InitializeComponent();
BindingContext = GameManager; BindingContext = GameManager;
GameManager.CurrentPlayer.UpdateLastPlayed();
GameManager.DiceRolled += TheGame_DiceRolled; GameManager.DiceRolled += TheGame_DiceRolled;
GameManager.DiceRolled += ResultAddition; GameManager.DiceRolled += ResultAddition;
@ -26,13 +28,46 @@ public partial class PageBoard : ContentPage
GameManager.DiceRolled += ResultSubstraction; GameManager.DiceRolled += ResultSubstraction;
GameManager.DiceRolled += ResultMultiplication; GameManager.DiceRolled += ResultMultiplication;
GameManager.PlayerOption += GameManager_PlayerOption; GameManager.PlayerOption += GameManager_PlayerOption;
GameManager.CellChosen += HandleCellChosen;
// We add this game to the list of games
GameManager.AddGame(GameManager); GameManager.AddGame(GameManager);
GameManager.OnPropertyChanged(nameof(GameManager.Games)); GameManager.OnPropertyChanged(nameof(GameManager.Games));
GameManager.SaveData(); GameManager.SaveData();
} }
private void HandleCellChosen(object sender, CellChosenEventArgs e)
{
YellowDice.IsVisible = false;
RedDice.IsVisible = false;
RollButton.IsEnabled = true;
}
private void ResetOperationButtonsAndDice()
{
Lower.IsVisible = false;
Higher.IsVisible = false;
Substraction.IsVisible = false;
Addition.IsVisible = false;
Multiplication.IsVisible = false;
RollButton.IsEnabled = true;
YellowDice.IsVisible = false;
RedDice.IsVisible = false;
}
private void SetOperationButtonState(Button selectedButton)
{
// Deselect all buttons
Lower.BackgroundColor = Colors.DarkSalmon;
Higher.BackgroundColor = Colors.DarkSalmon;
Substraction.BackgroundColor = Colors.DarkSalmon;
Addition.BackgroundColor = Colors.DarkSalmon;
Multiplication.BackgroundColor = Colors.DarkSalmon;
// Select the clicked button
selectedButton.BackgroundColor = Colors.LightCoral;
}
private void GameManager_PlayerOption(object? sender, PlayerOptionEventArgs e) private void GameManager_PlayerOption(object? sender, PlayerOptionEventArgs e)
{ {
/* IEnumerable<Cell> PlayedCellsQuery = /* IEnumerable<Cell> PlayedCellsQuery =
@ -92,8 +127,7 @@ public partial class PageBoard : ContentPage
private void OnOperationCellSelected(object sender, SelectionChangedEventArgs e) private void OnOperationCellSelected(object sender, SelectionChangedEventArgs e)
{ {
Debug.WriteLine("OnOperationCellSelected"); // Debug if (e.CurrentSelection.Count > 0) // Si un élément est sélectionné
if (e.CurrentSelection.Count > 0) // Si un <20>l<EFBFBD>ment est s<>lectionn<6E>
{ {
var selectedCell = (OperationCell)e.CurrentSelection[0]; var selectedCell = (OperationCell)e.CurrentSelection[0];
if (selectedCell != null && !selectedCell.IsChecked) if (selectedCell != null && !selectedCell.IsChecked)
@ -101,38 +135,48 @@ public partial class PageBoard : ContentPage
selectedCell.Check(); selectedCell.Check();
Debug.WriteLine("OperationCell at ({0}, {1}) is checked", selectedCell.X, selectedCell.Y); // Debug Debug.WriteLine("OperationCell at ({0}, {1}) is checked", selectedCell.X, selectedCell.Y); // Debug
} }
((CollectionView)sender).SelectedItem = null; // D<EFBFBD>selectionne l'<27>l<EFBFBD>ment pour la CollectionView ((CollectionView)sender).SelectedItem = null; // Déselectionne l'élément pour la CollectionView
} }
} }
private void HigherClicked(object sender, EventArgs e) private void HigherClicked(object sender, EventArgs e)
{ {
GameManager.PlayerOperation = Operation.HIGHER; GameManager.PlayerOperation = Operation.HIGHER;
Resultat = GameManager.PlayerChooseOperation(); SetOperationButtonState((Button)sender);
Result = GameManager.ResultOperation(Operation.HIGHER);
GameManager.HandlePlayerOperation(Operation.HIGHER);
} }
private void LowerClicked(object sender, EventArgs e) private void LowerClicked(object sender, EventArgs e)
{ {
GameManager.PlayerOperation = Operation.LOWER; GameManager.PlayerOperation = Operation.LOWER;
Resultat = GameManager.PlayerChooseOperation(); SetOperationButtonState((Button)sender);
Result = GameManager.ResultOperation(Operation.LOWER);
GameManager.HandlePlayerOperation(Operation.LOWER);
} }
private void AdditionClicked(object sender, EventArgs e) private void AdditionClicked(object sender, EventArgs e)
{ {
GameManager.PlayerOperation = Operation.ADDITION; GameManager.PlayerOperation = Operation.ADDITION;
Resultat = GameManager.PlayerChooseOperation(); SetOperationButtonState((Button)sender);
Result = GameManager.ResultOperation(Operation.ADDITION);
GameManager.HandlePlayerOperation(Operation.ADDITION);
} }
private void SubstractionClicked(object sender, EventArgs e) private void SubstractionClicked(object sender, EventArgs e)
{ {
GameManager.PlayerOperation = Operation.SUBTRACTION; GameManager.PlayerOperation = Operation.SUBTRACTION;
Resultat = GameManager.PlayerChooseOperation(); SetOperationButtonState((Button)sender);
Result = GameManager.ResultOperation(Operation.SUBTRACTION);
GameManager.HandlePlayerOperation(Operation.SUBTRACTION);
} }
private void MultiplicationClicked(object sender, EventArgs e) private void MultiplicationClicked(object sender, EventArgs e)
{ {
GameManager.PlayerOperation = Operation.MULTIPLICATION; GameManager.PlayerOperation = Operation.MULTIPLICATION;
Resultat = GameManager.PlayerChooseOperation(); SetOperationButtonState((Button)sender);
Result = GameManager.ResultOperation(Operation.MULTIPLICATION);
GameManager.HandlePlayerOperation(Operation.MULTIPLICATION);
} }
private void DiceButton_Clicked(object sender, EventArgs e) private void DiceButton_Clicked(object sender, EventArgs e)
@ -140,10 +184,33 @@ public partial class PageBoard : ContentPage
GameManager.RollAllDice(); GameManager.RollAllDice();
} }
private void OnCellSelected(object sender, SelectionChangedEventArgs e) private async void OnCellSelected(object sender, SelectionChangedEventArgs e)
{
if (!GameManager.DiceRolledFlag)
{
await DisplayAlert("Action Required", "You must roll the dice first.", "OK");
return;
}
if (!GameManager.OperationChosenFlag)
{
await DisplayAlert("Action Required", "You must choose an operation first.", "OK");
return;
}
if (e.CurrentSelection.Count > 0)
{ {
ChoosenCell = (Cell)e.CurrentSelection[0]; ChoosenCell = (Cell)e.CurrentSelection[0];
GameManager.PlayerCell = ChoosenCell; GameManager.PlayerCell = ChoosenCell;
GameManager.Resultat = Result;
OnPropertyChanged(nameof(GameManager.PlayerCell));
OnPropertyChanged(nameof(GameManager.Resultat));
GameManager.PlayerSelectionCell(); GameManager.PlayerSelectionCell();
((CollectionView)sender).SelectedItem = null;
ResetOperationButtonsAndDice();
}
} }
} }

@ -42,6 +42,16 @@
</DataTemplate> </DataTemplate>
</CollectionView.ItemTemplate> </CollectionView.ItemTemplate>
</CollectionView> </CollectionView>
<Button Text="Reprendre"
TextColor="White"
BackgroundColor="DarkRed"
FontAttributes="Bold"
FontSize="Large"
Grid.Row="2"
Margin="80"
HorizontalOptions="Center"
Clicked="ResumeButton_Clicked"
IsVisible="{Binding IsPreviousGameNotFinished}"/>
<Button Text="Retour" <Button Text="Retour"
FontAttributes="Bold" FontAttributes="Bold"
FontSize="Large" FontSize="Large"

@ -10,12 +10,14 @@ public partial class PageSelectMap : ContentPage
public Game SelectMapManager => (App.Current as App).Manager; public Game SelectMapManager => (App.Current as App).Manager;
private Map? _selectedMap; private Map? _selectedMap;
private bool isVisibleContinueButton = false;
protected override async void OnAppearing() protected override async void OnAppearing()
{ {
base.OnAppearing(); base.OnAppearing();
if (SelectMapManager.Games.Any(g => g.IsRunning)) if (SelectMapManager.Games.Any(g => g.IsRunning))
{ {
isVisibleContinueButton = true;
await DisplayAlert("Warning", "You've previously quit in the middle of a game.\nIf you start a new game, this one will be permanently lost.", "I understand"); await DisplayAlert("Warning", "You've previously quit in the middle of a game.\nIf you start a new game, this one will be permanently lost.", "I understand");
} }
@ -57,9 +59,26 @@ public partial class PageSelectMap : ContentPage
Player chosenPlayer = GetProfileByName(choosenPlayerName); Player chosenPlayer = GetProfileByName(choosenPlayerName);
SelectMapManager.InitializeGame(_selectedMap, chosenPlayer); var runningGames = SelectMapManager.Games.Where(g => g.IsRunning).ToList();
bool delete = false;
foreach (var game in runningGames)
{
SelectMapManager.Games.Remove(game);
delete = true;
}
if (delete)
{
await DisplayAlert("Game deleted", "The previous game has been deleted because you started a new one.", "OK");
SelectMapManager.OnPropertyChanged(nameof(SelectMapManager.Games));
SelectMapManager.SaveData();
}
if (SelectMapManager.UsedMap == _selectedMap && Equals(SelectMapManager.CurrentPlayer, chosenPlayer)) SelectMapManager.InitializeGame(_selectedMap.Clone(), chosenPlayer);
if (SelectMapManager.UsedMap != null && Equals(SelectMapManager.CurrentPlayer, chosenPlayer))
{ {
await Shell.Current.GoToAsync(nameof(PageBoard)); await Shell.Current.GoToAsync(nameof(PageBoard));
} }
@ -79,4 +98,17 @@ public partial class PageSelectMap : ContentPage
return SelectMapManager.Players.FirstOrDefault(p => p.Pseudo == pseudo); return SelectMapManager.Players.FirstOrDefault(p => p.Pseudo == pseudo);
} }
private async void ResumeButton_Clicked(object sender, EventArgs e)
{
Game game = SelectMapManager.Games.FirstOrDefault(g => g.IsRunning);
if (game == null)
{
await DisplayAlert("No game found", "No game found to resume. Please start a new game.", "OK");
return;
}
SelectMapManager.InitializeGame(game.UsedMap, game.CurrentPlayer, false);
await Shell.Current.GoToAsync(nameof(PageBoard));
}
} }
Loading…
Cancel
Save