initialisation

This commit is contained in:
2025-05-21 16:15:27 +02:00
commit 8d22ffe40c
154 changed files with 8296 additions and 0 deletions

122
.gitignore vendored Normal file
View File

@@ -0,0 +1,122 @@
# Compiled class file
*.class
# class diagram file
*.mdj
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.idea/
*.iml
# CMake
cmake-build-debug/
# Mongo Explorer plugin:
.idea/**/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
nbproject/private/
build/
# Mac OS metafiles
.DS_Store

BIN
documents/CouleurWagon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,70 @@
@startuml
skinparam nodesep 220
skinparam ranksep 120
class Jeu {
- joueurCourant: Joueur
+ defausserCarteWagon(CouleurWagon): void
+ piocherCarteWagon(): CouleurWagon
+ retirerCarteWagonVisible(CouleurWagon): void
+ piocherDestination(): Destination
+ remplirCartesWagonVisibles() : void
}
class Joueur {
- couleur : Couleur
- nom : String
- nbWagons : int
- nbGares : int
- score : int
+ joueurTour()
+ choisirDestinations(List<Destination>, int)
}
enum CouleurWagon{
}
class Route {
- nom : String
- longueur : int
- couleur : CouleurWagon
}
class Tunnel {
}
class Ferry {
}
class Destination {
- ville1 : String
- ville2 : String
- valeur: int
}
class Ville {
- nom : String
}
Route <|-- Tunnel
Route <|-- Ferry
Joueur "joueurs 2..5 "--* Jeu
Joueur -left->"*" CouleurWagon
Joueur "0..1 propriétaire"--"* destinations" Destination
Joueur "0..1 proprietaire"<- Route
Ville "0..3"-right->"0..1 prorpietaire" Joueur
Jeu -->"*" Destination
Jeu -right->"*" Route
Route -right->"ville1" Ville
Route -right->"ville2" Ville
@enduml

BIN
documents/reseau_Europe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 KiB

55
nbactions.xml Normal file
View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<actions>
<action>
<actionName>run</actionName>
<packagings>
<packaging>jar</packaging>
</packagings>
<goals>
<goal>process-classes</goal>
<goal>org.codehaus.mojo:exec-maven-plugin:3.1.0:exec</goal>
</goals>
<properties>
<exec.vmArgs></exec.vmArgs>
<exec.args>${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}</exec.args>
<exec.appArgs></exec.appArgs>
<exec.mainClass>vue.GameServer</exec.mainClass>
<exec.executable>java</exec.executable>
</properties>
</action>
<action>
<actionName>debug</actionName>
<packagings>
<packaging>jar</packaging>
</packagings>
<goals>
<goal>process-classes</goal>
<goal>org.codehaus.mojo:exec-maven-plugin:3.1.0:exec</goal>
</goals>
<properties>
<exec.vmArgs>-agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address}</exec.vmArgs>
<exec.args>${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}</exec.args>
<exec.appArgs></exec.appArgs>
<exec.mainClass>vue.GameServer</exec.mainClass>
<exec.executable>java</exec.executable>
<jpda.listen>true</jpda.listen>
</properties>
</action>
<action>
<actionName>profile</actionName>
<packagings>
<packaging>jar</packaging>
</packagings>
<goals>
<goal>process-classes</goal>
<goal>org.codehaus.mojo:exec-maven-plugin:3.1.0:exec</goal>
</goals>
<properties>
<exec.vmArgs></exec.vmArgs>
<exec.args>${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}</exec.args>
<exec.mainClass>vue.GameServer</exec.mainClass>
<exec.executable>java</exec.executable>
<exec.appArgs></exec.appArgs>
</properties>
</action>
</actions>

94
pom.xml Normal file
View File

@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>SLAM</groupId>
<artifactId>Aventuriers-du-Rail</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.17</maven.compiler.source>
<maven.compiler.target>1.17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.4.0-M1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.4.0-M1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.4.0-M1</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.3.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-server</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-container-grizzly</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>17</source>
<target>17</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
ressources/images/euMap.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

View File

@@ -0,0 +1,77 @@
package modele;
import java.util.*;
/**
* Représentation des couleurs du jeu utilisées pour les cartes wagon et les joueurs
*/
public enum CouleurWagon {
NOIR, BLANC, JAUNE, ROUGE, ORANGE, BLEU, VERT, ROSE, GRIS, LOCOMOTIVE;
@Override
public String toString() {
return switch (this) {
case NOIR -> "Noir";
case BLANC -> "Blanc";
case JAUNE -> "Jaune";
case ROUGE -> "Rouge";
case ORANGE -> "Orange";
case BLEU -> "Bleu";
case VERT -> "Vert";
case ROSE -> "Rose";
case GRIS -> "Gris"; // représente une couleur indéterminée
case LOCOMOTIVE -> "Locomotive"; // peut remplacer n'importe quelle couleur
};
}
public String toLog() {
return String.format("<img class=\"couleur\" src=\"images/symbole-%s.png\"><span class=\"couleur %s\">%s</span>", name(), name().toLowerCase(), this);
}
/**
* Renvoie la liste des couleurs "simples" c'est-à-dire sans LOCOMOTIVE ni GRIS
*/
public static ArrayList<CouleurWagon> getCouleursSimples() {
return new ArrayList<>(List.of(NOIR, BLANC, JAUNE, ROUGE, ORANGE, BLEU, VERT, ROSE));
}
/**
* Renvoie la représentation sous forme d'une chaîne de caractères d'une liste
* non ordonnée de couleurs.
*
* La chaîne est constituée du nom de chaque couleur qui apparaît dans la liste,
* suivie éventuellement d'une chaîne de la forme " x n" où n est le nombre de
* fois que la couleur apparaît dans la liste, si n > 1. Les couleurs sont
* séparées par des virgules.
*
* @param liste une liste de couleurs (considérée comme non ordonnée)
* @return une chaîne de caractères décrivant les éléments qui apparaissent dans
* la liste
*/
public static String listToString(List<CouleurWagon> liste) {
StringJoiner joiner = new StringJoiner(", ");
for (CouleurWagon c : CouleurWagon.values()) {
int count = Collections.frequency(liste, c);
if (count == 1) {
joiner.add(c.toString());
} else if (count > 1) {
joiner.add(c.toString() + " x" + count);
}
}
return joiner.toString();
}
public static String listToLog(List<CouleurWagon> liste) {
StringJoiner joiner = new StringJoiner(", ");
for (CouleurWagon c : CouleurWagon.values()) {
int count = Collections.frequency(liste, c);
if (count == 1) {
joiner.add(c.toLog());
} else if (count > 1) {
joiner.add(c.toLog() + " x" + count);
}
}
return joiner.toString();
}
}

View File

@@ -0,0 +1,105 @@
package modele;
import java.util.ArrayList;
import java.util.HashMap;
public class Destination {
/**
* Ville de départ
*/
private String ville1;
/**
* Ville d'arrivée
*/
private String ville2;
/**
* Nombre de points que vaut la destination
*/
private int valeur;
public Destination(String ville1, String ville2, int valeur) {
this.ville1 = ville1;
this.ville2 = ville2;
this.valeur = valeur;
}
@Override
public String toString() {
return getNom();
}
public String getNom() {
return String.format("%s - %s (%d)", ville1, ville2, valeur);
}
public Object asPOJO() {
HashMap<String, Object> data = new HashMap<>();
data.put("ville1", ville1);
data.put("ville2", ville2);
data.put("valeur", valeur);
return data;
}
/**
* @return une liste contenant toutes les destinations "normales" du jeu
*/
public static ArrayList<Destination> makeDestinationsEurope() {
ArrayList<Destination> destinations = new ArrayList<>();
destinations.add(new Destination("Athina", "Angora", 5));
destinations.add(new Destination("Budapest", "Sofia", 5));
destinations.add(new Destination("Frankfurt", "Kobenhavn", 5));
destinations.add(new Destination("Rostov", "Erzurum", 5));
destinations.add(new Destination("Sofia", "Smyrna", 5));
destinations.add(new Destination("Kyiv", "Petrograd", 6));
destinations.add(new Destination("Zurich", "Brindisi", 6));
destinations.add(new Destination("Zurich", "Budapest", 6));
destinations.add(new Destination("Warszawa", "Smolensk", 6));
destinations.add(new Destination("Zagrab", "Brindisi", 6));
destinations.add(new Destination("Paris", "Zagrab", 7));
destinations.add(new Destination("Brest", "Marseille", 7));
destinations.add(new Destination("London", "Berlin", 7));
destinations.add(new Destination("Edinburgh", "Paris", 7));
destinations.add(new Destination("Amsterdam", "Pamplona", 7));
destinations.add(new Destination("Roma", "Smyrna", 8));
destinations.add(new Destination("Palermo", "Constantinople", 8));
destinations.add(new Destination("Sarajevo", "Sevastopol", 8));
destinations.add(new Destination("Madrid", "Dieppe", 8));
destinations.add(new Destination("Barcelona", "Bruxelles", 8));
destinations.add(new Destination("Paris", "Wien", 8));
destinations.add(new Destination("Barcelona", "Munchen", 8));
destinations.add(new Destination("Brest", "Venezia", 8));
destinations.add(new Destination("Smolensk", "Rostov", 8));
destinations.add(new Destination("Marseille", "Essen", 8));
destinations.add(new Destination("Kyiv", "Sochi", 8));
destinations.add(new Destination("Madrid", "Zurich", 8));
destinations.add(new Destination("Berlin", "Bucuresti", 8));
destinations.add(new Destination("Bruxelles", "Danzig", 9));
destinations.add(new Destination("Berlin", "Roma", 9));
destinations.add(new Destination("Angora", "Kharkov", 10));
destinations.add(new Destination("Riga", "Bucuresti", 10));
destinations.add(new Destination("Essen", "Kyiv", 10));
destinations.add(new Destination("Venezia", "Constantinople", 10));
destinations.add(new Destination("London", "Wien", 10));
destinations.add(new Destination("Athina", "Wilno", 11));
destinations.add(new Destination("Stockholm", "Wien", 11));
destinations.add(new Destination("Berlin", "Moskva", 12));
destinations.add(new Destination("Amsterdam", "Wilno", 12));
destinations.add(new Destination("Frankfurt", "Smolensk", 13));
return destinations;
}
/**
* @return une liste contenant toutes les destinations "longues" du jeu
*/
public static ArrayList<Destination> makeDestinationsLonguesEurope() {
ArrayList<Destination> destinations = new ArrayList<>();
destinations.add(new Destination("Lisboa", "Danzig", 20));
destinations.add(new Destination("Brest", "Petrograd", 20));
destinations.add(new Destination("Palermo", "Moskva", 20));
destinations.add(new Destination("Kobenhavn", "Erzurum", 21));
destinations.add(new Destination("Edinburgh", "Athina", 21));
destinations.add(new Destination("Cadiz", "Stockholm", 21));
return destinations;
}
}

View File

@@ -0,0 +1,20 @@
package modele;
public class Ferry extends Route {
/**
* Nombre de locomotives qu'un joueur doit payer pour capturer le ferry
*/
private int nbLocomotives;
public Ferry(Ville ville1, Ville ville2, int longueur, CouleurWagon couleur, int nbLocomotives) {
super(ville1, ville2, longueur, couleur);
this.nbLocomotives = nbLocomotives;
}
@Override
public String toString() {
return String.format("[%s - %s (%d, %s, %d)]", getVille1(), getVille2(), getLongueur(), getCouleur(),
nbLocomotives);
}
}

View File

@@ -0,0 +1,309 @@
package modele;
import com.google.gson.Gson;
import vue.GameServer;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.stream.Collectors;
public class Jeu implements Runnable {
/**
* Liste des joueurs
*/
private List<Joueur> joueurs;
/**
* Le joueur dont c'est le tour
*/
private Joueur joueurCourant;
/**
* Liste des villes représentées sur le plateau de jeu
*/
private List<Ville> villes;
/**
* Liste des routes du plateau de jeu
*/
private List<Route> routes;
/**
* Pile de pioche (face cachée)
*/
private List<CouleurWagon> pileCartesWagon;
/**
* Cartes de la pioche face visible (normalement il y a 5 cartes face visible)
*/
private List<CouleurWagon> cartesWagonVisibles;
/**
* Pile de cartes qui ont été défaussée au cours de la partie
*/
private List<CouleurWagon> defausseCartesWagon;
/**
* Pile des cartes "Destination" (uniquement les destinations "courtes", les
* destinations "longues" sont distribuées au début de la partie et ne peuvent
* plus être piochées après)
*/
private List<Destination> pileDestinations;
/**
* File d'attente des instructions recues par le serveur
*/
private BlockingQueue<String> inputQueue;
/**
* Messages d'information du jeu
*/
private List<String> log;
public Jeu(String[] nomJoueurs) {
/*
* ATTENTION : Cette méthode est à réécrire.
*
* Le code indiqué ici est un squelette minimum pour que le jeu se lance et que
* l'interface graphique fonctionne.
* Vous devez modifier ce code pour que les différents éléments du jeu soient
* correctement initialisés.
*/
// initialisation des entrées/sorties
inputQueue = new LinkedBlockingQueue<>();
log = new ArrayList<>();
// création des cartes
pileCartesWagon = new ArrayList<>();
cartesWagonVisibles = new ArrayList<>();
defausseCartesWagon = new ArrayList<>();
pileDestinations = new ArrayList<>();
// création des joueurs
ArrayList<Joueur.Couleur> couleurs = new ArrayList<>(Arrays.asList(Joueur.Couleur.values()));
Collections.shuffle(couleurs);
joueurs = new ArrayList<>();
for (String nom : nomJoueurs) {
Joueur joueur = new Joueur(nom, this, couleurs.remove(0));
joueurs.add(joueur);
}
joueurCourant = joueurs.get(0);
// création des villes et des routes
Plateau plateau = Plateau.makePlateauEurope();
villes = plateau.getVilles();
routes = plateau.getRoutes();
}
public List<CouleurWagon> getPileCartesWagon() {
return pileCartesWagon;
}
public List<CouleurWagon> getCartesWagonVisibles() {
return cartesWagonVisibles;
}
public List<Ville> getVilles() {
return villes;
}
public List<Route> getRoutes() {
return routes;
}
public Joueur getJoueurCourant() {
return joueurCourant;
}
/**
* Exécute la partie
*/
public void run() {
/*
* ATTENTION : Cette méthode est à réécrire.
*
* Cette méthode doit :
* - faire choisir à chaque joueur les destinations initiales qu'il souhaite
* garder : on pioche 3 destinations "courtes" et 1 destination "longue", puis
* le
* joueur peut choisir des destinations à défausser ou passer s'il ne veut plus
* en défausser. Il doit en garder au moins 2.
* - exécuter la boucle principale du jeu qui fait jouer le tour de chaque
* joueur à tour de rôle jusqu'à ce qu'un des joueurs n'ait plus que 2 wagons ou
* moins
* - exécuter encore un dernier tour de jeu pour chaque joueur après
*/
/**
* Le code proposé ici n'est qu'un exemple d'utilisation des méthodes pour
* interagir avec l'utilisateur, il n'a rien à voir avec le code de la partie et
* doit donc être entièrement réécrit.
*/
// Exemple d'utilisation
while (true) {
// le joueur doit choisir une valeur parmi "1", "2", "3", "4", "6" ou "8"
// les choix possibles sont présentés sous forme de boutons cliquables
String choix = joueurCourant.choisir(
"Choisissez une taille de route.", // instruction
new ArrayList<>(), // choix (hors boutons, ici aucun)
new ArrayList<>(Arrays.asList("1", "2", "3", "4", "6", "8")), // boutons
false); // le joueur ne peut pas passer (il doit faire un choix)
// une fois la longueur choisie, on filtre les routes pour ne garder que les
// routes de la longueur choisie
int longueurRoute = Integer.parseInt(choix);
ArrayList<String> routesPossibles = new ArrayList<>();
for (Route route : routes) {
if (route.getLongueur() == longueurRoute) {
routesPossibles.add(route.getNom());
}
}
// le joueur doit maintenant choisir une route de la longueur choisie (les
// autres ne sont pas acceptées). Le joueur peut choisir de passer (aucun choix)
String choixRoute = joueurCourant.choisir(
"Choisissez une route de longueur " + longueurRoute, // instruction
routesPossibles, // choix (pas des boutons, il faut cliquer sur la carte)
new ArrayList<>(), // boutons (ici aucun bouton créé)
true); // le joueur peut passer sans faire de choix
if (choixRoute.equals("")) {
// le joueur n'a pas fait de choix (cliqué sur le bouton "passer")
log("Auncune route n'a été choisie");
} else {
// le joueur a choisi une route
log("Vous avez choisi la route " + choixRoute);
}
}
}
/**
* Ajoute une carte dans la pile de défausse.
* Dans le cas peu probable, où il y a moins de 5 cartes wagon face visibles
* (parce que la pioche
* et la défausse sont vides), alors il faut immédiatement rendre cette carte
* face visible.
*
* @param c carte à défausser
*/
public void defausserCarteWagon(CouleurWagon c) {
throw new RuntimeException("Méthode non implémentée !");
}
/**
* Pioche une carte de la pile de pioche
* Si la pile est vide, les cartes de la défausse sont replacées dans la pioche
* puis mélangées avant de piocher une carte
*
* @return la carte qui a été piochée (ou null si aucune carte disponible)
*/
public CouleurWagon piocherCarteWagon() {
throw new RuntimeException("Méthode non implémentée !");
}
/**
* Retire une carte wagon de la pile des cartes wagon visibles.
* Si une carte a été retirée, la pile de cartes wagons visibles est recomplétée
* (remise à 5, éventuellement remélangée si 3 locomotives visibles)
*/
public void retirerCarteWagonVisible(CouleurWagon c) {
throw new RuntimeException("Méthode non implémentée !");
}
/**
* Pioche et renvoie la destination du dessus de la pile de destinations.
*
* @return la destination qui a été piochée (ou `null` si aucune destination
* disponible)
*/
public Destination piocherDestination() {
throw new RuntimeException("Méthode non implémentée !");
}
public List<Joueur> getJoueurs() {
return joueurs;
}
@Override
public String toString() {
StringJoiner joiner = new StringJoiner("\n");
for (Joueur j : joueurs) {
joiner.add(j.toString());
}
return joiner.toString();
}
/**
* Ajoute un message au log du jeu
*/
public void log(String message) {
log.add(message);
}
/**
* Ajoute un message à la file d'entrées
*/
public void addInput(String message) {
inputQueue.add(message);
}
/**
* Lit une ligne de l'entrée standard
* C'est cette méthode qui doit être appelée à chaque fois qu'on veut lire
* l'entrée clavier de l'utilisateur (par exemple dans {@code Player.choisir})
*
* @return une chaîne de caractères correspondant à l'entrée suivante dans la
* file
*/
public String lireLigne() {
try {
return inputQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
/**
* Envoie l'état de la partie pour affichage aux joueurs avant de faire un choix
*
* @param instruction l'instruction qui est donnée au joueur
* @param boutons labels des choix proposés s'il y en a
* @param peutPasser indique si le joueur peut passer sans faire de choix
*/
public void prompt(String instruction, Collection<String> boutons, boolean peutPasser) {
System.out.println();
System.out.println(this);
if (boutons.isEmpty()) {
System.out.printf(">>> %s: %s <<<%n", joueurCourant.getNom(), instruction);
} else {
StringJoiner joiner = new StringJoiner(" / ");
for (String bouton : boutons) {
joiner.add(bouton);
}
System.out.printf(">>> %s: %s [%s] <<<%n", joueurCourant.getNom(), instruction, joiner);
}
Map<String, Object> data = Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("prompt", Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("instruction", instruction),
new AbstractMap.SimpleEntry<String, Object>("boutons", boutons),
new AbstractMap.SimpleEntry<String, Object>("nomJoueurCourant", getJoueurCourant().getNom()),
new AbstractMap.SimpleEntry<String, Object>("peutPasser", peutPasser))),
new AbstractMap.SimpleEntry<>("villes",
villes.stream().map(Ville::asPOJO).collect(Collectors.toList())),
new AbstractMap.SimpleEntry<>("routes",
routes.stream().map(Route::asPOJO).collect(Collectors.toList())),
new AbstractMap.SimpleEntry<String, Object>("joueurs",
joueurs.stream().map(Joueur::asPOJO).collect(Collectors.toList())),
new AbstractMap.SimpleEntry<String, Object>("piles", Map.ofEntries(
new AbstractMap.SimpleEntry<String, Object>("pileCartesWagon", pileCartesWagon.size()),
new AbstractMap.SimpleEntry<String, Object>("pileDestinations", pileDestinations.size()),
new AbstractMap.SimpleEntry<String, Object>("defausseCartesWagon", defausseCartesWagon),
new AbstractMap.SimpleEntry<String, Object>("cartesWagonVisibles", cartesWagonVisibles))),
new AbstractMap.SimpleEntry<String, Object>("log", log));
GameServer.setEtatJeu(new Gson().toJson(data));
}
public List<CouleurWagon> getDefausseCartesWagon() {
return defausseCartesWagon;
}
public List<Destination> getPileDestinations() {
return null;
}
}

View File

@@ -0,0 +1,269 @@
package modele;
import java.util.*;
import java.util.stream.Collectors;
public class Joueur {
public int getNbGares() {
return 0;
}
public int getScore() {
return 0;
}
/**
* Les couleurs possibles pour les joueurs (pour l'interface graphique)
*/
public static enum Couleur {
JAUNE, ROUGE, BLEU, VERT, ROSE;
}
/**
* Jeu auquel le joueur est rattaché
*/
private Jeu jeu;
/**
* Nom du joueur
*/
private String nom;
/**
* CouleurWagon du joueur (pour représentation sur le plateau)
*/
private Couleur couleur;
/**
* Nombre de gares que le joueur peut encore poser sur le plateau
*/
private int nbGares;
/**
* Nombre de wagons que le joueur peut encore poser sur le plateau
*/
private int nbWagons;
/**
* Liste des missions à réaliser pendant la partie
*/
private List<Destination> destinations;
/**
* Liste des cartes que le joueur a en main
*/
private List<CouleurWagon> cartesWagon;
/**
* Liste temporaire de cartes wagon que le joueur est en train de jouer pour
* payer la capture d'une route ou la construction d'une gare
*/
private List<CouleurWagon> cartesWagonPosees;
/**
* Score courant du joueur (somme des valeurs des routes capturées)
*/
private int score;
public Joueur(String nom, Jeu jeu, Joueur.Couleur couleur) {
this.nom = nom;
this.jeu = jeu;
this.couleur = couleur;
nbGares = 3;
nbWagons = 45;
cartesWagon = new ArrayList<>();
cartesWagonPosees = new ArrayList<>();
destinations = new ArrayList<>();
score = 12; // chaque gare non utilisée vaut 4 points
}
public String getNom() {
return nom;
}
public Couleur getCouleur() {
return couleur;
}
public int getNbWagons() {
return nbWagons;
}
public Jeu getJeu() {
return jeu;
}
public List<CouleurWagon> getCartesWagonPosees() {
return cartesWagonPosees;
}
public List<CouleurWagon> getCartesWagon() {
return cartesWagon;
}
public List<Destination> getDestinations() {
return destinations;
}
/**
* Attend une entrée de la part du joueur (au clavier ou sur la websocket) et
* renvoie le choix du joueur.
* <p>
* Cette méthode lit les entrées du jeu ({@code Jeu.lireligne()}) jusqu'à ce
* qu'un choix valide (un élément de {@code choix} ou de {@code boutons} ou
* éventuellement la chaîne vide si l'utilisateur est autorisé à passer) soit
* reçu.
* Lorsqu'un choix valide est obtenu, il est renvoyé par la fonction.
* <p>
* Si l'ensemble des choix valides ({@code choix} + {@code boutons}) ne comporte
* qu'un seul élément et que {@code canPass} est faux, l'unique choix valide est
* automatiquement renvoyé sans lire l'entrée de l'utilisateur.
* <p>
* Si l'ensemble des choix est vide, la chaîne vide ("") est automatiquement
* renvoyée par la méthode (indépendamment de la valeur de {@code canPass}).
* <p>
* Exemple d'utilisation pour demander à un joueur de répondre à une question
* par "oui" ou "non" :
* <p>
* {@code
* List<String> choix = Arrays.asList("Oui", "Non");
* String input = choisir("Voulez vous faire ceci ?", choix, new ArrayList<>(), false);
* }
* <p>
* <p>
* Si par contre on voulait proposer les réponses à l'aide de boutons, on
* pourrait utiliser :
* <p>
* {@code
* List<String> boutons = Arrays.asList("1", "2", "3");
* String input = choisir("Choisissez un nombre.", new ArrayList<>(), boutons, false);
* }
*
* @param instruction message à afficher à l'écran pour indiquer au joueur la
* nature du choix qui est attendu
* @param choix une collection de chaînes de caractères correspondant aux
* choix valides attendus du joueur
* @param boutons une collection de chaînes de caractères correspondant aux
* choix valides attendus du joueur qui doivent être
* représentés par des boutons sur l'interface graphique.
* @param peutPasser booléen indiquant si le joueur a le droit de passer sans
* faire de choix. S'il est autorisé à passer, c'est la
* chaîne de caractères vide ("") qui signifie qu'il désire
* passer.
* @return le choix de l'utilisateur (un élément de {@code choix}, ou de
* {@code boutons} ou la chaîne vide)
*/
public String choisir(String instruction, Collection<String> choix, Collection<String> boutons,
boolean peutPasser) {
// on retire les doublons de la liste des choix
HashSet<String> choixDistincts = new HashSet<>();
choixDistincts.addAll(choix);
choixDistincts.addAll(boutons);
// Aucun choix disponible
if (choixDistincts.isEmpty()) {
return "";
} else {
// Un seul choix possible (renvoyer cet unique élément)
if (choixDistincts.size() == 1 && !peutPasser)
return choixDistincts.iterator().next();
else {
String entree;
// Lit l'entrée de l'utilisateur jusqu'à obtenir un choix valide
while (true) {
jeu.prompt(instruction, boutons, peutPasser);
entree = jeu.lireLigne();
// si une réponse valide est obtenue, elle est renvoyée
if (choixDistincts.contains(entree) || (peutPasser && entree.equals("")))
return entree;
}
}
}
}
/**
* Affiche un message dans le log du jeu (visible sur l'interface graphique)
*
* @param message le message à afficher (peut contenir des balises html pour la
* mise en forme)
*/
public void log(String message) {
jeu.log(message);
}
@Override
public String toString() {
StringJoiner joiner = new StringJoiner("\n");
joiner.add(String.format("=== %s (%d pts) ===", nom, score));
joiner.add(String.format(" Gares: %d, Wagons: %d", nbGares, nbWagons));
joiner.add(" Destinations: "
+ destinations.stream().map(Destination::toString).collect(Collectors.joining(", ")));
joiner.add(" Cartes wagon: " + CouleurWagon.listToString(cartesWagon));
return joiner.toString();
}
/**
* @return une chaîne de caractères contenant le nom du joueur, avec des balises
* HTML pour être mis en forme dans le log
*/
public String toLog() {
return String.format("<span class=\"joueur\">%s</span>", nom);
}
/**
* Renvoie une représentation du joueur sous la forme d'un objet Java simple
* (POJO)
*/
public Object asPOJO() {
HashMap<String, Object> data = new HashMap<>();
data.put("nom", nom);
data.put("couleur", couleur);
data.put("score", score);
data.put("nbGares", nbGares);
data.put("nbWagons", nbWagons);
data.put("estJoueurCourant", this == jeu.getJoueurCourant());
data.put("destinations", destinations.stream().map(Destination::asPOJO).collect(Collectors.toList()));
data.put("cartesWagon", cartesWagon.stream().sorted().map(CouleurWagon::name).collect(Collectors.toList()));
data.put("cartesWagonPosees",
cartesWagonPosees.stream().sorted().map(CouleurWagon::name).collect(Collectors.toList()));
return data;
}
/**
* Propose une liste de cartes destinations, parmi lesquelles le joueur doit en
* garder un nombre minimum n.
* <p>
* Tant que le nombre de destinations proposées est strictement supérieur à n,
* le joueur peut choisir une des destinations qu'il retire de la liste des
* choix, ou passer (en renvoyant la chaîne de caractères vide).
* <p>
* Les destinations qui ne sont pas écartées sont ajoutées à la liste des
* destinations du joueur. Les destinations écartées sont renvoyées par la
* fonction.
*
* @param destinationsPossibles liste de destinations proposées parmi lesquelles
* le joueur peut choisir d'en écarter certaines
* @param n nombre minimum de destinations que le joueur
* doit garder
* @return liste des destinations qui n'ont pas été gardées par le joueur
*/
public List<Destination> choisirDestinations(List<Destination> destinationsPossibles, int n) {
throw new RuntimeException("Méthode non implémentée !");
}
/**
* Exécute un tour de jeu du joueur.
* <p>
* Cette méthode attend que le joueur choisisse une des options suivantes :
* - le nom d'une carte wagon face visible à prendre ;
* - le nom "GRIS" pour piocher une carte wagon face cachée s'il reste des
* cartes à piocher dans la pile de pioche ou dans la pile de défausse ;
* - la chaîne "destinations" pour piocher des cartes destination ;
* - le nom d'une ville sur laquelle il peut construire une gare (ville non
* prise par un autre joueur, le joueur a encore des gares en réserve et assez
* de cartes wagon pour construire la gare) ;
* - le nom d'une route que le joueur peut capturer (pas déjà capturée, assez de
* wagons et assez de cartes wagon) ;
* - la chaîne de caractères vide pour passer son tour
* <p>
* Lorsqu'un choix valide est reçu, l'action est exécutée (il est possible que
* l'action nécessite d'autres choix de la part de l'utilisateur, comme "choisir les cartes wagon à défausser pour capturer une route" ou
* "construire une gare", "choisir les destinations à défausser", etc.)
*/
public void jouerTour() {
throw new RuntimeException("Méthode non implémentée !");
}
}

View File

@@ -0,0 +1,197 @@
package modele;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Plateau {
/**
* Liste des villes
*/
private final List<Ville> villes;
/**
* Liste des routes
*/
private final List<Route> routes;
public Plateau(List<Ville> villes, List<Route> routes) {
this.villes = villes;
this.routes = routes;
}
public List<Ville> getVilles() {
return villes;
}
public List<Route> getRoutes() {
return routes;
}
static public Plateau makePlateauEurope() {
Map<String, Ville> villes = new HashMap<>();
villes.put("amsterdam", new Ville("Amsterdam"));
villes.put("angora", new Ville("Angora"));
villes.put("athina", new Ville("Athina"));
villes.put("barcelona", new Ville("Barcelona"));
villes.put("berlin", new Ville("Berlin"));
villes.put("brest", new Ville("Brest"));
villes.put("brindisi", new Ville("Brindisi"));
villes.put("bruxelles", new Ville("Bruxelles"));
villes.put("bucuresti", new Ville("Bucuresti"));
villes.put("budapest", new Ville("Budapest"));
villes.put("cadiz", new Ville("Cadiz"));
villes.put("constantinople", new Ville("Constantinople"));
villes.put("danzig", new Ville("Danzig"));
villes.put("dieppe", new Ville("Dieppe"));
villes.put("edinburgh", new Ville("Edinburgh"));
villes.put("erzurum", new Ville("Erzurum"));
villes.put("essen", new Ville("Essen"));
villes.put("frankfurt", new Ville("Frankfurt"));
villes.put("kharkov", new Ville("Kharkov"));
villes.put("kobenhavn", new Ville("Kobenhavn"));
villes.put("kyiv", new Ville("Kyiv"));
villes.put("lisboa", new Ville("Lisboa"));
villes.put("london", new Ville("London"));
villes.put("madrid", new Ville("Madrid"));
villes.put("marseille", new Ville("Marseille"));
villes.put("moskva", new Ville("Moskva"));
villes.put("munchen", new Ville("Munchen"));
villes.put("palermo", new Ville("Palermo"));
villes.put("pamplona", new Ville("Pamplona"));
villes.put("paris", new Ville("Paris"));
villes.put("petrograd", new Ville("Petrograd"));
villes.put("riga", new Ville("Riga"));
villes.put("roma", new Ville("Roma"));
villes.put("rostov", new Ville("Rostov"));
villes.put("sarajevo", new Ville("Sarajevo"));
villes.put("sevastopol", new Ville("Sevastopol"));
villes.put("smolensk", new Ville("Smolensk"));
villes.put("smyrna", new Ville("Smyrna"));
villes.put("sochi", new Ville("Sochi"));
villes.put("sofia", new Ville("Sofia"));
villes.put("stockholm", new Ville("Stockholm"));
villes.put("venezia", new Ville("Venezia"));
villes.put("warszawa", new Ville("Warszawa"));
villes.put("wien", new Ville("Wien"));
villes.put("wilno", new Ville("Wilno"));
villes.put("zagrab", new Ville("Zagrab"));
villes.put("zurich", new Ville("Zurich"));
ArrayList<Route> routes = new ArrayList<>();
routes.add(new Route(villes.get("amsterdam"), villes.get("bruxelles"), 1, CouleurWagon.NOIR));
routes.add(new Route(villes.get("amsterdam"), villes.get("essen"), 3, CouleurWagon.JAUNE));
routes.add(new Route(villes.get("amsterdam"), villes.get("frankfurt"), 2, CouleurWagon.BLANC));
routes.add(new Ferry(villes.get("amsterdam"), villes.get("london"), 2, CouleurWagon.GRIS, 2));
routes.add(new Tunnel(villes.get("angora"), villes.get("constantinople"), 2, CouleurWagon.GRIS));
routes.add(new Route(villes.get("angora"), villes.get("erzurum"), 3, CouleurWagon.NOIR));
routes.add(new Tunnel(villes.get("angora"), villes.get("smyrna"), 3, CouleurWagon.ORANGE));
routes.add(new Ferry(villes.get("athina"), villes.get("brindisi"), 4, CouleurWagon.GRIS, 1));
routes.add(new Route(villes.get("athina"), villes.get("sarajevo"), 4, CouleurWagon.VERT));
routes.add(new Ferry(villes.get("athina"), villes.get("smyrna"), 2, CouleurWagon.GRIS, 1));
routes.add(new Route(villes.get("athina"), villes.get("sofia"), 3, CouleurWagon.ROSE));
routes.add(new Route(villes.get("barcelona"), villes.get("madrid"), 2, CouleurWagon.JAUNE));
routes.add(new Route(villes.get("barcelona"), villes.get("marseille"), 4, CouleurWagon.GRIS));
routes.add(new Tunnel(villes.get("barcelona"), villes.get("pamplona"), 2, CouleurWagon.GRIS));
routes.add(new Route(villes.get("berlin"), villes.get("danzig"), 4, CouleurWagon.GRIS));
routes.add(new Route(villes.get("berlin"), villes.get("essen"), 2, CouleurWagon.BLEU));
routes.add(new Route(villes.get("berlin"), villes.get("frankfurt"), 3, CouleurWagon.ROUGE));
routes.add(new Route(villes.get("berlin"), villes.get("frankfurt"), 3, CouleurWagon.NOIR));
routes.add(new Route(villes.get("berlin"), villes.get("warszawa"), 4, CouleurWagon.JAUNE));
routes.add(new Route(villes.get("berlin"), villes.get("warszawa"), 4, CouleurWagon.ROSE));
routes.add(new Route(villes.get("berlin"), villes.get("wien"), 3, CouleurWagon.VERT));
routes.add(new Route(villes.get("brest"), villes.get("dieppe"), 2, CouleurWagon.ORANGE));
routes.add(new Route(villes.get("brest"), villes.get("pamplona"), 4, CouleurWagon.ROSE));
routes.add(new Route(villes.get("brest"), villes.get("paris"), 3, CouleurWagon.NOIR));
routes.add(new Ferry(villes.get("brindisi"), villes.get("palermo"), 3, CouleurWagon.GRIS, 1));
routes.add(new Route(villes.get("brindisi"), villes.get("roma"), 2, CouleurWagon.BLANC));
routes.add(new Route(villes.get("bruxelles"), villes.get("dieppe"), 2, CouleurWagon.VERT));
routes.add(new Route(villes.get("bruxelles"), villes.get("frankfurt"), 2, CouleurWagon.BLEU));
routes.add(new Route(villes.get("bruxelles"), villes.get("paris"), 2, CouleurWagon.JAUNE));
routes.add(new Route(villes.get("bruxelles"), villes.get("paris"), 2, CouleurWagon.ROUGE));
routes.add(new Tunnel(villes.get("bucuresti"), villes.get("budapest"), 4, CouleurWagon.GRIS));
routes.add(new Route(villes.get("bucuresti"), villes.get("constantinople"), 3, CouleurWagon.JAUNE));
routes.add(new Route(villes.get("bucuresti"), villes.get("kyiv"), 4, CouleurWagon.GRIS));
routes.add(new Route(villes.get("bucuresti"), villes.get("sevastopol"), 4, CouleurWagon.BLANC));
routes.add(new Tunnel(villes.get("bucuresti"), villes.get("sofia"), 2, CouleurWagon.GRIS));
routes.add(new Tunnel(villes.get("budapest"), villes.get("kyiv"), 6, CouleurWagon.GRIS));
routes.add(new Route(villes.get("budapest"), villes.get("sarajevo"), 3, CouleurWagon.ROSE));
routes.add(new Route(villes.get("budapest"), villes.get("wien"), 1, CouleurWagon.ROUGE));
routes.add(new Route(villes.get("budapest"), villes.get("wien"), 1, CouleurWagon.BLANC));
routes.add(new Route(villes.get("budapest"), villes.get("zagrab"), 2, CouleurWagon.ORANGE));
routes.add(new Route(villes.get("cadiz"), villes.get("lisboa"), 2, CouleurWagon.BLEU));
routes.add(new Route(villes.get("cadiz"), villes.get("madrid"), 3, CouleurWagon.ORANGE));
routes.add(new Ferry(villes.get("constantinople"), villes.get("sevastopol"), 4, CouleurWagon.GRIS, 2));
routes.add(new Tunnel(villes.get("constantinople"), villes.get("smyrna"), 2, CouleurWagon.GRIS));
routes.add(new Route(villes.get("constantinople"), villes.get("sofia"), 3, CouleurWagon.BLEU));
routes.add(new Route(villes.get("danzig"), villes.get("riga"), 3, CouleurWagon.NOIR));
routes.add(new Route(villes.get("danzig"), villes.get("warszawa"), 2, CouleurWagon.GRIS));
routes.add(new Ferry(villes.get("dieppe"), villes.get("london"), 2, CouleurWagon.GRIS, 1));
routes.add(new Ferry(villes.get("dieppe"), villes.get("london"), 2, CouleurWagon.GRIS, 1));
routes.add(new Route(villes.get("dieppe"), villes.get("paris"), 1, CouleurWagon.ROSE));
routes.add(new Route(villes.get("edinburgh"), villes.get("london"), 4, CouleurWagon.ORANGE));
routes.add(new Route(villes.get("edinburgh"), villes.get("london"), 4, CouleurWagon.NOIR));
routes.add(new Ferry(villes.get("erzurum"), villes.get("sevastopol"), 4, CouleurWagon.GRIS, 2));
routes.add(new Tunnel(villes.get("erzurum"), villes.get("sochi"), 3, CouleurWagon.ROUGE));
routes.add(new Route(villes.get("essen"), villes.get("frankfurt"), 2, CouleurWagon.VERT));
routes.add(new Ferry(villes.get("essen"), villes.get("kobenhavn"), 3, CouleurWagon.GRIS, 1));
routes.add(new Ferry(villes.get("essen"), villes.get("kobenhavn"), 3, CouleurWagon.GRIS, 1));
routes.add(new Route(villes.get("frankfurt"), villes.get("munchen"), 2, CouleurWagon.ROSE));
routes.add(new Route(villes.get("frankfurt"), villes.get("paris"), 3, CouleurWagon.ORANGE));
routes.add(new Route(villes.get("frankfurt"), villes.get("paris"), 3, CouleurWagon.BLANC));
routes.add(new Route(villes.get("kharkov"), villes.get("kyiv"), 4, CouleurWagon.GRIS));
routes.add(new Route(villes.get("kharkov"), villes.get("moskva"), 4, CouleurWagon.GRIS));
routes.add(new Route(villes.get("kharkov"), villes.get("rostov"), 2, CouleurWagon.VERT));
routes.add(new Route(villes.get("kobenhavn"), villes.get("stockholm"), 3, CouleurWagon.JAUNE));
routes.add(new Route(villes.get("kobenhavn"), villes.get("stockholm"), 3, CouleurWagon.BLANC));
routes.add(new Route(villes.get("kyiv"), villes.get("smolensk"), 3, CouleurWagon.ROUGE));
routes.add(new Route(villes.get("kyiv"), villes.get("warszawa"), 4, CouleurWagon.GRIS));
routes.add(new Route(villes.get("kyiv"), villes.get("wilno"), 2, CouleurWagon.GRIS));
routes.add(new Route(villes.get("lisboa"), villes.get("madrid"), 3, CouleurWagon.ROSE));
routes.add(new Tunnel(villes.get("madrid"), villes.get("pamplona"), 3, CouleurWagon.BLANC));
routes.add(new Tunnel(villes.get("madrid"), villes.get("pamplona"), 3, CouleurWagon.NOIR));
routes.add(new Route(villes.get("marseille"), villes.get("pamplona"), 4, CouleurWagon.ROUGE));
routes.add(new Route(villes.get("marseille"), villes.get("paris"), 4, CouleurWagon.GRIS));
routes.add(new Tunnel(villes.get("marseille"), villes.get("roma"), 4, CouleurWagon.GRIS));
routes.add(new Tunnel(villes.get("marseille"), villes.get("zurich"), 2, CouleurWagon.ROSE));
routes.add(new Route(villes.get("moskva"), villes.get("petrograd"), 4, CouleurWagon.BLANC));
routes.add(new Route(villes.get("moskva"), villes.get("smolensk"), 2, CouleurWagon.ORANGE));
routes.add(new Tunnel(villes.get("munchen"), villes.get("venezia"), 2, CouleurWagon.BLEU));
routes.add(new Route(villes.get("munchen"), villes.get("wien"), 3, CouleurWagon.ORANGE));
routes.add(new Tunnel(villes.get("munchen"), villes.get("zurich"), 2, CouleurWagon.JAUNE));
routes.add(new Ferry(villes.get("palermo"), villes.get("roma"), 4, CouleurWagon.GRIS, 1));
routes.add(new Ferry(villes.get("palermo"), villes.get("smyrna"), 6, CouleurWagon.GRIS, 2));
routes.add(new Route(villes.get("pamplona"), villes.get("paris"), 4, CouleurWagon.BLEU));
routes.add(new Route(villes.get("pamplona"), villes.get("paris"), 4, CouleurWagon.VERT));
routes.add(new Tunnel(villes.get("paris"), villes.get("zurich"), 3, CouleurWagon.GRIS));
routes.add(new Route(villes.get("petrograd"), villes.get("riga"), 4, CouleurWagon.GRIS));
routes.add(new Tunnel(villes.get("petrograd"), villes.get("stockholm"), 8, CouleurWagon.GRIS));
routes.add(new Route(villes.get("petrograd"), villes.get("wilno"), 4, CouleurWagon.BLEU));
routes.add(new Route(villes.get("riga"), villes.get("wilno"), 4, CouleurWagon.VERT));
routes.add(new Route(villes.get("roma"), villes.get("venezia"), 2, CouleurWagon.NOIR));
routes.add(new Route(villes.get("rostov"), villes.get("sevastopol"), 4, CouleurWagon.GRIS));
routes.add(new Route(villes.get("rostov"), villes.get("sochi"), 2, CouleurWagon.GRIS));
routes.add(new Tunnel(villes.get("sarajevo"), villes.get("sofia"), 2, CouleurWagon.GRIS));
routes.add(new Route(villes.get("sarajevo"), villes.get("zagrab"), 3, CouleurWagon.ROUGE));
routes.add(new Ferry(villes.get("sevastopol"), villes.get("sochi"), 2, CouleurWagon.GRIS, 1));
routes.add(new Route(villes.get("smolensk"), villes.get("wilno"), 3, CouleurWagon.JAUNE));
routes.add(new Route(villes.get("venezia"), villes.get("zagrab"), 2, CouleurWagon.GRIS));
routes.add(new Tunnel(villes.get("venezia"), villes.get("zurich"), 2, CouleurWagon.VERT));
routes.add(new Route(villes.get("warszawa"), villes.get("wien"), 4, CouleurWagon.BLEU));
routes.add(new Route(villes.get("warszawa"), villes.get("wilno"), 3, CouleurWagon.ROUGE));
routes.add(new Route(villes.get("wien"), villes.get("zagrab"), 2, CouleurWagon.GRIS));
// Correction du nom pour les routes doubles
for (int i = 0; i < routes.size(); i++) {
Route r1 = routes.get(i);
if (i < routes.size() - 1) {
Route r2 = routes.get(i + 1);
if (r1.getNom().equals(r2.getNom())) {
r1.setNom(r1.getNom() + "(1)");
r2.setNom(r2.getNom() + "(2)");
}
}
}
return new Plateau(new ArrayList<>(villes.values()), routes);
}
}

View File

@@ -0,0 +1,93 @@
package modele;
import java.util.HashMap;
public class Route {
/**
* Première extrémité
*/
private Ville ville1;
/**
* Deuxième extrémité
*/
private Ville ville2;
/**
* Nombre de segments
*/
private int longueur;
/**
* CouleurWagon pour capturer la route (éventuellement GRIS, mais pas LOCOMOTIVE)
*/
private CouleurWagon couleur;
/**
* Joueur qui a capturé la route (`null` si la route est encore à prendre)
*/
private Joueur proprietaire;
/**
* Nom unique de la route. Ce nom est nécessaire pour résoudre l'ambiguïté entre les routes doubles
* (voir la classe Plateau pour plus de clarté)
*/
private String nom;
public Route(Ville ville1, Ville ville2, int longueur, CouleurWagon couleur) {
this.ville1 = ville1;
this.ville2 = ville2;
this.longueur = longueur;
this.couleur = couleur;
nom = ville1.getNom() + " - " + ville2.getNom();
proprietaire = null;
}
public Ville getVille1() {
return ville1;
}
public Ville getVille2() {
return ville2;
}
public int getLongueur() {
return longueur;
}
public CouleurWagon getCouleur() {
return couleur;
}
public Joueur getProprietaire() {
return proprietaire;
}
public void setProprietaire(Joueur proprietaire) {
this.proprietaire = proprietaire;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String toLog() {
return String.format("<span class=\"route\">%s - %s</span>", ville1.getNom(), ville2.getNom());
}
@Override
public String toString() {
return String.format("[%s - %s (%d, %s)]", ville1, ville2, longueur, couleur);
}
/**
* @return un objet simple représentant les informations de la route
*/
public Object asPOJO() {
HashMap<String, Object> data = new HashMap<>();
data.put("nom", getNom());
if (proprietaire != null) {
data.put("proprietaire", proprietaire.getCouleur());
}
return data;
}
}

View File

@@ -0,0 +1,13 @@
package modele;
public class Tunnel extends Route {
public Tunnel(Ville ville1, Ville ville2, int longueur, CouleurWagon couleur) {
super(ville1, ville2, longueur, couleur);
}
@Override
public String toString() {
return "[" + super.toString() + "]";
}
}

View File

@@ -0,0 +1,48 @@
package modele;
import java.util.HashMap;
public class Ville {
/**
* Nom complet de la ville
*/
private String nom;
/**
* Joueur qui a construit une gare sur la ville (ou `null` si pas de gare)
*/
private Joueur proprietaire;
public Ville(String nom) {
this.nom = nom;
}
public String getNom() {
return nom;
}
public Joueur getProprietaire() {
return proprietaire;
}
public void setProprietaire(Joueur proprietaire) {
this.proprietaire = proprietaire;
}
@Override
public String toString() {
return nom;
}
public String toLog() {
return String.format("<span class=\"ville\">%s</span>", nom);
}
public Object asPOJO() {
HashMap<String, Object> data = new HashMap<>();
data.put("nom", nom);
if (proprietaire != null) {
data.put("proprietaire", proprietaire.getCouleur());
}
return data;
}
}

View File

@@ -0,0 +1,98 @@
package vue;
import modele.Jeu;
import org.glassfish.tyrus.server.Server;
import javax.websocket.DeploymentException;
import javax.websocket.Session;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
public class GameServer {
/**
* Liste des clients connectés au serveur
*/
private static ArrayList<Session> clients = new ArrayList<>();
/**
* Description de l'état du jeu, envoyé aux clients pour la mise à jour de l'interface graphique
*/
private static String etatJeu = "";
/**
* Instance de jeu exécutée par le serveur
*/
private static Jeu jeu;
public static void main(String[] args) {
// Lancement de la partie
jeu = new Jeu(new String[]{"Guybrush", "Largo", "LeChuck", "Elaine"});
// Prépare le serveur websocket
Server server = new Server("localhost", 3232, "/", WebSocketClient.class);
try (Scanner scanner = new Scanner(System.in)) {
server.start(); // lance le serveur
new Thread(jeu).start(); // démarre le jeu (exécute la méthode Jeu.run() dans un nouveau thread)
while (true) {
jeu.addInput(scanner.nextLine());
}
} catch (DeploymentException e) {
throw new RuntimeException(e);
} finally {
server.stop();
}
}
/**
* Ajoute une nouvelle instruction à la file d'instructions
* (cette méthode est appelée lorsqu'un message est reçue sur la websocket)
*
* @param message l'instruction à ajouter
*/
public static void addInput(String message) {
jeu.addInput(message);
}
/**
* Met à jour l'état de la partie, et envoie le nouvel état à tous les clients connectés
*
* @param etatJeu l'état de la partie
*/
public static void setEtatJeu(String etatJeu) {
GameServer.etatJeu = etatJeu;
// Envoie l'état de la partie à tous les clients
try {
for (Session session : clients) {
session.getBasicRemote().sendText(etatJeu);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Ajoute un nouveau client à la liste, et lui transmet l'état actuel de la partie
* (cette méthode est appelée lorsqu'une nouvelle connexion est établie)
*
* @param session la session du nouveau client
*/
public static void addClient(Session session) {
GameServer.clients.add(session);
try {
session.getBasicRemote().sendText(etatJeu);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Retire un client de la liste
* (cette méthode est appelée lorsqu'une connexion est fermée)
*
* @param session la session du client à retirer
*/
public static void removeClient(Session session) {
GameServer.clients.remove(session);
}
}

View File

@@ -0,0 +1,28 @@
package vue;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint(value = "/")
public class WebSocketClient {
@OnOpen
public void onOpen(Session session) {
GameServer.addClient(session);
}
@OnMessage
public void onMessage(String message, Session session) {
GameServer.addInput(message);
}
@OnClose
public void onClose(Session session) {
GameServer.removeClient(session);
}
@OnError
public void onError(Throwable exception, Session session) {
exception.printStackTrace();
System.err.println("Error for client: " + session.getId());
}
}

View File

@@ -0,0 +1,38 @@
package modele;
import modele.Jeu;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class IOJeu extends Jeu {
/**
* Liste contenant les instructions <20> lire (qui remplacent les entr<74>es au clavier)
*/
private List<String> instructions;
/**
* Constructeur, qui reprend exactement le constructeur de Game
*/
public IOJeu(String[] nomJoueurs) {
super(nomJoueurs);
this.instructions = new ArrayList<>();
}
/**
* Lit et renvoie une instruction dans la liste
*/
public String lireLigne() {
return instructions.remove(0);
}
/**
* Fixe la liste d'instructions du jeu.
*
* @param args liste de cha<68>nes de caract<63>res. Chaque <20>l<EFBFBD>ment est une instruction (sans '\n' <20> la fin)
*/
public void setInput(String... args) {
instructions.clear();
Collections.addAll(instructions, args);
}
}

View File

@@ -0,0 +1,95 @@
package modele;
import modele.CouleurWagon;
import modele.Destination;
import modele.Joueur;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class JeuProfTest {
private IOJeu jeu;
@BeforeEach
public void setUp() {
jeu = new IOJeu(new String[] { "Guybrush", "Largo", "LeChuck", "Elaine" });
}
@Test
void testCartesWagon() {
// regrouper toutes les cartes wagon du jeu
List<CouleurWagon> cartes = new ArrayList<>();
cartes.addAll(jeu.getPileCartesWagon());
cartes.addAll(jeu.getCartesWagonVisibles());
cartes.addAll(jeu.getDefausseCartesWagon());
for (Joueur j : jeu.getJoueurs()) {
cartes.addAll(j.getCartesWagon());
}
// compter le nombre de chaque couleur
HashMap<CouleurWagon, Integer> compteur = new HashMap<>();
for (CouleurWagon c : cartes) {
if (compteur.containsKey(c)) {
compteur.put(c, compteur.get(c) + 1);
} else {
compteur.put(c, 1);
}
}
// varifier le nombre d'exemplaires de chaque couleur
assertEquals(110, cartes.size());
assertEquals(12, compteur.get(CouleurWagon.NOIR));
assertEquals(12, compteur.get(CouleurWagon.BLANC));
assertEquals(12, compteur.get(CouleurWagon.JAUNE));
assertEquals(12, compteur.get(CouleurWagon.ROUGE));
assertEquals(12, compteur.get(CouleurWagon.ORANGE));
assertEquals(12, compteur.get(CouleurWagon.BLEU));
assertEquals(12, compteur.get(CouleurWagon.VERT));
assertEquals(12, compteur.get(CouleurWagon.ROSE));
assertEquals(14, compteur.get(CouleurWagon.LOCOMOTIVE));
}
@Test
void testInitialisationCartesVisibles() {
// v<>rifie que les cartes wagon face visible sont bien distribu<62>es dans le
// constructeur du jeu
assertEquals(5, jeu.getCartesWagonVisibles().size());
}
@Test
void testDestinationsInitialesTousLesJoueursPassent() {
jeu.setInput("", "", "", "");
try {
jeu.run();
} catch (IndexOutOfBoundsException e) {
// on v<>rifie que chaque joueur a 3 destinations normales et 1 destination
// longue
List<String> nomsDestinations = new ArrayList<>();
for (Destination d : Destination.makeDestinationsEurope()) {
nomsDestinations.add(d.getNom());
}
List<String> nomsDestinationsLongues = new ArrayList<>();
for (Destination d : Destination.makeDestinationsLonguesEurope()) {
nomsDestinationsLongues.add(d.getNom());
}
for (Joueur j : jeu.getJoueurs()) {
int nbDestinations = 0;
int nbDestinationsLongues = 0;
for (Destination d : j.getDestinations()) {
if (nomsDestinations.contains(d.getNom())) {
nbDestinations += 1;
} else if (nomsDestinationsLongues.contains(d.getNom())) {
nbDestinationsLongues += 1;
}
}
assertEquals(3, nbDestinations);
assertEquals(1, nbDestinationsLongues);
}
}
}
}

View File

@@ -0,0 +1,438 @@
package modele;
import modele.CouleurWagon;
import modele.Destination;
import modele.Ville;
import modele.Route;
import modele.Joueur;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class JoueurProfTest {
private IOJeu jeu;
private Joueur joueur1;
private Joueur joueur2;
private Joueur joueur3;
private Joueur joueur4;
/**
* Renvoie la route du jeu dont le nom est pass<73> en argument
*
* @param nom le nom de la route
* @return la route du jeu dont le nom est pass<73> en argument (ou null si aucune
* route ne correspond)
*/
public Route getRouteParNom(String nom) {
for (Route route : jeu.getRoutes()) {
if (route.getNom().equals(nom)) {
return route;
}
}
return null;
}
/**
* Renvoie la ville du jeu dont le nom est pass<73> en argument
*
* @param nom le nom de la ville
* @return la ville du jeu dont le nom est pass<73> en argument (ou null si aucune
* ville ne correspond)
*/
public Ville getVilleParNom(String nom) {
for (Ville ville : jeu.getVilles()) {
if (ville.getNom().equals(nom)) {
return ville;
}
}
return null;
}
@BeforeEach
void init() {
jeu = new IOJeu(new String[] { "Guybrush", "Largo", "LeChuck", "Elaine" });
List<Joueur> joueurs = jeu.getJoueurs();
joueur1 = joueurs.get(0);
joueur2 = joueurs.get(1);
joueur3 = joueurs.get(2);
joueur4 = joueurs.get(3);
}
/**
* Place 5 cartes ROUGE dans les cartes visibles, vide la pioche, la d<>fausse et
* les mains des joueurs
*/
void clear() {
List<CouleurWagon> cartesVisibles = jeu.getCartesWagonVisibles();
cartesVisibles.clear();
cartesVisibles.add(CouleurWagon.ROUGE);
cartesVisibles.add(CouleurWagon.ROUGE);
cartesVisibles.add(CouleurWagon.ROUGE);
cartesVisibles.add(CouleurWagon.ROUGE);
cartesVisibles.add(CouleurWagon.ROUGE);
jeu.getPileCartesWagon().clear();
jeu.getDefausseCartesWagon().clear();
joueur1.getCartesWagon().clear();
joueur2.getCartesWagon().clear();
joueur3.getCartesWagon().clear();
joueur4.getCartesWagon().clear();
}
@Test
void testInitialisation() {
for (Joueur joueur : jeu.getJoueurs()) {
assertEquals(3, joueur.getNbGares());
assertEquals(4, joueur.getCartesWagon().size());
assertEquals(45, joueur.getNbWagons());
}
}
@Test
void testChoisirDestinations() {
clear();
jeu.setInput("Athina - Angora (5)", "Frankfurt - Kobenhavn (5)");
ArrayList<Destination> destinationsPossibles = new ArrayList<>();
Destination d1 = new Destination("Athina", "Angora", 5);
Destination d2 = new Destination("Budapest", "Sofia", 5);
Destination d3 = new Destination("Frankfurt", "Kobenhavn", 5);
Destination d4 = new Destination("Rostov", "Erzurum", 5);
destinationsPossibles.add(d1);
destinationsPossibles.add(d2);
destinationsPossibles.add(d3);
destinationsPossibles.add(d4);
List<Destination> destinationsDefaussees = joueur1.choisirDestinations(destinationsPossibles, 2);
assertEquals(2, joueur1.getDestinations().size());
assertEquals(2, destinationsDefaussees.size());
assertTrue(destinationsDefaussees.contains(d1));
assertTrue(destinationsDefaussees.contains(d3));
assertTrue(joueur1.getDestinations().contains(d2));
assertTrue(joueur1.getDestinations().contains(d4));
}
@Test
void testJouerTourPrendreCartesWagon() {
clear();
List<CouleurWagon> cartesWagonVisibles = jeu.getCartesWagonVisibles();
// On met VERT x3, BLEU, LOCOMOTIVE (haut de pile) dans la pile de cartes wagon
List<CouleurWagon> pileCartesWagon = jeu.getPileCartesWagon();
pileCartesWagon.add(0, CouleurWagon.VERT);
pileCartesWagon.add(0, CouleurWagon.VERT);
pileCartesWagon.add(0, CouleurWagon.VERT);
pileCartesWagon.add(0, CouleurWagon.BLEU);
pileCartesWagon.add(0, CouleurWagon.LOCOMOTIVE);
jeu.setInput(
"JAUNE", // non valide (il n'y a que du ROUGE dans les cartes visibles)
"GRIS", // ok, pioche une LOCOMOTIVE sur le haut de la pile
"ROUGE"); // ok, prend dans les cartes visibles (remplac<61>e par BLEU)
joueur1.jouerTour();
// le joueur devrait piocher la LOCOMOTIVE, prendre une carte ROUGE
// puis le jeu devrait remettre une carte visible BLEU
assertTrue(TestUtils.contientExactement(
joueur1.getCartesWagon(),
CouleurWagon.ROUGE,
CouleurWagon.LOCOMOTIVE));
assertTrue(TestUtils.contientExactement(
cartesWagonVisibles,
CouleurWagon.BLEU,
CouleurWagon.ROUGE,
CouleurWagon.ROUGE,
CouleurWagon.ROUGE,
CouleurWagon.ROUGE));
assertTrue(TestUtils.contientExactement(
jeu.getPileCartesWagon(),
CouleurWagon.VERT,
CouleurWagon.VERT,
CouleurWagon.VERT));
}
@Test
void testJouerTourPiocherDestinations() {
clear();
Destination d1 = new Destination("Brest", "Marseille", 7);
Destination d2 = new Destination("London", "Berlin", 7);
Destination d3 = new Destination("Edinburgh", "Paris", 7);
Destination d4 = new Destination("Amsterdam", "Pamplona", 7);
Destination d5 = new Destination("Roma", "Smyrna", 8);
// le joueur choisir de piocher des destinations, pioche les destinations d1,
// d2, d3, choisit
// de d<>fausser d3 et passe (il garde donc d1 et d2)
jeu.setInput("destinations", d3.getNom(), "");
List<Destination> pileDestinations = jeu.getPileDestinations();
pileDestinations.clear();
pileDestinations.add(d1); // d<>but de la liste : haut de la pile
pileDestinations.add(d2);
pileDestinations.add(d3);
pileDestinations.add(d4);
pileDestinations.add(d5); // fin de la liste : fond de la pile
joueur1.jouerTour();
assertEquals(d4, pileDestinations.get(0));
assertEquals(d5, pileDestinations.get(1));
assertEquals(d3, pileDestinations.get(2)); // d3 est remise en fond de pile
assertEquals(2, joueur1.getDestinations().size());
assertTrue(joueur1.getDestinations().contains(d1));
assertTrue(joueur1.getDestinations().contains(d2));
}
@Test
void testJouerTourCapturerRoute() {
clear();
List<CouleurWagon> cartesWagon = joueur2.getCartesWagon();
cartesWagon.add(CouleurWagon.BLEU);
cartesWagon.add(CouleurWagon.BLEU);
cartesWagon.add(CouleurWagon.ROUGE);
cartesWagon.add(CouleurWagon.ROUGE);
cartesWagon.add(CouleurWagon.LOCOMOTIVE);
jeu.setInput(
"Brest - Pamplona", // co<63>te 4 ROSE (ne peut pas capturer)
"Bruxelles - Frankfurt", // co<63>te 2 BLEU
"BLEU", // ok
"ROUGE", // ne convient pas pour une route de 2 BLEU
"LOCOMOTIVE" // ok
);
joueur2.jouerTour();
assertEquals(null, getRouteParNom("Brest - Pamplona").getProprietaire());
assertEquals(joueur2, getRouteParNom("Bruxelles - Frankfurt").getProprietaire());
assertTrue(TestUtils.contientExactement(
joueur2.getCartesWagon(),
CouleurWagon.BLEU, CouleurWagon.ROUGE, CouleurWagon.ROUGE));
assertTrue(TestUtils.contientExactement(
jeu.getDefausseCartesWagon(),
CouleurWagon.BLEU,
CouleurWagon.LOCOMOTIVE));
assertEquals(14, joueur2.getScore());
}
@Test
void testJouerTourCapturerRoutePlusieursCouleursPossibles() {
clear();
List<CouleurWagon> cartesWagon = joueur2.getCartesWagon();
cartesWagon.add(CouleurWagon.VERT);
cartesWagon.add(CouleurWagon.BLEU);
cartesWagon.add(CouleurWagon.BLEU);
cartesWagon.add(CouleurWagon.BLEU);
cartesWagon.add(CouleurWagon.ROUGE);
cartesWagon.add(CouleurWagon.ROUGE);
cartesWagon.add(CouleurWagon.ROUGE);
cartesWagon.add(CouleurWagon.LOCOMOTIVE);
cartesWagon.add(CouleurWagon.LOCOMOTIVE);
jeu.setInput(
"Marseille - Paris", // co<63>te 4 GRIS
"VERT", // ne convient pas (impossible de payer en VERT)
"LOCOMOTIVE", // ok
"BLEU", // ok (paye tout le reste en BLEU ou LOCOMOTIVE)
"ROUGE", // ne convient pas car d<>j<EFBFBD> pay<61> BLEU
"BLEU", // ok
"LOCOMOTIVE" // ok
);
joueur2.jouerTour();
assertEquals(joueur2, getRouteParNom("Marseille - Paris").getProprietaire());
assertTrue(TestUtils.contientExactement(
joueur2.getCartesWagon(),
CouleurWagon.VERT,
CouleurWagon.BLEU,
CouleurWagon.ROUGE, CouleurWagon.ROUGE, CouleurWagon.ROUGE));
assertTrue(TestUtils.contientExactement(
jeu.getDefausseCartesWagon(),
CouleurWagon.BLEU,
CouleurWagon.BLEU,
CouleurWagon.LOCOMOTIVE,
CouleurWagon.LOCOMOTIVE));
assertEquals(19, joueur2.getScore());
}
@Test
void testJouerTourCapturerTunnelOK() {
clear();
List<CouleurWagon> cartesWagon = joueur2.getCartesWagon();
cartesWagon.add(CouleurWagon.ROSE);
cartesWagon.add(CouleurWagon.ROSE);
cartesWagon.add(CouleurWagon.ROUGE);
cartesWagon.add(CouleurWagon.ROUGE);
cartesWagon.add(CouleurWagon.LOCOMOTIVE);
// cartes qui seront pioch<63>es apr<70>s avoir pay<61> le prix initial du tunnel
jeu.getPileCartesWagon().add(0, CouleurWagon.BLEU);
jeu.getPileCartesWagon().add(0, CouleurWagon.ROSE);
jeu.getPileCartesWagon().add(0, CouleurWagon.JAUNE);
jeu.setInput(
"Marseille - Zurich", // co<63>te 2 ROSE (tunnel)
"ROSE", // ok
"LOCOMOTIVE", // ok
"ROSE" // co<63>t suppl<70>mentaire du tunnel
);
joueur2.jouerTour();
assertEquals(joueur2, getRouteParNom("Marseille - Zurich").getProprietaire());
assertTrue(TestUtils.contientExactement(
joueur2.getCartesWagon(),
CouleurWagon.ROUGE, CouleurWagon.ROUGE));
assertTrue(TestUtils.contientExactement(
jeu.getDefausseCartesWagon(),
CouleurWagon.ROSE,
CouleurWagon.ROSE,
CouleurWagon.LOCOMOTIVE,
CouleurWagon.BLEU,
CouleurWagon.ROSE,
CouleurWagon.JAUNE));
assertEquals(14, joueur2.getScore());
}
@Test
void testJouerTourCapturerTunnelImpossible() {
clear();
List<CouleurWagon> cartesWagon = joueur2.getCartesWagon();
cartesWagon.add(CouleurWagon.ROSE);
cartesWagon.add(CouleurWagon.ROUGE);
cartesWagon.add(CouleurWagon.ROUGE);
cartesWagon.add(CouleurWagon.LOCOMOTIVE);
// cartes qui seront pioch<63>es apr<70>s avoir pay<61> le prix initial du tunnel
jeu.getPileCartesWagon().add(0, CouleurWagon.ROSE);
jeu.getPileCartesWagon().add(0, CouleurWagon.BLEU);
jeu.getPileCartesWagon().add(0, CouleurWagon.JAUNE);
jeu.setInput(
"Marseille - Zurich", // co<63>te 2 ROSE (tunnel)
"ROSE", // ok
"LOCOMOTIVE" // ok, mais le joueur ne peut pas payer le co<63>t suppl<70>mentaire
);
joueur2.jouerTour();
assertEquals(null, getRouteParNom("Marseille - Zurich").getProprietaire());
assertTrue(TestUtils.contientExactement(
joueur2.getCartesWagon(),
CouleurWagon.ROSE, CouleurWagon.ROUGE, CouleurWagon.ROUGE, CouleurWagon.LOCOMOTIVE));
assertTrue(TestUtils.contientExactement(
jeu.getDefausseCartesWagon(),
CouleurWagon.ROSE,
CouleurWagon.BLEU,
CouleurWagon.JAUNE));
assertEquals(12, joueur2.getScore());
}
@Test
void testJouerTourCapturerTunnelAbandonne() {
clear();
List<CouleurWagon> cartesWagon = joueur2.getCartesWagon();
cartesWagon.add(CouleurWagon.ROSE);
cartesWagon.add(CouleurWagon.ROSE);
cartesWagon.add(CouleurWagon.ROUGE);
cartesWagon.add(CouleurWagon.ROUGE);
cartesWagon.add(CouleurWagon.LOCOMOTIVE);
// cartes qui seront pioch<63>es apr<70>s avoir pay<61> le prix initial du tunnel
jeu.getPileCartesWagon().add(0, CouleurWagon.BLEU);
jeu.getPileCartesWagon().add(0, CouleurWagon.JAUNE);
jeu.getPileCartesWagon().add(0, CouleurWagon.ROSE);
jeu.setInput(
"Marseille - Zurich", // co<63>te 2 ROSE (tunnel)
"ROSE", // ok
"LOCOMOTIVE", // ok
"" // le joueur pourrait payer mais choisit d'abandonner la capture
);
joueur2.jouerTour();
assertEquals(null, getRouteParNom("Marseille - Zurich").getProprietaire());
assertTrue(TestUtils.contientExactement(
joueur2.getCartesWagon(),
CouleurWagon.ROSE, CouleurWagon.ROSE, CouleurWagon.ROUGE, CouleurWagon.ROUGE,
CouleurWagon.LOCOMOTIVE));
assertTrue(TestUtils.contientExactement(
jeu.getDefausseCartesWagon(),
CouleurWagon.ROSE,
CouleurWagon.BLEU,
CouleurWagon.JAUNE));
assertEquals(12, joueur2.getScore());
}
@Test
void testJouerTourCapturerFerry() {
clear();
List<CouleurWagon> cartesWagon = joueur3.getCartesWagon();
cartesWagon.add(CouleurWagon.ROSE);
cartesWagon.add(CouleurWagon.JAUNE);
cartesWagon.add(CouleurWagon.JAUNE);
cartesWagon.add(CouleurWagon.JAUNE);
cartesWagon.add(CouleurWagon.LOCOMOTIVE);
// Remarque:
// Il est possible de faire en sorte que la locomotive impos<6F>e par le ferry soit
// imm<6D>diatement pay<61>e par le joueur sans demander d'input (l'utilisateur doit
// alors choisir les cartes restantes pour payer) ou bien de demander <20>
// l'utilisateur de choisir toutes les cartes pour payer (y compris la
// locomotive impos<6F>e). Le test devrait fonctionner dans les deux cas.
jeu.setInput(
"Constantinople - Sevastopol", // (ferry) co<63>te 4 GRIS dont 2 LOCOMOTIVE (ne peut pas acheter)
"Palermo - Roma", // (ferry) co<63>te 4 GRIS dont 1 LOCOMOTIVE (peut acheter)
"ROSE", // non valide (ne peut pas couvrir le co<63>t)
"JAUNE", // OK
"JAUNE", // OK
"JAUNE", // OK
"LOCOMOTIVE" // OK
);
joueur3.jouerTour();
assertEquals(joueur3, getRouteParNom("Palermo - Roma").getProprietaire());
assertTrue(TestUtils.contientExactement(
joueur3.getCartesWagon(),
CouleurWagon.ROSE));
assertTrue(TestUtils.contientExactement(
jeu.getDefausseCartesWagon(),
CouleurWagon.JAUNE, CouleurWagon.JAUNE, CouleurWagon.JAUNE,
CouleurWagon.LOCOMOTIVE));
assertEquals(null, getRouteParNom("Constantinople - Sevastopol").getProprietaire());
assertEquals(19, joueur3.getScore());
}
@Test
void testJouerTourConstruireUneGare() {
clear();
List<CouleurWagon> cartesWagon = joueur3.getCartesWagon();
cartesWagon.add(CouleurWagon.VERT);
cartesWagon.add(CouleurWagon.BLEU);
cartesWagon.add(CouleurWagon.BLEU);
cartesWagon.add(CouleurWagon.ROUGE);
cartesWagon.add(CouleurWagon.ROUGE);
jeu.setInput("Paris", "ROUGE");
joueur3.jouerTour();
assertEquals(joueur3, getVilleParNom("Paris").getProprietaire());
assertTrue(TestUtils.contientExactement(
joueur3.getCartesWagon(),
CouleurWagon.VERT, CouleurWagon.BLEU, CouleurWagon.BLEU, CouleurWagon.ROUGE));
assertTrue(TestUtils.contientExactement(
jeu.getDefausseCartesWagon(),
CouleurWagon.ROUGE));
assertEquals(2, joueur3.getNbGares());
}
}

View File

@@ -0,0 +1,96 @@
package modele;
import modele.CouleurWagon;
import modele.Destination;
import modele.Joueur;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class JoueurTest {
private IOJeu jeu;
private Joueur joueur1;
private Joueur joueur2;
private Joueur joueur3;
private Joueur joueur4;
@BeforeEach
void init() {
jeu = new IOJeu(new String[] { "Guybrush", "Largo", "LeChuck", "Elaine" });
List<Joueur> joueurs = jeu.getJoueurs();
joueur1 = joueurs.get(0);
joueur2 = joueurs.get(1);
joueur3 = joueurs.get(2);
joueur4 = joueurs.get(3);
joueur1.getCartesWagon().clear();
joueur2.getCartesWagon().clear();
joueur3.getCartesWagon().clear();
joueur4.getCartesWagon().clear();
}
@Test
void testChoisirDestinations() {
jeu.setInput("Athina - Angora (5)", "Frankfurt - Kobenhavn (5)");
ArrayList<Destination> destinationsPossibles = new ArrayList<>();
Destination d1 = new Destination("Athina", "Angora", 5);
Destination d2 = new Destination("Budapest", "Sofia", 5);
Destination d3 = new Destination("Frankfurt", "Kobenhavn", 5);
Destination d4 = new Destination("Rostov", "Erzurum", 5);
destinationsPossibles.add(d1);
destinationsPossibles.add(d2);
destinationsPossibles.add(d3);
destinationsPossibles.add(d4);
List<Destination> destinationsDefaussees = joueur1.choisirDestinations(destinationsPossibles, 2);
assertEquals(2, joueur1.getDestinations().size());
assertEquals(2, destinationsDefaussees.size());
assertTrue(destinationsDefaussees.contains(d1));
assertTrue(destinationsDefaussees.contains(d3));
assertTrue(joueur1.getDestinations().contains(d2));
assertTrue(joueur1.getDestinations().contains(d4));
}
@Test
void testJouerTourPrendreCartesWagon() {
jeu.setInput("GRIS", "ROUGE");
// On met 5 cartes ROUGE dans les cartes wagon visibles
List<CouleurWagon> cartesWagonVisibles = jeu.getCartesWagonVisibles();
cartesWagonVisibles.clear();
cartesWagonVisibles.add(CouleurWagon.ROUGE);
cartesWagonVisibles.add(CouleurWagon.ROUGE);
cartesWagonVisibles.add(CouleurWagon.ROUGE);
cartesWagonVisibles.add(CouleurWagon.ROUGE);
cartesWagonVisibles.add(CouleurWagon.ROUGE);
// On met VERT, BLEU, LOCOMOTIVE (haut de pile) dans la pile de cartes wagon
List<CouleurWagon> pileCartesWagon = jeu.getPileCartesWagon();
pileCartesWagon.add(0, CouleurWagon.BLEU);
pileCartesWagon.add(0, CouleurWagon.LOCOMOTIVE);
int nbCartesWagon = pileCartesWagon.size();
joueur1.jouerTour();
// le joueur devrait piocher la LOCOMOTIVE, prendre une carte ROUGE
// puis le jeu devrait remettre une carte visible BLEU
assertTrue(TestUtils.contientExactement(
joueur1.getCartesWagon(),
CouleurWagon.ROUGE,
CouleurWagon.LOCOMOTIVE));
assertTrue(TestUtils.contientExactement(
cartesWagonVisibles,
CouleurWagon.BLEU,
CouleurWagon.ROUGE,
CouleurWagon.ROUGE,
CouleurWagon.ROUGE,
CouleurWagon.ROUGE));
assertEquals(nbCartesWagon - 2, pileCartesWagon.size());
}
}

View File

@@ -0,0 +1,76 @@
package modele;
import modele.CouleurWagon;
import modele.Joueur;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class TestUtils {
/**
* Renvoie un attribut d'un objet <20> partir de son nom.
* La m<>thode cherche s'il existe un champ d<>clar<61> dans la classe de l'objet et
* si ce n'est pas le cas remonte dans la hi<68>rarchie des classes jusqu'<27> trouver
* un champ avec le nom voulu ou renvoie null.
*
* @param obj objet dont on cherche le champ
* @param name nom du champ
* @return le champ de l'objet, avec un type statique Object
*/
public static Object getAttribute(Object obj, String name) {
Class c = obj.getClass();
while (c != null) {
try {
Field field = c.getDeclaredField(name);
field.setAccessible(true);
return field.get(obj);
} catch (NoSuchFieldException e) {
c = c.getSuperclass();
continue;
} catch (IllegalAccessException e) {
e.printStackTrace();
return null;
}
}
return null;
}
/**
* Met les cartes wagon pass<73>es en argument dans la main d'un joueur (la main
* est vid<69>e avant, pour contenir exactement les cartes indiqu<71>es)
*
* @param joueur le joueur dont on fixe les cartes en main
*/
public static void setCartesWagon(Joueur joueur, CouleurWagon... cartesWagon) {
while (!joueur.getCartesWagon().isEmpty()) {
joueur.getCartesWagon().remove(0);
}
Collections.addAll(joueur.getCartesWagon(), cartesWagon);
}
/**
* Teste si la liste de CouleurWagon pass<73>e en premier argument contient
* exactement les couleurs indiqu<71>es, ind<6E>pendamment de leur ordre
*
* @param liste la liste de CouleurWagon <20> tester
* @param couleurs les couleurs que la liste devrait contenir (avec leur
* multiplicit<69>)
* @return true si la liste contient exactement les couleurs indiqu<71>es, avec
* leur multiplicit<69>, false sinon
*/
public static boolean contientExactement(List<CouleurWagon> liste, CouleurWagon... couleurs) {
if (liste.size() != couleurs.length) {
return false;
}
Arrays.sort(couleurs);
Collections.sort(liste);
for (int i = 0; i < couleurs.length; i++) {
if (couleurs[i] != liste.get(i)) {
return false;
}
}
return true;
}
}

3
svelte/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/node_modules/
.DS_Store

109
svelte/README.md Normal file
View File

@@ -0,0 +1,109 @@
*Psst — looking for a more complete solution? Check out [SvelteKit](https://kit.svelte.dev), the official framework for building web applications of all sizes, with a beautiful development experience and flexible filesystem-based routing.*
*Looking for a shareable component template instead? You can [use SvelteKit for that as well](https://kit.svelte.dev/docs#packaging) or the older [sveltejs/component-template](https://github.com/sveltejs/component-template)*
---
# svelte app
This is a project template for [Svelte](https://svelte.dev) apps. It lives at https://github.com/sveltejs/template.
To create a new project based on this template using [degit](https://github.com/Rich-Harris/degit):
```bash
npx degit sveltejs/template svelte-app
cd svelte-app
```
*Note that you will need to have [Node.js](https://nodejs.org) installed.*
## Get started
Install the dependencies...
```bash
cd svelte-app
npm install
```
...then start [Rollup](https://rollupjs.org):
```bash
npm run dev
```
Navigate to [localhost:8080](http://localhost:8080). You should see your app running. Edit a component file in `src`, save it, and reload the page to see your changes.
By default, the server will only respond to requests from localhost. To allow connections from other computers, edit the `sirv` commands in package.json to include the option `--host 0.0.0.0`.
If you're using [Visual Studio Code](https://code.visualstudio.com/) we recommend installing the official extension [Svelte for VS Code](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode). If you are using other editors you may need to install a plugin in order to get syntax highlighting and intellisense.
## Building and running in production mode
To create an optimised version of the app:
```bash
npm run build
```
You can run the newly built app with `npm run start`. This uses [sirv](https://github.com/lukeed/sirv), which is included in your package.json's `dependencies` so that the app will work when you deploy to platforms like [Heroku](https://heroku.com).
## Single-page app mode
By default, sirv will only respond to requests that match files in `public`. This is to maximise compatibility with static fileservers, allowing you to deploy your app anywhere.
If you're building a single-page app (SPA) with multiple routes, sirv needs to be able to respond to requests for *any* path. You can make it so by editing the `"start"` command in package.json:
```js
"start": "sirv public --single"
```
## Using TypeScript
This template comes with a script to set up a TypeScript development environment, you can run it immediately after cloning the template with:
```bash
node scripts/setupTypeScript.js
```
Or remove the script via:
```bash
rm scripts/setupTypeScript.js
```
If you want to use `baseUrl` or `path` aliases within your `tsconfig`, you need to set up `@rollup/plugin-alias` to tell Rollup to resolve the aliases. For more info, see [this StackOverflow question](https://stackoverflow.com/questions/63427935/setup-tsconfig-path-in-svelte).
## Deploying to the web
### With [Vercel](https://vercel.com)
Install `vercel` if you haven't already:
```bash
npm install -g vercel
```
Then, from within your project folder:
```bash
cd public
vercel deploy --name my-project
```
### With [surge](https://surge.sh/)
Install `surge` if you haven't already:
```bash
npm install -g surge
```
Then, from within your project folder:
```bash
npm run build
surge public my-project.surge.sh
```

788
svelte/package-lock.json generated Normal file
View File

@@ -0,0 +1,788 @@
{
"name": "svelte-app",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@babel/code-frame": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
"integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
"dev": true,
"requires": {
"@babel/highlight": "^7.16.7"
}
},
"@babel/helper-validator-identifier": {
"version": "7.16.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
"integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
"dev": true
},
"@babel/highlight": {
"version": "7.16.10",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz",
"integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.16.7",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
}
},
"@polka/url": {
"version": "1.0.0-next.21",
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz",
"integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g=="
},
"@rollup/plugin-commonjs": {
"version": "17.1.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-17.1.0.tgz",
"integrity": "sha512-PoMdXCw0ZyvjpCMT5aV4nkL0QywxP29sODQsSGeDpr/oI49Qq9tRtAsb/LbYbDzFlOydVEqHmmZWFtXJEAX9ew==",
"dev": true,
"requires": {
"@rollup/pluginutils": "^3.1.0",
"commondir": "^1.0.1",
"estree-walker": "^2.0.1",
"glob": "^7.1.6",
"is-reference": "^1.2.1",
"magic-string": "^0.25.7",
"resolve": "^1.17.0"
}
},
"@rollup/plugin-node-resolve": {
"version": "11.2.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz",
"integrity": "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==",
"dev": true,
"requires": {
"@rollup/pluginutils": "^3.1.0",
"@types/resolve": "1.17.1",
"builtin-modules": "^3.1.0",
"deepmerge": "^4.2.2",
"is-module": "^1.0.0",
"resolve": "^1.19.0"
}
},
"@rollup/pluginutils": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
"integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
"dev": true,
"requires": {
"@types/estree": "0.0.39",
"estree-walker": "^1.0.1",
"picomatch": "^2.2.2"
},
"dependencies": {
"estree-walker": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
"integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
"dev": true
}
}
},
"@types/estree": {
"version": "0.0.39",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
"dev": true
},
"@types/node": {
"version": "17.0.18",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.18.tgz",
"integrity": "sha512-eKj4f/BsN/qcculZiRSujogjvp5O/k4lOW5m35NopjZM/QwLOR075a8pJW5hD+Rtdm2DaCVPENS6KtSQnUD6BA==",
"dev": true
},
"@types/resolve": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
"integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
},
"anymatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
"dev": true,
"requires": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
}
},
"balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
}
},
"buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true
},
"builtin-modules": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz",
"integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==",
"dev": true
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
"dev": true,
"requires": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
"fsevents": "~2.3.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
"commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
"dev": true
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true
},
"console-clear": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/console-clear/-/console-clear-1.1.1.tgz",
"integrity": "sha512-pMD+MVR538ipqkG5JXeOEbKWS5um1H4LUUccUQG68qpeqBYbzYy79Gh55jkd2TtPdRfUaLWdv6LPP//5Zt0aPQ=="
},
"deepmerge": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
"dev": true
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true
},
"fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"optional": true
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"get-port": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz",
"integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw="
},
"glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"requires": {
"is-glob": "^4.0.1"
}
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"requires": {
"function-bind": "^1.1.1"
}
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"dev": true
},
"is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
"requires": {
"binary-extensions": "^2.0.0"
}
},
"is-core-module": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz",
"integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==",
"dev": true,
"requires": {
"has": "^1.0.3"
}
},
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
"dev": true
},
"is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"requires": {
"is-extglob": "^2.1.1"
}
},
"is-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
"integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
"dev": true
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"is-reference": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
"integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
"dev": true,
"requires": {
"@types/estree": "*"
}
},
"jest-worker": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
"integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
"dev": true,
"requires": {
"@types/node": "*",
"merge-stream": "^2.0.0",
"supports-color": "^7.0.0"
},
"dependencies": {
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
},
"kleur": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.4.tgz",
"integrity": "sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA=="
},
"livereload": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/livereload/-/livereload-0.9.3.tgz",
"integrity": "sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw==",
"dev": true,
"requires": {
"chokidar": "^3.5.0",
"livereload-js": "^3.3.1",
"opts": ">= 1.2.0",
"ws": "^7.4.3"
}
},
"livereload-js": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-3.3.3.tgz",
"integrity": "sha512-a7Jipme3XIBIryJluWP5LQrEAvhobDPyScBe+q+MYwxBiMT2Ck7msy4tAdF8TAa33FMdJqX4guP81Yhiu6BkmQ==",
"dev": true
},
"local-access": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/local-access/-/local-access-1.1.0.tgz",
"integrity": "sha512-XfegD5pyTAfb+GY6chk283Ox5z8WexG56OvM06RWLpAc/UHozO8X6xAxEkIitZOtsSMM1Yr3DkHgW5W+onLhCw=="
},
"magic-string": {
"version": "0.25.7",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
"integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
"dev": true,
"requires": {
"sourcemap-codec": "^1.4.4"
}
},
"merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true
},
"minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="
},
"mrmime": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz",
"integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ=="
},
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"requires": {
"wrappy": "1"
}
},
"opts": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/opts/-/opts-2.0.2.tgz",
"integrity": "sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==",
"dev": true
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true
},
"path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true
},
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dev": true,
"requires": {
"safe-buffer": "^5.1.0"
}
},
"readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"requires": {
"picomatch": "^2.2.1"
}
},
"require-relative": {
"version": "0.8.7",
"resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz",
"integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=",
"dev": true
},
"resolve": {
"version": "1.22.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
"integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
"dev": true,
"requires": {
"is-core-module": "^2.8.1",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
}
},
"rollup": {
"version": "2.67.2",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.67.2.tgz",
"integrity": "sha512-hoEiBWwZtf1QdK3jZIq59L0FJj4Fiv4RplCO4pvCRC86qsoFurWB4hKQIjoRf3WvJmk5UZ9b0y5ton+62fC7Tw==",
"dev": true,
"requires": {
"fsevents": "~2.3.2"
}
},
"rollup-plugin-css-only": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-3.1.0.tgz",
"integrity": "sha512-TYMOE5uoD76vpj+RTkQLzC9cQtbnJNktHPB507FzRWBVaofg7KhIqq1kGbcVOadARSozWF883Ho9KpSPKH8gqA==",
"dev": true,
"requires": {
"@rollup/pluginutils": "4"
},
"dependencies": {
"@rollup/pluginutils": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.1.2.tgz",
"integrity": "sha512-ROn4qvkxP9SyPeHaf7uQC/GPFY6L/OWy9+bd9AwcjOAWQwxRscoEyAUD8qCY5o5iL4jqQwoLk2kaTKJPb/HwzQ==",
"dev": true,
"requires": {
"estree-walker": "^2.0.1",
"picomatch": "^2.2.2"
}
}
}
},
"rollup-plugin-livereload": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/rollup-plugin-livereload/-/rollup-plugin-livereload-2.0.5.tgz",
"integrity": "sha512-vqQZ/UQowTW7VoiKEM5ouNW90wE5/GZLfdWuR0ELxyKOJUIaj+uismPZZaICU4DnWPVjnpCDDxEqwU7pcKY/PA==",
"dev": true,
"requires": {
"livereload": "^0.9.1"
}
},
"rollup-plugin-svelte": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-svelte/-/rollup-plugin-svelte-7.1.0.tgz",
"integrity": "sha512-vopCUq3G+25sKjwF5VilIbiY6KCuMNHP1PFvx2Vr3REBNMDllKHFZN2B9jwwC+MqNc3UPKkjXnceLPEjTjXGXg==",
"dev": true,
"requires": {
"require-relative": "^0.8.7",
"rollup-pluginutils": "^2.8.2"
}
},
"rollup-plugin-terser": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz",
"integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
"jest-worker": "^26.2.1",
"serialize-javascript": "^4.0.0",
"terser": "^5.0.0"
}
},
"rollup-pluginutils": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
"integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
"dev": true,
"requires": {
"estree-walker": "^0.6.1"
},
"dependencies": {
"estree-walker": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
"dev": true
}
}
},
"sade": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
"integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==",
"requires": {
"mri": "^1.1.0"
}
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true
},
"semiver": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/semiver/-/semiver-1.1.0.tgz",
"integrity": "sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg=="
},
"serialize-javascript": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
"integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
"dev": true,
"requires": {
"randombytes": "^2.1.0"
}
},
"sirv": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.2.tgz",
"integrity": "sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==",
"requires": {
"@polka/url": "^1.0.0-next.20",
"mrmime": "^1.0.0",
"totalist": "^3.0.0"
}
},
"sirv-cli": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/sirv-cli/-/sirv-cli-2.0.2.tgz",
"integrity": "sha512-OtSJDwxsF1NWHc7ps3Sa0s+dPtP15iQNJzfKVz+MxkEo3z72mCD+yu30ct79rPr0CaV1HXSOBp+MIY5uIhHZ1A==",
"requires": {
"console-clear": "^1.1.0",
"get-port": "^3.2.0",
"kleur": "^4.1.4",
"local-access": "^1.0.1",
"sade": "^1.6.0",
"semiver": "^1.0.0",
"sirv": "^2.0.0",
"tinydate": "^1.0.0"
}
},
"source-map": {
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
"dev": true
},
"source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"sourcemap-codec": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
"dev": true
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
},
"supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true
},
"svelte": {
"version": "3.46.4",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.46.4.tgz",
"integrity": "sha512-qKJzw6DpA33CIa+C/rGp4AUdSfii0DOTCzj/2YpSKKayw5WGSS624Et9L1nU1k2OVRS9vaENQXp2CVZNU+xvIg==",
"dev": true
},
"terser": {
"version": "5.10.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz",
"integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==",
"dev": true,
"requires": {
"commander": "^2.20.0",
"source-map": "~0.7.2",
"source-map-support": "~0.5.20"
}
},
"tinydate": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/tinydate/-/tinydate-1.3.0.tgz",
"integrity": "sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w=="
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
},
"totalist": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.0.tgz",
"integrity": "sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw=="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true
},
"ws": {
"version": "7.5.7",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
"dev": true
}
}
}

23
svelte/package.json Normal file
View File

@@ -0,0 +1,23 @@
{
"name": "svelte-app",
"version": "1.0.0",
"private": true,
"scripts": {
"build": "rollup -c",
"dev": "rollup -c -w",
"start": "sirv public --no-clear"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-node-resolve": "^11.0.0",
"rollup": "^2.3.4",
"rollup-plugin-css-only": "^3.1.0",
"rollup-plugin-livereload": "^2.0.0",
"rollup-plugin-svelte": "^7.0.0",
"rollup-plugin-terser": "^7.0.0",
"svelte": "^3.0.0"
},
"dependencies": {
"sirv-cli": "^2.0.0"
}
}

1
svelte/public/bundle.css Normal file
View File

@@ -0,0 +1 @@
main.svelte-urompm{display:flex;flex-direction:row}.joueurs.svelte-urompm{float:right}#board.svelte-1s8m8k5{background:url(images/euMap.jpg);background-size:contain;width:850px;height:548px;border:1px var(--col-dark) solid;border-radius:8px;box-shadow:2px 2px 2px var(--col-dark)}.ville.svelte-1s8m8k5{stroke:none;fill:#0000}.route.svelte-1s8m8k5{stroke:none;fill:#0000}.no-pointer.svelte-1s8m8k5{pointer-events:none}.joueur.svelte-vqlws6.svelte-vqlws6{color:var(--col-dark);border:1px solid var(--col-dark);border-radius:8px;width:280px;padding:4px;margin-left:4px;margin-bottom:4px;box-shadow:2px 2px 2px var(--col-dark)}.joueur.BLEU.svelte-vqlws6.svelte-vqlws6{background:var(--col-light-BLEU)}.joueur.VERT.svelte-vqlws6.svelte-vqlws6{background:var(--col-light-VERT)}.joueur.ROSE.svelte-vqlws6.svelte-vqlws6{background:var(--col-light-ROSE)}.joueur.ROUGE.svelte-vqlws6.svelte-vqlws6{background:var(--col-light-ROUGE)}.joueur.JAUNE.svelte-vqlws6.svelte-vqlws6{background:var(--col-light-JAUNE)}.header.svelte-vqlws6.svelte-vqlws6{display:flex;flex-direction:row;justify-content:space-between;margin-bottom:4px}.info.svelte-vqlws6.svelte-vqlws6{width:100%}.nom.svelte-vqlws6.svelte-vqlws6{width:100%;text-align:center;font-size:1.5em;font-weight:bold}.avatar.svelte-vqlws6.svelte-vqlws6{height:84px;width:66px}.secret.svelte-vqlws6.svelte-vqlws6{display:none}.joueur.svelte-vqlws6:hover .secret.svelte-vqlws6,.joueur.actif.svelte-vqlws6 .secret.svelte-vqlws6{display:block}.destinations.svelte-vqlws6.svelte-vqlws6{align-content:right}.cartes-wagon.svelte-vqlws6.svelte-vqlws6{display:flex;flex-wrap:wrap;flex-direction:row;width:250px}.carte-wagon.svelte-vqlws6.svelte-vqlws6{border:1px solid var(--col-dark);border-radius:4px;overflow:hidden;position:relative;width:calc(248px * 0.3);height:calc(160px * 0.3);padding:0;margin-right:-42px}.carte-wagon.svelte-vqlws6 .overlay.svelte-vqlws6{position:absolute;top:0;left:0;width:100%;height:100%;background:var(--col-dark);opacity:0.5}.image-wagon.svelte-vqlws6.svelte-vqlws6{width:100%;height:100%;background-size:cover}.nom-joueur.svelte-19y2w7e{font-weight:bold}#piles.svelte-1eir9gx.svelte-1eir9gx{justify-content:space-around}.carte.svelte-1eir9gx.svelte-1eir9gx{width:100px;font-size:0.8em;text-align:center}.carte-stub.svelte-1eir9gx.svelte-1eir9gx{width:100px;height:67px;margin-bottom:5px}.carte.svelte-1eir9gx img.svelte-1eir9gx{margin-bottom:5px;border-radius:4px;border:1px var(--col-dark) solid;box-shadow:2px 2px 2px var(--col-dark)}#cartes-visibles.svelte-1eir9gx.svelte-1eir9gx{width:500px;height:89px;flex-direction:row-reverse}#defausse-cartes-wagon.svelte-1eir9gx.svelte-1eir9gx{flex-direction:column-reverse}#defausse-cartes-wagon.svelte-1eir9gx img.svelte-1eir9gx{margin-top:-55px;display:none}#defausse-cartes-wagon.svelte-1eir9gx:hover img.svelte-1eir9gx{display:block}#defausse-cartes-wagon.svelte-1eir9gx img.svelte-1eir9gx:last-child{margin-top:0;display:block}#pile-destinations.svelte-1eir9gx.svelte-1eir9gx,#pile-cartes-wagon.svelte-1eir9gx.svelte-1eir9gx{margin-left:10px}#log.svelte-1r9y78z{margin:5px 0;padding:10px 30px 12px 26px;width:408px;height:263px;font-family:monospace;background:url(images/dialogue-box_Big.png);background-size:cover}#inner-log.svelte-1r9y78z{padding:0px;height:100%;overflow:overlay}.svelte-1r9y78z::-webkit-scrollbar{background-color:transparent}

3672
svelte/public/bundle.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

BIN
svelte/public/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

157
svelte/public/global.css Normal file
View File

@@ -0,0 +1,157 @@
@import url('https://fonts.googleapis.com/css2?family=IM+Fell+English+SC&display=swap');
* {
box-sizing: border-box;
}
html {
--col-BLEU: #205099;
--col-light-BLEU: #87BDE1;
--col-ROUGE: #D64036;
--col-light-ROUGE: #CC916C;
--col-VERT: #65964C;
--col-light-VERT: #C6E370;
--col-JAUNE: #C69943;
--col-light-JAUNE: #F6E678;
--col-ROSE: #5E3182;
--col-light-ROSE: #D89FDB;
--col-dark: #373F3B;
}
html, body {
position: relative;
width: 100%;
height: 100%;
}
body {
color: var(--col-dark);
margin: 0;
padding: 8px;
box-sizing: border-box;
font-family: "IM Fell English SC", serif;
background: #E1E5E7;
}
a {
color: rgb(0, 100, 200);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
a:visited {
color: rgb(0, 80, 160);
}
label {
display: block;
}
input, button, select, textarea {
font-family: inherit;
font-size: inherit;
-webkit-padding: 0.4em 0;
padding: 0.4em;
margin: 0 0 0.5em 0;
box-sizing: border-box;
border: 1px solid #ccc;
border-radius: 2px;
}
input:disabled {
color: #ccc;
}
button {
color: #333;
background-color: #f4f4f4;
outline: none;
}
button:disabled {
color: #999;
}
button:not(:disabled):active {
background-color: #ddd;
}
button:focus {
border-color: #666;
}
.column {
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
}
#log .tour {
margin-left: 100px;
font-weight: bold;
text-decoration: underline;
}
#log .joueur {
font-weight: bold;
}
#log .ville, #log .route {
font-style: italic;
font-weight: bold;
}
#log .couleur {
text-decoration: underline;
text-decoration-thickness: 2px;
font-weight: bold;
}
#log .couleur.rouge {
text-decoration-color: #be3c33;
}
#log .couleur.vert {
text-decoration-color: #96c156;
}
#log .couleur.bleu {
text-decoration-color: #489fd9;
}
#log .couleur.jaune {
text-decoration-color: #fbe969;
}
#log .couleur.orange {
text-decoration-color: #d58b44;
}
#log .couleur.noir {
text-decoration-color: #3a4f59;
}
#log .couleur.blanc {
text-decoration-color: #e8e9ec;
}
#log .couleur.rose {
text-decoration-color: #b991bb;
}
#log .couleur.gris {
text-decoration-color: #969b9d;
}
img.couleur {
width: 1.5em;
height: 1.5em;
margin-bottom: -0.5em;
}

Some files were not shown because too many files have changed in this diff Show More