v0.8 - Application Console
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/tag Build is passing Details

Reviewed-on: #67
pull/90/head v0.8
Rémi LAVERGNE 11 months ago
commit e4e14adf45

@ -0,0 +1,71 @@
kind: pipeline
type: docker
name: CI
trigger:
when:
branch:
- master
- dev
- CI/CD
event:
- push
steps:
- name: build-Models
image: mcr.microsoft.com/dotnet/sdk:8.0
commands:
- cd source/Trek-12/Models
- dotnet restore
- dotnet build -c Release --no-restore
- dotnet publish -c Release --no-restore -o $CI_PROJECT_DIR/build/release
- name: build-ConsoleApp
image: mcr.microsoft.com/dotnet/sdk:8.0
commands:
- cd source/Trek-12/ConsoleApp
- dotnet restore
- dotnet build -c Release --no-restore
- dotnet publish -c Release --no-restore -o $CI_PROJECT_DIR/build/release
depends_on: [build-Models]
- name: tests
image: mcr.microsoft.com/dotnet/sdk:8.0
commands:
- cd source/Trek-12
- dotnet restore CI-Trek-12.sln
- dotnet test CI-Trek-12.sln --no-restore
depends_on: [build-Models]
- name: code-analysis
image: hub.codefirst.iut.uca.fr/marc.chevaldonne/codefirst-dronesonarplugin-dotnet8
secrets: [ SECRET_SONAR_LOGIN ]
settings:
# accessible en ligne de commande par ${PLUGIN_SONAR_HOST}
sonar_host: https://codefirst.iut.uca.fr/sonar/
# accessible en ligne de commande par ${PLUGIN_SONAR_TOKEN}
sonar_token:
from_secret: SECRET_SONAR_LOGIN
commands:
- cd source/Trek-12
- dotnet restore CI-Trek-12.sln
- dotnet sonarscanner begin /k:"Trek-12" /d:sonar.host.url=$${PLUGIN_SONAR_HOST} /d:sonar.coverageReportPaths="coveragereport/SonarQube.xml" /d:sonar.coverage.exclusions="Tests/**" /d:sonar.login=$${PLUGIN_SONAR_TOKEN}
- dotnet build CI-Trek-12.sln -c Release --no-restore
- dotnet test CI-Trek-12.sln --logger trx --no-restore /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura --collect "XPlat Code Coverage"
- reportgenerator -reports:"**/coverage.cobertura.xml" -reporttypes:SonarQube -targetdir:"coveragereport"
- dotnet publish CI-Trek-12.sln -c Release --no-restore -o $CI_PROJECT_DIR/build/release
- dotnet sonarscanner end /d:sonar.login=$${PLUGIN_SONAR_TOKEN}
depends_on: [tests]
- name: generate-and-deploy-docs
image: hub.codefirst.iut.uca.fr/maxime.batista/codefirst-docdeployer:latest
failure: ignore
commands:
- /entrypoint.sh -l documentation/doxygen -t doxygen
when:
branch:
- master
- dev
event:
- push
depends_on: [ tests ]

@ -1,5 +1,21 @@
![Static Badge](https://img.shields.io/badge/Trek12-En_Production-red)
<details>
<summary>Sonarcube Ratings</summary>
[![Maintainability Rating](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=Trek-12&metric=sqale_rating&token=7584294f89189be7a1ed771405ce4114938dca12)](https://codefirst.iut.uca.fr/sonar/dashboard?id=Trek-12)
[![Reliability Rating](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=Trek-12&metric=reliability_rating&token=7584294f89189be7a1ed771405ce4114938dca12)](https://codefirst.iut.uca.fr/sonar/dashboard?id=Trek-12)
[![Security Rating](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=Trek-12&metric=security_rating&token=7584294f89189be7a1ed771405ce4114938dca12)](https://codefirst.iut.uca.fr/sonar/dashboard?id=Trek-12)
</details>
[![Build Status](https://codefirst.iut.uca.fr/api/badges/remi.lavergne/Trek-12/status.svg)](https://codefirst.iut.uca.fr/remi.lavergne/Trek-12)
[![Quality Gate Status](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=Trek-12&metric=alert_status&token=7584294f89189be7a1ed771405ce4114938dca12)](https://codefirst.iut.uca.fr/sonar/dashboard?id=Trek-12)
[![Bugs](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=Trek-12&metric=bugs&token=7584294f89189be7a1ed771405ce4114938dca12)](https://codefirst.iut.uca.fr/sonar/dashboard?id=Trek-12)
[![Coverage](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=Trek-12&metric=coverage&token=7584294f89189be7a1ed771405ce4114938dca12)](https://codefirst.iut.uca.fr/sonar/dashboard?id=Trek-12)
[![Vulnerabilities](https://codefirst.iut.uca.fr/sonar/api/project_badges/measure?project=Trek-12&metric=vulnerabilities&token=7584294f89189be7a1ed771405ce4114938dca12)](https://codefirst.iut.uca.fr/sonar/dashboard?id=Trek-12)
<img src="trek12.png" alt="Trek12" width="40%" style="align: center; display: block; margin: 20px auto;">
<br>

@ -0,0 +1,428 @@
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "Trek 12"
PROJECT_NUMBER = 1.0.0
PROJECT_BRIEF = "Application de jeu plateau en roll & write sur le framework .NET MAUI avec XAML et C#"
PROJECT_LOGO = /trek12.png
OUTPUT_DIRECTORY = /documentation/doxygen
CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = French
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
JAVADOC_BANNER = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
PYTHON_DOCSTRING = YES
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
ALIASES =
OPTIMIZE_OUTPUT_FOR_C = NO
# Well... the one for Java looks so similar to the one for C#...
OPTIMIZE_OUTPUT_JAVA = YES
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
OPTIMIZE_OUTPUT_SLICE = NO
EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 5
AUTOLINK_SUPPORT = YES
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
GROUP_NESTED_COMPOUNDS = NO
SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
NUM_PROC_THREADS = 1
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = YES
# I do not like other members to see my private members... but you can set it to YES if you prefer.
EXTRACT_PRIVATE = NO
EXTRACT_PRIV_VIRTUAL = NO
EXTRACT_PACKAGE = NO
EXTRACT_STATIC = YES
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
RESOLVE_UNNAMED_PARAMS = YES
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = NO
HIDE_SCOPE_NAMES = NO
HIDE_COMPOUND_REFERENCE= NO
SHOW_HEADERFILE = YES
SHOW_INCLUDE_FILES = YES
SHOW_GROUPED_MEMB_INC = NO
FORCE_LOCAL_INCLUDES = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = NO
SORT_BRIEF_DOCS = NO
SORT_MEMBERS_CTORS_1ST = NO
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_FILES = YES
SHOW_NAMESPACES = YES
FILE_VERSION_FILTER =
LAYOUT_FILE =
CITE_BIB_FILES =
#---------------------------------------------------------------------------
# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_IF_INCOMPLETE_DOC = YES
WARN_NO_PARAMDOC = NO
WARN_AS_ERROR = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = source
INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.idl \
*.ddl \
*.odl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.l \
*.cs \
*.d \
*.php \
*.php4 \
*.php5 \
*.phtml \
*.inc \
*.m \
*.markdown \
*.md \
*.mm \
*.dox \
*.py \
*.pyw \
*.f90 \
*.f95 \
*.f03 \
*.f08 \
*.f18 \
*.f \
*.for \
*.vhd \
*.vhdl \
*.ucf \
*.qsf \
*.ice
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS = */Tests/*
EXCLUDE_PATTERNS += */bin/*
EXCLUDE_PATTERNS += */obj/*
EXCLUDE_SYMBOLS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE =
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
REFERENCES_LINK_SOURCE = YES
SOURCE_TOOLTIPS = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
CLANG_ASSISTED_PARSING = NO
CLANG_ADD_INC_PATHS = YES
CLANG_OPTIONS =
CLANG_DATABASE_PATH =
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_STYLESHEET =
HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES = images/CodeFirst.png images/clubinfo.png
HTML_COLORSTYLE_HUE = 215
HTML_COLORSTYLE_SAT = 45
HTML_COLORSTYLE_GAMMA = 240
HTML_TIMESTAMP = NO
HTML_DYNAMIC_MENUS = YES
HTML_DYNAMIC_SECTIONS = NO
HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_FEEDURL =
DOCSET_BUNDLE_ID = org.doxygen.Project
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
DOCSET_PUBLISHER_NAME = Publisher
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
CHM_INDEX_ENCODING =
BINARY_TOC = NO
TOC_EXPAND = NO
GENERATE_QHP = NO
QCH_FILE =
QHP_NAMESPACE = org.doxygen.Project
QHP_VIRTUAL_FOLDER = doc
QHP_CUST_FILTER_NAME =
QHP_CUST_FILTER_ATTRS =
QHP_SECT_FILTER_ATTRS =
QHG_LOCATION =
GENERATE_ECLIPSEHELP = NO
ECLIPSE_DOC_ID = org.doxygen.Project
DISABLE_INDEX = NO
GENERATE_TREEVIEW = NO
FULL_SIDEBAR = NO
ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
OBFUSCATE_EMAILS = YES
HTML_FORMULA_FORMAT = png
FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
FORMULA_MACROFILE =
USE_MATHJAX = NO
MATHJAX_VERSION = MathJax_2
MATHJAX_FORMAT = HTML-CSS
MATHJAX_RELPATH =
MATHJAX_EXTENSIONS =
MATHJAX_CODEFILE =
SEARCHENGINE = YES
SERVER_BASED_SEARCH = NO
EXTERNAL_SEARCH = NO
SEARCHENGINE_URL =
SEARCHDATA_FILE = searchdata.xml
EXTERNAL_SEARCH_ID =
EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME =
MAKEINDEX_CMD_NAME = makeindex
LATEX_MAKEINDEX_CMD = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4
EXTRA_PACKAGES =
LATEX_HEADER =
LATEX_FOOTER =
LATEX_EXTRA_STYLESHEET =
LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = NO
LATEX_EMOJI_DIRECTORY =
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_SUBDIR =
MAN_LINKS = NO
#---------------------------------------------------------------------------
# Configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
XML_NS_MEMB_FILE_SCOPE = NO
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# Configuration options related to Sqlite3 output
#---------------------------------------------------------------------------
#---------------------------------------------------------------------------
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED =
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration options related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
DIA_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
DOT_NUM_THREADS = 0
DOT_FONTNAME = Helvetica
DOT_FONTSIZE = 10
DOT_FONTPATH =
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
UML_LIMIT_NUM_FIELDS = 10
DOT_UML_DETAILS = NO
DOT_WRAP_THRESHOLD = 17
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DIR_GRAPH_MAX_DEPTH = 1
DOT_IMAGE_FORMAT = png
INTERACTIVE_SVG = NO
DOT_PATH =
DOTFILE_DIRS =
MSCFILE_DIRS =
DIAFILE_DIRS =
PLANTUML_JAR_PATH =
PLANTUML_CFG_FILE =
PLANTUML_INCLUDE_PATH =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34408.163
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Models", "Models\Models.csproj", "{807AB723-7AD3-42DD-9DA6-7AA5B0A9AAB4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{383C4215-C680-4C2E-BC7E-B62F0B164370}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{807AB723-7AD3-42DD-9DA6-7AA5B0A9AAB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{807AB723-7AD3-42DD-9DA6-7AA5B0A9AAB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{807AB723-7AD3-42DD-9DA6-7AA5B0A9AAB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{807AB723-7AD3-42DD-9DA6-7AA5B0A9AAB4}.Release|Any CPU.Build.0 = Release|Any CPU
{383C4215-C680-4C2E-BC7E-B62F0B164370}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {50EAA59B-6857-44DC-86B9-E8D258C0DC86}
EndGlobalSection
EndGlobal

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Models\Models.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,246 @@
// 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
{
/// <summary>
/// Main function of the console app
/// </summary>
/// <param name="args"></param>
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();
}
}
/// <summary>
/// Handles the event when the game has started.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
static void OnGameStarted(object sender, GameStartedEventArgs e)
{
Console.WriteLine($"The game has started! Player: {e.CurrentPlayer.Pseudo}");
}
/// <summary>
/// Handles the event when the game has ended.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
static void OnGameEnded(object sender, GameEndedEventArgs e)
{
Console.WriteLine($"The game has ended! Player: {e.CurrentPlayer.Pseudo}");
}
/// <summary>
/// Handles the event when the board is updated.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
static void OnBoardUpdated(object sender, EventArgs e)
{
DisplayBoard(((Game)sender).UsedMap);
DisplayOperationTable(((Game)sender).UsedMap.OperationGrid);
}
/// <summary>
/// Handles the event when the dice are rolled.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
static void OnDiceRolled(object sender, DiceRolledEventArgs e)
{
Console.WriteLine($"Dice 1: {e.Dice1Value} | Dice 2: {e.Dice2Value}");
Operation playerOperation = GetPlayerOperation();
((Game)sender).HandlePlayerOperation(playerOperation);
}
/// <summary>
/// Handles the event when an operation is chosen by the player.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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);
}
}
/// <summary>
/// Handles the event when a cell is chosen by the player.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
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);
}
/// <summary>
/// Displays the game board.
/// </summary>
/// <param name="map">Used map to display</param>
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();
}
}
}
/// <summary>
/// Displays the operation table.
/// </summary>
/// <param name="operationTable">The operation table to display.</param>
static void DisplayOperationTable(List<OperationCell> 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();
}
}
/// <summary>
/// Gets the cell chosen by the player.
/// </summary>
/// <returns>The cell chosen by the player.</returns>
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);
}
}
/// <summary>
/// Gets the operation chosen by the player.
/// </summary>
/// <returns></returns>
/// <exception cref="ArgumentOutOfRangeException"></exception>
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()
};
}
/// <summary>
/// Displays the operation options for the player to choose from.
/// </summary>
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)");
}
}

@ -0,0 +1,19 @@
using Models.Game;
namespace Models.Events
{
/// <summary>
/// Event arguments for when a cell is chosen.
/// </summary>
public class CellChosenEventArgs : EventArgs
{
public Cell Cell { get; }
public int Result { get; }
public CellChosenEventArgs(Cell cell, int result)
{
Cell = cell;
Result = result;
}
}
}

@ -0,0 +1,19 @@
using Models.Game;
namespace Models.Events
{
/// <summary>
/// Event arguments for when the dice are rolled.
/// </summary>
public class DiceRolledEventArgs : EventArgs
{
public int Dice1Value { get; }
public int Dice2Value { get; }
public DiceRolledEventArgs(int dice1Value, int dice2Value)
{
Dice1Value = dice1Value;
Dice2Value = dice2Value;
}
}
}

@ -0,0 +1,17 @@
using Models.Game;
namespace Models.Events
{
/// <summary>
/// Event arguments for when the game ends.
/// </summary>
public class GameEndedEventArgs : EventArgs
{
public Player CurrentPlayer { get; }
public GameEndedEventArgs(Player winner)
{
CurrentPlayer = winner;
}
}
}

@ -0,0 +1,18 @@
using Models.Game;
namespace Models.Events
{
/// <summary>
/// Event arguments for when the game starts.
/// </summary>
public class GameStartedEventArgs : EventArgs
{
public Player CurrentPlayer { get; }
public GameStartedEventArgs(Player selectedPlayer)
{
CurrentPlayer = selectedPlayer;
}
}
}

@ -0,0 +1,19 @@
using Models.Game;
namespace Models.Events
{
/// <summary>
/// Event arguments for when an operation is chosen.
/// </summary>
public class OperationChosenEventArgs : EventArgs
{
public Operation Operation { get; }
public int Result { get; }
public OperationChosenEventArgs(Operation operation, int result)
{
Operation = operation;
Result = result;
}
}
}

@ -0,0 +1,11 @@
namespace Models.Exceptions
{
/// <summary>
/// Exception for when the cell coordinates are invalid.
/// </summary>
public class InvalidCellCoordinatesException : Exception
{
public InvalidCellCoordinatesException(string message) : base(message) { }
}
}

@ -0,0 +1,11 @@
namespace Models.Exceptions
{
/// <summary>
/// Exception for when the cell is invalid.
/// </summary>
public class InvalidCellException : Exception
{
public InvalidCellException(string message) : base(message) { }
}
}

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Models.Game
{
/// <summary>
/// This class represents the best score of a player.
/// </summary>
public class BestScore
{
/// <summary>
/// Initialize a new instance of the BestScore class.
/// </summary>
/// <param name="gamesPlayed">Number of games played by the new user</param>
/// <param name="score">Best score</param>
public BestScore(int gamesPlayed, int score)
{
GamesPlayed = gamesPlayed;
Score = score;
if (GamesPlayed < 0)
GamesPlayed = 0;
if (Score < 0)
Score = 0;
}
/// <summary>
/// Number of games played by the user.
/// </summary>
public int GamesPlayed { get; private set; }
/// <summary>
/// Best score of the player.
/// </summary>
private int _score;
public int Score
{
get
{
return _score;
}
private set
{
if (value > _score)
_score = value;
}
}
/// <summary>
/// Increment the number of games played by the user.
/// </summary>
public void IncrGamesPlayed()
{
GamesPlayed += 1;
}
/// <summary>
/// Update the best score of the player.
/// </summary>
/// <param name="newScore">New best score</param>
public void UpdateScore(int newScore)
{
Score = newScore;
}
}
}

@ -0,0 +1,64 @@
namespace Models.Game
{
/// <summary>
/// The Cell class represents a cell in the application.
/// </summary>
public class Cell : Position, IEquatable<Cell>
{
/// <summary>
/// The value of the cell.
/// </summary>
private int? _value;
public int? Value {
get => _value;
set
{
if (value < 0)
{
throw new Exception("La valeur doit être supérieure à 0");
}
this._value = value;
}
}
/// <summary>
/// The fact that the cell is dangerous or not.
/// </summary>
private bool IsDangerous { get; set; }
/// <summary>
/// Atribute to know if the cell is a penalty cell.
/// </summary>
private bool Penalty { get; set; }
/// <summary>
/// Constructor of the Cell class.
/// </summary>
/// <param name="x">the x position</param>
/// <param name="y">the y position</param>
/// <param name="isDangerous">if the cell is a dangerous cell or not</param>
public Cell(int x, int y,bool isDangerous = false):base(x,y)
{
IsDangerous = isDangerous;
Penalty = false;
}
/// <summary>
/// Function in order to return the fact that the cell is dangerous or not.
/// </summary>
/// <returns>If the cell is dangerous or not</returns>
public bool GetCellType() => IsDangerous;
/// <summary>
/// Redefine the equal operation between cells.
/// </summary>
/// <param name="other">The object to compare with the current cell.</param>
/// <returns>true if the specified object is equal to the current cell; otherwise, false.</returns>
public bool Equals(Cell? other)
{
if (other == null) return false;
if (this.X == other.X && this.Y == other.Y) return true;
return false;
}
}
}

@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Models.Game
{
/// <summary>
/// The Dice class represents a dice in the application.
/// </summary>
public class Dice
{
/// <summary>
/// Lowest number on the dice.
/// </summary>
public int NbMin { get; private set; }
/// <summary>
/// Highest number on the dice.
/// </summary>
public int NbMax { get; private set; }
/// <summary>
/// Value of the dice.
/// </summary>
private int _value;
public int Value {
get => _value;
private set
{
if (value < NbMin || value > NbMax)
{
value = NbMin;
}
_value = value;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="Dice"/> class.
/// </summary>
/// <param name="nbmin">The lowest number on the dice, on which the highest number is set</param>
public Dice(int nbmin)
{
if (nbmin < 0) nbmin = 0;
if (nbmin > 1) nbmin = 1;
NbMin = nbmin;
NbMax = nbmin + 5;
}
/// <summary>
/// Initializes a new instance of the <see cref="Dice"/> class.
/// </summary>
public Dice()
{
NbMin = 0;
NbMax = 5;
}
public override string ToString()
{
return $"Ce dé a pour valeur {Value} et est entre {NbMin} et {NbMax}";
}
/// <summary>
/// Rolls the dice.
/// </summary>
public void Roll()
{
Value = new Random().Next(NbMin, NbMax + 1);
}
/// <summary>
/// Compare 2 dice values.
/// </summary>
/// <param name="dice2">Another dice</param>
/// <returns>true if the dice2 is higher than the dice1; otherwise, false.</returns>
public bool IsLower(Dice dice2)
{
return dice2.Value > this.Value;
}
}
}

@ -0,0 +1,252 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using Models.Events;
using Models.Exceptions;
using Models.Rules;
namespace Models.Game
{
/// <summary>
/// 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.
/// </summary>
public class Game
{
private bool _isRunning;
public Player CurrentPlayer { get; private set; }
public Map UsedMap { get; private set; }
private Dice Dice1 { get; }
private Dice Dice2 { get; }
private int Turn { get; set; }
public Rules.Rules GameRules { get; }
// == Events ==
public event EventHandler<GameStartedEventArgs> GameStarted;
public event EventHandler<GameEndedEventArgs> GameEnded;
public event EventHandler BoardUpdated;
public event EventHandler<DiceRolledEventArgs> DiceRolled;
public event EventHandler<OperationChosenEventArgs> OperationChosen;
public event EventHandler<CellChosenEventArgs> CellChosen;
/// <summary>
/// Initializes a new instance of the <see cref="Game"/> class.
/// </summary>
/// <param name="player">The player who play the game.</param>
/// <param name="map">The map to be used in the game.</param>
public Game(Player player, Map map)
{
_isRunning = false;
UsedMap = map;
CurrentPlayer = player;
Dice1 = new Dice();
Dice2 = new Dice(1);
Turn = 1;
GameRules = new Rules.Rules();
}
/// <summary>
/// Rolls all the dice.
/// </summary>
private void RollAllDice()
{
Dice1.Roll();
Dice2.Roll();
DiceRolled?.Invoke(this, new DiceRolledEventArgs(Dice1.Value, Dice2.Value));
}
/// <summary>
/// Marks an operation as checked in the operation grid of the game.
/// </summary>
/// <param name="operation"></param>
private void MarkOperationAsChecked(Operation operation)
{
int operationIndex = (int)operation;
int operationsPerType = 4; // Chaque type d'opération peut être fait 4 fois
for (int i = operationIndex * operationsPerType; i < (operationIndex + 1) * operationsPerType; i++)
{
if (!UsedMap.OperationGrid[i].IsChecked)
{
UsedMap.OperationGrid[i].Check();
break;
}
}
}
/// <summary>
/// Performs an operation on the values of two dice based on the provided operation.
/// </summary>
/// <param name="o">The operation to perform. This can be LOWER, HIGHER, SUBTRACTION, ADDITION, or MULTIPLICATION.</param>
/// <returns>
/// The result of the operation. If the operation is LOWER or HIGHER, it returns the lower or higher value of the two dice respectively.
/// If the operation is SUBTRACTION, it returns the difference between the higher and lower value of the two dice.
/// If the operation is ADDITION, it returns the sum of the values of the two dice.
/// 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.
/// </returns>
private int ResultOperation(Operation o)
{
int result = o switch
{
Operation.LOWER => Dice1.IsLower(Dice2) ? Dice1.Value : Dice2.Value,
Operation.HIGHER => Dice1.IsLower(Dice2) ? Dice2.Value : Dice1.Value,
Operation.SUBTRACTION => Dice1.IsLower(Dice2) ? Dice2.Value - Dice1.Value : Dice1.Value - Dice2.Value,
Operation.ADDITION => Dice2.Value + Dice1.Value,
Operation.MULTIPLICATION => Dice2.Value * Dice1.Value,
_ => throw new ArgumentOutOfRangeException()
};
MarkOperationAsChecked(o);
return result;
}
/// <summary>
/// Places the result of a dice operation into a chosen cell on the game board.
/// The result can be placed in the chosen cell if it's the first turn or if the chosen cell is valid according to the game rules.
/// </summary>
/// <param name="playerChoice">The cell chosen by the player to place the result.</param>
/// <param name="result">The result of the dice operation to be placed in the cell.</param>
private void PlaceResult(Cell playerChoice, int result)
{
if (Turn == 1 || GameRules.NearCellIsValid(playerChoice, UsedMap.Boards))
{
playerChoice.Value = result;
BoardUpdated?.Invoke(this, EventArgs.Empty);
}
}
/// <summary>
/// Add the choosen cell to a rope path if it's possible.
/// </summary>
/// <param name="playerChoice"></param>
/// <param name="adjacentes"></param>
private void AddToRopePath(Cell playerChoice,List<Cell> adjacentes)
{
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<Cell> {playerChoice, cells});
}
// A modifier dans le cas ou il est possible de fusionner deux chemins de corde
if (GameRules.IsInRopePaths(playerChoice, UsedMap.RopePaths, index)) break;
// Le cas si il existe des chemins de corde
// 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<Cell> { playerChoice, cells });
continue;
}
if (!GameRules.AsValue(playerChoice,UsedMap.RopePaths,index))
{
UsedMap.RopePaths[index].Add(playerChoice);
}
// 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
}
}
}
/// <summary>
/// Initializes the game.
/// </summary>
public void InitializeGame()
{
_isRunning = true;
GameStarted?.Invoke(this, new GameStartedEventArgs(CurrentPlayer));
GameLoop();
}
/// <summary>
/// Ends the game.
/// </summary>
private void EndGame()
{
_isRunning = false;
GameEnded?.Invoke(this, new GameEndedEventArgs(CurrentPlayer));
}
/// <summary>
/// The main game loop that runs while the game is active.
/// </summary>
private void GameLoop()
{
while (_isRunning)
{
if (Turn == 20)
{
EndGame();
break;
}
RollAllDice();
Turn++;
}
}
/// <summary>
/// Handles the player's choice of an operation based on the dice values.s
/// </summary>
/// <param name="operation">The operation chosen by the player.</param>
public void HandlePlayerOperation(Operation operation)
{
int result = ResultOperation(operation);
OperationChosen?.Invoke(this, new OperationChosenEventArgs(operation, result));
}
/// <summary>
/// Handles the player's choice of a cell on the game board.
/// </summary>
/// <param name="cell"></param>
/// <param name="result"></param>
/// <exception cref="InvalidCellCoordinatesException"></exception>
/// <exception cref="InvalidCellException"></exception>
public void 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.");
}
if (!GameRules.IsCellValid(cell, UsedMap.Boards))
{
throw new InvalidCellException("Cell is not valid. Please choose again.");
}
PlaceResult(cell, result);
GameRules.IsZoneValidAndAddToZones(cell, UsedMap);
AddToRopePath(cell, GameRules.EveryAdjacentCells(cell, UsedMap.Boards));
CellChosen?.Invoke(this, new CellChosenEventArgs(cell, result));
BoardUpdated?.Invoke(this, EventArgs.Empty);
}
}
}

@ -0,0 +1,78 @@
namespace Models.Game
{
/// <summary>
/// The Map class is the representation of the game map with the board and the operations table.
/// </summary>
public class Map
{
/// <summary>
/// It is the list of cells on the map.
/// </summary>
public List<Cell> Boards { get; private set; }
/// <summary>
/// It is the backgrond image of the map
/// </summary>
public string Background { get; private set; }
/// <summary>
/// It is the grid of the possible operation in the game
/// </summary>
public List<OperationCell> OperationGrid { get; private set; }
/// <summary>
/// It is a list of a list containing user's rope paths in the current game
/// </summary>
public List<List<Cell>> RopePaths { get; private set; }
/// <summary>
/// It is a list of a list containing user's zones in the current game
/// </summary>
public List<List<Cell>> Zones { get; private set; }
/// <summary>
/// Initializes a new instance of the Map class.
/// </summary>
/// <param name="background">The background of the map.</param>
public Map(string background)
{
Boards = InitializeBoards();
Background = background;
OperationGrid = InitializeOperationGrid();
RopePaths = new List<List<Cell>>();
Zones = new List<List<Cell>>();
}
/// <summary>
/// Initializes the boards of the map.
/// </summary>
/// <returns>Return the boards</returns>
private List<Cell> InitializeBoards()
{
var boards = new List<Cell>();
for (int i = 0; i < 36; i++) // 6x6 board
{
boards.Add(new Cell(i / 6, i % 6));
}
return boards;
}
/// <summary>
/// Initializes the operation grid of the map.
/// </summary>
/// <returns>Return the operation grid</returns>
private List<OperationCell> InitializeOperationGrid()
{
var operationGrid = new List<OperationCell>();
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));
}
}
return operationGrid;
}
}
}

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Models.Game
{
/// <summary>
/// Represents the available operations in the game.
/// </summary>
public enum Operation
{
LOWER,
HIGHER,
SUBTRACTION,
ADDITION,
MULTIPLICATION
}
}

@ -0,0 +1,30 @@
namespace Models.Game
{
/// <summary>
/// Represents a cell in the operation grid of the game.
/// </summary>
public class OperationCell : Position
{
/// <summary>
/// It tells if the operation is checked or not in the operation grid of the game.
/// </summary>
public bool IsChecked { get; private set; }
/// <summary>
/// Constructor of the OperationCell class.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
public OperationCell(int x, int y) : base(x, y)
{
}
/// <summary>
/// Check the operation cell.
/// </summary>
public void Check()
{
IsChecked = true;
}
}
}

@ -0,0 +1,82 @@
namespace Models.Game
{
/// <summary>
/// Represents a player in the game.
/// </summary>
public class Player
{
/// <summary>
/// It is he pseudo of the player.
/// </summary>
public string Pseudo { get; private set; }
/// <summary>
/// It is the profile picture of the player.
/// </summary>
public string ProfilePicture { get; private set; }
/// <summary>
/// It is the creation date of the player.
/// </summary>
public string? CreationDate { get; private set; }
/// <summary>
/// It tells when was the last time the player played.
/// </summary>
public string? LastPlayed { get; private set; }
/// <summary>
/// Constructor with default values.
/// </summary>
public Player()
{
Pseudo = "Player";
ProfilePicture = "DefaultProfilePicture";
}
/// <summary>
/// Construct a new instance of Player with specified pseudo and profile picture.
/// </summary>
/// <param name="pseudo">The pseudo of the player.</param>
/// <param name="profilePicture">The profile picture of the player.</param>
public Player(string pseudo, string profilePicture = "DefaultProfilePicture")
{
Pseudo = pseudo;
ProfilePicture = profilePicture;
}
/// <summary>
/// Chooses the operation for the player.
/// </summary>
/// <returns>The chosen operation.</returns>
public Operation ChooseOperation()
{
return Operation.LOWER;
}
/// <summary>
/// Redefine the equal operation between player.
/// </summary>
/// <param name="obj">The object to compare with the current player.</param>
/// <returns>true if the specified object is equal to the current player; otherwise, false.</returns>
public override bool Equals(object? obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
Player c = (Player)obj;
return (Pseudo == c.Pseudo);
}
/// <summary>
/// Returns the hash code for the current player, in order for the Equals operation to work
/// </summary>
/// <returns>The hash code for the current player.</returns>
public override int GetHashCode()
{
return Pseudo.GetHashCode();
}
}
}

@ -0,0 +1,30 @@
namespace Models.Game
{
/// <summary>
/// The Position (x,y) of a cell in the game.
/// </summary>
public class Position
{
/// <summary>
/// The X coordinate.
/// </summary>
public int X { get; set; }
/// <summary>
/// The Y coordinate.
/// </summary>
public int Y { get; set; }
/// <summary>
/// Constructor of the Position class.
/// </summary>
/// <param name="x">The X coordinate.</param>
/// <param name="y">The Y coordinate.</param>
public Position(int x, int y)
{
X = x;
Y = y;
}
}
}

@ -0,0 +1,128 @@
using Models.Game;
namespace Models.Interfaces
{
/// <summary>
/// Interface for the rules of the game.
/// </summary>
public interface IRules
{
//public bool NearCellIsValid(Position playerChoicePosition, SortedDictionary<Position, Cell> cells);
/// <summary>
/// Return true if the cell is empty, otherwise false.
/// </summary>
/// <param name="playerChoice">The cell that the player chose</param>
/// <returns> Return true if the cell is empty, otherwise false.</returns>
public bool IsCellEmpty(Cell playerChoice);
/// <summary>
/// Check if the cell is valid.
/// </summary>
/// <param name="playerChoicePosition">The cell that the player chose</param>
/// <param name="cells">Boards of the actual game</param>
/// <returns>true if the cell is valid; otherwise, false</returns>
public bool IsCellValid(Cell playerChoicePosition, List<Cell> cells);
//public bool IsRopePath(Cell playerChoice, HashSet<RopePath> ropePaths);
//public bool IsAdjacent(Cell cell1, Cell cell2, List<Position, Cell> cells);
//public int HowMany(Cell playerChoice, List<Position, Cell> cells);
//public void SetValueAndPenalty(int valueChoice, Cell playerChoice, List<Position, Cell> cells);
/// <summary>
/// Check if the given cell is adjacent to the target cell.
/// </summary>
/// <param name="choosenCell">The chosen cell.</param>
/// <param name="targetCell">The target cell.</param>
/// <returns>True if the given cell is adjacent to the target cell; otherwise false.</returns>
public bool IsCellAdjacent(Cell choosenCell, Cell targetCell);
/// <summary>
/// Check if the given cell can be played there.
/// If there isn't any adjacent cell with a value, or if the cell is null, it returns false.
/// </summary>
/// <param name="choosenCell">The chosen cell.</param>
/// <param name="cells">The list of cells.</param>
/// <returns>True if the chosen cell can be played here; otherwise false.</returns>
public bool NearCellIsValid(Cell choosenCell, List<Cell> cells);
/// <summary>
/// Check if the chosen cell is valid and add it to the matching zone.
/// If there is a nearby cell with matching value but no zone already created, it creates one
/// </summary>
/// <param name="chosenCell">The chosen cell.</param>
/// <param name="map">The map.</param>
/// <returns></returns>
public void IsZoneValidAndAddToZones(Cell chosenCell, Map map);
/// <summary>
/// Check if the value of the chosen cell is in the zones of the player.
/// </summary>
/// <param name="chosenCell">The cell chosen by the player.</param>
/// <param name="zones">The list of the player's zones.</param>
/// <returns>True if the value is in the zones; otherwise false.</returns>
public bool IsValueInZones(Cell chosenCell, List<List<Cell>> zones);
/// <summary>
/// Check if the chosen cell is in any of the player's zones.
/// </summary>
/// <param name="chosenCell">The chosen cell.</param>
/// <param name="zones">The list of the player's zones.</param>
/// <returns>True if the cell is in any of the zones; otherwise false.</returns>
public bool IsCellInZone(Cell chosenCell, List<List<Cell>> zones);
/// <summary>
/// Add the chosen cell to the list of zones.
/// The zone must be created before.
/// </summary>
/// <param name="chosenCell">The chosen cell.</param>
/// <param name="zones">The list of zones.</param>
public void AddToZone(Cell chosenCell, List<List<Cell>> zones);
/// <summary>
/// Create a new zone with the two cells and add it to the map.
/// </summary>
/// <param name="firstCell">The first cell.</param>
/// <param name="secondCell">The second cell.</param>
/// <param name="map">The map.</param>
public void NewZoneIsCreated(Cell firstCell, Cell secondCell, Map map);
/// <summary>
/// Get every adjacent cell of the chosen cell.
/// </summary>
/// <param name="choosenCell">The chosen cell.</param>
/// <param name="cells">The list of cells.</param>
/// <returns>The list of adjacent cells.</returns>
public List<Cell> EveryAdjacentCells(Cell choosenCell, List<Cell> cells);
/// <summary>
/// Calculate the final score by summing up the values of all the zones.
/// </summary>
/// <param name="zones">The list of zones.</param>
/// <returns>The final score.</returns>
public int? FinalCalculusOfZones(List<List<Cell>> zones);
/// <summary>
/// Check if the adjacent cell is in any of the rope paths.
/// </summary>
/// <param name="adjacente">The adjacent cell.</param>
/// <param name="ropePaths">The list of rope paths.</param>
/// <param name="index">The index of the rope path.</param>
/// <returns>True if the adjacent cell is in the rope path; otherwise false.</returns>
public bool IsInRopePaths(Cell adjacente, List<List<Cell>> ropePaths, int index);
/// <summary>
/// Check if the chosen cell has the same value as the rope path at the given index.
/// </summary>
/// <param name="choosenCell">The chosen cell.</param>
/// <param name="ropePaths">The list of rope paths.</param>
/// <param name="index">The index of the rope path.</param>
/// <returns>True if the chosen cell has the same value as the rope path; otherwise false.</returns>
public bool AsValue(Cell choosenCell, List<List<Cell>> ropePaths, int index);
}
}

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Folder Include="Game\" />
<Folder Include="Interfaces\" />
<Folder Include="Rules\" />
</ItemGroup>
</Project>

@ -0,0 +1,205 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Models.Game;
using Models.Interfaces;
namespace Models.Rules
{
/// <summary>
/// The Rules class contains all the rules of the game. It is used to check if a move is valid or not.
/// </summary>
public class Rules : IRules
{
public bool IsCellEmpty(Cell playerChoice)
{
if (playerChoice == null || playerChoice.Value == null) return true;
return false;
}
public bool IsCellValid(Cell playerChoicePosition, List<Cell> cells)
{
if (!IsCellEmpty(playerChoicePosition)) 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;
return true;
}
public bool IsInRopePaths (Cell adjacente,List<List<Cell>> ropePaths,int index)
{
foreach (List<Cell> path in ropePaths)
{
if (path.Contains(adjacente))
{
index=ropePaths.IndexOf(path);
return true;
}
}
return false;
}
public bool AsValue (Cell choosenCell, List<List<Cell>> ropePaths,int index)
{
foreach (var item in ropePaths[index])
{
if (choosenCell.Value == item.Value) return true;
}
return false;
}
public bool NearCellIsValid(Cell choosenCell, List<Cell> cells)
{
if (choosenCell == null || cells == null) return false;
IEnumerable<Cell> PlayedCellsQuery =
from cell in cells
where cell.Value != null
select cell;
foreach (var cell in PlayedCellsQuery)
{
if(!IsCellAdjacent(choosenCell, cell)) continue;
return true;
}
return false;
}
public void IsZoneValidAndAddToZones(Cell chosenCell, Map map)
{
if (chosenCell == null ||chosenCell.Value == null) return;
List<Cell> adjacentCells = new List<Cell>();
adjacentCells = EveryAdjacentCells(chosenCell, map.Boards);
foreach(var cells in adjacentCells)
{
if (cells.Value == chosenCell.Value)
{
if(IsValueInZones(cells, map.Zones))
{
AddToZone(chosenCell, map.Zones);
}
else
{
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<List<Cell>> zones)
{
if (chosenCell == null) return false;
for (int i = 0; i < zones.Count; i++)
{
if (zones[i][0].Value == chosenCell.Value)
{
return true;
}
}
return false;
}
public bool IsCellInZone(Cell chosenCell, List<List<Cell>> zones)
{
if (chosenCell == null) return false;
for (int i = 0; i < zones.Count; i++)
{
if (zones[i].Contains(chosenCell))
{
return true;
}
}
return false;
}
public void AddToZone(Cell chosenCell, List<List<Cell>> zones)
{
if (chosenCell == null || chosenCell.Value == null) return;
if (IsCellInZone(chosenCell, zones)) return;
for (int i = 0; i < zones.Count; i++)
{
if (zones[i][0].Value == chosenCell.Value)
{
zones[i].Add(chosenCell);
return;
}
}
return;
}
public void NewZoneIsCreated(Cell firstCell, Cell secondCell, Map map)
{
if (firstCell == null || secondCell == null || firstCell.Value == null || secondCell.Value == null) return;
List<Cell> newZone = new List<Cell>();
newZone.Add(firstCell);
newZone.Add(secondCell);
map.Zones.Add(newZone);
}
public List<Cell> EveryAdjacentCells(Cell choosenCell, List<Cell> cells)
{
List<Cell> adjacentCells = new List<Cell>();
foreach (var cell in cells)
{
if (choosenCell == cell) continue;
if (IsCellAdjacent(choosenCell, cell))
{
adjacentCells.Add(cell);
}
}
return adjacentCells;
}
public int? FinalCalculusOfZones(List<List<Cell>> zones)
{
int? calculus = 0;
for(int i = 0; i < zones.Count; i++)
{
calculus += zones[i].Count - 1 + zones[i][0].Value;
if (zones[i].Count > 9)
{
calculus += (zones[i].Count - 9) * 5;
}
}
return calculus;
}
}
}

@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Models.Game;
namespace Tests
{
public class BestScoreTests
{
[Fact]
public void Constructor_WithNegativeInputs_SetsPropertiesToZero()
{
var bestScore = new BestScore(-5, -10);
Assert.Equal(0, bestScore.GamesPlayed);
Assert.Equal(0, bestScore.Score);
}
[Fact]
public void Constructor_WithPositiveInputs_SetsPropertiesCorrectly()
{
var bestScore = new BestScore(5, 10);
Assert.Equal(5, bestScore.GamesPlayed);
Assert.Equal(10, bestScore.Score);
}
[Fact]
public void IncrGamesPlayed_IncrementsGamesPlayed()
{
var bestScore = new BestScore(0, 0);
bestScore.IncrGamesPlayed();
Assert.Equal(1, bestScore.GamesPlayed);
}
[Fact]
public void ScoreSetter_WithLowerValue_DoesNotChangeScore()
{
var bestScore = new BestScore(0, 10);
bestScore.UpdateScore(5);
Assert.Equal(10, bestScore.Score);
}
[Fact]
public void ScoreSetter_WithHigherValue_ChangesScore()
{
var bestScore = new BestScore(0, 5);
bestScore.UpdateScore(10);
Assert.Equal(10, bestScore.Score);
}
}
}

@ -0,0 +1,50 @@
namespace Tests;
using Models.Game;
public class CellTests
{
[Fact]
public void CellConstructor_SetsCorrectValues()
{
Cell cell = new Cell(1, 2, true);
Assert.Equal(1, cell.X);
Assert.Equal(2, cell.Y);
Assert.True(cell.GetCellType());
}
[Fact]
public void CellConstructor_SetsDefaultValues()
{
Cell cell = new Cell(1, 2);
Assert.Equal(1, cell.X);
Assert.Equal(2, cell.Y);
Assert.False(cell.GetCellType());
}
[Fact]
public void ValueSetter_ThrowsException_WhenValueIsNegative()
{
Cell cell = new Cell(1, 2);
Assert.Throws<Exception>(() => cell.Value = -1);
}
[Fact]
public void ValueSetter_SetsValue_WhenValueIsPositive()
{
Cell cell = new Cell(1, 2);
cell.Value = 5;
Assert.Equal(5, cell.Value);
}
[Fact]
public void ValueSetter_SetsValue_WhenValueIsNull()
{
Cell cell = new Cell(1, 2);
Assert.Null(cell.Value);
}
}

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Models.Game;
namespace Tests;
public class DiceTests
{
[Fact]
public void Constructor_WithNegativeNbMin_SetsNbMinToZero()
{
Dice dice = new Dice(-1);
Assert.Equal(0, dice.NbMin);
}
[Fact]
public void Constructor_WithNbMinGreaterThanOne_SetsNbMinToOne()
{
Dice dice = new Dice(2);
Assert.Equal(1, dice.NbMin);
}
[Fact]
public void Constructor_WithValidNbMin_SetsNbMinAndNbMaxCorrectly()
{
Dice dice = new Dice(1);
Assert.Equal(1, dice.NbMin);
Assert.Equal(6, dice.NbMax);
}
[Fact]
public void DefaultConstructor_SetsNbMinToZeroAndNbMaxToFive()
{
Dice dice = new Dice();
Assert.Equal(0, dice.NbMin);
Assert.Equal(5, dice.NbMax);
}
[Fact]
public void Roll_SetsValueBetweenNbMinAndNbMax()
{
Dice dice = new Dice();
dice.Roll();
Assert.True(dice.Value >= dice.NbMin && dice.Value <= dice.NbMax);
}
}

@ -0,0 +1,44 @@
using Models;
using Models.Game;
namespace Tests;
public class MapTests
{
[Fact]
public void Map_Initialization_SetsBackground()
{
string background = "test_background";
var map = new Map(background);
Assert.Equal(background, map.Background);
}
[Fact]
public void Map_Initialization_InitializesBoards()
{
string background = "test_background";
var map = new Map(background);
Assert.Equal(36, map.Boards.Count);
for (int i = 0; i < 36; i++)
{
Assert.Equal(new Cell(i / 6, i % 6), map.Boards[i]);
}
}
[Fact]
public void Map_Initialization_InitializesRopePathsAndZones()
{
string background = "test_background";
var map = new Map(background);
Assert.NotNull(map.RopePaths);
Assert.NotNull(map.Zones);
Assert.Empty(map.RopePaths);
Assert.Empty(map.Zones);
}
}

@ -0,0 +1,27 @@
using Models.Game;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests
{
public class OperationCellTests
{
[Fact]
public void Constructor_WithValidCoordinates_SetsCoordinatesCorrectly()
{
OperationCell operationCell = new OperationCell(1, 2);
Assert.Equal(1, operationCell.X);
Assert.Equal(2, operationCell.Y);
}
[Fact]
public void Constructor_WithValidCoordinates_SetsIsCheckedToFalse()
{
OperationCell operationCell = new OperationCell(1, 2);
Assert.False(operationCell.IsChecked);
}
}
}

@ -0,0 +1,43 @@
namespace Tests;
using Models.Game;
public class PlayerTests
{
[Theory]
[InlineData("Player", "DefaultProfilePicture")]
[InlineData("John Doe", "N/A.png")]
public void Constructor_WithPseudoAndProfilePicture_SetsPseudoAndProfilePictureCorrectly(string pseudo, string profilePicture)
{
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);
}
[Theory]
[InlineData("John Doe", "John Doe", true)]
[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);
Assert.Equal(expectedResult, player1.Equals(player2));
}
[Theory]
[InlineData("John Doe", "John Doe", true)]
[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);
Assert.Equal(expectedResult, player1.GetHashCode() == player2.GetHashCode());
}
}

@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0"/>
<PackageReference Include="xunit" Version="2.4.2"/>
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Models\Models.csproj" />
</ItemGroup>
</Project>

@ -5,6 +5,12 @@ 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}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "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}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -17,6 +23,18 @@ Global
{41EE7BF8-DDE6-4B00-9434-076589C0B419}.Release|Any CPU.ActiveCfg = Release|Any CPU
{41EE7BF8-DDE6-4B00-9434-076589C0B419}.Release|Any CPU.Build.0 = Release|Any CPU
{41EE7BF8-DDE6-4B00-9434-076589C0B419}.Release|Any CPU.Deploy.0 = Release|Any CPU
{807AB723-7AD3-42DD-9DA6-7AA5B0A9AAB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{807AB723-7AD3-42DD-9DA6-7AA5B0A9AAB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{807AB723-7AD3-42DD-9DA6-7AA5B0A9AAB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{807AB723-7AD3-42DD-9DA6-7AA5B0A9AAB4}.Release|Any CPU.Build.0 = Release|Any CPU
{795F2C88-3C43-4795-9764-E52F7330888D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{795F2C88-3C43-4795-9764-E52F7330888D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{795F2C88-3C43-4795-9764-E52F7330888D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{795F2C88-3C43-4795-9764-E52F7330888D}.Release|Any CPU.Build.0 = Release|Any CPU
{383C4215-C680-4C2E-BC7E-B62F0B164370}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{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
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

@ -6,16 +6,37 @@
xmlns:local="clr-namespace:Trek_12"
xmlns:views="clr-namespace:Trek_12.Views"
Shell.FlyoutBehavior="Flyout"
Title="Trek_12">
Title="Trek_12"
Shell.NavBarIsVisible="False">
<ShellContent
Title="Home"
ContentTemplate="{DataTemplate views:PageMenuPrincipal}"
Route="PageMenuPrincipal" />
Route="MenuPrincipal" />
<ShellContent
Title="LeaderBoard"
ContentTemplate="{DataTemplate views:PageLeaderBoard}"
Route="LeaderBoard"/>
<ShellContent
Title="Profils"
ContentTemplate="{DataTemplate views:PageProfils}"
Route="Profils"/>
<ShellContent
Title="Règles"
ContentTemplate="{DataTemplate views:PageRegles}"
Route="Regles"/>
<!--<ShellContent
Title="Map Select"
ContentTemplate="{DataTemplate views:PageMapSelect}"
Route="MapSelect"/>-->
<!--<ShellContent
Title="Plateau"
ContentTemplate="{DataTemplate views:PagePlateau}"
Route="Plateau"/>-->
</Shell>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 MiB

@ -57,6 +57,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Maui" Version="7.0.1" />
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
@ -66,10 +67,16 @@
<Compile Update="Views\PageLeaderBoard.xaml.cs">
<DependentUpon>PageLeaderBoard.xaml</DependentUpon>
</Compile>
<Compile Update="Views\pageProfils.xaml.cs">
<DependentUpon>PageProfils.xaml</DependentUpon>
</Compile>
<Compile Update="Views\pageRegles.xaml.cs">
<DependentUpon>PageRegles.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<MauiXaml Update="Views\component\ContentLeaderBoard.xaml">
<MauiXaml Update="Views\Components\ContentLeaderBoard.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Views\PageLeaderBoard.xaml">

@ -1,46 +1,46 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Trek_12.Views.component.ContentLeaderBoard">
<Grid ColumnDefinitions="auto,*,*,*,*"
RowDefinitions="*,*"
Margin="0,20">
<Frame Margin="10"
BorderColor="Black"
CornerRadius="50"
HeightRequest="60"
WidthRequest="60"
IsClippedToBounds="True"
HasShadow="True">
<Image Source="profile.jpg"
Aspect="AspectFill"
Margin="-20"/>
</Frame>
<Label Text="Kiwi6026"
Grid.Column="1"
VerticalOptions="Center"
FontSize="Title"
TextColor="DarkSalmon"
Margin="10,0"/>
<Label Text="nbParties"
Grid.Column="2"
VerticalOptions="Center"
FontSize="Title"
TextColor="DarkSalmon"/>
<Label Text="map"
Grid.Column="3"
VerticalOptions="Center"
FontSize="Title"
TextColor="DarkSalmon"/>
<Label Text="bestScore"
Grid.Column="4"
VerticalOptions="Center"
FontSize="Title"
TextColor="DarkSalmon"/>
<BoxView Color="DarkSalmon"
Grid.Row="1"
HeightRequest="1"
WidthRequest="700"
Grid.ColumnSpan="5"/>
</Grid>
</ContentView>
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Trek_12.Views.Components.ContentLeaderBoard">
<Grid ColumnDefinitions="auto,*,*,*,*"
RowDefinitions="*,*"
Margin="0,20">
<Frame Margin="10"
BorderColor="Black"
CornerRadius="50"
HeightRequest="60"
WidthRequest="60"
IsClippedToBounds="True"
HasShadow="True">
<Image Source="profile.jpg"
Aspect="AspectFill"
Margin="-20"/>
</Frame>
<Label Text="Kiwi6026"
Grid.Column="1"
VerticalOptions="Center"
FontSize="Title"
TextColor="DarkSalmon"
Margin="10,0"/>
<Label Text="nbParties"
Grid.Column="2"
VerticalOptions="Center"
FontSize="Title"
TextColor="DarkSalmon"/>
<Label Text="map"
Grid.Column="3"
VerticalOptions="Center"
FontSize="Title"
TextColor="DarkSalmon"/>
<Label Text="bestScore"
Grid.Column="4"
VerticalOptions="Center"
FontSize="Title"
TextColor="DarkSalmon"/>
<BoxView Color="DarkSalmon"
Grid.Row="1"
HeightRequest="1"
WidthRequest="700"
Grid.ColumnSpan="5"/>
</Grid>
</ContentView>

@ -1,9 +1,9 @@
namespace Trek_12.Views.component;
public partial class ContentLeaderBoard : ContentView
{
public ContentLeaderBoard()
{
InitializeComponent();
}
namespace Trek_12.Views.Components;
public partial class ContentLeaderBoard : ContentView
{
public ContentLeaderBoard()
{
InitializeComponent();
}
}

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Trek_12.Views.viewsProfils"
xmlns:views="clr-namespace:Trek_12.Views">
x:Class="Trek_12.Views.Components.viewsProfils">
<VerticalStackLayout>
<Grid ColumnDefinitions="*,*,*,*" >
<Frame Margin="10"

@ -1,4 +1,4 @@
namespace Trek_12.Views;
namespace Trek_12.Views.Components;
public partial class viewsProfils : ContentView
{

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:view="clr-namespace:Trek_12.Views.component"
xmlns:views="clr-namespace:Trek_12.Views.Components"
x:Class="Trek_12.Views.PageLeaderBoard"
Title="PageLeaderBoard">
<Grid BackgroundColor="BlanchedAlmond"
@ -22,12 +22,12 @@
VerticalScrollBarVisibility="Never"
Margin="0,10">
<VerticalStackLayout>
<view:ContentLeaderBoard/>
<view:ContentLeaderBoard/>
<view:ContentLeaderBoard/>
<view:ContentLeaderBoard/>
<view:ContentLeaderBoard/>
<view:ContentLeaderBoard/>
<views:ContentLeaderBoard/>
<views:ContentLeaderBoard/>
<views:ContentLeaderBoard/>
<views:ContentLeaderBoard/>
<views:ContentLeaderBoard/>
<views:ContentLeaderBoard/>
</VerticalStackLayout>
</ScrollView>
<Button Text="Back"

@ -2,8 +2,8 @@ namespace Trek_12.Views;
public partial class PageLeaderBoard : ContentPage
{
public PageLeaderBoard()
{
InitializeComponent();
}
public PageLeaderBoard()
{
InitializeComponent();
}
}

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Trek_12.Views.pageProfils"
xmlns:views="clr-namespace:Trek_12.Views"
x:Class="Trek_12.Views.PageProfils"
xmlns:views="clr-namespace:Trek_12.Views.Components"
Title="pageProfils">
<ContentPage.Content>

@ -1,8 +1,8 @@
namespace Trek_12.Views;
public partial class pageProfils : ContentPage
public partial class PageProfils : ContentPage
{
public pageProfils()
public PageProfils()
{
InitializeComponent();
}

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Trek_12.Views.PageRegles"
xmlns:views="clr-namespace:Trek_12.Views.Components"
Title="pageRegles">
<ContentPage.Content>
<Grid RowDefinitions="2*,3*,*">
<Image Source="bg_regles.jpg" Grid.RowSpan="3" Aspect="AspectFill"/>
<Label Text="Règles" TextColor="black" HorizontalTextAlignment="Center" FontSize="Header" Margin="30"/>
<ScrollView Grid.Row="1">
<Grid RowDefinitions="*,*,*,*,*,*,*,*,*">
<!--<views:viewsProfils />
<views:viewsProfils Grid.Row="1" />
<views:viewsProfils Grid.Row="2"/>
<views:viewsProfils Grid.Row="3"/>
<views:viewsProfils Grid.Row="4"/>
<views:viewsProfils Grid.Row="5"/>-->
<Label Text="But du jeu &#10;&#10;
Obtenir le score le plus élevé en remplissant astucieusement les cases circulaires afin de créer des chemins de corde et de cartographier des zones, au fur à mesure de votre ascension.
&#10;
Sélectionner votre carte pour débuter votre ascension.Pour une toute première partie, nous vous conseillons d'utiliser la carte DUNAI &#10;" Grid.Row="0"/>
<Label Text=" &#10;Comment Jouer :&#10;
1. Lancer les deux dés.&#10;
Ici 1 et 4&#10;" Grid.Row="1" />
<Label Text="2. Choisissez votre résultat&#10;
a. Pour choisir votre résultat, vous devez choisir une seule opération suivante :&#10;
⬇Le résultat du plus petit dé (ici 1)&#10;
⬆Le résultat du plus grand dé (ici 4)&#10;
- La différence entre les deux dés (ici 3 - Une différence peut être nulle mais jamais négative)&#10;
+ La somme des deux dés (ici 5)&#10;
x Le produit des deux dés (ici 4)&#10;" Grid.Row="2" />
<Label Text=" &#10;b. Sélectionnez une case libre dans la ligne correspondant à votre choix&#10;
Lorsque tous les emplacements d'une même opération sont cochés,ce choix ne vous est plus accessible.&#10;" Grid.Row="3" />
<Label Text=" &#10;c. Sélectionnez la case circulaire de votre choix, pour y placer votre résultat.En respectant les règles suivantes&#10;
Placez votre 1er résultat dans la case de votre choix&#10;
Tous les résultats suivants doivent être placés adjacents a une case déjà remplie.&#10;
Les conséquences de votre choix sont appliquez immédiatement : Chemin de corde et/ou Zone&#10;" Grid.Row="4" />
<Label Text=" &#10;Les chemins de corde&#10;
Un chemin de corde est une suite de nombres qui se suivent exactement.&#10;
Au moment ou vous placez un nombre, s'il crée ou continue une suite avec un nombre voisin (croissant ou décroissant), un chemin de corde sera alors crée représenté par un trait reliant deux nombres &#10;
Si votre résultat peut être relié à plusieurs nombres voisins, vous devrez donc en choisir un seul. &#10;" Grid.Row="5" />
<Label Text="&#10;Deux types de cases &#10;
Cases de Base : 12 MAX Dans ces cases, vous ne pouvez avoir un nombre supérieur a 12. Si vous choisissez, ou êtes oblige, d'y mettre un résultat supérieur a 12, un symbole y sera mit a la place&#10;
Cases Dangereuses : 6 MAX Dans ces cases, il est INTERDIT d'y avoir un nombre strictement supérieur a 6. Si vous choisissez, ou êtes oblige, d'inscrire un résultat supérieur a 6 sur une case dangereuse un symbole y sera mit a la place&#10;
Un symbole donne un Malus en fin de partie. &#10;" Grid.Row="6" />
<Label Text=" &#10;Cartographier des zones&#10;
Une zone cartographiée est un groupe d'au moins 2 nombres contigus de même valeur.&#10;
Au moment ou vous placez un nombre, s'il est identique à un nombre voisin, il crée ou agrandit une zone.&#10;
Un motif sera alors représentez dans chaque case constituant la zone.&#10;" Grid.Row="7" />
<Label Text=" &#10;Fin de partie&#10;
Une fois que toutes les cases de la surface de jeu sont remplies la partie est alors terminé.La valeur des chemins de corde, des zones, des bonus et malus sont additionné.&#10;
Chemins de corde : Chaque Chemin de corde rapporte autant de points que son nombre le plus élevé, +1 point par autre case qui compose cette zone.&#10;
Zones : Chaque Zone cartographiée rapporte autant de points que le nombre de l'une de ses cases,+1 point par autre case qui compose cette zone.&#10;
Bonus : Votre plus long Chemin de corde ET votre plus grande Zone rapportent un bonus dépendant de leur taille.&#10;
Malus : Un symbole est placé dans chaque case orpheline (contenant un nombre qui n'appartient ni à une zone ni à un Chemin de corde)&#10;
Chaque symbole donne un malus de 3 points." Grid.Row="8"/>
</Grid>
</ScrollView>
<HorizontalStackLayout Grid.Row="2" HorizontalOptions="Center" Spacing="50">
<Button Text="Retour" WidthRequest="300" HeightRequest="60" CornerRadius="4"/>
<Button Text="Acheter" WidthRequest="300" HeightRequest="60" CornerRadius="4"/>
</HorizontalStackLayout>
</Grid>
</ContentPage.Content>
</ContentPage>

@ -0,0 +1,9 @@
namespace Trek_12.Views;
public partial class PageRegles : ContentPage
{
public PageRegles()
{
InitializeComponent();
}
}
Loading…
Cancel
Save