diff --git a/.gitignore b/.gitignore index 7ece5fbacc5cb647f56e4b10e0320b5bcad6b4f1..e7f54c1f2d11142d30369965f6987f1d317d4700 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ target # dependencies node_modules +node # IDEs and editors /.idea @@ -17,6 +18,8 @@ node_modules *.launch .settings/ *.sublime-workspace +.java-version +*.iml # IDE - VSCode .vscode/* diff --git a/README.adoc b/README.adoc index c5c655fc49b901811df513c1a5dbdfb3a052c495..4a31eac84355fb461fe03892dba45ad64567fe04 100644 --- a/README.adoc +++ b/README.adoc @@ -23,4 +23,10 @@ service. Après avoir lancé un SOS, le capitaine ordonne l’évacuation du vai l’inévitable crash. Sains et saufs, vous entamez l’exploration des environs lorsque vous entendez les cris d’agonie de votre capitaine. Au loin, vous distinguez une silhouette qui vous observe. -Vous n’êtes pas seul … \ No newline at end of file +Vous n’êtes pas seul... + +== Project Layout + +The current source code organization is based on the following article: + +https://frakton.com/utilizing-maven-front-end-plugin-for-angular-spring-boot/ \ No newline at end of file diff --git a/not-alone-core/.gitignore b/not-alone-core/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..81325b3d8200e98905917c1c244bd7c9c23841bd --- /dev/null +++ b/not-alone-core/.gitignore @@ -0,0 +1,2 @@ +/bin/ + diff --git a/not-alone-core/pom.xml b/not-alone-core/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..f7ebef956b4eaaf5ac3325e01d94b8e9b2ce0ea1 --- /dev/null +++ b/not-alone-core/pom.xml @@ -0,0 +1,60 @@ + + + + not-alone + fr.univnantes.alma + 1.0-SNAPSHOT + + 4.0.0 + + not-alone-core + Not Alone Core + + + + + org.apache.thrift.tools + maven-thrift-plugin + + java + + + + thrift-compile + generate-sources + + compile + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + build-helper-add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/thrift/ + + + + + + + + + + + org.apache.thrift + libthrift + + + diff --git a/not-alone-core/src/main/thrift/common.thrift b/not-alone-core/src/main/thrift/common.thrift new file mode 100644 index 0000000000000000000000000000000000000000..03e419022d874fecc1e99ecc2540c4b01f5c3344 --- /dev/null +++ b/not-alone-core/src/main/thrift/common.thrift @@ -0,0 +1,138 @@ +namespace java fr.univnantes.alma.thrift +namespace js common + +exception InvalidOperationException { + 1: i32 code, + 2: string message +} + +exception GameNotFound { + 1: i32 code, + 2: string message +} + +struct Response{ + 1: bool state, + 2: string message +} + +struct TCard { + 1: string cardType, + 2: string cardName, + 3: list attributes +} + +struct TJeton{ + 1: string symbol +} + + +struct TBoard { + 1: string board +} + +struct TColor { + 1: string color +} + +struct TPositionJeton{ + 1: list position +} + +struct TPlacedJeton{ + 1: TJeton jeton, + 2: TPositionJeton position +} + +struct TPhase { + 1: string name +} + +struct TPair { + 1: string key, + 2: string value +} + +struct TAction { + 1: string type, + 2: list params +} + +struct TAskAction { + 1: string type, + 2: string message, + 3: list choices +} + + +struct TPlayerTeam{ + 1: string type +} + +struct THand{ + 1: list cards, + 2: list visibleCards, + 3: list jetons, + 4: i32 numberPionVolonte, + 5: list defausse, +} + +struct TScore{ + 1: i32 traqueScore, + 2: i32 creatureScore, + 3: TBoard boardDistribution, + 4: TColor boardColor +} + +struct TPlacedCard{ + 1: TCard card, + 2: string place +} + +struct TBalise{ + 1: string type, + 2: i32 state +} + +struct TPlanet{ + 1: list placedCard, + 2: list jetons, + 3: TBalise balise +} + +struct TCardReserve{ + 1: TCard card, + 2: i32 number +} + +struct TTraque{ + 1: string name, + 2: list visibleCards, + 3: i32 hiddenPlaceCardNumber, + 4: list defausse, + 5: i32 hiddenSurvivalCardNumber, + 6: i32 numberPionVolonte +} + +struct TCreature{ + 1: string name, + 2: list visibleCards, + 3: i32 hiddenTrackingCardNumber, + 4: list jetons +} + +struct TGameVariable{ + 1: string name, + 2: list values +} + +struct TDescription{ + 1: TPlayerTeam team, + 2: THand hand, + 3: TScore score, + 4: TPlanet planet + 5: list reserve, + 6: list variables, + 7: list traquesInformation, + 8: TCreature creatureInformation +} \ No newline at end of file diff --git a/not-alone-core/src/main/thrift/game-service.thrift b/not-alone-core/src/main/thrift/game-service.thrift new file mode 100644 index 0000000000000000000000000000000000000000..d3810b87c9ecce0d580c45b47f14d747214a3f7e --- /dev/null +++ b/not-alone-core/src/main/thrift/game-service.thrift @@ -0,0 +1,45 @@ +include "common.thrift" + +namespace java fr.univnantes.alma.thrift +namespace js common + +// Types + +struct JoinRequest { + 1: string name +} + +struct TPlayer { + 1: string token, + 2: string name, + 3: string address, + 4: i32 port +} + +struct TRoomId { + 1: string token +} + + +//Service + +service GameService { + + TRoomId createRoom(TPlayer player) throws (1:common.InvalidOperationException e) + + common.Response sendStartGame(TPlayer player, i32 creatureId, common.TBoard board, common.TColor color, list placeCards) + + common.Response joinRoom(TPlayer player, TRoomId roomId) + + common.TDescription getGameDescription(TPlayer player) + + void sendFinishPhase(TPlayer player, common.TPhase phase) + + void sendPlayCards(TPlayer player, list playerCards) + + void sendPlaceJetons(TPlayer player, list placedJetons) + + void sendResist(TPlayer player, i32 number) + + void sendGiveUp(TPlayer player) +} diff --git a/not-alone-core/src/main/thrift/player-service.thrift b/not-alone-core/src/main/thrift/player-service.thrift new file mode 100644 index 0000000000000000000000000000000000000000..e0f9e4b6764bc25a9c4494539a36a46eb8d2b6dd --- /dev/null +++ b/not-alone-core/src/main/thrift/player-service.thrift @@ -0,0 +1,29 @@ +include "common.thrift" + +namespace java fr.univnantes.alma.thrift +namespace js common + + +//Service + +service PlayerService { + bool ping() throws (1:common.InvalidOperationException e) + + void sendGameDescription(common.TDescription gameDescription) + + void sendGameStart() + + void sendGameIsFinished(common.TPlayerTeam winner) + + void sendFirstRoundStart() + + void sendStartPhase(common.TPhase phase, common.TDescription gameDescription) + + common.TAction askAction(common.TAskAction askedAction) + + void sendAction(common.TAskAction askedAction) + + void sendResponse(common.Response response) +} + + diff --git a/not-alone-doc/pom.xml b/not-alone-doc/pom.xml index 0c715837b43c59f9e8dc631d920a07d29f3e0e52..b15cbb6fb415c0c1483e5a740ccb17e36bd7050c 100644 --- a/not-alone-doc/pom.xml +++ b/not-alone-doc/pom.xml @@ -47,10 +47,8 @@ pdf - + coderay font diff --git a/not-alone-doc/src/doc/asciidoc/_sections/analyse.adoc b/not-alone-doc/src/doc/asciidoc/_sections/analyse.adoc index b0d8ddacd2755706c48b59d0daa4c3f576dacf57..476f3ec72e58f96948bc5ef6fc01e2a6d7af6396 100644 --- a/not-alone-doc/src/doc/asciidoc/_sections/analyse.adoc +++ b/not-alone-doc/src/doc/asciidoc/_sections/analyse.adoc @@ -1,36 +1,1262 @@ = Analyse du domaine +== Présentation des entités +=== Objets -[plantuml, exemple-mind-map, png] +==== Plateau +Un plateau est composé de 31 cases, des cases Traqué, des cartes Créature et une case Victoire. +Sur les cases Traqués, il peut y avoir le symbole Artemia. +Le Plateau est également composé d'un pion Assimilation et d'un pion Secours. +Chaque pion est respectivement placé sur une case Créature et une case Traqué. +Deux types de Plateau sont possibles : recto et verso. +la seule différence entre ces deux plateaux est la répartition des symboles Artemia. + + +[plantuml, obj-plateau, png] +.... +hide circle +skinparam monochrome true + +class Plateau{ + pionAssimilation : int + pionSecours : int + avancerAssimilation() : void + avancerSecours() : void + reculerAssimilation() : void + reculerSecours() : void + isCaseArtemia() : boolean +} + +class PlateauRecto + +class PlateauVerso + +Plateau <|-- PlateauRecto +Plateau <|-- PlateauVerso +.... + + +==== Joueur, Traqué et Créature +Un joueur représente une entité participant à une partie du jeu. +Les joueurs sont répartis en deux catégories : les Traqués (1-6 joueurs), la Créature (1 joueur). + +Les Traqués ont des pions Volontés (entre 0 et 3), des cartes Survie (0 ou plus) et des cartes Lieu (entre 0 et 10). +La Créature a des jetons Traque (3) et des cartes Traques (3). + +[plantuml, obj-joueur, png] +.... +hide circle +skinparam monochrome true + +class Joueur{ + nom : String +} + +class Traqué{ + pionVolonté : int +} + +class Créature + +Joueur <|-- Traqué +Joueur <|-- Créature +.... + +==== Réserve +La réserve représente une pioche pour Carte Lieu. +Elle contient un certains nombre d'exemplaires des Cartes Lieu numérotées de 6 à 10. + +[plantuml, obj-reserve, png] +.... +hide circle +skinparam monochrome true + +class Réserve{ + piocher(Entier) : Carte +} + +Réserve o- CarteLieu +.... + +==== Pioche +La pioche représente une pioche de cartes (Traque ou Survie). +Elle permet des actions comme mélanger les cartes et piocher aléatoirement une carte. +Elle sert également de défausse. Les cartes défaussées sont alors mises en fin de pioche. + +[plantuml, obj-pioche, png] +.... +hide circle +skinparam monochrome true +class Pioche{ + piocher() : Carte + mélanger() : void +} + +Pioche <|-- PiocheSurvie +Pioche <|-- PiocheTraque +PiocheSurvie o-- CarteSurvie +PiocheTraque o-- CarteTraque +.... + +==== Planète +La planète possède des lieux. +Ces lieux sont ceux représentés par les cartes Lieu. +Chaque lieu peut accueillir tous les Traqués (0-6) et tous les jetons Traques (0-3). + +[plantuml, obj-planete] +.... +hide circle +skinparam monochrome true + +Planète -- CarteLieu +Planète -- JetonTraque +Planète -- Traqué +.... + +==== Défausse et Main +La défausse représente la défausse personnelle de chaque Traqué pour ses cartes Lieu. +Les cartes défaussées sont visibles par tous les joueurs. +La défausse d'un Traqué peut contenir entre 0 à 10 cartes. +Un Traqué peut reprendre plusieurs cartes Lieu et peut défausser plusieurs cartes Lieu. + +La main représente les cartes Lieu que le Traqué peut jouer. +Les cartes présentes dans la main ne sont visibles que par le Traqué les possédant. +La main d'un Traqué peut contenir entre 0 à 10 cartes. + +[plantuml, obj-defausse-main, png] +.... +hide circle +skinparam monochrome true + +Main o-- "lieux[0..10]" CarteLieu +Défausse o-- "lieux[0..10]" CarteLieu +Main "main[1]" - "défausse[1]" Défausse : \t\t\t\t +.... + +==== Carte, CarteLieu, CarteJoueur, CarteSurvie et CarteTraque +L'entité Carte définit la représentation virtuelle d'une carte de jeu. +Une carte a un *Pouvoir* qui peuvent être modifiés, +appliqués, ou non appliqués. +Il existe plusieurs types de cartes : CarteLieu, CarteSurvie, +CarteTraque. Une carte peut être défaussée, piochée, jouée. + + +L'entité CarteLieu hérite de Carte. +Il existe 10 CarteLieu différentes, et chacune d'entre elle est numérotée. +Une *CarteLieu* peut être détenue par un *Traqué*, +être dans la défausse d'un joueur, être dans la *Réserve*, +ou encore sur la *Planète*. +Une CarteLieu ne peut être jouée que dans la phase 1. + + +L'entité CarteJoueur représente une Carte pouvant être présente +dans la "main" du *Joueur* et possédant une *Phase*. +Chaque CarteJoueur ne peut être jouée que lors de leur *Phase*. +Ces cartes peuvent être soit dans la "main" d'un *Joueur*, +soit dans la *Pioche*. + + +L'entité CarteSurvie caractérise une CarteJoueur +qui ne peut être possédée que par un Traqué. +Dans le jeu, elles peuvent donner un avantage situationnel aux *Traqués*. + + +L'entité CarteTraque est une CarteJoueur +qui ne peut être possédée que par la Créature. +Elle peut posséder des Symboles (Cible ou Artemia). + Dans le jeu elles peuvent donner un avantage situationnel à la *Créature*. + +[plantuml, obj-carte, png] +.... +hide circle +skinparam monochrome true + +class Carte{ + nom : String + activerPouvoir() : void +} + +class CarteLieu{ + numero : int +} + +class CarteJoueur{ + phase : Phase +} + +Carte <|-- CarteLieu +Carte <|-- CarteJoueur +Carte o- Pouvoir +CarteJoueur <|-- CarteSurvie +CarteJoueur <|-- CarteTraque +CarteTraque -- "symboles [0-2]" Symbole +Symbole <|-- SymboleArtemia +Symbole <|-- SymboleCible +.... + +==== JetonTraque, JetonCible, JetonArtemia et JetonCreature + +Le JetonTraque définit une pièce de jeu virtuelle, qui est posée +par la Créature durant la Phase 3. +Un jeton peut être posé sur une plusieurs CarteLieu de la Planète. +Un jeton symbolise un *Pouvoir*. + +Le JetonCible qualifie un JetonTraque qui a le pouvoir +d'une carteTraque. +Cette dernière décide si le JetonCible est jouable ou non. + +Le JetonArtemia définit un JetonTraque qui a toujours +au moins un *Pouvoir* constant : bloquer le *Pouvoir* de la *CarteLieu* +sur laquelle il est posé. +Le JetonArtemia n'est jouable que si la case du *Plateau* est Artemia +ou si la CarteTraque contient le symbole Artemia. + +Le JetonCréature caractérise un JetonTraque jouable à tous +les tours par la *Créature*. +Il détient au moins un *Pouvoir* : annuler l'effet de la *CarteLieu* +sur laquelle il est posé et retirer un pion de volonté à tout joueur +se trouvant sur la même *CarteLieu*. + +[plantuml, obj-jeton-traque, png] +.... +hide circle +skinparam monochrome true + +JetonTraque <|-- JetonCréature +JetonTraque <|-- JetonCible +JetonTraque <|-- JetonArtemia +.... + +==== Système + +Représentation du système dans son ensemble. + +[plantuml, obj-ensemble, png] +.... +hide circle +skinparam monochrome true + +class Joueur{ + nom : String +} + +class Traqué{ + pionVolonté : int +} + +class Créature + +class Plateau{ + pionAssimilation : int + pionSecours : int + avancerAssimilation() : void + avancerSecours() : void + reculerAssimilation() : void + reculerSecours() : void + isCaseArtemia() : boolean +} + +class PlateauRecto + +class PlateauVerso + +class Carte{ + nom : String + activerPouvoir() : void +} + +class CarteLieu{ + numero : int +} + +class CarteJoueur{ + phase : Phase +} + + +class Réserve{ + piocher() : Carte + remettre(Carte) : void +} + +class Pioche{ + piocher() : Carte + mélanger() : void +} + +Main o-- "lieux[1..10]" CarteLieu +Défausse o-- "lieux[1..10]" CarteLieu +Main "main[1]" - "défausse[1]" Défausse : \t\t\t\t +Pioche <|-- PiocheSurvie +Pioche <|-- PiocheTraque +PiocheSurvie o-- CarteSurvie +PiocheTraque o-- CarteTraque +Réserve o- CarteLieu +Partie -> "tours [1..*]" Tour : \t\t +Tour -> "phases[4]" Phase : \t\t +Partie o-- "joueurs[2..7]" Joueur +Partie o-- Réserve +Partie o-- Plateau +Partie o-- Planète +Carte <|-- CarteLieu +Carte <|-- CarteJoueur +Carte o- Pouvoir +CarteJoueur <|-- CarteSurvie +CarteJoueur <|-- CarteTraque +Plateau <|-- PlateauRecto +Plateau <|-- PlateauVerso +Joueur <|-- Traqué +Joueur <|-- Créature +Traqué o-- Main +Traqué o-- Défausse +Traqué -- PiocheSurvie +Créature -- PiocheTraque +JetonTraque <|-- JetonCréature +JetonTraque <|-- JetonCible +JetonTraque <|-- JetonArtemia +Créature -- JetonTraque +.... + +=== Actions + +==== Piocher + +===== Variante CarteSurvie + +Un Traqué prend une CarteSurvie dans la PiocheSurvie. + +.Avant de piocher +[plantuml, action-piocher-survie-avant, png] +.... +hide circle +skinparam monochrome true + +class "Anna : Traqué" as Anna{} + +class "Détecteur : CarteSurvie" as Detecteur{} +class "Drone : CarteSurvie" as Drone{} +class "Cavale : CarteSurvie" as Cavale{} + +class "Pioche : PiocheSurvie" as Pioche{} + +Anna -- Detecteur +Pioche -- Drone +Pioche -- Cavale +.... + +.Après avoir piocher +[plantuml, action-piocher-survie-apres, png] +.... +hide circle +skinparam monochrome true + +class "Anna : Traqué" as Anna{} + +class "Détecteur : CarteSurvie" as Detecteur{} +class "Drone : CarteSurvie" as Drone{} +class "Cavale : CarteSurvie" as Cavale{} + +class "Pioche : PiocheSurvie" as Pioche{} + +Anna -- Detecteur +Anna -- Drone +Pioche -- Cavale +.... + +===== Variante CarteTraque + +La Créture prend une CarteTraque dans la PiocheTraque. + +.Avant de piocher +[plantuml, action-piocher-traque-avant, png] +.... +hide circle +skinparam monochrome true + +class "Bob : Créature" as Bob{} + +class "Acharnement : CarteTraque" as Acharnement{} +class "Angoisse : CarteTraque" as Angoisse{} +class "Anticipation : CarteTraque" as Anticipation{} + +class "Pioche : PiocheTraque" as Pioche{} + +Bob -- Acharnement +Pioche -- Angoisse +Pioche -- Anticipation +.... + +.Après avoir piocher +[plantuml, action-piocher-traque-apres, png] +.... +hide circle +skinparam monochrome true + +class "Bob : Créature" as Bob{} + +class "Acharnement : CarteTraque" as Acharnement{} +class "Angoisse : CarteTraque" as Angoisse{} +class "Anticipation : CarteTraque" as Anticipation{} + +class "Pioche : PiocheTraque" as Pioche{} + +Bob -- Acharnement +Bob -- Angoisse +Pioche -- Anticipation +.... + +==== Mélanger + +La Pioche est mélangée : l'ordre des cartes est modifié aléatoirement. + +===== Variante PiocheSurvie + +.Avant avoir mélanger +[plantuml, action-mélanger-survie-avant, png] +.... +hide circle +skinparam monochrome true + +class "Cavale : CarteSurvie" as Cavale{ + ordre : 1 +} + +class "Détecteur : CarteSurvie" as Detecteur{ + ordre : 2 +} +class "Drone : CarteSurvie" as Drone{ + ordre : 3 +} + +class "Pioche : PiocheSurvie" as Pioche{} + +Pioche -- Cavale +Pioche -- Drone +Pioche -- Detecteur +.... + +.Après avoir mélanger +[plantuml, action-mélanger-survie-apres, png] +.... +hide circle +skinparam monochrome true + +class "Détecteur : CarteSurvie" as Detecteur{ + ordre : 1 +} +class "Drone : CarteSurvie" as Drone{ + ordre : 2 +} +class "Cavale : CarteSurvie" as Cavale{ + ordre : 3 +} +class "Pioche : PiocheSurvie" as Pioche{} + +Pioche -- Cavale +Pioche -- Detecteur +Pioche -- Drone +.... + +===== Variante PiocheTraque + +.Avant avoir mélanger +[plantuml, action-mélanger-traque-avant, png] +.... +hide circle +skinparam monochrome true + +class "Acharnement : CarteTraque" as Acharnement{ + ordre : 1 +} + +class "Angoisse : CarteTraque" as Angoisse{ + ordre : 2 +} +class "Anticipation : CarteTraque" as Anticipation{ + ordre : 3 +} + +class "Pioche : PiocheTraque" as Pioche{} + +Pioche -- Acharnement +Pioche -- Angoisse +Pioche -- Anticipation +.... + +.Après avoir mélanger +[plantuml, action-mélanger-traque-apres, png] +.... +hide circle +skinparam monochrome true + +class "Angoisse : CarteTraque" as Angoisse{ + ordre : 1 +} +class "Acharnement : CarteTraque" as Acharnement{ + ordre : 2 +} +class "Anticipation : CarteTraque" as Anticipation{ + ordre : 3 +} +class "Pioche : PiocheTraque" as Pioche{} + +Pioche -- Acharnement +Pioche -- Angoisse +Pioche -- Anticipation +.... + +==== Résister + +Un Traqué peut décider de résister. +Il va perdre des pions Volontés mais récupérer des cartes Lieu. + +===== Variante 1 + +.Avant résister +[plantuml, action-resister-1-avant, png] +.... +hide circle + +skinparam monochrome true +class "Anna : Traqué" as anna{ + pionVolonté : 3 +} + +class "Antre : CarteLieu" as antre{} +class "Plage : CarteLieu" as plage{} +class "Jungle : CarteLieu" as jungle{} +class "Rivière : CarteLieu" as riviere{} +class "Rover : CarteLieu" as rover{} + +anna - main +anna - defausse +main -- antre +defausse -- plage +defausse -- jungle +defausse -- riviere +defausse -- rover +.... + +.Après résister +[plantuml, action-resister-1-apres, png] +.... +hide circle + +skinparam monochrome true +class "Anna : Traqué" as anna{ + pionVolonté : 2 +} + +class "Antre : CarteLieu" as antre{} +class "Plage : CarteLieu" as plage{} +class "Jungle : CarteLieu" as jungle{} +class "Rivière : CarteLieu" as riviere{} +class "Rover : CarteLieu" as rover{} + +anna - main +anna - defausse +main -- antre +main -- plage +defausse -- jungle +main -- riviere +defausse -- rover +.... + +===== Variante 2 + +.Avant résister +[plantuml, action-resister-2-avant, png] +.... +hide circle + +skinparam monochrome true +class "Anna : Traqué" as anna{ + pionVolonté : 3 +} + +class "Antre : CarteLieu" as antre{} +class "Plage : CarteLieu" as plage{} +class "Jungle : CarteLieu" as jungle{} +class "Rivière : CarteLieu" as riviere{} +class "Rover : CarteLieu" as rover{} + +anna - main +anna - defausse +main -- antre +defausse -- plage +defausse -- jungle +defausse -- riviere +defausse -- rover +.... + +.Après résister +[plantuml, action-resister-2-apres, png] +.... +hide circle + +skinparam monochrome true +class "Anna : Traqué" as anna{ + pionVolonté : 1 +} + +class "Antre : CarteLieu" as antre{} +class "Plage : CarteLieu" as plage{} +class "Jungle : CarteLieu" as jungle{} +class "Rivière : CarteLieu" as riviere{} +class "Rover : CarteLieu" as rover{} + +anna - main +anna - defausse +main -- antre +main -- plage +main -- jungle +main -- riviere +main -- rover +.... + +==== Jouer Carte Lieu + +Un Traqué doit durant le tour jouer une carte lieu. + +===== Variante 1 +Un traqué joue 1 carte face cachée + +.Avant de jouer une carte lieu + +[plantuml, action-jouer-1-carte-avant, png] +.... +hide circle +skinparam monochrome true + +class "Anna : Traqué" as Anna{} + + +class "Antre : CarteLieu" as antre{} +class "Plage : CarteLieu" as plage{} +class "Jungle : CarteLieu" as jungle{} +class "Rivière : CarteLieu" as riviere{} +class "Rover : CarteLieu" as rover{} + +class "Cachée : Carte face cachée" as Caché{} + +Anna -- antre +Anna -- plage +Anna -- jungle +Anna -- riviere +Anna -- rover +.... + +.Après avoir joué une carte lieu + +[plantuml, action-jouer-1-carte-après, png] +.... +hide circle +skinparam monochrome true + +class "Anna : Traqué" as Anna{} + + +class "Antre : CarteLieu" as antre{} +class "Plage : CarteLieu" as plage{} +class "Jungle : CarteLieu" as jungle{} +class "Rivière : CarteLieu" as riviere{} +class "Rover : CarteLieu" as rover{} + +class "Cachée : Carte face cachée" as Caché{} + +Anna -- antre +Anna -- plage +Anna -- jungle +Anna -- riviere +Caché -- rover +.... + +===== Variante 2 +Un traqué joue 2 cartes faces cachées + +.Avant de jouer une carte lieu + +[plantuml, action-jouer-2-carte-avant, png] .... -@startmindmap -* Debian -** Ubuntu -*** Linux Mint -*** Kubuntu -*** Lubuntu -*** KDE Neon -** LMDE -** SolydXK -** SteamOS -** Raspbian with a very long name -*** Raspmbc => OSMC -*** Raspyfi => Volumio -@endmindmap +hide circle +skinparam monochrome true + +class "Anna : Traqué" as Anna{} + + +class "Antre : CarteLieu" as antre{} +class "Plage : CarteLieu" as plage{} +class "Jungle : CarteLieu" as jungle{} +class "Rivière : CarteLieu" as riviere{} +class "Rover : CarteLieu" as rover{} + +class "Cachées : Cartes faces cachées" as Caché{} + +Anna -- antre +Anna -- plage +Anna -- jungle +Anna -- riviere +Anna -- rover .... +.Après avoir joué une carte lieu -[plantuml, class-diagram-example, png] +[plantuml, action-jouer-2-carte-apres, png] .... hide circle skinparam monochrome true -class Joueur +class "Anna : Traqué" as Anna{} + -class Partie +class "Antre : CarteLieu" as antre{} +class "Plage : CarteLieu" as plage{} +class "Jungle : CarteLieu" as jungle{} +class "Rivière : CarteLieu" as riviere{} +class "Rover : CarteLieu" as rover{} -Partie -> "creature [1]" Joueur : \t\t +class "Cachées : Cartes faces cachées" as Caché{} -Partie -> "traques [1-6]" Joueur : \t\t +Anna -- antre +Anna -- plage +Anna -- jungle +Caché -- riviere +Caché -- rover .... + +==== Jouer Carte Traque +La créature doit jouer une carte Traque durant le tour. + +===== Variante 1 + + +.Avant de jouer +[plantuml, action-jouer-carte-traque-avant, png] +.... +hide circle +skinparam monochrome true + +class "Bob : Créature" as Bob{} + +class "Acharnement : CarteTraque" as Acharnement{} +class "Angoisse : CarteTraque" as Angoisse{} +class "Anticipation : CarteTraque" as Anticipation{} + +class "Mutation : CarteTraque" as Mutation{ +ordre : 1 +} + +class "Pioche : PiocheTraque" as Pioche{} + +Bob -- Acharnement +Bob -- Angoisse +Bob -- Anticipation +Pioche -- Mutation +.... + +.Après avoir joué +[plantuml, action-jouer-carte-traque-apres, png] +.... +hide circle +skinparam monochrome true + +class "Bob : Créature" as Bob{} + +class "Acharnement : CarteTraque" as Acharnement{} +class "Angoisse : CarteTraque" as Angoisse{} +class "Mutation : CarteTraque" as Mutation{ +ordre : 1 +} +class "Anticipation : CarteTraque" as Anticipation{ +ordre : 2 +} + +class "Pioche : PiocheTraque" as Pioche{} + +Bob -- Acharnement +Bob -- Angoisse +Pioche -- Mutation +Pioche -- Anticipation +.... + + +===== Variante 2 +La créature pose deux cartes. + +.Avant de jouer +[plantuml, action-jouer-carte-traque-avant2, png] +.... +hide circle +skinparam monochrome true + +class "Bob : Créature" as Bob{} + +class "Acharnement : CarteTraque" as Acharnement{} +class "Angoisse : CarteTraque" as Angoisse{} +class "Anticipation : CarteTraque" as Anticipation{} + +class "Mutation : CarteTraque" as Mutation{ +ordre : 1 +} + +class "Pioche : PiocheTraque" as Pioche{} + +Bob -- Acharnement +Bob -- Angoisse +Bob -- Anticipation +Pioche -- Mutation +.... + +.Après avoir joué +[plantuml, action-jouer-carte-traque-apres2, png] +.... +hide circle +skinparam monochrome true + +class "Bob : Créature" as Bob{} + +class "Acharnement : CarteTraque" as Acharnement{} +class "Angoisse : CarteTraque" as Angoisse{ +ordre : 3 +} +class "Mutation : CarteTraque" as Mutation{ +ordre : 1 +} +class "Anticipation : CarteTraque" as Anticipation{ +ordre : 2 +} + +class "Pioche : PiocheTraque" as Pioche{} + +Bob -- Acharnement +Pioche -- Angoisse +Pioche -- Mutation +Pioche -- Anticipation +.... + +==== Jouer carte Survie + +Un Traqué met une CarteSurvie dans la PiocheSurvie. + +.Avant de jouer une carte survie +[plantuml, action-jouer-carte-survie-avant, png] +.... +hide circle +skinparam monochrome true + +class "Anna : Traqué" as Anna{} + +class "Détecteur : CarteSurvie" as Detecteur{} +class "Drone : CarteSurvie" as Drone{ +ordre = 1 +} + +class "Pioche : PiocheSurvie" as Pioche{} + +Anna -- Detecteur +Pioche -- Drone +.... + +.Après avoir piocher +[plantuml, action-jouer-carte-survie-apres, png] +.... +hide circle +skinparam monochrome true + +class "Anna : Traqué" as Anna{} + + +class "Drone : CarteSurvie" as Drone{ +ordre = 1 +} +class "Détecteur : CarteSurvie" as Detecteur{ +ordre = 2 +} + +class "Pioche : PiocheSurvie" as Pioche{} + +Pioche -- Detecteur +Pioche -- Drone +.... + +==== Lâcher-prise + +Un Traqué lâche prise quand il n'a plus de pionVolonté. +Il va récupérer ses pions Volontés et ses cartes Lieu dans la défausse. +Le pion assimilation va avancer de 1 en appelant AvancerPionAssimilation. + +.Avant Lâcher-prise +[plantuml, action-Lâcher-prise-1-avant, png] +.... +hide circle + +skinparam monochrome true +class "Anna : Traqué" as anna{ + pionVolonté : 0 +} + +class "Antre : CarteLieu" as antre{} +class "Plage : CarteLieu" as plage{} +class "Jungle : CarteLieu" as jungle{} +class "Rivière : CarteLieu" as riviere{} +class "Rover : CarteLieu" as rover{} + +anna - main +anna - defausse +main -- antre +defausse -- plage +defausse -- jungle +defausse -- riviere +defausse -- rover +.... + +.Après Lâcher-prise +[plantuml, action-Lâcher-prise-1-apres, png] +.... +hide circle + +skinparam monochrome true +class "Anna : Traqué" as anna{ + pionVolonté : 3 +} + +class "Antre : CarteLieu" as antre{} +class "Plage : CarteLieu" as plage{} +class "Jungle : CarteLieu" as jungle{} +class "Rivière : CarteLieu" as riviere{} +class "Rover : CarteLieu" as rover{} + +anna - main +anna - defausse +main -- antre +main -- plage +main -- jungle +main -- riviere +main -- rover +.... + +==== Défausser carte Survie + +Un Traqué peut défausser une CarteSurvie dans la PiocheSurvie. + +.Avant de défausser une carte survie +[plantuml, action-defausser-carte-survie-avant, png] +.... +hide circle +skinparam monochrome true + +class "Anna : Traqué" as Anna{} + +class "Détecteur : CarteSurvie" as Detecteur{} +class "Drone : CarteSurvie" as Drone{ +ordre = 1 +} + +class "Pioche : PiocheSurvie" as Pioche{} + +Anna -- Detecteur +Pioche -- Drone +.... + +.Après avoir défausser une carte Survie +[plantuml, action-defausser-carte-survie-apres, png] +.... +hide circle +skinparam monochrome true + +class "Anna : Traqué" as Anna{} + + +class "Drone : CarteSurvie" as Drone{ +ordre = 1 +} +class "Détecteur : CarteSurvie" as Detecteur{ +ordre = 2 +} + +class "Pioche : PiocheSurvie" as Pioche{} + +Pioche -- Detecteur +Pioche -- Drone +.... + +==== Défausser Carte Lieu + +Un Traqué peut devoir défausser une carte lieu. + + + +.Avant de défausser une carte lieu + +[plantuml, action-defausse-1-carte-avant, png] +.... +hide circle +skinparam monochrome true + +class "Anna : Traqué" as Anna{} +class "main" as main{} + + +class "Antre : CarteLieu" as antre{} +class "Plage : CarteLieu" as plage{} +class "Jungle : CarteLieu" as jungle{} +class "Rivière : CarteLieu" as riviere{} +class "Rover : CarteLieu" as rover{} + +class "Defausse " as Defausse{} +Anna -- Defausse +Anna -- main +main -- antre +main -- plage +main -- jungle +main -- riviere +main -- rover +.... + +.Après avoir défaussé une carte lieu + +[plantuml, action-defausse-1-carte-après, png] +.... +hide circle +skinparam monochrome true + +class "Anna : Traqué" as Anna{} +class "main" as main{} + + +class "Antre : CarteLieu" as antre{} +class "Plage : CarteLieu" as plage{} +class "Jungle : CarteLieu" as jungle{} +class "Rivière : CarteLieu" as riviere{} +class "Rover : CarteLieu" as rover{} + +class "Defausse " as Defausse{} + +Anna -- Defausse +Anna -- main +Defausse -- antre +main -- plage +main -- jungle +main -- riviere +main -- rover +.... + +==== Défausser Carte Traque +La créature peut devoir défausser une carte Traque durant le tour + + +.Avant de défausser +[plantuml, action-defausser-carte-traque-avant, png] +.... +hide circle +skinparam monochrome true + +class "Bob : Créature" as Bob{} + +class "Acharnement : CarteTraque" as Acharnement{} +class "Angoisse : CarteTraque" as Angoisse{} +class "Anticipation : CarteTraque" as Anticipation{} + +class "Mutation : CarteTraque" as Mutation{ +ordre : 1 +} + +class "Pioche : PiocheTraque" as Pioche{} + +Bob -- Acharnement +Bob -- Angoisse +Bob -- Anticipation +Pioche -- Mutation +.... + +.Après avoir défaussé +[plantuml, action-defausser-carte-traque-apres, png] +.... +hide circle +skinparam monochrome true + +class "Bob : Créature" as Bob{} + +class "Acharnement : CarteTraque" as Acharnement{} +class "Angoisse : CarteTraque" as Angoisse{} +class "Mutation : CarteTraque" as Mutation{ +ordre : 1 +} +class "Anticipation : CarteTraque" as Anticipation{ +ordre : 2 +} + +class "Pioche : PiocheTraque" as Pioche{} + +Bob -- Acharnement +Bob -- Angoisse +Pioche -- Mutation +Pioche -- Anticipation +.... + +==== Avancer pion assimilation + +Après avoir gagné un point, la créature a son pion assimilation avancé de 1 + +.Avant d'avancer +[plantuml, action-avancer-pion-assimilation-avant, png] +.... +hide circle +skinparam monochrome true + +class Plateau{ + pionAssimilation : 2 +} + +.... + +.Apres avoir avancé +[plantuml, action-avancer-pion-assimilation-apres, png] +.... +hide circle +skinparam monochrome true + +class Plateau{ + pionAssimilation : 3 +} +.... + +==== Reculer pion assimilation + +Après avoir perdu un point, la créature a son pion assimilation reculé de 1 + +.Avant de reculer +[plantuml, action-reculer-pion-assimilation-avant, png] +.... +hide circle +skinparam monochrome true + +class Plateau{ +pionAssimilation : 3 + +} + +.... + +.Apres avoir reculé +[plantuml, action-reculer-pion-assimilation-apres, png] +.... +hide circle +skinparam monochrome true + +class Plateau{ +pionAssimilation : 2 +} + +.... + +==== Avancer pion secours + +Après avoir gagné un point, l'équipe des Traqués a son pion secours avancé de 1 + +.Avant d'avancer +[plantuml, action-avancer-pion-secours-avant, png] +.... +hide circle +skinparam monochrome true + +class Plateau{ + pionSecours : 2 +} + +.... + +.Apres avoir avancé +[plantuml, action-avancer-pion-secours-apres, png] +.... +hide circle +skinparam monochrome true + +class Plateau{ + pionSecours : 3 +} +.... + +==== Reculer pion assimilation + +Après avoir perdu un point, l'équipe des Traqués a son pion secours reculé de 1 + +.Avant de reculer +[plantuml, action-reculer-pion-secours-avant, png] +.... +hide circle +skinparam monochrome true + +class Plateau{ +pionSecours : 3 + +} + +.... + +.Apres avoir reculé +[plantuml, action-reculer-pion-secours-apres, png] +.... +hide circle +skinparam monochrome true + +class Plateau{ +pionSecours : 2 +} + +.... + +==== RécupérerDéfausseCartesLieu + +Un Traqué peut récupérer de la défausse une carte lieu . + +.Avant de récupérer +[plantuml, action-recupérer-carte-lieu-avant, png] +.... +hide circle + +skinparam monochrome true +class "Anna : Traqué" as anna{ + +} + +class "Antre : CarteLieu" as antre{} +class "Plage : CarteLieu" as plage{} +class "Jungle : CarteLieu" as jungle{} +class "Rivière : CarteLieu" as riviere{} +class "Rover : CarteLieu" as rover{} + +anna - main +anna - defausse +main -- antre +defausse -- plage +defausse -- jungle +defausse -- riviere +defausse -- rover +.... + +.Après avoir récuperé +[plantuml, action-recupérer-carte-lieu-apres, png] +.... +hide circle + +skinparam monochrome true +class "Anna : Traqué" as anna{ +} + +class "Antre : CarteLieu" as antre{} +class "Plage : CarteLieu" as plage{} +class "Jungle : CarteLieu" as jungle{} +class "Rivière : CarteLieu" as riviere{} +class "Rover : CarteLieu" as rover{} + +anna - main +anna - defausse +main -- antre +main -- plage +defausse -- jungle +defausse -- riviere +defausse -- rover +.... + diff --git a/not-alone-doc/src/doc/asciidoc/_sections/composants.adoc b/not-alone-doc/src/doc/asciidoc/_sections/composants.adoc index bdf3d391d8fd4211a533fb7359162c6eebcfd3ed..bbdcad8396a004e522f29fbbf00b0a3a394bf3b1 100644 --- a/not-alone-doc/src/doc/asciidoc/_sections/composants.adoc +++ b/not-alone-doc/src/doc/asciidoc/_sections/composants.adoc @@ -1 +1,254 @@ = Conception préliminaire + +== Liste des fonctions de l'interface Client-Serveur + +=== Game Service +- createRoom(player : TPlayer) : TRoomId +- joinRoom(player : TPlayer, roomId : TRoomId) : Response +- sendStartGame(player : TPlayer, creatureId : Integer, board : TBoard, color : TColor, placeCards : Tcards[*]) : Response +- getGameDescription(player : TPlayer) : TDescription +- sendFinishPhase(player : TPlayer, phase : TPhase) : void +- sendPlayCards(player : TPlayer, playerCards : TCard[*]) : void +- sendPlaceJetons(player : TPlayer, placedJetons : TPlacedJeton[*]) : void +- sendResist(player : TPlayer, number : Integer) : void +- sendGiveUp(player : TPlayer) : void + +=== Player Service + +- sendGameDescription(gameDescription : TDescription) : void +- sendGameStart(): void +- sendGameIsFinished(common.TPlayerTeam winner) : void +- sendFirstRoundStart() : void +- sendStartPhase(phase : TPhase, gameDescription : TDescription) : void +- askAction(askedAction : TAskAction) : TAction +- sendAction(askedAction : TAskAction) : void +- sendResponse(response : Response) : void + +== Components diagram + +- Not alone (Joueur, Créature, Traqué, Main, Carte, Pioche, Réserve, Planète, Partie, Pouvoir) +- Base de données (Sauvegarde de joueurs) +- Authentificateur (SecurityWrapper) +- Client + +== Components diagram + +[plantuml, components-diagram, png] +.... +hide circle +skinparam monochrome true + +component GameService as na + +component GameClient as c + +database DataBase as db + +component SecurityWrapper as sw + +interface Data as dbi + +interface GameService as nai + +interface Security as swi + +interface PlayerService as ci + +c - ci +nai - na +na .> "use" swi +c .> "use" nai +na ..> "use" ci + +dbi - db + +swi - sw +sw .> "use" dbi + +.... + +=== Interface + +[plantuml, interface-diagrams, png] +.... +hide circle +skinparam monochrome true + +class "«interface» \n Data" as dbi{ + existUser(id : String):Boolean + findUser(id : String):User + findPlaceCard(id : String):PlaceCard + findPlaceCards(ids : String[*]):PlaceCard[*] + findSurvivalCard(id : String):SurvivalCard + findSurvivalCards(ids : String[*]):SurvivalCard[*] + findAllSurvivalCards():SurvivalCard[*] + findTrackingCard(id : String):TrackingCard + findTrackingCards(ids : String[*]):TrackingCard[*] + findAllTrackingCards():TrackingCard[*] +} + +class "«interface» \n Security" as swi{ + verifyUser(id : String, password : String):Boolean + generateToken(id : String , gameId : String):String + getUser(id : String):User +} + +class "«interface» \n GameService" as si{ + createRoom(player : TPlayer) : TRoomId + joinRoom(player : TPlayer, roomId : TRoomId) : Response + sendStartGame(player : TPlayer, creatureId : Integer, board : TBoard, color : TColor, placeCards : Tcards[*]) : Response + getGameDescription(player : TPlayer) : TDescription + sendFinishPhase(player : TPlayer, phase : TPhase) : void + sendPlayCards(player : TPlayer, playerCards : TCard[*]) : void + sendPlaceJetons(player : TPlayer, placedJetons : TPlacedJeton[*]) : void + sendResist(player : TPlayer, number : Integer) : void + sendGiveUp(player : TPlayer) : void +} + +class "«interface» \n PlayerService" as csi{ + sendGameDescription(gameDescription : TDescription) : void + sendGameStart(): void + sendGameIsFinished(common.TPlayerTeam winner) : void + sendFirstRoundStart() : void + sendStartPhase(phase : TPhase, gameDescription : TDescription) : void + askAction(askedAction : TAskAction) : TAction + sendAction(askedAction : TAskAction) : void + sendResponse(response : Response) : void +} +.... + + +== Diagrammes de séquence + +== Diagramme de séquence de mise en place + +- TPlayer tPlayer1 = {"Jean", "192.168.1.12:4200"} +- TPlayer tPlayer2 = {"Sébastien", "192.168.1.13:4200"} + +Couleur partie : Bleu +[plantuml] +---- +hide circle +skinparam monochrome true + +C1Client -> S1Serveur : createRoom(tPlayer1) +C1Client <-- S1Serveur : 1001 +C2Client -> S1Serveur : joinGame(tPlayer2, 1001) +C2Client <-- S1Serveur : {true, ""} +C1Client -> S1Serveur : sendStartGame(tPlayer1, 1, "PLATEAU_RECTO_ID", "Bleu", [Nexus, Jungle, Rivière, Dôme, Plage, Mangrove , Abri, Epave, Fungi, Portail]) +C1Client <-- S1Serveur : {true, ""} +S1Serveur ->> C1Client : sendFirstRoundStart() +S1Serveur ->> C2Client : sendFirstRoundStart() +C1Client -> S1Serveur : getGameDescription(tPlayer1) +C1Client <-- S1Serveur : gameDescription +C2Client -> S1Serveur : getGameDescription(tPlayer2) +C2Client <-- S1Serveur : gameDescription +---- + +=== Diagramme de séquence du déroulement d'une manche + +- TPlayer tPlayerTraque = {"Jean", "192.168.1.12:4200"} +- TPlayer tPlayerCreature = {"Sébastien", "192.168.1.13:4200"} + +[plantuml] +---- +hide circle +skinparam monochrome true + +C1Client <<-- S1Serveur : sendStartPhase("PREPHASE_1", {GameDescription}) +C2Client <<-- S1Serveur : sendStartPhase("PREPHASE_1", {GameDescription}) +C1Client --> S1Serveur : sendResist(tPlayerTraque, 1) +C1Client <-- S1Serveur : {true, ""} +C1Client --> S1Serveur : sendPlayCards(tPlayerTraque, ["Adrenaline"]) +C1Client <-- S1Serveur : {true, ""} +C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PREPHASE_1") +C1Client <-- S1Serveur : {true, ""} +C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PREPHASE_1") +C2Client <-- S1Serveur : {true, ""} + +C1Client <<-- S1Serveur : sendStartPhase("PHASE_1", {GameDescription}) +C2Client <<-- S1Serveur : sendStartPhase("PHASE_1", {GameDescription}) +C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PHASE_1") +C2Client <-- S1Serveur : {true, ""} +C1Client --> S1Serveur : sendPlayCards(tPlayerTraque, ["La_Plage"]) +C1Client <-- S1Serveur : {true, ""} +C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PHASE_1") +C1Client <-- S1Serveur : {true, ""} + +C1Client <<-- S1Serveur : sendStartPhase("POSTPHASE_1", {GameDescription}) +C2Client <<-- S1Serveur : sendStartPhase("POSTPHASE_1", {GameDescription}) +C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "POSTPHASE_1") +C1Client <-- S1Serveur : {true, ""} +C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "POSTPHASE_1") +C2Client <-- S1Serveur : {true, ""} + +C1Client <<-- S1Serveur : sendStartPhase("PREPHASE_2", {GameDescription}) +C2Client <<-- S1Serveur : sendStartPhase("PREPHASE_2", {GameDescription}) +C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PREPHASE_2") +C1Client <-- S1Serveur : {true, ""} +C2Client --> S1Serveur : sendPlayCards(tPlayerCreature, ["Soif_de_sang"]) +C2Client <-- S1Serveur : {true, ""} +C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PREPHASE_2") +C2Client <-- S1Serveur : {true, ""} + +C1Client <<-- S1Serveur : sendStartPhase("PHASE_2", {GameDescription}) +C2Client <<-- S1Serveur : sendStartPhase("PHASE_2", {GameDescription}) +C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PHASE_2") +C1Client <-- S1Serveur : {true, ""} +C2Client --> S1Serveur : sendPlaceJetons(tPlayerCreature, "{{"Creature", "Place_1"}, {"Cible", "Place_7"}}") +C2Client <-- S1Serveur : {true, ""} +C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PHASE_2") +C2Client <-- S1Serveur : {true, ""} + +C1Client <<-- S1Serveur : sendStartPhase("POSTPHASE_2", {GameDescription}) +C2Client <<-- S1Serveur : sendStartPhase("POSTPHASE_2", {GameDescription}) +C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "POSTPHASE_2") +C2Client <-- S1Serveur : {true, ""} +C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "POSTPHASE_2") +C1Client <-- S1Serveur : {true, ""} + +C1Client <<-- S1Serveur : sendStartPhase("PREPHASE_3", {GameDescription}) +C2Client <<-- S1Serveur : sendStartPhase("PREPHASE_3", {GameDescription}) +C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PREPHASE_3") +C1Client <-- S1Serveur : {true, ""} +C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PREPHASE_3") +C2Client <-- S1Serveur : {true, ""} + +C1Client <<-- S1Serveur : sendStartPhase("PHASE_3", {GameDescription}) +C2Client <<-- S1Serveur : sendStartPhase("PHASE_3", {GameDescription}) +C1Client <- S1Serveur : askAction({"CHOOSE_POWER" ,"Choose a power",[{"1", "Power 1"}, {"2", "Power 2"}]}) +C1Client --> S1Serveur : {"CHOOSE_POWER", ["1"]} +C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PHASE_3") +C1Client <-- S1Serveur : {true, ""} +C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PHASE_3") +C2Client <-- S1Serveur : {true, ""} + +C1Client <<-- S1Serveur : sendStartPhase("POSTPHASE_3", {GameDescription}) +C2Client <<-- S1Serveur : sendStartPhase("POSTPHASE_3", {GameDescription}) +C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "POSTPHASE_3") +C1Client <-- S1Serveur : {true, ""} +C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "POSTPHASE_3") +C2Client <-- S1Serveur : {true, ""} + +C1Client <<-- S1Serveur : sendStartPhase("PREPHASE_4", {GameDescription}) +C2Client <<-- S1Serveur : sendStartPhase("PREPHASE_4", {GameDescription}) +C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PREPHASE_4") +C1Client <-- S1Serveur : {true, ""} +C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PREPHASE_4") +C2Client <-- S1Serveur : {true, ""} + +C1Client <<-- S1Serveur : sendStartPhase("PHASE_4", {GameDescription}) +C2Client <<-- S1Serveur : sendStartPhase("PHASE_4", {GameDescription}) +C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "PHASE_4") +C1Client <-- S1Serveur : {true, ""} +C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "PHASE_4") +C2Client <-- S1Serveur : {true, ""} + +C1Client <<-- S1Serveur : sendStartPhase("POSTPHASE_4", "GameDescription") +C2Client <<-- S1Serveur : sendStartPhase("POSTPHASE_4", {GameDescription}) +C1Client --> S1Serveur : sendFinishPhase(tPlayerTraque, "POSTPHASE_4") +C1Client <-- S1Serveur : {true, ""} +C2Client --> S1Serveur : sendFinishPhase(tPlayerCreature, "POSTPHASE_4") +C2Client <-- S1Serveur : {true, ""} + +---- \ No newline at end of file diff --git a/not-alone-doc/src/doc/asciidoc/_sections/conception.adoc b/not-alone-doc/src/doc/asciidoc/_sections/conception.adoc index de9c910e42ee8871937c5ec8a470f959e6d84d90..e343e05b2f10130cf614b34ef08ed92060e38e34 100644 --- a/not-alone-doc/src/doc/asciidoc/_sections/conception.adoc +++ b/not-alone-doc/src/doc/asciidoc/_sections/conception.adoc @@ -1 +1,1568 @@ = Conception détaillée + +== Game + +[plantuml] +.... +class Room{ + - requests : BlockingQueue + - playersCounter : AtomicInteger + - roomId : String + - creator : User + - players : Map + - users : Map + - isStart : Boolean + - isClose : Boolean + - play : Thread + - game : Game + - static(MAX_PLAYER : Integer) + - static(MIN_PLAYER : Integer) + + getRoomId() : String + + getNumberPlayers() : AtomicInteger + + isCreator(user : User) : Boolean + + setGame(game : Game) + + join(user : User) : Response + + start(user : User, creatureNumber : Integer, board : Board, planet : Planet) : Response + + getGameDescription(user : User) : TDescription + - requestManagement() + - handleRequest(request : GameRequest) + + sendFinishPhase(user : User, phase : Phase) + + sendPlayCards(user : User, playerCards : PlayerCards[*]) + + sendPlaceJetons(user : User, placedJetons : PlacedJeton[*]) + + sendResist(user : User, number : Integer) + + sendGiveUp(user : User) + + askAction(inGameIdPlayer : Integer, askedAction : TAskAction ) : Action + + sendAction(inGameIdPlayer : Integer, askedAction : TAskAction ) + + sendFirstRoundStart() + + sendStartPhase(idPlayer : Integer, tPhase : TPhase, description : TDescription ) + + sendDescription(idPlayer : Integer, description : TDescription ) + + sendGameIsFinished(winner : TPlayerTeam ) + - inGameIdToUser(id : Integer ) : User + - inGameIdToUser(user : User ) : Integer + - playersToIdNamePairList(user : User ) : (Pair)[*] + - playerToIdNamePair(inGameId : Integer ) + - userIsInRoom(user : User ) boolean + + +} + + + + interface GameInterface{ + + isFinish() : Boolean + + playerHasFinished(playerId : Integer, phase : Phase) + + playerPlayCard(playerId : Integer, card : Card) : Response + + playerPlayCard(playerId : Integer, cards : Card[*]) : Response + + + playerPlaceJeton(playerId : Integer, jeton : PlacedJeton) : Response + + playerPlaceJeton(playerId : Integer, jetons : PlacedJeton[*]) : Response + + + playerResist(playerId : Integer, number : Integer) : Response + + playerGiveUp(playerId : Integer): Response + + playerChooseAction(playerId : Integer, action : Action): Response + + askAction(inGameIdPlayer : Integer, askedAction : TAskAction): Action + + sendAction(inGameIdPlayer : Integer, askedAction : TAskAction) + + sendFirstRoundStart() + + sendStartPhase() + + sendDescription() + + sendGameIsFinished() + } + + class Game{ + - nextRoundPowers : Power[*] + - planet : Planet + - reserve : Reserve + - survivalCardPioche : Pioche + - trackingCardPioche : Pioche + - board : Board + - database : NotAloneDatabase + - creature : Creature + - traques : Traque[*] + - playersMap : Map + - state : Phase + - room : Room + - gameRoundVariables : GameRoundVariables + + - initializePlayer(playersId : Integer[*], creatureId : Integer) + - initializePlayer(players : (Pair)[*], creatureId : Integer) + - initializeReserve(playerNumber : Integer) + - initializeSurvivalCardPioche() + - initializeTrackingCardPioche() + - initializeCardsOfPlayers() + + + getPlanet() : Planet + + getReserve() : Reserve + + getSurvivalCardPioche() : Pioche + + getTrackingCardPioche() : Pioche + + getBoard() : Board + + getCreature() : Creature + + getTraques() : Traque[*] + + getPlayersMap() : Map + + getPlayer(idPlayer : Integer) : Player + + getGameRoundVariables() : GameRoundVariables + + getState() : Phase + + getRoom() : Room + + isJetonArtemiaIsActive() : boolean + + getNumberWillingnessDecrementByJetonCreature() : Integer + + traqueCanResist() : boolean + + getIdPlayerTargetByTrackingCardAnticipation() : Integer + + traqueCanPickSurvivalCards() : boolean + + addPowerForNextRound(power : Power) + + disableJetonArtemia() + + enableJetonArtemia() + + setNumberWillingnessDecrementByJetonCreature( number : Integer) + + addNumberWillingnessByJetonCreature() + + setTraqueCanResist(traqueCanResist : boolean) + + setIdPlayerTargetByTrackingCardAnticipation(idPlayerTargetByJetonCreature : Integer) + + setTraqueCanPickSurvivalCards(traqueCanPickSurvivalCards : Boolean) + + + isFinish() : Boolean + + + playerHasFinished(playerId : Integer, phase : Phase) : Response + + creatureHasFinished(creature : Creature, phase : Phase) : Response + + boolean traqueHasFinished(traque : Traque, phase : Phase ) + + playerFinishedPhase(player : Player, phase : Phase) + + playerPlayCard(playerId : Integer, card : Card) : Response + + playerPlayCard(playerId : Integer, cards : Card[*]) : Response + + + playerPlaceJeton(playerId : Integer, jeton : PlacedJeton) : Response + + playerPlaceJeton(playerId : Integer, jetons : PlacedJeton[*]) : Response + + + playerResist(playerId : Integer; number : Integer) : Response + + playerGiveUp(playerId : Integer) : Response + + askAction(inGameIdPlayer : Integer, action : TAskAction) : Action + + sendAction(inGameIdPlayer : Integer, askedAction : TAskAction) + + sendFirstRoundStart() + + sendStartPhase() + + sendDescription() + + sendGameIsFinished() + + playerPlayPlayerCard(player : Player, card : Card ) : Response + + playerPlayPlayerCard(player : Player, cards : Card[*] ) : Response + + creaturePlayTrackingCard(creature : Creature, trackingCard : TrackingCard ) : Response + + creaturePlayTrackingCard(creature : Creature, trackingCards : TrackingCard[*] ) : Response + - applyCreaturePlayTrackingCard(creature : Creature, trackingCard : TrackingCard ) + + creatureCanPlayThisTrackingCards(creature : Creature, trackingCard : TrackingCard ) : boolean + + creatureCanPlayThisTrackingCards(creature : Creature, trackingCard : TrackingCard[*] ) : boolean + + traquePlaySurvivalCard(traque : Traque, survivalCard : SurvivalCard) : Response + + traquePlaySurvivalCard(traque : Traque, survivalCard : SurvivalCard[*]) : Response + - applyTraquePlaySurvivalCard( traque : Traque, survivalCard : SurvivalCard) + + traqueCanPlayThisSurvivalCards( traque : Traque, survivalCard : SurvivalCard) : boolean + + traqueCanPlayThisSurvivalCards( traque : Traque, survivalCards : SurvivalCard[*]) : boolean + + traquePlayPlaceCard( traque : Traque, placeCard PlaceCard) : Response + + traquePlayPlaceCard( traque : Traque, placeCard PlaceCard[*]) : Response + + playerCardsPlayedPhaseAndAppliedPhaseDifferent( playerCard : PlayerCard) : boolean + + creaturePlaceAJeton( creature : Creature, placedJeton : PlacedJeton) : Response + + nextPhase(phase : Phase) : Phase + + allPlayersHasFinishedCurrentPhase() : boolean + + startNextPhase() + + managePhase3() + - choosePlaceCardsToReveal(traque : Traque) : PlaceCard[*] + + managePhase4() + + nextRound() + - applyNextRoundPowers() + - applyModificatorPower(power : PowerModificator) + - useWillingnessOnBoard() + + choosePlaceCardsAction(idPlayer : Integer, max : Integer, placesCards : PlaceCard[*]) : PlaceCard[*] + + chooseSurvivalCardsAction(idPlayer : Integer, max : Integer, survivalCards : SurvivalCard[*]) : SurvivalCard[*] + + chooseTrackingCardsAction(idPlayer : Integer, max : Integer, trackingCards : TrackingCard[*]) : TrackingCard[*] + + chooseCardsAction(idPlayer : Integer, max : Integer, cardsToChoose : Card[*]) : Card[*] + - createTActionForChooseCardsAction( max : Integer, cardsToChoose : Card[*]) : TAskAction + + sendPlaceCardsAction( idPlayer : Integer, cardsToShow : PlaceCard[*]) + + sendCardsAction( idPlayer : Integer, cardsToShow : Card[*]) + - createTActionForSendCardsAction(cardsToShow : Card[*]) : TAskAction + - computeCardListFromCardNames( cardNames : CardName[*], cardsToChoose : Card[*]) : Card[*] + + choosePower(idPlayer : Integer, powersDescription : String[*]) : Integer + + targetPlayer(idPlayer : Integer) : Integer + + choosePlace(idPlayer : Integer, number : Integer) : Place[*] + + choosePlace(idPlayer : Integer, number : Integer, message : String) : Place[*] + + movePlayer(idPlayer : Integer) : Pair + + swapJetons(idPlayer : Integer) : Pair + + associateCardNamesToPlaces(idPlayer : Integer, cardsToAssociate : Card[*]) : Map + - createTActionForAssociateCardNamesToPlaces( cardsToAssociate : Card[*]) : TAskAction + - computeMapCardToPlaceFromMapCardNamesToPlace( cardNamePlaceMap : Map, cards : Card[*]) : Map + - isJetonCibleOnThisPlace(place : Place[*]) : boolean + + createDescription(playerId : Integer) : TDescription + + + } + + +class RoomFactory{ + - {static} idCounter : AtomicInteger + - {static} createRoom(playerId : String) : Room +} +class RoomServiceController{ + - rooms : Map + - players : Map + - getRooms() : Map + - getPlayers() : Map + + addRoom(room : Room) : boolean + + createRoom(playerId : String) : String + + joinRoom(playerId : String, roomId : String) : Response + + startGame(playerId : String, creatureId : Integer, board : Board, planet : Planet) : Response + + getGameDescription(user : User) : TDescription + + sendFinishPhase(user : User, phase : Phase) + + sendPlayCards(user : User, cards : Card[*]) + + sendPlaceJetons(user : User, placedJetons : PlacedJeton[*]) + + sendResist(user : User, number : Integer) + + sendGiveUp(user : User) +} +class PowerApplicator{ + - database : NotAloneDatabase + + applyPlayerCard(game : Game, idPlayer : Integer, playerCard : PlayerCard) + + resolvePlace(game : Game, idPlayer : Integer, playerCard : PlayerCard) + - filterSpecialCaseBlockPlace(game : Game, idPlayer : Integer, playerCard : PlayerCard) : Boolean + - filterJetonBlockPlace(game : Game, idPlayer : Integer, playerCard : PlayerCard) : Boolean + + applyPlaceCardPower(game : Game, cardName : CardName, idPlayer : Integer) + + applyTrackingCardPower(game : Game, cardName : CardName, idPlayer : Integer) + + applySurvivalCardPower(game : Game, cardName : CardName, idPlayer : Integer) + + applyJetonArtemia(game : Game, idPlayer : Integer) + + applyJetonCreature(game : Game, idPlayer : Integer, placeCard : PlaceCard) + + applyJetonCible(game : Game, idPlayer : Integer) + - applyPlaceAntre(game : Game, idPlayer : Integer) + - applyPlaceJungle(game : Game, idPlayer : Integer) + - applyPlaceRiviere(game : Game, idPlayer : Integer) + - applyPlacePlage(game : Game, idPlayer : Integer) + - applyPlaceRover(game : Game, idPlayer : Integer) + - applyPlaceMarais(game : Game, idPlayer : Integer) + - applyPlaceAbri(game : Game, idPlayer : Integer) + - applyPlaceEpave(game : Game, idPlayer : Integer) + - applyPlaceSource(game : Game, idPlayer : Integer) + - applyPlaceArtefact(game : Game, idPlayer : Integer) + - applyPlaceBlueArtefact(game : Game, idPlayer : Integer, powersDescription : String[*]) + - applyPlaceGreenArtefact(game : Game, idPlayer : Integer, powersDescription : String[*]) + - applyPlaceRedArtefact(game : Game, idPlayer : Integer, powersDescription : String[*]) + - applyPlaceYellowArtefact(game : Game, idPlayer : Integer, powersDescription : String[*]) + - applyPlaceNexus(game : Game, idPlayer : Integer) + - applyPlaceOasis(game : Game, idPlayer : Integer) + - applyPlaceFjord(game : Game, idPlayer : Integer) + - applyPlaceDome(game : Game, idPlayer : Integer) + - applyPlaceLabyrinthe(game : Game, idPlayer : Integer) + - applyPlaceLabyrintheNotAllRevealed(game : Game, idPlayer : Integer) + - applyPlaceLabyrintheAllRevealed(game : Game, idPlayer : Integer) + - applyPlaceMangrove(game : Game, idPlayer : Integer) + - applyPlaceArchipel(game : Game, idPlayer : Integer) + - applyPlacePole(game : Game, idPlayer : Integer) + - applyPlaceFungi(game : Game, idPlayer : Integer) + - applyPlacePortail(game : Game, idPlayer : Integer) + - applyTrackingAcharnement(game : Game) + - applyTrackingAngoisse(game : Game) + - applyTrackingAnticipation(game : Game, idPlayer : Integer) + - applyTrackingCataclysme(game : Game, idPlayer : Integer) + - applyTrackingChampDeForce(game : Game) + - applyTrackingClone(game : Game) + - applyTrackingDeploiement(game : Game, idPlayer : Integer) + - applyTrackingDesespoir(game : Game) + - applyTrackingDetour(game : Game, idPlayer : Integer) + - applyTrackingDomination(game : Game, idPlayer : Integer) + - applyTrackingEffroi(game : Game, idPlayer : Integer) + - applyTrackingEmprise(game : Game, idPlayer : Integer) + - applyTrackingEpidemie(game : Game, idPlayer : Integer) + - applyTrackingFailleTemporelle(game : Game) + - applyTrackingFlashback(game : Game) + - applyTrackingGargantua(game : Game) + - applyTrackingHarcelement(game : Game) + - applyTrackingHurlement(game : Game) + - applyTrackingInertie(game : Game) + - applyTrackingInterference(game : Game) + - applyTrackingIntuition(game : Game, idPlayer : Integer) + - applyTrackingMagnetisme(game : Game) + - applyTrackingMirage(game : Game) + - applyTrackingMutation(game : Game) + - applyTrackingPsychose(game : Game, idPlayer : Integer) + - applyTrackingReminiscence(game : Game, idPlayer : Integer) + - applyTrackingReperage(game : Game, idPlayer : Integer) + - applyTrackingSablesMouvants(game : Game) + - applyTrackingSoifDeSang(game : Game) + - applyTrackingStase(game : Game) + - applyTrackingTelepathie(game : Game, idPlayer : Integer) + - applyTrackingTornade(game : Game, idPlayer : Integer) + - applyTrackingToxine(game : Game) + - applyTrackingUbiquite(game : Game, idPlayer : Integer) + - applyTrackingVirus(game : Game) + - applyTrackingZoneInterdite(game : Game) + - applySurvivalAdrenaline(game : Game, idPlayer : Integer) + - applySurvivalAlerte(game : Game, idPlayer : Integer) + - applySurvivalAmplificateur(game : Game) + - applySurvivalBrouillage(game : Game) + - applySurvivalCavale(game : Game, idPlayer : Integer) + - applySurvivalDetecteur(game : Game, idPlayer : Integer) + - applySurvivalDrone(game : Game, idPlayer : Integer) + - applySurvivalEntrave(game : Game) + - applySurvivalEquipement(game : Game, idPlayer : Integer) + - applySurvivalEsquive(game : Game, idPlayer : Integer) + - applySurvivalFaussePiste(game : Game, idPlayer : Integer) + - applySurvivalHologramme(game : Game, idPlayer : Integer) + - applySurvivalLeurre(game : Game, idPlayer : Integer) + - applySurvivalMimetisme(game : Game, idPlayer : Integer) + - applySurvivalNavette(game : Game) + - applySurvivalPlanques(game : Game, idPlayer : Integer) + - applySurvivalPortail(game : Game, idPlayer : Integer) + - applySurvivalRalliement(game : Game) + - applySurvivalRefuge(game : Game, idPlayer : Integer) + - applySurvivalRegeneration(game : Game, idPlayer : Integer) + - applySurvivalResistance(game : Game, idPlayer : Integer) + - applySurvivalRetraite(game : Game, idPlayer : Integer) + - applySurvivalRiposte(game : Game) + - applySurvivalSacrifice(game : Game, idPlayer : Integer) + - applySurvivalSecondSouffle(game : Game, idPlayer : Integer) + - applySurvivalSixiemeSens(game : Game, idPlayer : Integer) + - applySurvivalSystemeD(game : Game) + - applySurvivalTenacite(game : Game, idPlayer : Integer) + - applySurvivalVaccin(game : Game) + - applySurvivalVolteFace(game : Game, idPlayer : Integer) + - applySurvivalVortex(game : Game, idPlayer : Integer) + + playNewPlaceCard(game : Game, idPlayer : Integer) + + swapHandAndDefaussePlaceCard(game : Game, idPlayer : Integer) + + revealAHiddenPlaceAndApplyItsPower(game : Game, idPlayer : Integer) + + addWillingnessToAPlayer(game : Game, idPlayer : Integer, numberWillingness : Integer) + + chooseCardFromReserve(game : Game, idPlayer : Integer) + + takeBackAllCardsFromDefausse(game : Game, idPlayer : Integer) + + takeBackCardsFromDefausse(game : Game, idPlayer : Integer, numberCards : Integer) + + takeBackCard(game : Game, idPlayer : Integer, cardName : CardName) + + copyPowerWhereJetonCreatureIs(game : Game, idPlayer : Integer) + + copyPowerOfOneCardInDefausse(game : Game, idPlayer : Integer) + + copyPowerOfOneCardInInterval(game : Game, idPlayer : Integer, a : Integer, b : Integer) + + pickSurvivalCards(game : Game, idPlayer : Integer, numberCardsToPick : Integer, numberCardToKeep : Integer) + + throwAwayPlaceCards(game : Game, idPlayer : Integer, numberCardsToThrowAway : Integer) + + throwAwaySurvivalCards(game : Game, idPlayer : Integer, numberCardsToThrowAway : Integer) + + moveTraqueOnAdjacentPlace(game : Game, idPlayer : Integer) + + moveTraqueOnAdjacentPlaceAndAddHimToRetraiteList(game : Game, idPlayer : Integer) + + moveJetonOnAdjacentPlace(game : Game, idPlayer : Integer, symbol : JetonSymbol) + + chooseTwoAdjacentPlace(game : Game, idPlayer : Integer) : Pair + + applyPlanetPawn(game : Game) + + applyBeaconPawn(game : Game) + + applyShieldPawn(game : Game) + + checkPlayerIsNotCreature(game : Game, idPlayer : Integer) + + checkPlayerIsNotCreature(game : Game) + + checkEpidemieCondition(game : Game, placeCard : PlaceCard) : boolean + + checkInertieCondition(game : Game) : boolean + + checkAlerteCondition(variables : GameRoundVariables, place : Place) : boolean + + isABlockedPlaceCard(game : Game, placeCard : PlaceCard) : boolean + + checkIfAdjacentToJetonCible(game : Game, placeCard : PlaceCard) : boolean + + findPlaceCardWhereTheJetonCibleIsAndAdjacent(game : Game, placeCard : PlaceCard) : PlaceCard + + subWillingness(game : Game, traque : Traque, numberWillingnessDecrement : Integer) + + subWillingness(game : Game, idTraque : Integer, numberWillingnessDecrement : Integer) + +} +class GameRoundVariables{ + - numberPawnWillingnessOnBoard : Integer + - actionJetonCible : BiConsumer + - actionAdjacentPlaceJetonCible : BiConsumer + - incrementScoreTraque : Integer + - numberWillingnessDecrementByJetonCreature : Integer + - numberMaxPlaceCardsGetByPlacePower : Integer + - idPlayerTargetByTrackingCardAnticipation : Integer + - idPlayerTargetByTrackingCardDomination : Integer + - idPlayerTargetByTrackingCardEpidemie : Integer + - targetByAlerte : Place + + - playerWhoHaveLostAllWillingness : Integer[*] + - playersWhoHaveResist : Integer[*] + - playersCaughtByCreature : Integer[*] + - playersCaughtByCreatureOnNexus : Integer[*] + - playersWhoDodgeJetonArtemia : Integer[*] + - playersWhoDodgeJetonCreature : Integer[*] + - playersWhoDodgeJetonCible : Integer[*] + - playersWhoHavePlayCavale : Integer[*] + - playersWhoHavePlayDrone : Integer[*] + - playersWhoHavePlayMimetisme : Integer[*] + - playersWhoHavePlayPortail : Integer[*] + - playersWhoHavePlayRegeneration : Integer[*] + - playersWhoIsTargetRetraite : Integer[*] + - playersWhoHavePlayVolteFace : Integer[*] + - playersWhoUseFjordInPreviousRound : Integer[*] + + - traqueCanResist : boolean + - traqueCanPickSurvivalCards : boolean + - jetonArtemiaIsActive : boolean + - jetonArtemiaMadeLoseOneWillingness : boolean + - rescuePawnCanMoveForward : boolean + - jetonCibleCanBeOnTwoAdjacentPlaces : boolean + - jetonCreatureCanBeOnTwoAdjacentPlaces : boolean + - jetonArtemiaCanBeOnTwoAdjacentPlaces : boolean + - defaussePlaceCardsAreHidden : boolean + - canPlaceJetonCreatureOnPlaces6To10 : boolean + - survivalCardRalliementIsActive : boolean + - survivalCardRefugeIsActive : boolean + - canPlayTrackingCard : boolean + - inertieTrackingCardIsPlayed : boolean + - jetonCibleBlockPlace : boolean + - jetonCibleBlockAdjacentPlace : boolean + - jetonCibleAdjacentPlaceMoveTraque : boolean + - ralliementIsActive : boolean + - refugeIsActive : boolean + + + reset() + + resetAfterNextRoundPowersApplication() + + addPawnWillingnessOnBoard(number : Integer) + + isPawnWillingnessOnBoard() : boolean + + usePawnWillingnessOnBoard() + + getActionJetonCible() : BiConsumer + + setActionJetonCible(actionJetonCible : BiConsumer) + + getActionAdjacentPlaceJetonCible() : BiConsumer + + setActionAdjacentPlaceJetonCible(actionAdjacentPlaceJetonCible : BiConsumer) + + getIncrementScoreTraque() : Integer + + setIncrementScoreTraque( incrementScoreTraque : Integer) + + getNumberWillingnessDecrementByJetonCreature() : Integer + + setNumberWillingnessDecrementByJetonCreature( numberWillingnessDecrementByJetonCreature : Integer) + + numberMaxPlaceCardsGetByPlacePowerIsLimited() : boolean + + addNumberWillingnessByJetonCreature() + + getNumberMaxPlaceCardsGetByPlacePower() : Integer + + setNumberWillingnessDecrementByJetonCreature( numberMaxPlaceCardsGetByPlacePower : Integer) + + getIdPlayerTargetByTrackingCardAnticipation() : Integer + + setIdPlayerTargetByTrackingCardAnticipation( idPlayerTargetByJetonCreature : Integer) + + playerIsTargetByTrackingCardDomination() : boolean + + playerIsTargetByTrackingCardEpidemie() : boolean + + getIdPlayerTargetByTrackingCardDomination() : Integer + + setIdPlayerTargetByTrackingCardDomination( idPlayerTargetByTrackingCardDomination : Integer) + + getIdPlayerTargetByTrackingCardEpidemie() : Integer + + setIdPlayerTargetByTrackingCardEpidemie( idPlayerTargetByTrackingCardEpidemie : Integer) + + alerteIsActive() : boolean + + getTargetByAlerte() : Place + + setTargetByAlerte(targetByAlerte : Place) + + getPlayerWhoHaveLostAllWillingness() : Integer[*] + + addPlayerWhoHaveLostAllWillingness(idPlayer : Integer) + + getPlayersWhoHaveResist() : Integer[*] + + addPlayersWhoHaveResist(idPlayer : Integer) + + getPlayersWhoHasCaughtByCreature() : Integer[*] + + addPlayersWhoHasCaughtByCreature(idPlayer : Integer) + + getPlayersWhoHasCaughtByCreatureOnNexus() : Integer[*] + + + addPlayersWhoHasCaughtByCreatureOnNexus(idPlayer : Integer) + + getPlayersWhoHavePlayCavale() : Integer[*] + + addPlayerWhoHavePlayCavale(idPlayer : Integer) + + getPlayersWhoDodgeJetonArtemia() : Integer[*] + + addPlayersWhoDodgeJetonArtemia(idPlayer : Integer) + + getPlayersWhoHavePlayDrone() : Integer[*] + + addPlayersWhoHavePlayDrone(idPlayer : Integer) + + getPlayersWhoDodgeJetonCreature() : Integer[*] + + addPlayersWhoDodgeJetonCreature(idPlayer : Integer) + + getPlayersWhoHavePlayMimetisme() : Integer[*] + + addPlayersWhoHavePlayMimetisme(idPlayer : Integer) + + getPlayersWhoHavePlayPortail() : Integer[*] + + addPlayersWhoHavePlayPortail(idPlayer : Integer) + + getPlayersWhoHavePlayRegeneration() : Integer[*] + + addPlayersWhoHavePlayRegeneration(idPlayer : Integer) + + getPlayersWhoDodgeJetonCible() : Integer[*] + + addPlayersWhoDodgeJetonCible(idPlayer : Integer) + + getPlayersWhoIsTargetRetraite() : Integer[*] + + addPlayersWhoIsTargetByRetraite(idPlayer : Integer) + + getPlayersWhoHavePlayVolteFace() : Integer[*] + + addPlayersWhoHavePlayVolteFace(idPlayer : Integer) + + getplayersWhoUseFjordInPreviousRound() : Integer[*] + + addplayersWhoUseFjordInPreviousRound(idPlayer : Integer) + + ralliementIsActive() : boolean + + setRalliementIsActive(ralliementIsActive : boolean) + + refugeIsActive() : boolean + + setRefugeIsActive(refugeIsActive : boolean) + + isJetonArtemiaIsActive() : boolean + + disableJetonArtemia() + + enableJetonArtemia() + + traqueCanResist() : boolean + + setTraqueCanResist(traqueCanResist : boolean) + + traqueCanPickSurvivalCards() : boolean + + setTraqueCanPickSurvivalCards(traqueCanPickSurvivalCards : boolean) + + setJetonArtemiaIsActive(jetonArtemiaIsActive : boolean) + + jetonArtemiaMadeLoseOneWillingness() : boolean + + setJetonArtemiaMadeLoseOneWillingness(jetonArtemiaMadeLoseOneWillingness : boolean) + + rescuePawnCanMoveForward() : boolean + + setRescuePawnCanMoveForward(rescuePawnCanMoveForward : boolean) + + jetonCibleCanBeOnTwoAdjacentPlaces() : boolean + + setJetonCibleCanBeOnTwoAdjacentPlaces(jetonCibleCanBeOnTwoAdjacentPlaces : boolean) + + jetonCreatureCanBeOnTwoAdjacentPlaces() : boolean + + setJetonCreatureCanBeOnTwoAdjacentPlaces(jetonCreatureCanBeOnTwoAdjacentPlaces : boolean) + + jetonArtemiaCanBeOnTwoAdjacentPlaces() : boolean + + jetonArtemiaCanBeOnTwoAdjacentPlaces(jetonArtemiaCanBeOnTwoAdjacentPlaces : boolean) + + defaussePlaceCardsAreHidden() : boolean + + setDefaussePlaceCardsAreHidden(defaussePlaceCardsAreHidden : boolean) + + canPlaceJetonCreatureOnPlaces6To10() : boolean + + setCanPlaceJetonCreatureOnPlaces6To10(canPlaceJetonCreatureOnPlaces6To10 : boolean) + + survivalCardRalliementIsActive() : boolean + + setSurvivalCardRalliementIsActive(survivalCardRalliementIsActive : boolean) + + survivalCardRefugeIsActive() : boolean + + setSurvivalCardRefugeIsActive(survivalCardRefugeIsActive : boolean) + + canPlayTrackingCard() : boolean + + setCanPlayTrackingCard(canPlayTrackingCard : boolean) + + inertieTrackingCardIsPlayed() : boolean + + setInertieTrackingCardIsPlayed(inertieTrackingCardIsPlayed : boolean) + + isJetonCibleBlockPlace() : boolean + + setJetonCibleBlockPlace(jetonCibleBlockPlace : boolean) + + isJetonCibleBlockAdjacentPlace() : boolean + + setJetonCibleBlockAdjacentPlace(jetonCibleBlockAdjacentPlace : boolean) + + isJetonCibleAdjacentPlaceMoveTraque() : boolean + + setJetonCibleAdjacentPlaceMoveTraque(jetonCibleAdjacentPlaceMoveTraque : boolean) + + + } +Game "1" -- "1" Room +Room *-- RoomServiceController +Game *-- GameRoundVariables + +.... + + + +=== Item + +==== Action + +.Package action +[plantuml] +.... +package action{ + abstract class Action{ + # {abstract} getActionType() : ActionType + } + + class ActionAssociateCardNamesToPlaces{ + - cardNamePlaceMap : Map + + getActionType() : ActionType + + getCardNamePlaceMap() : Map + + equals(obj : Object) : boolean + } + + class ActionChooseCard{ + - cards : Card[*] + + getCards : Card[*] + + getActionType() : ActionType + + equals(obj : Object) : boolean + + } + + class ActionChoosePlace{ + - places : Place[*] + + getPlaces() : Place[*] + + getActionType() : ActionType + + equals(obj : Object) : boolean + + } + + class ActionChoosePower{ + - idPowerChosen : Integer + + getIdPowerChosen() : Integer + + getActionType() : ActionType + + equals(obj : Object) : boolean + + } + + class ActionMovePlayer{ + - idPlayer : Integer + - place : Place + + getIdPlayer() : Integer + + getPlace() : Place + + getActionType() : ActionType + + equals(obj : Object) : boolean + + } + + class ActionSwapJeton{ + - jeton1 : JetonSymbol + - jeton2 : JetonSymbol + + getJeton1() : JetonSymbol + + getJeton2() : JetonSymbol + + getActionType() : ActionType + + equals(obj : Object) : boolean + + } + + class ActionTargetPlayer{ + - idPlayer : Integer + + getIdPlayer() : Integer + + getActionType() : ActionType + + equals(obj : Object) : boolean + + } + + enum ActionType{ + CHOOSE_POWER + TARGET_PLAYER + MOVE_PLAYER + CHOOSE_CARD + CHOOSE_PLACE + SWAP_JETONS + MOVE_JETON + ASSOCIATE_SURVIVAL_CARDS_TO_PLACES + SHOW_CARD + } + enum TPairType{ + NUMBER + CARD + PLACE + JETON + PLAYER + } + + Action <|-- ActionChooseCard + Action <|-- ActionChoosePlace + Action <|-- ActionChoosePower + Action <|-- ActionMovePlayer + Action <|-- ActionSwapJeton + Action <|-- ActionTargetPlayer + Action <|-- ActionAssociateCardNamesToPlaces +} +.... + + +==== Board +.Package board +[plantuml] +.... +package board{ + + class Board{ + - boardDistribution : BoardDistribution + - boardColor : BoardColor + - score : Score + + getScore() : Score + + getBoardDistribution() : BoardDistribution + + getBoardColor() : BoardColor + + isArtemiaSquare() : Boolean + + toString() : String + + initializeScore(playerNumber : Integer) + + isFinish() : boolean + + getScoreTraque() : Integer + + getScoreCreature() : Integer + + actualBestTeam() : PlayerTeam + + winner() : PlayerTeam + + moveForwardTraque(delta : Integer) + + moveForwardTraque() + + moveBackTraque(delta : Integer) + + moveBackTraque() + + moveForwardCreature(delta : Integer) + + moveForwardCreature() + + moveBackCreature(delta : Integer) + + moveBackCreature() + + } + enum BoardColor{ + BLUE + RED + GREEN + YELLOW + } + enum BoardDistribution{ + FRONT + BACK + } + + class Score{ + - scoreTraque : Integer + - scoreCreature : Integer + - winner : PlayerTeam + - static(BASE_TRAQUE : Integer) + - static(BASE_CREATURE : Integer) + + getScoreTraque() : Integer + + getScoreCreature() : Integer + + isFinish() : Boolean + + actualBestTeam() : PlayerTeam + + winner() : PlayerTeam + + scoreCreatureGreaterThanBase() : Boolean + + scoreTraqueGreaterThanBase() : Boolean + + moveForwardTraque(delta : Integer) + + moveBackTraque(delta : Integer) + + moveForwardCreature(delta : Integer) + + moveBackCreature(delta : Integer) + + equals(obj : Object) : Boolean + + toString() : String + } + + + Board "1" o-- "1 score" Score +} +.... + +==== Card +.Package card +[plantuml] +.... +package card{ + enum CardType{ + SURVIVAL + TRACKING + PLACE + } + + abstract class Card{ + + # name : String + # CardName : String + # description : String + + getName() : String + + getCardName() : String + + getDescription() : String + + getType() : String + + equals(obj : Object) : Boolean + + toString() : String + + hashCode() : Integer + } + enum CardName{ + ANTRE, JUNGLE, RIVIERE, PLAGE, ROVER, MARAIS, ABRI, EPAVE, SOURCE, ARTEFACT, + NEXUS, OASIS, FJORD, DOME, LABYRINTHE, MANGROVE, ARCHIPEL, POLE, FUNGI, PORTAIL, + + ACHARNEMENT, ANGOISSE, ANTICIPATION, CATACLYSME, CHAMP_DE_FORCE, CLONE, DEPLOIEMENT, DESESPOIR, DETOUR, DOMINATION, EFFROI, + EMPRISE, EPIDEMIE, FAILLE_TEMPORELLE, FLASHBACK, GARGANTUA, HARCELEMENT, HURLEMENTS, INERTIE, INTERFERENCES, INTUITION, + MAGNETISME, MIRAGE, MUTATION, PSYCHOSE, REMINISCENCE, REPERAGE, SABLES_MOUVANTS, SOIF_DE_SANG, STASE, TELEPATHIE, + TORNADE, TOXINE, UBIQUITE, VIRUS, ZONE_INTERDITE, + + ADRENALINE, ALERTE, AMPLIFICATEUR, BROUILLAGE, CAVALE, DETECTEUR, DRONE, ENTRAVE, EQUIPEMENT, ESQUIVE, + FAUSSE_PISTE, HOLOGRAMME, LEURRE, MIMETISME, NAVETTE, PLANQUES, PORTAIL_SURVIVAL, RALLIEMENT, REFUGE, REGENERATION, + RESISTANCE, RETRAITE, RIPOSTE, SACRIFICE, SECOND_SOUFFLE, SIXIEME_SENS, SYSTEME_D, TENACITE, VACCIN, VOLTE_FACE, + VORTEX + } + + class PlaceCard { + - number : Integer + - imageUrl : String + - color : String + + getNumber() : Integer + + getImageUrl() : String + + getColor() : String + + getType() : CardType + } + + abstract class PlayerCard { + # phase : Phase + # phaseToApply : Phase + + getPhase() : Phase + + getPhaseToApply() : Phase + } + + class SurvivalCard { + + getType() : CardType + } + + class TrackingCard { + - symbols : List + + getType() : CardType + + getJetons() : List + + containsSymbol(type : JetonSymbol) : boolean + + } + + Card <|-- PlaceCard + Card <|-- PlayerCard + PlayerCard <|-- SurvivalCard + PlayerCard <|-- TrackingCard +} +.... + + + +==== Jeton +.Package jeton +[plantuml] +.... +package jeton{ + + + enum JetonSymbol{ + CIBLE + ARTEMIA + CREATURE + } + + class PlacedJeton{ + - jetonSymbol : JetonSymbol + - places : Place[*] + + getJetonSymbol() : Jeton + + getPlaces() : Place[*] + + equals(obj : object) : boolean + } +} +.... + +==== Pioche +.Package pioche +[plantuml] +.... +package pioche{ + class Pioche { + - cards : T[*] + - trash : T[*] + - random : Random + - mix() + + draw() : T + + draw(number : Integer) : T[*] + + throwAway(cards : T[*]) + + throwAway(card : T) + + drawLastTrashCards(number : Integer) : T[*] + + getTrash() : T[*] + + getCards() : T[*] + } +} +.... + +==== Planet +.Package planet +[plantuml] +.... +package planet{ + class BeaconPawn{ + - state : Integer + - nextState() + + isActive() : Boolean + + getType() : PawnType + + maxMovesInOneRound() : Integer + + stateToInt() : Integer + } + enum PawnType{ + SHIELD + BEACON + } + enum Place{ + PLACE_ONE + PLACE_TWO + PLACE_THREE + PLACE_FOUR + PLACE_FIVE + PLACE_SIX + PLACE_SEVEN + PLACE_EIGHT + PLACE_NINE + PLACE_TEN + } + class PlaceDistribution{ + - mapCardNumberToPlaceCard : Map + - mapPlaceCardToPlace : Map + - placeIsHidden : Map + - initialization(placeCards : PlaceCard[*]) + - initializePlaceCardsVisibility() + - initializePlaces() + + createPawn() : PlanetPawn + + isValidPlacesForJeton(adjacentPlaces Place[*]) : boolean + + isValidPlacesForJeton(adjacentPlacesCard : PlaceCard[*]) : Boolean + + placeCardToPlace(card : PlaceCard) : Place + + placeToPlaceCard(place : Place) : PlaceCard + + useCardLabyrinthe() : Boolean + + useCardDome() : Boolean + + useCardPole() : Boolean + + getPlaceCardsInInterval(a : Integer, b : Integer) : PlaceCard[*] + + getPlaceCards() : PlaceCard[*] + + isHiddenCards() : boolean + + getHiddenCards() : PlaceCard[*] + + getHiddenPlaces() : Place[*] + + revealPlace(place : Place) + + revealPlace(placeCard : PlaceCard) + + isRevealedPlace(place : Place) + + isRevealedPlace(placeCard : PlaceCard) + } + class Planet{ + - static(LABYRINTHE_NUMBER : Integer) + - static(DOME_NUMBER : Integer) + - static(POLE_NUMBER : Integer) + + - mapPlaceToJetons : Map + - blockedPlaces : Map + - placeSurvivalCardMap : Map + - numberMovesAllowInRound : Integer + - placeDistribution : PlaceDistribution + - planetPawn : PlanetPawn + - epaveUsedInTheRound : Boolean + + getPlaceDistribution() : PlaceDistribution + + getMapPlaceToJetons() : JetonSymbol[*] + + getPlacedJetons() : PlacedJeton[*] + + reset() + + placeJeton(placedJeton : PlacedJeton) + + findPlacesWhereJetonIs(symbol : JetonSymbol) : Place[*] + + findPlaceCardsWhereJetonIs(symbol : JetonSymbol) : PlaceCard[*] + + removeJeton(symbol : JetonSymbol) + + blockPlaces(places : Place[*]) + + blockPlaces(place : Place) + + blockPlaces(placeCard : PlaceCard[*]) + + isBlockedPlace(card : PlaceCard) : Boolean + + isJetonOnPlace(place : Place) : Boolean + + isJetonOnPlace(placeCard : PlaceCard) : Boolean + + findJetonsSymbolsOnCard(placeCard : PlaceCard) : JetonSymbol[*] + + isJetonSymbolOnPlaceCard(symbol : JetonSymbol,placeCard : PlaceCard) : boolean + + getPlanetPawn() : PlanetPawn + + canMovePlanetPawn() : Boolean + + movePlanetPawn() : Boolean + + forceMovePlanetPawn() + + moveBackPlanetPawn() + + resetPawn() + + placesWhereJetonCreatureIs() : PlaceCard[*] + + getPlaceCardsInInterval(a : Integer, b : Integer) : PlaceCard[*] + + planetPawnIsActive() : Boolean + + getPlanetPawnType() : PawnType + + canUseEpavePower() : boolean + + setEpavePowerToUsed() + + placeToPlaceCard(place : Place) : PlaceCard + + isASurvivalCardOnPlace(place : Place) : boolean + + isASurvivalCardOnPlace(placeCard : PlaceCard) : boolean + + takeSurvivalCardOnPlace(place : Place) : SurvivalCard + + takeSurvivalCardOnPlace(placeCard : PlaceCard) : SurvivalCard + + putSurvivalCardOnPlace(pair : Pair) + + putSurvivalCardOnPlace(pair : (Pair)[*]) + + placeToNumber(place : Place) : Integer + + numberToPlace(number : Integer) : Place + + isAdjacentPlaces(place1 : Integer, place2 : Integer) : boolean + + isAdjacentPlaces(placeCard : PlaceCard, place : Place) : boolean + + isAdjacentPlaces(placeCard1 : PlaceCard, placeCard1 : PlaceCard) : boolean + + isAdjacentPlaces(place1 : Place, place2 : Place) : boolean + + isHiddenCards() : boolean + + getHiddenCards() : PlaceCard[*] + + getHiddenPlaces() : Place[*] + + revealPlace(place : Place) + + revealPlace(placeCard : PlaceCard) + + isRevealedPlace(place : Place): boolean + + isRevealedPlace(placeCard : PlaceCard): boolean + + swapJeton(symbol1 : JetonSymbol, symbol2 : JetonSymbol) + } + + abstract class PlanetPawn{ + # {abstract} getType() : PawnType + # {abstract} nextState() + + previousState() + # {abstract} isActive() : Boolean + # {abstract} maxMovesInOneRound() : Integer + + reset() + # {abstract} stateToInt() : Integer + + } + + + + class ShieldPawn{ + - location : Integer + - hasReachDome : boolean + + getLocation() : Integer + + nextState() + + previousState() + + isActive() : Boolean + + getType() : PawnType + + maxMovesInOneRound() : Integer + + reset() + + stateToInt() : Integer + + } + + + Planet "1" -- "1 placeDistribution" PlaceDistribution + Planet "1" -- "1 planetPawn" PlanetPawn + PlanetPawn <|-- ShieldPawn + PlanetPawn <|-- BeaconPawn + Planet *-- Place +} +.... + + +==== Player +.Package player +[plantuml] +.... +package player{ + enum PlayerTeam{ + CREATURE + TRAQUE + } + abstract class Player{ + # name : String + # inGameId : Integer + # Phase : currentPhase + + getName() : String + + getInGameId() : Integer + + getCurrentPhase() : Phase + # {abstract} getTeam() : PlayerTeam + + setCurrentPhase(currentPhase : Phase) + + teamEqualsTo(team : PlayerTeam) : boolean + } + + class Traque{ + - static(MAX_WILLINGNESS : Integer) + - numberWillingness : Integer + - hand : HandTraque + - rights : TraqueRight + - placeCardsPlayedAfterMoving : PlaceCard[*] + - placeCardsPlayedAndVisible : PlaceCard[*] + + getNumberWillingness() : Integer + + getMaxWillingness() : Integer + + getHand() : HandTraque + + getRights() : TraqueRight + + addWillingness(delta : Integer) + + subWillingness(delta : Integer) + + incrementWillingness() + + decrementWillingness() + + fillWillingness() + + addPlaceCardsAfterMoving(placeCard : PlaceCard) + + addPlaceCardsAfterMoving(placeCards : PlaceCard[*]) + + getPlaceCardsPlayedAndVisible() : PlaceCard[*] + + addPlaceCardsPlayedAndVisible(placeCard : PlaceCard) + + addPlaceCardsPlayedAndVisible(placeCards : PlaceCard[*]) + + reset() + + getTeam() : PlayerTeam + + getPlaceCards() : PlaceCard[*] + + getPlaceCardsPlayed() : PlaceCard[*] + + getDefausse() : PlaceCard[*] + + setPlaceCards(placeCards : PlaceCard[*]) + + setDefausse(placeCards : PlaceCard[*]) + + placeCardHandSize() : Integer + + placeCardIsEmpty() : boolean + + defausseSize() : Integer + + defausseIsEmpty() : boolean + + placeCardPlayedSize() : Integer + + placeCardPlayedIsEmpty() : boolean + + throwAwayPlaceCard() : boolean + + throwAwayPlaceCard(placeCard : PlaceCard) : boolean + + throwAwayPlaceCard(placeCards : PlaceCard[*]) : boolean + + takeBackPlaceCard(placeCard : PlaceCard) : boolean + + takeBackPlaceCard(placeCards : PlaceCard[*]) : boolean + + takeBackAllPlaceCardFromDefausse() + + addPlaceCard(placeCard : PlaceCard) : boolean + + addPlaceCard(placeCards : PlaceCard[*]) : boolean + + addPlaceCardInDefausse(placeCard : PlaceCard) : boolean + + addPlaceCardInDefausse(placeCards : PlaceCard[*]) : boolean + + playPlaceCard(placeCard : PlaceCard) : boolean + + playPlaceCard(placeCards : PlaceCard[*]) : boolean + + getSurvivalCardsHand() : SurvivalCard[*] + + getSurvivalCardsPlayed() : SurvivalCard[*] + + survivalCardHandSize() : Integer + + survivalCardPlayedSize() : Integer + + survivalCardIsEmpty() : boolean + + survivalCardPlayedIsEmpty() : boolean + + clearSurvivalCardPlayed() + + addSurvivalCard(survivalCard : SurvivalCard) : boolean + + addSurvivalCard(survivalCards : SurvivalCard[*]) : boolean + + removeSurvivalCard(survivalCard : SurvivalCard) : boolean + + removeSurvivalCard(survivalCards : SurvivalCard[*]) : boolean + + playSurvivalCard(survivalCard : SurvivalCard) : boolean + + playSurvivalCard(survivalCards : SurvivalCard[*]) : boolean + + addSurvivalCardToApplied(survivalCard : SurvivalCard) + + removeSurvivalCardToApplied(survivalCard : SurvivalCard) + + removeSurvivalCardToApplied(survivalCards : SurvivalCard[*]) + + getSurvivalCardsToApplied() : SurvivalCard[*] + + resetRight() + + getMaxPlacesCardChoosable() : Integer + + setMaxPlacesCardChoosable(maxPlacesCardChoosable : Integer) + + getMaxPlacesCardPlayable() : Integer + + setMaxPlacesCardPlayable(maxPlacesCardPlayable : Integer) + + getMaxSurvivalCardPlayable() : Integer + + setMaxSurvivalCardPlayable(maxSurvivalCardPlayable : Integer) + + canResist() : boolean + + setCanResist(canResist : boolean) + + canGiveUp() : boolean + + setCanGiveUp(canGiveUp : boolean) + + getPlaceCardsVisible() : Integer + + setPlaceCardsVisible(placeCardsVisible : Integer) + + } + + class Creature{ + - hand : HandCreature + - rights : CreatureRight + + getHand() : HandCreature + + getRights() : CreatureRight + + getTeam() : PlayerTeam + + reset() + + initializationJeton() + + jetonsSize() : Integer + + jetonsPlayedSize() : Integer + + jetonsIsEmpty() : boolean + + getJetons() : JetonSymbol[*] + + playJeton(jeton : JetonSymbol) : boolean + + playJeton(jetons : JetonSymbol[*]) : boolean + + jetonsPlayedIsEmpty() : boolean + + getMaxTrackingCards() : Integer + + getTrackingCardHand() : TrackingCard[*] + + getTrackingCardsPlayed() : TrackingCard[*] + + trackingCardHandSize() : Integer + + trackingCardPlayedSize() : Integer + + trackingCardIsEmpty() : Boolean + + trackingCardPlayedIsEmpty() : Boolean + + clearTrackingCardPlayed() + + addTrackingCard(trackingCard : TrackingCard) : Boolean + + addTrackingCard(trackingCards : TrackingCard[*]) : Boolean + + removeTrackingCard(trackingCard : TrackingCard) : Boolean + + removeTrackingCard(trackingCards : TrackingCard[*]) : Boolean + + playTrackingCard(trackingCard : TrackingCard) : Boolean + + playTrackingCard(trackingCards : TrackingCard[*]) : Boolean + + addTrackingCardToApplied(trackingCard : TrackingCard) + + addTrackingCardToApplied(trackingCards : TrackingCard[*]) + + removeTrackingCardToApplied(trackingCard : TrackingCard) + + removeTrackingCardToApplied(trackingCards : TrackingCard[*]) + + setMaxTrackingCardPlayable(maxTrackingCardPlayable : Integer) + + getTrackingCardToApplied() : TrackingCard[*] + + getMaxTrackingCardPlayable() : Integer + + + + } + + package rights{ + class TraqueRight{ + - maxPlacesCardChoosable : Integer + - placeCardsVisible : Integer + - maxPlacesCardPlayable : Integer + - maxSurvivalCardPlayable : Integer + - canResist : boolean + - canGiveUp : boolean + - numberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist : Integer + + reset() + + getMaxPlacesCardChoosable() : Integer + + setMaxPlacesCardChoosable(maxPlacesCardChoosable : Integer) + + getMaxPlacesCardPlayable() : Integer + + setMaxPlacesCardPlayable(maxPlacesCardPlayable : Integer) + + getMaxSurvivalCardPlayable() : Integer + + setMaxSurvivalCardPlayable(maxSurvivalCardPlayable : Integer) + + getPlaceCardsVisible() : Integer + + setPlaceCardsVisible(placeCardsVisible : Integer) + + getNumberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist() : Integer + + setNumberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist(number : Integer) + + canResist() : boolean + + setCanResist(canResist : boolean) + + canGiveUp() : boolean + + setCanGiveUp(canGiveUp : boolean) + + } + + class CreatureRight{ + - maxTrackingCardPlayable : Integer + + getMaxTrackingCardPlayable() : Integer + + setMaxTrackingCardPlayable(maxTrackingCardPlayable : Integer) + + reset() + } + } + + package hand{ + class Deck { + - cards : T[*] + - playedCards : T[*] + - maxCards : Integer + + getMaxCards(): Integer + + getCards(): T[*] + + getPlayedCards(): T[*] + + clear() + + add(card : T) : Boolean + + add(cardList : T[*]) : Boolean + + remove(card : T) : Boolean + + remove(cardList : T[*]) : Boolean + + play(card : T) : Boolean + + play(cardList : T[*]): Boolean + + handSize(): Integer + + playedCardSize(): Integer + + handIsEmpty(): boolean + + playedCardIsEmpty(): boolean + + } + + class PlaceCardDeck{ + - placeCards : PlaceCard[*] + - defausse : PlaceCard[*] + - playedCards : PlaceCard[*] + + getPlayedCards() : PlaceCard[*] + + getPlaceCards() : PlaceCard[*] + + getDefausse() : PlaceCard[*] + + setPlaceCards(placeCards : PlaceCard[*]) + + setDefausse(defausse : PlaceCard[*]) + + setPlayedCards(playedCards : PlaceCard[*]) + + throwAway() : Boolean + + throwAway(card : PlaceCard) : Boolean + + throwAway(cards : PlaceCard[*]) : Boolean + + takeBack(card : PlaceCard) : Boolean + + takeBack(cards : PlaceCard[*]) : Boolean + + takeBackAllFromDefausse() + + takeBackPlayedPlaceCards() + + add(card : PlaceCard) : Boolean + + add(cards : PlaceCard[*]) : Boolean + + addInDefausse(card : PlaceCard) : Boolean + + addInDefausse(cards : PlaceCard[*]) : Boolean + + play(card : PlaceCard) : Boolean + + play(cards : PlaceCard) : Boolean + + handSize() : Integer + + handIsEmpty() : boolean + + defausseSize() : Integer + + defausseIsEmpty() : boolean + + playedCardSize() : Integer + + playedCardIsEmpty() : boolean + } + + class HandCreature{ + - trackingCards : Deck + - jetons : JetonSymbol[*] + - jetonSymbolsPlayed : JetonSymbol[*] + - trackingCardsToApplied : TrackingCard[*] + + initializationJeton() + + addTrackingCardToApplied(trackingCard : TrackingCard) + + addTrackingCardToApplied(trackingCards : TrackingCard[*]) + + removeTrackingCardToApplied(trackingCard : TrackingCard) + + removeTrackingCardToApplied(trackingCards : TrackingCard[*]) + + getTrackingCardToApplied() : TrackingCard[*] + + getJetonSymbolsPlayed() : JetonSymbol[*] + + getJetonSymbols() : JetonSymbol[*] + + playJeton(jeton : Jeton) : Boolean + + playJeton(jetons : Jeton[*]) : Boolean + + jetonsSize() : Integer + + jetonsPlayedSize() : Integer + + jetonsIsEmpty() : boolean + + jetonsPlayedIsEmpty() : boolean + + getMaxTrackingCards() : Integer + + getTrackingCardsDeck() : Deck + + getTrackingCardHand() : TrackingCard[*] + + getTrackingCardsPlayed() : TrackingCard[*] + + trackingCardHandSize() : Integer + + trackingCardPlayedSize() : Integer + + trackingCardIsEmpty() : boolean + + trackingCardPlayedIsEmpty() : boolean + + clearTrackingCardPlayed() + + addTrackingCard(trackingCard : TrackingCard) : boolean + + addTrackingCard(cardList : TrackingCard[*]) : boolean + + removeTrackingCard(trackingCard : TrackingCard) : boolean + + removeTrackingCard(cardList : TrackingCard[*]) : boolean + + playTrackingCard(trackingCard : TrackingCard) : boolean + + playTrackingCard(cardList : TrackingCard[*]) : boolean + + } + + class HandTraque{ + - survivalCards : Deck + - placeCards : PlaceCardDeck + - survivalCardsToApplied : SurvivalCard[*] + + addSurvivalCardToApplied(survivalCard : SurvivalCard) + + addSurvivalCardToApplied(survivalCards : SurvivalCard[*]) + + removeSurvivalCardToApplied(survivalCard : SurvivalCard) + + removeSurvivalCardToApplied(survivalCards : SurvivalCard[*]) + + getSurvivalCardsToApplied() : SurvivalCard[*] + + getPlaceCards() : PlaceCard[*] + + getPlaceCardsPlayed() : PlaceCard[*] + + getDefausse() : PlaceCard[*] + + setPlaceCards(placeCards : PlaceCard[*]) + + setDefausse(placeCards : PlaceCard[*]) + + getPlaceCardsDeck() : PlaceCardDeck + + placeCardHandSize() : Integer + + placeCardIsEmpty() : boolean + + defausseSize() : Integer + + defausseIsEmpty() : boolean + + placeCardPlayedSize() : Integer + + placeCardPlayedIsEmpty() : boolean + + throwAwayPlaceCard() : boolean + + throwAwayPlaceCard(card : PlaceCard) : boolean + + throwAwayPlaceCard(cards : PlaceCard[*]) : boolean + + takeBackPlaceCard(card : PlaceCard) : boolean + + takeBackPlaceCard(cards : PlaceCard[*]) : boolean + + takeBackPlayedPlaceCards(card : PlaceCard) : boolean + + takeBackPlaceCard(cards : PlaceCard[*]) : boolean + + takeBackPlayedPlaceCards() + + takeBackAllPlaceCardFromDefausse() + + addPlaceCard(card : PlaceCard) : boolean + + addPlaceCard(cards : PlaceCard[*]) : boolean + + addPlaceCardInDefausse(card : PlaceCard) : boolean + + addPlaceCardInDefausse(cards : PlaceCard[*]) : boolean + + playPlaceCard(card : PlaceCard) : boolean + + playPlaceCard(cards : PlaceCard[*]) : boolean + + getSurvivalCardsDeck() : Deck + + getSurvivalCardsHand() : SurvivalCard[*] + + getSurvivalCardsPlayed() : SurvivalCard[*] + + survivalCardHandSize() : Integer + + survivalCardPlayedSize() : Integer + + survivalCardIsEmpty() : boolean + + survivalCardPlayedIsEmpty() : boolean + + clearSurvivalCardPlayed() + + addSurvivalCard(card : SurvivalCard) : boolean + + addSurvivalCard(cards : SurvivalCard[*]) : boolean + + removeSurvivalCard(card : SurvivalCard) : boolean + + removeSurvivalCard(cards : SurvivalCard[*]) : boolean + + playSurvivalCard(card : SurvivalCard) : boolean + + playSurvivalCard(cards : SurvivalCard[*]) : boolean + + + } + + + HandTraque "1" -- "1" PlaceCardDeck + HandCreature "1" -- "1" Deck + HandTraque "1" -- "1" Deck + } + + Player <|-- Creature + Player <|-- Traque + + PlayerStatus <|-- CreatureRight + PlayerStatus <|-- TraqueRight + + Creature "1" - "1" CreatureRight + Traque "1" - "1" TraqueRight +} + +.... + + + + +==== Power +.Package power +[plantuml] +.... +package power{ + class Power{ + - inGameIdPlayer : Integer + + getInGameIdPlayer() : Integer + # {abstract} getType() : PowerType + } + + enum PowerType{ + MODIFICATOR + RECURRENT + } + package modifier{ + class PowerModifier{ + - modificatorType : PowerModifierType + - modifiedValue : Object + + getModificatorType() : PowerModifierType + + getModifiedValue() : Object + + getType() : PowerType + } + enum PowerType{ + CHOOSABLE_PLACE_CARD + PLAYABLE_PLACE_CARD + CHOOSABLE_VISIBLE_ADDITIONAL_PLACE_CARD + PLAYABLE_TRACKING_CARD + USE_FJORD_IN_PREVIOUS_ROUND + } + package recurrent{ + class PowerRecurrent{ + - action : BiConsumer + - condition : BiPredicate + + apply(game : Game) + + conditionIsTrue(game : Game) : Boolean + + getType() : PowerType + } + } + + +} +.... +==== Phase +.Phase +[plantuml] +.... +enum Phase{ + PREPHASE_1 + PHASE_1 + POSTPHASE_1 + PREPHASE_2 + PHASE_2 + POSTPHASE_2 + PREPHASE_3 + PHASE_3 + POSTPHASE_3 + PREPHASE_4 + PHASE_4 + POSTPHASE_4 +} +.... + +==== Reserve +.Reserve +[plantuml] +.... +class Reserve{ + - placeCards : Map> + + getNotEmptyPlaceCard() : PlaceCard[*] + + copiesNumber(numberPlayer : Integer) : Integer + + isNotEmpty() : Boolean + + notEmpty(cardNumber : Integer) : Boolean + + + pick(cardNumber : Integer) : PlaceCard + + add(placeCard : PlaceCard) + + equals(obj : Object) : Boolean + + toString() : String +} + + +.... + +=== Utilitary +.Package utilitary +[plantuml] +.... +package utilitary{ + package request{ + enum GameRequestType{ + JOIN + FINISH_PHASE + PLAY_CARDS + PLACE_JETONS + RESIST + GIVE_UP + } + + class GameFinishPhaseRequest{ + - phase : Phase + + getPhase() : Phase + + getType() : GameRequestType + + equals(obj : Object) : boolean + } + class GameGiveUpRequest{ + + getType() : GameRequestType + + } + + class GameJoinRequest{ + - inGameId : Integer + + getInGameId() : Integer + + getType() : GameRequestType + + equals(obj : Object) : boolean + } + + class GamePlaceJetonsRequest{ + - jetonList : PlacedJeton[*] + + getJetonList() : PlacedJeton[*] + + getType() : GameRequestType + + equals(obj : Object) : boolean + } + class GamePlayCardsRequest{ + - cards : Card[*] + + getCards() : Card[*] + + getType() : GameRequestType + + equals(obj : Object) : boolean + } + abstract class GameRequest{ + # user : User + # {abstract} getType() : GameRequestType + + getUser() : User + + equals(obj : Object) : boolean + } + class GameResistRequest{ + - number : Integer + + getNumber() : Integer + + getType() : GameRequestType + + equals(obj : Object) : boolean + } + + GameRequest <|-- GameJoinRequest + GameRequest <|-- GameResistRequest + GameRequest <|-- GamePlayCardsRequest + GameRequest <|-- GamePlaceJetonsRequest + GameRequest <|-- GameGiveUpRequest + GameRequest <|-- GameFinishPhaseRequest + } + class Conversion{ + - {static} DATABASE : NotAloneDatabase + + {static} toPhase(s : String) : Phase + + {static} toPhase(tphase : TPhaseId) : Phase + + {static} toBoardColor(s : String) : BoardColor + + {static} toBoardColor(color : TColor) : BoardColor + + {static} toBoardDistribution(s : String) : BoardDistribution + + {static} toBoardDistribution(tBoard : TBoard) : BoardDistribution + + {static} toCardType(tCardType : String) : CardType + + {static} toCard(tCard : TCard) : Card + + {static} toCardList(tCards : TCard[*]) : Card[*] + + {static} toPlaceCardList(tPlaceCards : TCards[*]) : PlaceCard[*] + + {static} toCardName(name : String) : CardName[*] + + {static} toTCard(card : PlaceCard) : TCard + + {static} toTCard(card : SurvivalCard) : TCard + + {static} toTCard(card : TrackingCard) : TCard + + {static} toTCard(card : Card) : TCard + + {static} toJetonSymbol(s : String) : JetonSymbol + + {static} toPlacedJeton(tPlacedJeton : TPlacedJeton) : PlacedJeton + + {static} toPlacedJetonList(tPlacedJetons : TPlacedJeton[*]) : PlacedJeton[*] + + {static} toPlace(s : String) : Place + + {static} toPlaceList(positionJeton : TPositionJeton) : Place[*] + + {static} toPlaceList(strings : String[*]) : Place[*] + + {static} toTPairType(name : String) : TPairType + + {static} toAction(tAction : TAction) : Action + + {static} toUser(tPlayer : TPlayer) : User + + {static} toTScore(board : Board) : TScore + + {static} toTPlacedCard(placeCard : PlaceCard, place : Place) : TPlacedCard + + {static} toTPlacedJetonList(placedJetons : PlacedJeton[*]) : TPlacedJeton[*] + + {static} toTJeton(symbol : JetonSymbol) : TJeton + + {static} toTBalise(planetPawn : PlanetPawn) : PlanetPawn + + {static} toTPlanet(planet : Planet) : TPlanet + + {static} toTCardReserve(pair : Pair) : TCardReserve + + {static} toTCardReserveList(reserve : Reserve) : TCardReserve[*] + + {static} toTGameVariable(variables : GameRoundVariables) : TGameVariable[*] + + {static} toTCreature(creature : Creature) : TCreature + + {static} toTTraque(traque : Traque) : TTraque + + {static} toTTraquePlaceCardPlayedVisible(traque : Traque) : TTraque + + {static} toTHand(traque : Traque) : THand + + {static} toTHand(creature : Creature) : THand + + {static} toTHand(player : Player) : THand + } + class Pair{ + - key : T + - value : U + + getKey() : T + + getValue() : U + + equals(obj : Object) : boolean + + toString() : String + } +} + + +.... + + +== Handler + +.Package Handler +[plantuml] +.... +package Handler{ + class GameServiceHandler{ + - service : RoomService + + createRoom(playerId : TPlayerId) : TRoomId + + sendStartGame(playerId : TPlayerId, idCreature : Integer, TBoard : board, Tcolor : color, tPlaceCards : TCard[*]) : Response + + joinRoom(playerId : TPlayerId, roomId : TRoomId) : Response + + getGameDescription(playerId : TPlayerId) : Response + + sendFinishPhase(playerId : TPlayerId, phaseId : TPhaseId) : Response + + sendPlayCards(playerId : TPlayerId, playerCards : TCard[*]) : Response + + sendPlaceJetons(playerId : TPlayerId, placedJetons : TPlacedJeton[*]) : Response + + sendResist(playerId : TPlayerId, number : Integer) : Response + + sendGiveUp(playerId : TPlayerId) : Response + } + +} + +.... +== User + +.Package User +[plantuml] +.... +package User{ + class PlayerInterface{ + + sendGameDescription(gameDescription : TDescription) : TRoomId + + sendGameStart() + + sendGameIsFinished(winner : TPlayerTeam) + + sendFirstRoundStart() + + sendStartPhase(phase : TPhase, gameDescription : TDescription) + + askAction(askedAction : TAskAction ) : TAction + + sendAction(askedAction : TAskAction ) + + sendResponse(response : Response ) + } + class PlayerProxy{ + - client : PlayerService.Client + + ping() : boolean + + sendGameStart() + + sendGameDescription(gameDescription : TDescription) + + sendGameIsFinished(winner : TplayerTeam) + + sendFirstRoundStart() + + sendStartPhase(phase : TPhase, gameDescription : TDescription) + + askAction(askedAction : TAskAction ) : TAction + + sendAction(askedAction : TAskAction ) + + sendResponse(response : Response ) + } + class User{ + - id : String + - name : String + - service : PlayerProxy + + getId() : String + + getName() : String + + getService() : PlayerProxy + + ping() : boolean + + sendGameStart() + + sendGameDescription(gameDescription : TDescription) + + sendGameIsFinished(winner : TplayerTeam) + + sendFirstRoundStart() + + sendStartPhase(phase : TPhase, gameDescription : TDescription) + + askAction(askedAction : TAskAction ) : TAction + + sendAction(askedAction : TAskAction ) + + sendResponse(response : Response ) + + equals(obj : Object ) : boolean + + hashCode() : Integer + } + +} + +.... + diff --git a/not-alone-doc/src/doc/asciidoc/_sections/exigences.adoc b/not-alone-doc/src/doc/asciidoc/_sections/exigences.adoc new file mode 100644 index 0000000000000000000000000000000000000000..390e48977bfb00afe472cc099b13a65031d619a9 --- /dev/null +++ b/not-alone-doc/src/doc/asciidoc/_sections/exigences.adoc @@ -0,0 +1,250 @@ +:project: Not Alone + += Requirements Specification + +== Introduction + +// Ce chapitre décrit les exigences du projet «{project}». Il suit la norme IEEE 830-1998. + +=== Purpose + +The purpose of this document is to describe the requirement specifications for the project «{project}» for software engineering students. + +The intended audience of this specification includes the prospective developers of the tool, as well as the technical assessment personnel. + +// Identify the product whose software requirements are specified in this document, including the revision or release number. Describe the scope of the product that is covered by this SRS, particularly if this SRS describes only part of the system or a single subsystem. + +=== Document Conventions + +None so far. + +// Describe any standards or typographical conventions that were followed when writing this SRS, such as fonts or highlighting that have special significance. For example, state whether priorities for higher-level requirements are assumed to be inherited by detailed requirements, or whether every requirement statement is to have its own priority. + +=== Intended Audience and Reading Suggestions + + +// Describe the different types of reader that the document is intended for, such as developers, project managers, marketing staff, users, testers, and documentation writers. Describe what the rest of this SRS contains and how it is organized. Suggest a sequence for reading the document, beginning with the overview sections and proceeding through the sections that are most pertinent to each reader type. + +=== Project Scope + +// Provide a short description of the software being specified and its purpose, including relevant benefits, objectives, and goals. Relate the software to corporate goals or business strategies. If a separate vision and scope document is available, refer to it rather than duplicating its contents here. + +The software system to be produced is a simplified version of the Hearthstone online room, which will be referred to as «{project}» thorough this document. + +The {project} system will allow players from different locations to confront each-other in short and intensive games. + +=== References + +. IEEE Standard 830-1993: IEEE Recommended Practice for Software Requirements Specifications + + +// List any other documents or Web addresses to which this SRS refers. These may include user interface style guides, contracts, standards, system requirements specifications, use case documents, or a vision and scope document. Provide enough information so that the reader could access a copy of each reference, including title, author, version number, date, and source or location. + +=== Overview + +The rest of this document contains an overall description of the {project} software system (section <>), the specific functional requirements (section <>), and the non-functional requirements for the system (see <>. + +[#description] +== Overall Description + +=== Product Perspective + +Hearthstone is a card room where two players confront each-other. +The {project} software should allow players that are connected to the Internet to use their connected devices to play. +Thus, «{project}» is an online, electronic version of the card room. + +While the system is distributed and organized in different components, players should perceive it as a single piece of software. +Figure <> presents the overall architecture of the software. +Players interact with a Web Client, which uses the HTTP protocol to communicate with (at most) one Game Server. +Servers use TCP/IP to communicate with a Database Management Server, which stores all software data. + +// Describe the context and origin of the product being specified in this SRS. For example, state whether this product is a follow-on member of a product family, a replacement for certain existing systems, or a new, self-contained product. If the SRS defines a component of a larger system, relate the requirements of the larger system to the functionality of this software and identify interfaces between the two. A simple diagram that shows the major components of the overall system, subsystem interconnections, and external interfaces can be helpful. + +[#deployment] +.UML Deployment Diagram +[plantuml, deployment-diagram, png] +---- +@startuml + +node Client { + artifact WebClient +} +node Server { + artifact GameServer +} + +node Database { + artifact DBMS +} + +WebClient -left- Server : TCP/IP - WebSockets +Server -up- Database : JPA + +@enduml +---- + +=== Product Functions + +The {project} software must provide two main functions: + +. Game creation: allowing two players to discover each other and start a room. +. Game play: allowing players to actually play {project} until the victory of one of them. + +// Summarize the major functions the product must perform or must let the user perform. Details will be provided in Section 3, so only a high level summary (such as a bullet list) is needed here. Organize the functions to make them understandable to any reader of the SRS. A picture of the major groups of related requirements and how they relate, such as a top level data flow diagram or object class diagram, is often effective. + +=== User Classes and Characteristics + +// Identify the various user classes that you anticipate will use this product. User classes may be differentiated based on frequency of use, subset of product functions used, technical expertise, security or privilege levels, educational level, or experience. Describe the pertinent characteristics of each user class. Certain requirements may pertain only to certain user classes. Distinguish the most important user classes for this product from those who are less important to satisfy. + +The {project} software has only one class of user: players. +Players may have different levels: beginners, intermediate, or expert. +However, independently from their level, players should use the same user interface to play against each other. + +=== Operating Environment + +// Describe the environment in which the software will operate, including the hardware platform, operating system and versions, and any other software components or applications with which it must peacefully coexist. + +The {project} software should operate on any popular and recent operating system: Linux, Windows, or MacOS. +The Web Client should operate on any recent web browser: Firefox, Chrome, Safari, or Edge. + +=== Design and Implementation Constraints + +// Describe any items or issues that will limit the options available to the developers. These might include: corporate or regulatory policies; hardware limitations (timing requirements, memory requirements); interfaces to other applications; specific technologies, tools, and databases to be used; parallel operations; language requirements; communications protocols; security considerations; design conventions or programming standards (for example, if the customer’s organization will be responsible for maintaining the delivered software). + +. The Game Server must be developed in Java (version 1.8), using the https://spring.io[Spring Framework]. +. The Client must be developed in TypeScript (version 3.1), using the https://angular.io[Angular Framework]. +. All software artifacts must use a building too: Maven or Groovy for Java, npm for TypeScript. +. Dynamic tests must use JUnit (version >= 5.0) and Jasmine (version >= 3.5.0). +. The code must log its main operations using https://www.slf4j.org[SLF4J]. + + +=== Verification Constraints + +. Test Doubles must be used to test each component independently. +. Each unit test must describe its intention. + +=== User Documentation + +// List the user documentation components (such as user manuals, on-line help, and tutorials) that will be delivered along with the software. Identify any known user documentation delivery formats or standards. + +No user documentation is required for the first version of the software. + +=== Assumptions and Dependencies + +// List any assumed factors (as opposed to known facts) that could affect the requirements stated in the SRS. These could include third-party or commercial components that you plan to use, issues around the development or operating environment, or constraints. The project could be affected if these assumptions are incorrect, are not shared, or change. Also identify any dependencies the project has on external factors, such as software components that you intend to reuse from another project, unless they are already documented elsewhere (for example, in the vision and scope document or the project plan). + +None until now. + +== External Interface Requirements + +=== User Interfaces + +// Describe the logical characteristics of each interface between the software product and the users. This may include sample screen images, any GUI standards or product family style guides that are to be followed, screen layout constraints, standard buttons and functions (e.g., help) that will appear on every screen, keyboard shortcuts, error message display standards, and so on. Define the software components for which a user interface is needed. Details of the user interface design should be documented in a separate user interface specification. + +=== Hardware Interfaces + +// Describe the logical and physical characteristics of each interface between the software product and the hardware components of the system. This may include the supported device types, the nature of the data and control interactions between the software and the hardware, and communication protocols to be used. + +The software does not interact directly with any hardware device. + +=== Software Interfaces} + +The client part of the software must operate on web browsers, whereas the server part must interact with a database through the Java Persistence API (JPA). + +// Describe the connections between this product and other specific software components (name and version), including databases, operating systems, tools, libraries, and integrated commercial components. Identify the data items or messages coming into the system and going out and describe the purpose of each. Describe the services needed and the nature of communications. Refer to documents that describe detailed application programming interface protocols. Identify data that will be shared across software components. If the data sharing mechanism must be implemented in a specific way (for example, use of a global data area in a multitasking operating system), specify this as an implementation constraint. + +=== Communications Interfaces + +// Describe the requirements associated with any communications functions required by this product, including e-mail, web browser, network server communications protocols, electronic forms, and so on. Define any pertinent message formatting. Identify any communication standards that will be used, such as FTP or HTTP. Specify any communication security or encryption issues, data transfer rates, and synchronization mechanisms. + +Communications between the client and the room server must use Websockets. + +[#features] +== System Features + +// This template illustrates organizing the functional requirements for the product by system features, the major services provided by the product. You may prefer to organize this section by use case, mode of operation, user class, object class, functional hierarchy, or combinations of these, whatever makes the most logical sense for your product. + +=== Game initialization + +// Don’t really say “System Feature 1.” State the feature name in just a few words. + +The {project} software must allow the setup of a room with two players and automatically prepare and distribute cards. + +==== Description and Priority + +See Chapter <> (domain analysis) for further details. + +// Provide a short description of the feature and indicate whether it is of High, Medium, or Low priority. You could also include specific priority component ratings, such as benefit, penalty, cost, and risk (each rated on a relative scale from a low of 1 to a high of 9). + +==== Stimulus/Response Sequences + +// List the sequences of user actions and system responses that stimulate the behavior defined for this feature. These will correspond to the dialog elements associated with use cases. + +==== Functional Requirements + +// Itemize the detailed functional requirements associated with this feature. These are the software capabilities that must be present in order for the user to carry out the services provided by the feature, or to execute the use case. Include how the product should respond to anticipated error conditions or invalid inputs. Requirements should be concise, complete, unambiguous, verifiable, and necessary. Use “TBD” as a placeholder to indicate when necessary information is not yet available. + +// Each requirement should be uniquely identified with a sequence number or a meaningful tag of some kind.$>$ + +// % REQ-1: REQ-2: + +=== Game play + +The {project} software must allow two players to play against each other until a winer is settled. +See Chapter <> (domain analysis) for further details. + +[#nonfunctional] +== Other Nonfunctional Requirements + +=== Performance Requirements} + +. The room must be _playable_, meaning that users must have fast feedback for their actions and delays due to communications/connection problems must be correctly held. +. The Web Client must be able to execute on a personal computer with 4GB of RAM. + + +// If there are performance requirements for the product under various circumstances, state them here and explain their rationale, to help the developers understand the intent and make suitable design choices. Specify the timing relationships for real time systems. Make such requirements as specific as possible. You may need to state performance requirements for individual functional requirements or features. + +=== Safety Requirements + +// Specify those requirements that are concerned with possible loss, damage, or harm that could result from the use of the product. Define any safeguards or actions that must be taken, as well as actions that must be prevented. Refer to any external policies or regulations that state safety issues that affect the product’s design or use. Define any safety certifications that must be satisfied. + +=== Security Requirements + +// Specify any requirements regarding security or privacy issues surrounding use of the product or protection of the data used or created by the product. Define any user identity authentication requirements. Refer to any external policies or regulations containing security issues that affect the product. Define any security or privacy certifications that must be satisfied. + +=== Software Quality Attributes + +// Specify any additional quality characteristics for the product that will be important to either the customers or the developers. Some to consider are: adaptability, availability, correctness, flexibility, interoperability, maintainability, portability, reliability, reusability, robustness, testability, and usability. Write these to be specific, quantitative, and verifiable when possible. At the least, clarify the relative preferences for various attributes, such as ease of use over ease of learning. + +==== Extensibility + +The software must be extensible, it must be easy for developers to add new cards and heroes to the room. + +==== Maintainability + +. The software must be readable and easy to maintain. +. The Java source must respect Google's guidelines: https://google-styleguide.googlecode.com/svn/trunk/javaguide.html + +=== Business Rules + +// List any operating principles about the product, such as which individuals or roles can perform which functions under specific circumstances. These are not functional requirements in themselves, but they may imply certain functional requirements to enforce the rules. + + +== Other Requirements + +// Define any other requirements not covered elsewhere in the SRS. This might include database requirements, internationalization requirements, legal requirements, reuse objectives for the project, and so on. Add any new sections that are pertinent to the project. + +=== Appendix A: Glossary + +//see https://en.wikibooks.org/wiki/LaTeX/Glossary +// Define all the terms necessary to properly interpret the SRS, including acronyms and abbreviations. You may wish to build a separate glossary that spans multiple projects or the entire organization, and just include terms specific to a single project in each SRS. + +=== Appendix B: Analysis Models + +See Chapter <> (domain analysis) for further details. + +// Optionally, include any pertinent analysis models, such as data flow diagrams, class diagrams, state-transition diagrams, or entity-relationship diagrams. + +=== Appendix C: To Be Determined List + +// Collect a numbered list of the TBD (to be determined) references that remain in the SRS so they can be tracked to closure. diff --git a/not-alone-doc/src/doc/asciidoc/_sections/termes.adoc b/not-alone-doc/src/doc/asciidoc/_sections/termes.adoc index 5f69debccac755e14fd9d4ad5f0ee2b486679596..08699cc8e0da6e0e4ec7dec08eb4bc4dffdf0b09 100644 --- a/not-alone-doc/src/doc/asciidoc/_sections/termes.adoc +++ b/not-alone-doc/src/doc/asciidoc/_sections/termes.adoc @@ -8,9 +8,115 @@ |*Signification* |*Exemples* -| Créature -| a -| ax +|Joueur +| Chacun des participants au jeu. +| +| Anna, Mathis, Kévin. + +|Traqué +| Joueur(s) devant survivre aux assauts de la Créature. +| +| Anna, Kévin. + +|Créature +| Joueur incarnant le monstre pourchassant les Traqués. +| +| Mathis. + +|Plateau +| Objet faisant office de score. Il est composé de cases Assimilation et de cases Secours. Il peut être disposé de deux façons différentes. +| +| Les cases marquée Artémia sur les cases Secours sont successives (et non 1/2). + +|Planète +| Représente l'endroit où se déroule le jeu. Elle se nomme Artémia, et elle est composé de dix lieux. | +| L'Ante, la Jungle, la Rivière, la Plage, le Rover, le Marais, l'Abri, l'Épave, la Source, l'Artefact. +|Pion +| Objet permettant de marquer le score des joueurs sur le plateau. +| +| + +|PionAssimilation +| Pion permettant de marquer le score de la Créature. +| +| + +|PionSecours +| Pion permettant de marquer le score de l'équipe des Traqués. +| +| + +| Pouvoir +| Un pouvoir représente un ensemble d'actions. Ces actions peuvent modifier une règle ou un élément de la partie (score, cartes, ...). +| +| Evitez les effets du jeton Créature ; Reprenez en main cette carte Lieu et une carte Lieu de votre défausse. + + +| Carte +| Objet possédant un pouvoir. +| +| + +|CarteLieu +| Carte représentant un lieu et possédant un pouvoir. +| +|La rivière. + +|CarteSurvie +| Cartes jouables uniquement par les Traqués et possédant un pouvoir. +| +| Vortex + + +|CarteTraque +| Cartes jouables uniquement par la Créature et possédant un pouvoir. +| +| Clone + + +|Main +| Représente les cartes lieux possédées par un Traqué à un moment de la partie. +| +| La Plage, l'Antre pour Anna et la Rivière et l'Épave pour Kévin. + + +|Défausse +| Représente l'endroit où un Traqué met ses CarteLieux défaussées. +| +| La Plage, l'Antre, le Rover et la Jungle pour Kévin. Le Rover, la Rivière, la Plage, l'Antre pour Anna. + + +|PionVolonté +| Représente la volonté d'un Traqué. +| +| 2 pions pour Anna, 1 pour Kévin. + + +|Réserve +| Représente l'endroit où sont stockées les CarteLieux numérotées de 6 à 10 quand elles n'ont pas encore été mises en jeu. +| +| + + +|JetonTraque +| Représente les jetons dont dispose la Créature pour marquer certains lieux durant un tour. +| +| + +|JetonCible +|Si un traqué choisit le lieu marqué de ce pion : il subit l'effet de la carte cible et peut ensuite utiliser le pouvoir de la carte Lieu OU reprendre en main 1 carte Lieu au choix de sa défausse. +| +| + +|JetonCréature +| Si un traqué choisit le lieu marqué de ce pion : il perd un pion de volonté. Peut importe le nombre de joueur le pion assimilation avance de 1. +| +| + +|JetonArtemia +|Si un traqué choisit le lieu marqué de ce pion : il perd 1 carte lieu de sa main et ne créer pas l'effet du lieu où est le jeton. +| +| |=== diff --git a/not-alone-doc/src/doc/asciidoc/_sections/use-cases/deroulement.adoc b/not-alone-doc/src/doc/asciidoc/_sections/use-cases/deroulement.adoc new file mode 100644 index 0000000000000000000000000000000000000000..aa68922621f3897675d4c0f87eaacf94227cad45 --- /dev/null +++ b/not-alone-doc/src/doc/asciidoc/_sections/use-cases/deroulement.adoc @@ -0,0 +1,94 @@ + +[cols="30s,70n",options="header", frame=sides] +|=== +| Item | Description + +| # | 2 +| Use Case | Déroulement + +| AKA +| + +| Goal in Context +| Effectuer un tour + + +| Scope | scope + +| Level | Summary +| Success End Condition | +| Failed End Condition | +| Primary Actor | Les joueurs + +| Secondary Actor +|  + +| Trigger | Fin de mise en place ou fin d'un déroulement +| Priority | Elevée + +| Frequency | Plusieurs fois à chaque partie + + +| Pre-conditions +a| +- Le jeu a été mis en place antérieurement +- Tous les joueurs présents lors de la mise en place sont toujours présents +- La partie n'est pas finie + +| Post-conditions +| + +|Main success scenario +a| +1. Phase 1 + a. Les Traqués jouent une CarteLieu face cachée +2. Phase 2 + a. La créature pose son JetonCréature sur une CarteLieu de la planète +3. Phase 3 + a. Les Traqués dévoilent simultanément leur CarteLieu jouée + b. Les Traqués résolvent les lieux correspondants à la CarteLieu jouée dans un ordre préalablement défini +4. Phase 4 + a. Chaque Traqué défausse sa CarteLieu jouée face visible + b. La Créature reprend ses JetonTraque + c. La Créature pioche des CarteTraque jusqu'à en avoir 3 en mains + d. Le Pion Secours avance d'une case +5. Fin de tour + a. Déclencher un nouveau déroulement +| Variations +a| +1. Au début de chaque phase : + a. La Créature joue une CarteTraque (sauf contre-indication : au maximum une CarteTraque par déroulement) + b. Un ou des Traqués jouent une CarteSurvie +2. Phase 1 + a. Un ou des Traqués résistent + b. Un ou des Traqués lâchent prise + c. Le pion assimilation atteint la case Victoire et la partie est finie. +3. Phase 2 + a. La Créature pose son JetonArtemia + b. La Créature pose son JetonCible +4. Phase 3 + a. Un Traqué explore un lieu avec le JetonCréature. + Il perds un PionVolonté et ne peut pas résoudre le lieu lors de la phase suivante. + Le PionAssimilation avance de 1 case si c'est le premier Traqué attrapé lors de cette phase. + b. Un Traqué explore un lieu avec le JetonArtemia. + Le pouvoir du lieu sera inutilisable lors de la phase suivante. + Il défausse une CarteLieu de sa main. + c. Un Traqué explore un lieu avec le jeton Cible. + Le Pouvoir de la CarteTraque s'applique. + d. Le PionAssimilation atteint la case Victoire. La partie est finie. +5. Fin de tour + a. Le PionSecours atteint la case Victoire. La partie est finie. + + +|Superordinate Use Case | None +|Subordinate Use Cases | optional, depending on tools, links to sub.use cases +|Performance Target |the amount of time this use case should take + +|Open Issues +a| + +|Schedule | +|Constraints | +|Annexes +| +|=== diff --git a/not-alone-doc/src/doc/asciidoc/_sections/use-cases/mise-en-place.adoc b/not-alone-doc/src/doc/asciidoc/_sections/use-cases/mise-en-place.adoc new file mode 100644 index 0000000000000000000000000000000000000000..681d34bd4a58deefc695c8172bb41a50b7371dc0 --- /dev/null +++ b/not-alone-doc/src/doc/asciidoc/_sections/use-cases/mise-en-place.adoc @@ -0,0 +1,76 @@ +== Tableau de mise en place + +[cols="30s,70n",options="header", frame=sides] +|=== +| Item | Description + +| # | 1 +| Use Case | Mise en place + +| AKA +| + +| Goal in Context +| Préparer le jeu + + +| Scope | scope + +| Level | Summary +| Success End Condition | +| Failed End Condition | +| Primary Actor | Le maître du jeu + +| Secondary Actor +| Les joueurs + +| Trigger | Début de partie +| Priority | Elevée + +| Frequency | Avant chaque partie + + +| Pre-conditions +a|. Il y a entre 2 et 7 joueurs. +. Un joueur est désigné Créature +. Les autres joueurs sont des Traqués + +| Post-conditions +a|. Chaque Traqué possède un exemplaire de chacune des cartes Lieu numérotées de 1 à 5, ainsi que 3 pions Volonté et 1 carte Survie +. La créature possède 3 pions Traque et 3 cartes Traque +. Le plateau est initialisé avec les pions Secours et Assimilation placés respectivement sur la bonne case en fonction du nombre de joueurs. +. Les pioches sont mélangés +. La réserve contient le bon nombre d'exemplaires de chaque carte Lieu numérotée de 6 à 10 en fonction du nombre de joueurs. +. La planète est mise en place. + + +|Main success scenario +a| +. Maître du jeu met en place le plateau +. Maître du jeu met en place la planète +. Maître du jeu prépare les pioches +. Les Traqués préparent leur main +. La Créature prépare sa main + +| Extensions +a| + + +| Variations +a| . Plateau peut être mis en place de 2 manières différents +|Superordinate Use Case | None +|Subordinate Use Cases | optional, depending on tools, links to sub.use cases +|Performance Target +|the amount of time this use case should take + +|Open Issues +a| + + +|Schedule | +|Constraints | +|Annexes +| +|=== + +--- \ No newline at end of file diff --git a/not-alone-doc/src/doc/asciidoc/_sections/use-cases/use-cases.adoc b/not-alone-doc/src/doc/asciidoc/_sections/use-cases/use-cases.adoc new file mode 100644 index 0000000000000000000000000000000000000000..4aa740ffbd7e4b863501c75709714a0cba1aba40 --- /dev/null +++ b/not-alone-doc/src/doc/asciidoc/_sections/use-cases/use-cases.adoc @@ -0,0 +1,25 @@ +== Use Cases + + +[plantuml, uc-not-alone, png] +.... +left to right direction +skinparam packageStyle rectangle +actor Client_Application +entity Bob +rectangle "Not Alone" { + Client_Application -- (Deroulement) + Client_Application -- (Discovery) + Bob -- (Mise en place) +} +.... + +=== Mise en place + +include::mise-en-place.adoc[] + +=== Déroulement + +include::deroulement.adoc[] + + diff --git a/not-alone-doc/src/doc/asciidoc/synthese.adoc b/not-alone-doc/src/doc/asciidoc/synthese.adoc new file mode 100644 index 0000000000000000000000000000000000000000..33c07801b490742038c2f922bfd9ca671dbf5828 --- /dev/null +++ b/not-alone-doc/src/doc/asciidoc/synthese.adoc @@ -0,0 +1,766 @@ += Synthèse des règles + +== Cartes lieu + +Fonctionnement:: Chaque carte Lieu possède un n°, un nom et un pouvoir pouvant être activé par les Traqués. + +Adjacence:: Deux cartes Lieu sont adjacentes si elles ont un bord en commun, horizontal ou vertical. + +Lieux multiples:: Quand un jeton est placé sur 2 Lieux adjacents, le placer à cheval sur ces 2 Lieux. + +Copier le pouvoir d'un Lieu:: Pour utiliser cet effet, un Traqué doit pouvoir utiliser le pouvoir de la carte Lieu qu’il a initialement jouée en Phase 1 : + +- cet effet permet à ce Traqué d’utiliser un Lieu révélé sans jouer la carte associée, même si ce lieu est inutilisable ou inaccessible pour lui, + +- tout jeton Traque sur le Lieu copié est sans effet sur ce Traqué. + +Lieu inaccessible:: Un Lieu non révélé est inaccessible pour les Traqués. +Les jetons Traque peuvent être placés ou déplacés sur un Lieu inaccessible. + +Lieu inutilisable:: Lorsqu'un Lieu est inutilisable, son pourovir peut être copié grâce au pouvoir d’une carte Lieu ou d’une carte Survie. + +.Liste des cartes lieu +[cols="10,30,60",options="header"] +|=== + +| N° +| Nom +| Pouvoir + +| 1 +| L'Antre +a| Au choix : + +- reprenez en main les cartes Lieu de votre défausse (mais pas celui-ci), +- copiez le pouvoir d'un Lieu où le jeton Créature se trouve, + +Perdez 1 Volonté supplémentaire si le jeton Créature vous attrape. + +| 2 +| La Jungle +| Reprenez en main cette carte Lieu et 1 carte Lieu de votre défausse. + +| 3 +| La Rivière +| Au prochain tour, jouez 2 cartes Lieu. + +Avant de révéler, choisissez-en une et reprenez l'autre en main. + +| 4 +| La Plage +a| Au choix, 1 fois par tour : + +- placez le pion Balise sur la Plage, + +- retirez le pion Balise de la Plage pour avancer le pion Secours d’une case (max 1x/tour). + +Si plusieurs Traqués explorent la Plage, l’un d’eux peut utiliser le pouvoir de la Plage et les autres peuvent récupérer 1 carte Lieu de leur défausse. + +Le pouvoir de la Plage est cumulable avec celui de l’Épave. + +| 5 +| Le Rover +| Prenez de la réserve une carte Lieu que vous ne possédez pas et ajoutez-le à votre main. + + +| 6 +| Le Marais +a| Reprenez en main cette carte Lieu et 2 cartes Lieu de votre défausse. + +.Précision: +- Si le Marais est révélé grâce au Labyrinthe et que vous l’activez directement, ni le Marais ni le Labyrinthe ne sont repris en main. + +| 7 +| L'Abri +| Piochez 2 carte Survie, gardez-en une et défaussez l'autre. + +| 8 +| L'Épave +| Avancez le pion Secours d'1 case (1 fois par tour, quel que soit le nombre de Traqués explorant l’Épave). + +Si plusieurs Traqués explorent l’Épave, l’un d’eux peut utiliser le pouvoir de l’Épave et les autres peuvent récupérer 1 carte Lieu de leur défausse. + +Le pouvoir de l’Épave est cumulable avec celui de la Plage. + +| 9 +| La Source +a| Au choix : + +- le Traqué de votre choix (vous ou un autre joueur) récupère 1 Volonté, +- piochez 1 carte Survie. + +| 10 +| L'Artefact +a| Le pouvoir de l'Artefact varie selon la couleur choisie pour la partie. + +L’Artefact ne peut être copié (que ce soit par le pouvoir d'un Lieu ou une carte Survie). + +.Bleu +Au prochain tour, jouez 2 cartes Lieu. + +Résolvez les deux Lieu individuellement dans l’ordre de votre choix en respectant les règles de la Phase 3. + +Lorsqu’un Traqué révèle ses cartes Lieu, s’il peut appliquer les effets de la Rivière et de l’Artefact bleu durant +un même tour, il doit choisir l’un des deux effets, puis il peut reprendre une carte Lieu de sa défausse. + +.Rouge +Copiez les effets d'1 carte Lieu de votre défausse. + +.Vert +Défaussez 1 carte Lieu et déplacez 1 Traqué de votre choix sur un Lieu adjacent. + +.Jaune +Au choix : + +- annulez les effets du jeton Artemia, +- récupérez 2 cartes Lieu de votre défausse. + +|=== + + + + +== Cartes traque + +Fonctionnement:: +Chaque carte Traque possède un nom, une Phase où elle peut être joéue et un effet pouvant être activé par la Créature. +Certaines cartes Traque possèdent également le symbole Cible ou Artemia. +Une carte Traque se joue à tout moment de la phase indiquée sur la carte et est ensuite défaussée. + +Précision:: +Quand l'effet d'une carte Traque qui indique "Dès que les cartes Lieu sont révélées à la Phase 3" : il est appliqué dès que chaque Traqué a dévoilé sa carte Lieu, avant la résolution des cartes Lieu. + +Symbole Cible:: +Lorsqu'une carte Traque avec le symbole Cible est jouée, la Créature pose le jeton Cible sur une des dix cartes Lieu d'Artemia. +Si la Créature joue 2 cartes Traque avec ce symbole au cours d’un même tour, leurs effets sont cumulés sur le Lieu ciblé. + +Symbole Artemia:: +Lorsqu'une carte Traque avec le symbole Artemia est jouée, la Créature pose le jeton Artemia sur une des dix cartes Lieu d'Artemia. +Si la Créature joue 2 cartes Traque avec ce symbole au cours d’un même tour, leurs effets sont cumulés. + +.Liste des cartes traque +[cols="30,10,60",options="header"] +|=== +| Nom +| Phase +| Effet + +| Acharnement +| 2 +| Le jeton Créature fait perdre 1 Volonté supplémentaire. + +| Angoisse +| 1 - Artémia +| Les traqués ne peuvent pas Résister. + +| Anticipation +| 2 +| Désigner 1 Traqué : si vous l’attrapez avec le jeton Créature, avancez le jeton Assimilation d’1 case supplémentaire. + +| Cataclysme +| 3 +| Le pouvoir du Lieu de votre choix est inutilisable. + +| Champ de force +| 1 - Cible +| Avant que les Traqués ne jouent, ciblez 2 Lieux adjacents : ces Lieux sont inaccessibles pour ce tour. + +| Clone +| 2 - Cible +| Considérez le jeton Cible comme un second jeton Créature. + +| Déploiement +| 3 +| Dès que les cartes Lieu sont révélées en Phase 3, reculer le pion Assimilation d'1 case +pour déplacer le jeton Créature sur un Lieu adjacent. + +| Désespoir +| 1 - Artemia +| Aucune carte Survie ne peut être jouée ou piochée pour le reste du tour. + +| Détour +| 3 +| Avant de résoudre les Lieux, déplacer 1 Traqué vers 1 Lieu adjacent. + +| Domination +| 2 +|Poser cette carte devant 1 Traqué : à la fin de chaque tour, celui-ci doit défausser 1 carte Lieu de sa +main. + +Si ce Traqué tombe à 0 Volonté, défausser cette carte. + +| Effroi +| 1 +| Obligez un Traqué qui utilise l'action Résister à Lâcher prise. + +| Emprise +| 2 +| Cibler 1 Traqué : il défausse toutes ses cartes Lieu sauf 2. + +| Épidémie +| 2 +a| Désignez 1 Traqué : + +- le Lieu où il se trouve est inutilisable, +- chaque autre Traqué présent sur ce Lieu perd 1 Volonté. + +| Faille temporelle +| 2 - Cible +| Pour chaque Traqué présent sur le Lieu ciblé, avancer le pion Assimilation d'autant de cases, puis le pion Secours d'autant de cases. + +| Flashback +| Spécial +| À jouer à la phase de la carte copiée : copier la dernière carte Traque défaussée. + +| Gargantua +| 2 +| Placer le jeton Créature sur 2 Lieux adjacents : ses effets s'appliquent sur ces 2 Lieux. +Si un Traqué copie le pouvoir du Lieu où se trouve le jeton Créature, il copie 1 seul des 2 Lieux. + +| Harcèlement +| 2 +| Chaque Traqué ne peut récupérer qu'1 carte Lieu quand il utilise le pouvoir d'un Lieu. + +| Hurlements +| 2 - Cible +| Chaque Traqué présent sur le Lieu ciblé doit, selon son choix, défausser 2 cartes Lieu ou perdre 1 Volonté. + +| Inertie +| 2 - Cible +| Dès que les cartes Lieu sont révélées à la Phase 3, si au moins 1 Traqué se trouve sur le Lieu ciblé : +les pouvoirs de tous les Lieux sont inutilisables, les effets des jetons Créature et Artemia sont quand même résolus. + +| Interférences +| 2 +a| Au choix: + +- les pouvoirs de la Plage et de l’Épave sont inutilisables, +- reculer le pion Bouclier d'1 Lieu. + +| Intuition +| 1 +a| +. Piocher 3 cartes Traque, +. Jouer 1 de ces cartes durant le tour et défausser les 2 autres. + +| Magnétisme +| 2 - Cible +| Dès que les cartes Lieu sont révélées en Phase 3, chaque Traqué adjacent au Lieu ciblé est déplacé sur le Lieu ciblé. + +| Mirage +| 2 - Cible +| Ciblez 2 Lieux adjacents (placer le jeton Cible entre ces 2 Lieux) : leur pouvoir est inutilisable. + +| Mutation +| 2 - Artemia +| En plus de ses effets, le jeton Artemia fait perdre 1 Volonté. + +| Psychose +| 2 - Artemia +| Désigner 1 Traqué : il vous montre toutes les cartes Lieu de sa main sauf 2. + +| Réminiscence +| 2 - Artemia +| Reprendre 1 carte Traque de la défausse. + +| Repérage +| 4 +| Au prochain tour, vous pouvez jouer jusqu’à 2 cartes Traque. + +| Sables mouvants +| 2 - Cible +| Chaque Traqué présent sur le Lieu ciblé choisit et défausse toutes les cartes Lieu de sa main sauf 2. + +| Soif de sang +| 2 - Cible +a| +. Chaque Traqué présent sur le Lieu ciblé récupère 1 Volonté, si possible, +. Chaque Traqué présent sur un Lieu adjacent au Lieu ciblé perd 1 Volonté. + +| Stase +| 4 +| Le pion Secours n'avance pas lors de cette Phase. + +| Télépathie +| 2 - Artemia +a| +. Désigner 1 Lieu, +. Choisir 1 Traqué, tirer au hasard 1 carte de sa main et la défausser, +. Si la carte correspond au Lieu désigné : avancer le pion Assimilation d'1 case. + +| Tornade +| 2 - Artemia +| Dès que les cartes Lieu sont révélées à la Phase 3, vous pouvez déplacer le jeton Artemia sur un Lieu adjacent. + +| Toxine +| 2 - Cible +| Chaque Traqué sur le Lieu ciblé défausse 1 carte Survie. + +Le pouvoir de ce lieu est inutilisable. + +| Ubiquité +| 2 - Artemia + Cible +| Dès que les cartes Lieu sont révélées à la Phase 3, vous pouvez permuter les jetons Traque. + +Si un jeton Traque se trouve sur 2 Lieux adjacents, le jeton qui le remplace est placé sur ces 2 Lieux adjacents. + +| Virus +| 2 - Artemia +| Ciblez 2 Lieux adjacents : les effets du jeton Artemia s'appliquent sur ces 2 Lieux. + +| Zone interdite +| 2 +| Tous les Traqués défaussent simultanément 1 carte Lieu de leur choix. + +|=== + +== Cartes survie + +Fonctionnement:: +Chaque carte Survie possède un nom, une Phase où elle peut être joéue et un effet pouvant être activé par le Traqué qui la détient. +Une carte Survie se joue à tout moment de la phase indiquée sur la carte et est ensuite défaussée. + +.Liste des cartes survie +[cols="30,10,60"] +|=== +| Nom | Phase | Effet + +| Adrénaline +| 1 +| Récupérez 1 Volonté. + +| Alerte +| 3 +a| Désigner 1 Lieu : + +- les jetons Traque présents sur ce Lieu sont sans effet, +- le pouvoir de ce Lieu est inutilisable. + +| Amplificateur +| 4 +a| Au choix: + +- retirez le jeton Balise de la Plage pour avancer le pion Secours d’1 case, +- avancez le pion Bouclier d'1 Lieu vers le Dôme. + +| Brouillage +| 1 +| Tous les Traqués cachent les cartes Lieu de leur défausse jusqu’à la fin du tour + +| Cavale +| 1 +a| +. Jouez 3 cartes Lieu, +. En Phase 3 : révélez celle de votre choix, +. En Phase 4 : reprenez en main la carte révélée et défaussez les 2 autres. + +| Détecteur +| 3 +| Évitez les effets du jeton Artemia. + +| Drone +| 3 +| À la place d'utiliser le pouvoir de votre carte Lieu, +prenez de la réserve 1 carte d'un Lieu révélé que vous ne possédez pas et +ajoutez-la à votre main. + +| Entrave +| 1 +| Le jeton Créature ne peut pas être posé sur les Lieux 6 à 10. + +| Équipement +| 4 +a| Au choix : + +- piochez 1 carte Survie, +- prenez la carte Survie du dessus de la défausse. + +| Esquive +| 3 +| Évitez les effets du jeton Créature. + +| Fausse piste +| 3 +| Déplacez le jeton Créature sur un Lieu adjacent. + +| Hologramme +| 3 +| Déplacez le jeton Artemia sur un Lieu adjacent. + +| Leurre +| 3 +a| +. Permutez 2 jetons Traque, +. Reprenez 1 carte Lieu de votre défausse. + +| Mimétisme +| 1 +| En Phase 3, si vous êtes sur le même Lieu que le jeton Créature : avancez le pion Secours d'1 case, +vous ne subissez pas les effets du jeton Créature. + +| Navette +| 4 +| Jouer cette carte quand le pion Secours se trouve à 1 case de la case Victoire : +les Traqués reportent la partie. + +| Planques +| 4 +| Piocher 2 cartes Survie et les placer face cachée chacune sous 1 Lieu d'Artemia : +si un Traqué explore un de ces Lieux et peut utiliser son pouvoir, +il peut également récupérer la carte Survie qui s'y trouve. + +| Portail +| 3 +| À la place d'utiliser le pouvoir de votre carte Lieu, copiez le pouvoir d’1 +Lieu adjacent. + +| Ralliement +| 4 +| Chaque Traqué attrapé par le jeton Créature peut reprendre en main la carte Lieu sur laquelle il s'est fait attraper. + +| Refuge +| 1 +| Poser le jeton Cible sur 2 Lieux adjacents : le jeton Créature ne peut être posé sur +ces Lieux Aucune carte Traque avec le symbole Cible ne peut être jouée. + +| Régénération +| 3 +| À la place d'utiliser le pouvoir de votre carte Lieu, +copiez le pouvoir d’1 carte Lieu de votre défausse. + +| Résistance +| 3 +| Évitez les effets du jeton Cible. + +| Retraite +| 3 +| Déplacez 1 Traqué de votre choix sur un Lieu adjacent, le Lieu de destination n'est pas résolu. + +| Riposte +| 1 +| Tirer 2 cartes Traque au hasard de la main de la Créature et placez-lez sous la pioche Traque. + +| Sacrifice +| 1 +| Défaussez 1 carte Lieu : aucune carte Traque ne peut être jouée ce tour-ci. + +| Second souffle +| 1 +| Si vous avez au plus 1 carte Lieu en main : récupérez toutes les cartes Lieu de votre défausse. + +| Sixième sens +| 1 +| Reprenez en main 2 carte Lieu de votre défausse. + +| Système D +| 1 +a| Au choix: + +- placez le pion Balise sur la Plage, +- avancez le pion Bouclier d'1 Lieu vers le Dôme. + +| Ténacité +| 1 +| Récupérez 1 carte Lieu supplémentaire pour chaque Volonté dépensée dans l'action Résister. + +| Vaccin +| 1 +| Reculer le pion Assimilation d'1 case. + +| Volte-face +| 4 +| Reprenez en main votre carte Lieu jouée. + +| Vortex +| 2 +| Échangez votre carte Lieu jouée contre 1 carte Lieu de votre défausse. + +|=== + +== Mise en place + +.Nombre cartes lieu +[cols="60h,10,10,10"] +|=== +| Nombre de Traqués | 1 | 2-3 | 4-6 +| Nombre de Cartes Lieu 6 à 10 | 1 | 2 | 3 +|=== + +.Mise en place +[cols="30h,40"] +|=== +| Action | Description + +| Choix +a| +. Choisir un mode de difficulté : normal ou expert. +. Choisir si l'extension Exploration est utilisée. +. Choisir si la variante Labyrinthe est utilisée (l'extension Exploration est obligatoire dans ce cas). +. Choisir quel joueur incarne la Créature, les autres joueurs étant les Traqués. + +| Créer la planète Artemia +a| +. Placer 1 exemplaire des 10 cartes Lieu devant la créature en 2 rangées de chacune 5 cartes, par ordre croissant, +. Placer le pion Balise à côté de la carte Plage. + +| Extension Exploration +a| Choisir les 10 Lieux qui formeront la planète Artemia en s'assurant que chaque n° de 1 à 10 n’apparaisse qu’une seule fois. +Les Lieux suivants requièrent une mise en place spécifique : + +Le Dôme:: Le pion Balise devient le pion Bouclier : le Placer sur la carte Lieu 1 de la planète Artemia. + +Le Labyrinthe:: +. Mélanger les cinq cartes Lieu 6 à 10 qui forment la planète Artemia, +. Placer aléatoirement face cachée ces 5 cartes sous la rangée des cartes Lieu 1 à 5. + +Le Pôle:: La carte Pôle n’existe qu’en 2 exemplaires : la première carte sert à former la planète Artemia et la seconde est placée dans la réserve Lieux, indépendamment du nombre de Traqués. + +| Pioche Traque +| Mélanger et placer face cachée les cartes Traque à proximité de la Créature. + +| Pioche Survie +| Mélanger et placer face cachée les cartes Survie à proximité des Traqués. + +| La Créature: +a| +- place le plateau au centre de la table sur la face de son choix, +- place le pion Secours et le pion Assimilation sur le chiffre de leur piste respective correspondant au nombre de joueurs, +- pioche 3 cartes Traque et prend les 3 jetons Traque (Créature, Cible et Artemia). + +| Chaque Traqué: +a| +- prend 3 pions Volonté, les pions Volonté restants sont retirés du jeu, +- prend un set de 5 cartes Lieu numérotées de 1 à 5, les cartes inutilisées sont retirées du jeu, +- pioche 1 carte Survie. + +| Réserve +| Former la réserve Lieux avec les cartes Lieu numérotées de 6 à 10. + +Placer près du plateau le nombre d’exemplaires de chaque carte Lieu correspondant au nombre de Traqués (voir le tableau "Traqués"), face visible, les cartes inutilisées sont retirées du jeu. + +|=== + +== Conditions de victoire + +La Créature remporte immédiatement la partie si le pion Assimilation atteint la case Victoire. + +Les Traqués remportent immédiatement la partie si le pion Secours atteint la case Victoire. + +== Déroulement d'une partie + +.Règles générales +[cols="30h,70"] +|=== +| Fonctionnement +| La partie est une succession de tours de jeu. + +| Règle d'or +| Tout effet ou pouvoir qui contredit la règle prévaut sur elle. + +| Informations +| Les cartes Lieu défaussées par les Traqués sont visibles de tous. + +Le nombre de cartes en possession de chacun et leur type (leur dos) est connu de tous, mais il est interdit de montrer ses cartes aux autres joueurs. + +Les Traqués peuvent communiquer et bluffer, mais uniquement à voix haute. + +| Cartes en main +| Le nombre de cartes Survie qu’un Traqué peut détenir n’est pas limité. + +| Durée des effets +| Les effets des cartes Traque et des cartes Survie sont limités au tour de jeu en cours. + +Les effets d'une carte Survie ciblent uniquement leur propriétaire, sauf indication contraire. + +| Ordre de résolution des cartes +| Les effets des cartes Traque et des cartes Survie jouées lors d’une même phase sont résolus dans l’ordre dans lequel les cartes ont été jouées. + +En cas de conflit, la Créature décide de l’ordre de résolution. + +| Pions Volonté +| Un Traqué ne peut jamais avoir plus de 3 pions Volonté en sa possession. + +Tout effet qui ferait perdre plus que les pions Volonté restants à un Traqué se limite à lui faire perdre les pions Volonté restants. + +| Pioche Survie +| Si, au moment de piocher, la pile des cartes Survie est vide : +mélanger les cartes Survie défaussées pour former une nouvelle pioche. + +|=== + +.Tour de jeu +[cols="30h,70"] +|=== +| Fonctionnement +| Résoudre les Phases suivantes dans l'ordre. + +| Créature +| Par défaut, la Créature ne peut jouer qu’1 carte Traque par tour. + +| Traqués +| Chaque Traqué ne peut jouer qu’1 carte Survie par tour, et ce, même s’il est attrapé par la Créature. + +| Phase 1 : Exploration +| Les Traqués jouent simultanément et obligatoirement 1 carte Lieu de leur main en la posant face cachée devant eux. + +| Actions optionnelles +| Avant de jouer une carte Lieu, chaque Traqué peut Résister ou Lâcher prise. + +| Résister +a| Lorsqu'un Traqué Résiste, il choisit 1 des cas suivants : + +- perdre 1 pion Volonté pour choisir et reprendre en main 2 cartes Lieu de sa défausse, +- perdre 2 pions Volonté pour choisir et reprendre en main 4 cartes Lieu de sa défausse. + +Si par cette action un Traqué perd son dernier pion Volonté, il doit résoudre Lâcher prise. + +| Lâcher prise +a| +. Récupérer ses 3 pions Volonté et reprendre en main toutes ses cartes Lieu défaussées, +. Avancer le pion Assimilation d'1 case. + +| Phase 2 : Traque +a| La Créature pose sur les cartes Lieu d'Artemia de son choix : + +- le jeton Créature, +- le jeton Cible si le symbole se trouve sur une carte Traque jouée, +- le jeton Artemia si le symbole se trouve sur une carte Traque jouée ou sur une case située sous le pion Secours. + +| Précision +| Plusieurs jetons Traque peuvent être posés sur un même Lieu pour en cumuler leurs effets. + +| Phase 3 : Résolution +| Résoudre les étapes suivantes dans l'ordre : + +| 1) Choix des Traqués +| Les Traqués qui ont le choix parmi plusieurs cartes Lieu décident secrètement du Lieu qu’ils vont explorer. + +| 2) Révélation +| Les Traqués dévoilent simultanément leur carte Lieu. + +| 3) Lieux sans jeton Traque +a| Résoudre les Lieux sans jeton Traque, en sens horaire depuis le joueur à gauche de la Créature. Le Traqué peut au choix, si le Lieu n'est pas inutilisable : + +- utiliser le pouvoir du Lieu, +- reprendre en main 1 carte Lieu au choix de sa défausse. + +| 4) Lieu avec jeton Cible +a| Résoudre le Lieu avec le jeton Cible, en sens horaire depuis le joueur à gauche de la Créature : + +A) Chaque Traqué présent sur ce Lieu subit l’effet de la carte Traque, + +B) Chaque Traqué présent sur ce Lieu peut au choix, si le Lieu n'est pas inutilisable : + +- utiliser le pouvoir du Lieu, +- reprendre en main 1 carte Lieu au choix de sa défausse. + +| 5) Lieu avec jeton Artemia +a| Résoudre le Lieu avec le jeton Artemia, en sens horaire depuis le joueur à gauche de la Créature : + +A) Chaque Traqué présent sur ce Lieu choisit et défausse 1 carte Lieu de sa main, + +B) Le pouvoir du Lieu est inutilisable et le Traqué ne peut pas reprendre de carte Lieu de sa défausse. + +| 6) Lieu avec jeton Créature +a| Résoudre le Lieu avec le jeton Créature, en sens horaire depuis le joueur à gauche de la Créature : + +A) Le pouvoir du Lieu est inutilisable et le Traqué ne peut pas reprendre de carte Lieu de sa défausse, + +B) Avancer immédiatement le pion Assimilation d'1 case, + +C) Chaque Traqué présent sur ce Lieu est attrapé par la Créature et perd 1 pion Volonté, + +D) Si au moins 1 Traqué perd son dernier pion Volonté : avancer le pion Assimilation d'1 case. + +| 7) Récupération +a| Pour chaque Traqué ayant perdu ses 3 pions Volonté, en fonction du mode de difficulté. + +Mode normal:: Il reprend en main toutes les cartes Lieu de sa défausse ainsi que ses 3 pions Volonté. + +Mode expert:: Il reprend en main toutes les cartes Lieu de sa défausse ainsi que 2 pions Volonté (le pion restant peut être récupéré par tout autre moyen). + +| Phase 4 : Maintenance +a| +A) Chaque Traqué défausse sa carte Lieu jouée, face visible de façon à ce que le n° de chacune de ses cartes Lieu défaussées soit visible, + +B) La Créature reprend ses jetons Traque et pioche des cartes Traque jusqu’à en avoir 3 en main, + +C) Avancer le pion Secours d'1 case, un nouveau tour de jeu commence. +|=== + +== Extension Exploration + +.Liste des cartes lieu (exploration) +[cols="10,20,70"] +|=== +| N° | Nom | Effet + +| 1 +| Le Nexus +a| +. Copiez le pouvoir d'1 Lieu 2à 5. +. Avancez le pion Assimilation d'1 case supplémentaire si le jeton Créature attrape au moins 1 Traqué sur le Nexus. + +| 2 +| L'Oasis +| Reprenez en main cette carte Lieu plus 1 carte Lieu de votre défausse par Volonté qu'il vous manque, si possible. + +| 3 +| Le Fjord +a| Lors du prochain tour : + +. En Phase 1 : vous pouvez jouer une 2ème carte Lieu, face visible, de votre défausse, s'il n'y en a, +. En Phase 3 : résolvez 1 de ces Lieux, +. En Phase 4 : défaussez ces 2 cartes Lieu. + +| 4 +| Le Dôme +a| +. Déplacez le Bouclier d'1 Lieu vers le Dôme. +. Si le pion Boucler atteint le Dôme : reculer le pion Assimilation d'1 case et replacer le pion Bouclier sur le Lieu 1 (max 1x/tour). + +| 5 +| Le Labyrinthe +a| Au choix : + +- révéler un Lieu : retourner, face visible, une des 5 cartes Lieu 6 à 10 de la planète Artemia et activer son pouvoir ou prendre 1 carte Lieu correspondante, +- prendre de la réserve 1 carte Lieu déjà révélé. + +| 6 +| La Mangrove +a| +. Échanger les cartes Lieu de sa main contre celles de sa défausse, +. Reprendre cette carte Lieu en main. + +Précision:: Si la Mangrove est révélée grâce au Labyrinthe et que vous l’activez directement, +ni la Mangrove ni le Labyrinthe ne sont repris en main. + +| 7 +| L'Archipel +a| +. Piocher 1 carte Survie, +. S'il vous reste moins de 3 cartes Lieu en main, le Traqué de votre choix récupère 1 Volonté. + +| 8 +| Le Pôle +a| +. Sacrifiez 1 Volonté (même si c'est le dernier), puis avancez le pion Secours de 2 cases, +. En Phase 4, replacer le pôle dans la réserve, qu’elle ait pu être activée ou non, + +Le Pôle ne peut être copié (que ce soit par le pouvoir d'un Lieu ou une carte Survie). + +| 9 +| Les Fungi +a| Au choix : + +- piocher 1 carte Survie, +- placer jusqu’à 2 pions Volonté (si possible) sur des cases libres différentes de la piste Secours, ce pouvoir est inutilisable si la réserve de pions Volonté est vide ou s’il n’y a plus de case libre pour placer un pion Volonté. Quand le pion Secours atteint une de ces cases : les Traqués décident ensemble qui récupère le pion Volonté. Si un Traqué doit récupérer au moins 1 Volonté alors que la réserve est vide, il prend les pions Volonté disponibles de son choix sur la piste Secours. + +| 10 +| Le Portail +a| +. Défausser le Portail pour jouer une autre carte Lieu de sa main et la résoudre. +Le Portail téléporte le Traqué sur le second lieu joué, ce Traqué est donc susceptible de s’y faire attraper par un jeton Traque et/ou d’y être la cible d’une carte Traque, +. Le Portail est défaussé en phase 3 et la seconde carte Lieu en phase 4. +|=== + diff --git a/not-alone-player/.gitignore b/not-alone-player/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..baaba59f84e372e88b9b329c75e4acbf7d097457 --- /dev/null +++ b/not-alone-player/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +node/ +dist/ +src/codegen/ \ No newline at end of file diff --git a/not-alone-player/package-lock.json b/not-alone-player/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..864d98c5957b41161a5273dcf7a6e175d30c8825 --- /dev/null +++ b/not-alone-player/package-lock.json @@ -0,0 +1,3269 @@ +{ + "name": "not-alone-player", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "version": "0.0.0", + "dependencies": { + "@creditkarma/thrift-client": "^0.16.1", + "@creditkarma/thrift-server-core": "^0.16.1", + "@creditkarma/thrift-server-express": "^0.16.1" + }, + "devDependencies": { + "@creditkarma/thrift-parser": "^1.2.0", + "@creditkarma/thrift-typescript": "^3.7.6", + "@types/thrift": "^0.10.10", + "codelyzer": "^6.0.1", + "tslint": "^6.1.3" + } + }, + "node_modules/@angular/compiler": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.0.tgz", + "integrity": "sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ==", + "dev": true, + "peerDependencies": { + "tslib": "^1.10.0" + } + }, + "node_modules/@angular/core": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.0.tgz", + "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w==", + "dev": true, + "peerDependencies": { + "rxjs": "^6.5.3", + "tslib": "^1.10.0", + "zone.js": "~0.10.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "node_modules/@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@creditkarma/thrift-client": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@creditkarma/thrift-client/-/thrift-client-0.16.1.tgz", + "integrity": "sha512-oTlz6dNGj0nQjPyTB+eLwMDE2DAsbsfgz4xmPt7yf8tMd4lazFY7eVzEK0slh6zj9KYD/wuS21wz3Bmofp3pQw==", + "dependencies": { + "@types/generic-pool": "^3.1.4", + "@types/request": "^2.48.1", + "generic-pool": "^3.4.2", + "request": "^2.88.0" + }, + "peerDependencies": { + "@creditkarma/thrift-server-core": "0.16.x" + } + }, + "node_modules/@creditkarma/thrift-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@creditkarma/thrift-parser/-/thrift-parser-1.2.0.tgz", + "integrity": "sha512-mSRxjSXvU6sBfWhMBWXl7H/XEKWHQ7x+MUDLwyeFIwwX9UaZKPOc7TgGd0N78kcZtIMk82ArdxO6aFhqnBuNtg==", + "dev": true, + "bin": { + "thrift-parser": "dist/main/bin/index.js" + } + }, + "node_modules/@creditkarma/thrift-server-core": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@creditkarma/thrift-server-core/-/thrift-server-core-0.16.1.tgz", + "integrity": "sha512-rbzmS46vH6oth1I7zcSLcTslRlzolAiD9TSCNoxZHdnwfM65QJQIVCJ8Tz3l/78fzZAiZ71+9wZAuf61jl0Wzg==", + "dependencies": { + "@types/lodash": "^4.14.136", + "lodash": "^4.17.15" + } + }, + "node_modules/@creditkarma/thrift-server-express": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@creditkarma/thrift-server-express/-/thrift-server-express-0.16.1.tgz", + "integrity": "sha512-XPUPRnnJkGbLCZZMwLRSNGMZgxlC0n1LYIW2CXuH24aZIcTd9hQP09xc1khs5STMZii6q79wWx2hg6H/oZDDYA==", + "dependencies": { + "zipkin": "^0.15.0" + }, + "peerDependencies": { + "@creditkarma/thrift-server-core": "0.16.x", + "@types/express": ">=4.0.0 <5.0.0", + "express": ">=4.0.0 <5.0.0" + } + }, + "node_modules/@creditkarma/thrift-typescript": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/@creditkarma/thrift-typescript/-/thrift-typescript-3.7.6.tgz", + "integrity": "sha512-v/9Bi3YqExw8bOHA1F/087zru14qExO1e4rdV/+hjYOnUk0HX3zmi6giu/QR9c9QK+5bxekZd4pUxgX7HWwvwQ==", + "dev": true, + "dependencies": { + "@creditkarma/thrift-parser": "^1.2.0", + "@types/fs-extra": "^7.0.0", + "fs-extra": "^8.0.1", + "glob": "^7.1.2", + "typescript": "3.5.x" + }, + "bin": { + "thrift-typescript": "dist/main/bin/index.js" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "peer": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" + }, + "node_modules/@types/connect": { + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", + "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.9", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.9.tgz", + "integrity": "sha512-SDzEIZInC4sivGIFY4Sz1GG6J9UObPwCInYJjko2jzOf/Imx/dlpume6Xxwj1ORL82tBbmN4cPDIDkLbWHk9hw==", + "peer": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.14.tgz", + "integrity": "sha512-uFTLwu94TfUFMToXNgRZikwPuZdOtDgs3syBtAIr/OXorL1kJqUJT9qCLnRZ5KBOWfZQikQ2xKgR2tnDj1OgDA==", + "peer": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/fs-extra": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-7.0.0.tgz", + "integrity": "sha512-ndoMMbGyuToTy4qB6Lex/inR98nPiNHacsgMPvy+zqMLgSxbt8VtWpDArpGp69h1fEDQHn1KB+9DWD++wgbwYA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/generic-pool": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@types/generic-pool/-/generic-pool-3.1.9.tgz", + "integrity": "sha512-IkXMs8fhV6+E4J8EWv8iL7mLvApcLLQUH4m1Rex3KCPRqT+Xya0DDHIeGAokk/6VXe9zg8oTWyr+FGyeuimEYQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/lodash": { + "version": "4.14.165", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.165.tgz", + "integrity": "sha512-tjSSOTHhI5mCHTy/OOXYIhi2Wt1qcbHmuXD1Ha7q70CgI/I71afO4XtLb/cVexki1oVYchpul/TOuu3Arcdxrg==" + }, + "node_modules/@types/mime": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", + "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==", + "peer": true + }, + "node_modules/@types/node": { + "version": "14.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz", + "integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ==" + }, + "node_modules/@types/node-int64": { + "version": "0.4.29", + "resolved": "https://registry.npmjs.org/@types/node-int64/-/node-int64-0.4.29.tgz", + "integrity": "sha512-rHXvenLTj/CcsmNAebaBOhxQ2MqEGl3yXZZcZ21XYR+gzGTTcpOy2N4IxpvTCz48loyQNatHvfn6GhIbbZ1R3Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/q": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", + "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.5", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.5.tgz", + "integrity": "sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ==", + "peer": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", + "peer": true + }, + "node_modules/@types/request": { + "version": "2.48.5", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", + "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", + "dependencies": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "node_modules/@types/serve-static": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.8.tgz", + "integrity": "sha512-MoJhSQreaVoL+/hurAZzIm8wafFR6ajiTM1m4A0kv6AGeVBl4r4pOV8bGFrjjq1sGxDTnCoF8i22o0/aE5XCyA==", + "peer": true, + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/thrift": { + "version": "0.10.10", + "resolved": "https://registry.npmjs.org/@types/thrift/-/thrift-0.10.10.tgz", + "integrity": "sha512-sEhRbmmQgiTn+JdophEPiuTFkc9QRl7R/Kxs/le5GXZAc2K1/VCHauW734nCwpu1cFI8jL1niyrqk7E4tGL92w==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/node-int64": "*", + "@types/q": "*" + } + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==" + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "peer": true, + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/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, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/app-root-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", + "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==", + "dev": true, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/argparse/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", + "dev": true, + "dependencies": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "peer": true + }, + "node_modules/asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "node_modules/axobject-query": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", + "dev": true, + "dependencies": { + "ast-types-flow": "0.0.7" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "peer": true, + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/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, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "node_modules/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, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/codelyzer": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.1.tgz", + "integrity": "sha512-cOyGQgMdhnRYtW2xrJUNrNYDjEgwQ+BrE2y93Bwz3h4DJ6vJRLfupemU5N3pbYsUlBHJf0u1j1UGk+NLW4d97g==", + "dev": true, + "dependencies": { + "@angular/compiler": "9.0.0", + "@angular/core": "9.0.0", + "app-root-path": "^3.0.0", + "aria-query": "^3.0.0", + "axobject-query": "2.0.2", + "css-selector-tokenizer": "^0.7.1", + "cssauron": "^1.4.0", + "damerau-levenshtein": "^1.0.4", + "rxjs": "^6.5.3", + "semver-dsl": "^1.0.1", + "source-map": "^0.5.7", + "sprintf-js": "^1.1.2", + "tslib": "^1.10.0", + "zone.js": "~0.10.3" + }, + "peerDependencies": { + "@angular/compiler": ">=2.3.1 <12.0.0 || ^11.0.0-next || ^11.1.0-next || ^11.2.0-next", + "@angular/core": ">=2.3.1 <12.0.0 || ^11.0.0-next || ^11.1.0-next || ^11.2.0-next", + "tslint": "^5.0.0 || ^6.0.0" + } + }, + "node_modules/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, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/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 + }, + "node_modules/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 + }, + "node_modules/content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "peer": true, + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "peer": true + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/css-selector-tokenizer": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", + "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, + "node_modules/cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", + "dev": true, + "dependencies": { + "through": "X.X.X" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz", + "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==", + "dev": true + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "peer": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "peer": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "peer": true + }, + "node_modules/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, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "peer": true, + "dependencies": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "peer": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/generic-pool": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.7.1.tgz", + "integrity": "sha512-ug6DAZoNgWm6q5KhPFA+hzXfBLFQu5sTXxPpv44DmE0A2g+CiHoq9LTVdkXpZMkYVMoGw83F6W+WT0h0MFMK/w==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "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" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "peer": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "peer": true + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "peer": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "peer": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "node_modules/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 + }, + "node_modules/js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "node_modules/json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.6" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "node_modules/lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "peer": true + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "peer": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dependencies": { + "mime-db": "1.44.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "peer": true + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "peer": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "peer": true + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "node_modules/proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "peer": true, + "dependencies": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "peer": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "peer": true, + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rxjs": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver-dsl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", + "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=", + "dev": true, + "dependencies": { + "semver": "^5.3.0" + } + }, + "node_modules/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "peer": true, + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "peer": true + }, + "node_modules/serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "peer": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "peer": true + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/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, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "peer": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + }, + "bin": { + "tslint": "bin/tslint" + }, + "engines": { + "node": ">=4.8.0" + }, + "peerDependencies": { + "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" + } + }, + "node_modules/tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "peerDependencies": { + "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "peer": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", + "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "peer": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/zipkin": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/zipkin/-/zipkin-0.15.0.tgz", + "integrity": "sha512-kKzRYWErW93bLh0kzyGPa7rQN49IN+TdeWWDNrF5r/B1VyPbj0Hqmwp2h0bsRiaukd+DBjprj22GbatOCjDVWA==", + "dependencies": { + "base64-js": "^1.1.2", + "is-promise": "^2.1.0" + } + }, + "node_modules/zone.js": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz", + "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==", + "dev": true + } + }, + "dependencies": { + "@angular/compiler": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.0.tgz", + "integrity": "sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ==", + "dev": true, + "requires": {} + }, + "@angular/core": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.0.tgz", + "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w==", + "dev": true, + "requires": {} + }, + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@creditkarma/thrift-client": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@creditkarma/thrift-client/-/thrift-client-0.16.1.tgz", + "integrity": "sha512-oTlz6dNGj0nQjPyTB+eLwMDE2DAsbsfgz4xmPt7yf8tMd4lazFY7eVzEK0slh6zj9KYD/wuS21wz3Bmofp3pQw==", + "requires": { + "@types/generic-pool": "^3.1.4", + "@types/request": "^2.48.1", + "generic-pool": "^3.4.2", + "request": "^2.88.0" + } + }, + "@creditkarma/thrift-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@creditkarma/thrift-parser/-/thrift-parser-1.2.0.tgz", + "integrity": "sha512-mSRxjSXvU6sBfWhMBWXl7H/XEKWHQ7x+MUDLwyeFIwwX9UaZKPOc7TgGd0N78kcZtIMk82ArdxO6aFhqnBuNtg==", + "dev": true + }, + "@creditkarma/thrift-server-core": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@creditkarma/thrift-server-core/-/thrift-server-core-0.16.1.tgz", + "integrity": "sha512-rbzmS46vH6oth1I7zcSLcTslRlzolAiD9TSCNoxZHdnwfM65QJQIVCJ8Tz3l/78fzZAiZ71+9wZAuf61jl0Wzg==", + "requires": { + "@types/lodash": "^4.14.136", + "lodash": "^4.17.15" + } + }, + "@creditkarma/thrift-server-express": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@creditkarma/thrift-server-express/-/thrift-server-express-0.16.1.tgz", + "integrity": "sha512-XPUPRnnJkGbLCZZMwLRSNGMZgxlC0n1LYIW2CXuH24aZIcTd9hQP09xc1khs5STMZii6q79wWx2hg6H/oZDDYA==", + "requires": { + "zipkin": "^0.15.0" + } + }, + "@creditkarma/thrift-typescript": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/@creditkarma/thrift-typescript/-/thrift-typescript-3.7.6.tgz", + "integrity": "sha512-v/9Bi3YqExw8bOHA1F/087zru14qExO1e4rdV/+hjYOnUk0HX3zmi6giu/QR9c9QK+5bxekZd4pUxgX7HWwvwQ==", + "dev": true, + "requires": { + "@creditkarma/thrift-parser": "^1.2.0", + "@types/fs-extra": "^7.0.0", + "fs-extra": "^8.0.1", + "glob": "^7.1.2", + "typescript": "3.5.x" + } + }, + "@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "peer": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" + }, + "@types/connect": { + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", + "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", + "peer": true, + "requires": { + "@types/node": "*" + } + }, + "@types/express": { + "version": "4.17.9", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.9.tgz", + "integrity": "sha512-SDzEIZInC4sivGIFY4Sz1GG6J9UObPwCInYJjko2jzOf/Imx/dlpume6Xxwj1ORL82tBbmN4cPDIDkLbWHk9hw==", + "peer": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.14.tgz", + "integrity": "sha512-uFTLwu94TfUFMToXNgRZikwPuZdOtDgs3syBtAIr/OXorL1kJqUJT9qCLnRZ5KBOWfZQikQ2xKgR2tnDj1OgDA==", + "peer": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/fs-extra": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-7.0.0.tgz", + "integrity": "sha512-ndoMMbGyuToTy4qB6Lex/inR98nPiNHacsgMPvy+zqMLgSxbt8VtWpDArpGp69h1fEDQHn1KB+9DWD++wgbwYA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/generic-pool": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@types/generic-pool/-/generic-pool-3.1.9.tgz", + "integrity": "sha512-IkXMs8fhV6+E4J8EWv8iL7mLvApcLLQUH4m1Rex3KCPRqT+Xya0DDHIeGAokk/6VXe9zg8oTWyr+FGyeuimEYQ==", + "requires": { + "@types/node": "*" + } + }, + "@types/lodash": { + "version": "4.14.165", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.165.tgz", + "integrity": "sha512-tjSSOTHhI5mCHTy/OOXYIhi2Wt1qcbHmuXD1Ha7q70CgI/I71afO4XtLb/cVexki1oVYchpul/TOuu3Arcdxrg==" + }, + "@types/mime": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", + "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==", + "peer": true + }, + "@types/node": { + "version": "14.14.10", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz", + "integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ==" + }, + "@types/node-int64": { + "version": "0.4.29", + "resolved": "https://registry.npmjs.org/@types/node-int64/-/node-int64-0.4.29.tgz", + "integrity": "sha512-rHXvenLTj/CcsmNAebaBOhxQ2MqEGl3yXZZcZ21XYR+gzGTTcpOy2N4IxpvTCz48loyQNatHvfn6GhIbbZ1R3Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/q": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz", + "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==", + "dev": true + }, + "@types/qs": { + "version": "6.9.5", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.5.tgz", + "integrity": "sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ==", + "peer": true + }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", + "peer": true + }, + "@types/request": { + "version": "2.48.5", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", + "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", + "requires": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "@types/serve-static": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.8.tgz", + "integrity": "sha512-MoJhSQreaVoL+/hurAZzIm8wafFR6ajiTM1m4A0kv6AGeVBl4r4pOV8bGFrjjq1sGxDTnCoF8i22o0/aE5XCyA==", + "peer": true, + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/thrift": { + "version": "0.10.10", + "resolved": "https://registry.npmjs.org/@types/thrift/-/thrift-0.10.10.tgz", + "integrity": "sha512-sEhRbmmQgiTn+JdophEPiuTFkc9QRl7R/Kxs/le5GXZAc2K1/VCHauW734nCwpu1cFI8jL1niyrqk7E4tGL92w==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/node-int64": "*", + "@types/q": "*" + } + }, + "@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==" + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "peer": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "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" + } + }, + "app-root-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", + "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + }, + "dependencies": { + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + } + } + }, + "aria-query": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz", + "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7", + "commander": "^2.11.0" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "peer": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "axobject-query": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", + "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==", + "dev": true, + "requires": { + "ast-types-flow": "0.0.7" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "peer": true, + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "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" + } + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "peer": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "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" + } + }, + "codelyzer": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.1.tgz", + "integrity": "sha512-cOyGQgMdhnRYtW2xrJUNrNYDjEgwQ+BrE2y93Bwz3h4DJ6vJRLfupemU5N3pbYsUlBHJf0u1j1UGk+NLW4d97g==", + "dev": true, + "requires": { + "@angular/compiler": "9.0.0", + "@angular/core": "9.0.0", + "app-root-path": "^3.0.0", + "aria-query": "^3.0.0", + "axobject-query": "2.0.2", + "css-selector-tokenizer": "^0.7.1", + "cssauron": "^1.4.0", + "damerau-levenshtein": "^1.0.4", + "rxjs": "^6.5.3", + "semver-dsl": "^1.0.1", + "source-map": "^0.5.7", + "sprintf-js": "^1.1.2", + "tslib": "^1.10.0", + "zone.js": "~0.10.3" + } + }, + "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 + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "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 + }, + "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 + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "peer": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "peer": true + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "peer": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "peer": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "css-selector-tokenizer": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz", + "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, + "cssauron": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz", + "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=", + "dev": true, + "requires": { + "through": "X.X.X" + } + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "damerau-levenshtein": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz", + "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "peer": true, + "requires": { + "ms": "2.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "peer": true + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "peer": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "peer": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "peer": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "peer": 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 + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "peer": true + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "peer": true, + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==", + "dev": true + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "peer": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "peer": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "peer": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": 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 + }, + "generic-pool": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.7.1.tgz", + "integrity": "sha512-ug6DAZoNgWm6q5KhPFA+hzXfBLFQu5sTXxPpv44DmE0A2g+CiHoq9LTVdkXpZMkYVMoGw83F6W+WT0h0MFMK/w==" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "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" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "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 + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "peer": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "peer": true + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "peer": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "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 + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "peer": true + }, + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "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 + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "peer": true + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "peer": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "peer": true + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "peer": true + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "requires": { + "mime-db": "1.44.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "peer": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "peer": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "peer": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "peer": 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.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "peer": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "peer": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "peer": true + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "peer": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "peer": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + } + } + }, + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "rxjs": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "semver-dsl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz", + "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "peer": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "peer": true + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "peer": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "peer": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "peer": 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" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "peer": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "peer": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typescript": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", + "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", + "dev": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "peer": true + }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "requires": { + "punycode": "^2.1.0" + } + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "peer": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "peer": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "zipkin": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/zipkin/-/zipkin-0.15.0.tgz", + "integrity": "sha512-kKzRYWErW93bLh0kzyGPa7rQN49IN+TdeWWDNrF5r/B1VyPbj0Hqmwp2h0bsRiaukd+DBjprj22GbatOCjDVWA==", + "requires": { + "base64-js": "^1.1.2", + "is-promise": "^2.1.0" + } + }, + "zone.js": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz", + "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg==", + "dev": true + } + } +} diff --git a/not-alone-player/package.json b/not-alone-player/package.json new file mode 100644 index 0000000000000000000000000000000000000000..7e48baa52be3640716125b97237db3b07092b8ff --- /dev/null +++ b/not-alone-player/package.json @@ -0,0 +1,32 @@ +{ + "name": "not-alone-player", + "version": "0.0.0", + "main": "dist/main.js", + "scripts": { + "prebuild": "tslint -c tslint.json -p tsconfig.json --fix", + "build": "tsc", + "prestart": "npm run build", + "start": "node ./dist/main.js", + "test": "echo \"Error: no test specified\" && exit 1", + "codegen": "\"./node_modules/.bin/thrift-typescript\" --target thrift-server --sourceDir \"../not-alone-core/src/main/thrift/\" --outDir \"./src/codegen/\"" + }, + "private": true, + "devDependencies": { + "@creditkarma/thrift-parser": "^1.2.0", + "@creditkarma/thrift-typescript": "^3.7.6", + "@types/thrift": "^0.10.10", + "codelyzer": "^6.0.1", + "tslint": "^6.1.3" + }, + "dependencies": { + "@creditkarma/thrift-client": "^0.16.1", + "@creditkarma/thrift-server-core": "^0.16.1", + "@creditkarma/thrift-server-express": "^0.16.1", + "@types/express": "^4.17.9", + "express": "^4.17.1" + }, + "browser": { + "crypto": false, + "stream": false + } +} diff --git a/not-alone-player/pom.xml b/not-alone-player/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..4ca80c0fb5a5e01dc0f466f0bcbf2c0079447db9 --- /dev/null +++ b/not-alone-player/pom.xml @@ -0,0 +1,74 @@ + + + + not-alone + fr.univnantes.alma + 1.0-SNAPSHOT + + 4.0.0 + + not-alone-player + Not Alone Player Services + + + + + com.github.eirslett + frontend-maven-plugin + 1.10.0 + + ./ + v14.11.0 + 7.0.10 + + + + install node and npm + + install-node-and-npm + + generate-resources + + + npm install + + npm + + + install + + generate-resources + + + npm run build + + npm + + + run build + + + + code generation + compile + + npm + + + run codegen + + + + + + + + ./dist/not-alone-web + static + + + + + diff --git a/not-alone-player/src/core/game.ts b/not-alone-player/src/core/game.ts new file mode 100644 index 0000000000000000000000000000000000000000..b5e59123a18f4720f339d631a0167db5e6e6a239 --- /dev/null +++ b/not-alone-player/src/core/game.ts @@ -0,0 +1,26 @@ +import { TPlayer, TRoomId, TBoard, TColor, TCard, TPlacedJeton, TPhase, TDescription } from 'src/codegen/common'; + +export interface GameInterface { + +/* + createGame(numberOfPlayers: number): Promise; + join(gameId: number): Promise; +*/ + createRoom(player: TPlayer): Promise; + + sendStartGame(player: TPlayer, creatureId: number, board: TBoard, color: TColor, placeCards: TCard[]): Promise; + + joinRoom(player: TPlayer, roomId: TRoomId): Promise; + + getGameDescription(player: TPlayer): Promise; + + sendFinishPhase(player: TPlayer, phase: TPhase): Promise; + + sendPlayCards(player: TPlayer, playerCards: TCard[]): Promise; + + sendPlaceJetons(player: TPlayer, placedJetons: TPlacedJeton[]): Promise; + + sendResist(player: TPlayer, number: number): Promise; + + sendGiveUp(player: TPlayer): Promise; +} diff --git a/not-alone-player/src/game/items/player-team.ts b/not-alone-player/src/game/items/player-team.ts new file mode 100644 index 0000000000000000000000000000000000000000..00a40e482656afa36fa21cf441e46116e0095d2e --- /dev/null +++ b/not-alone-player/src/game/items/player-team.ts @@ -0,0 +1,4 @@ +export enum PlayerTeam { + CREATURE, + TRAQUES +} diff --git a/not-alone-player/src/game/utilitary/conversion.ts b/not-alone-player/src/game/utilitary/conversion.ts new file mode 100644 index 0000000000000000000000000000000000000000..031b1611294de510ecbcf4706e85dd6e968854bc --- /dev/null +++ b/not-alone-player/src/game/utilitary/conversion.ts @@ -0,0 +1,16 @@ +import { TPlayerTeam } from 'src/codegen/common'; +import { PlayerTeam } from '../items/player-team'; + +export class Conversion { + + public static toPlayerTeam(tTeam: TPlayerTeam): PlayerTeam { + if (tTeam.type === 'CREATURE') { + return PlayerTeam.CREATURE; + } else if (tTeam.type === 'TRAQUES') { + return PlayerTeam.TRAQUES; + } else { + throw new Error(tTeam.type + ' is not a valid PlayerTeam'); + } + } + +} diff --git a/not-alone-player/src/handler/client-service-handler.ts b/not-alone-player/src/handler/client-service-handler.ts new file mode 100644 index 0000000000000000000000000000000000000000..979955456871da428d8c7018e3c8e1040ee2acfc --- /dev/null +++ b/not-alone-player/src/handler/client-service-handler.ts @@ -0,0 +1,106 @@ +import { TDescription, TPlayerTeam, TPhase, TAction, TAskAction, Response } from 'src/codegen/common'; +import { PlayerTeam } from 'src/game/items/player-team'; +import { Conversion } from 'src/game/utilitary/conversion'; +// import { IHandler } from '../codegen/common/GameService'; +import { IHandler } from '../codegen/common/PlayerService'; +import { PlayerService } from '../player/player-service'; + +export class ClientServiceHandler implements IHandler { + + private service: PlayerService; + + constructor() { + this.service = new PlayerService(); + } + + /* + public createGame(numberOfPlayers: number, context?: Context): number | Promise { + throw new Error('Method not implemented.'); + } + + public join(gameId: number, request: IJoinRequest, context?: Context): number | Promise { + throw new Error('Method not implemented.'); + } + + public startGame(gameId: number): void | Promise { + return this.service.startGame(gameId); + } + */ + + public ping(): boolean | Promise { + // return this.service.ping(); + throw new Error('Method not implemented.'); + } + + public sendGameDescription(gameDescription: TDescription): void | Promise { + throw new Error('Method not implemented.'); + } + + public sendGameStart(): void | Promise { + throw new Error('Method not implemented.'); + } + + public sendGameIsFinished(winner: TPlayerTeam): void | Promise { + const team: PlayerTeam = Conversion.toPlayerTeam(winner); + throw new Error('Method not implemented.'); + } + + public sendFirstRoundStart(): void | Promise { + throw new Error('Method not implemented.'); + } + + public sendStartPhase(phase: TPhase, gameDescription: TDescription): void | Promise { + throw new Error('Method not implemented.'); + } + + public askAction(askedAction: TAskAction): TAction | Promise { + throw new Error('Method not implemented.'); + } + + public sendAction(askedAction: TAskAction): void | Promise { + throw new Error('Method not implemented.'); + } + + public sendResponse(response: Response): void | Promise { + throw new Error('Method not implemented.'); + } + + /* + public ping(): boolean | Promise { + return service.ping(); + } + + public sendGameDescription(gameDescription: TDescription): void | Promise { + throw new Error('Method not implemented.'); + } + + public void sendGameStart() : void | Promise { + throw new Error('Method not implemented.'); + } + + public void sendGameIsFinished(winner : TPlayerTeam) : void | Promise { + throw new Error('Method not implemented.'); + } + + public void sendFirstRoundStart() : void | Promise { + throw new Error('Method not implemented.'); + } + + public void sendStartPhase(phase : TPhase, gameDescription : TDescription) : void | Promise { + throw new Error('Method not implemented.'); + } + + public askAction(askedAction : TAskAction) : TAction | Promise { + return null; + } + + public sendAction(askedAction : TAskAction) : void | Promise { + throw new Error('Method not implemented.'); + } + + public sendResponse(response : Response) : void | Promise { + throw new Error('Method not implemented.'); + } + */ + +} diff --git a/not-alone-player/src/main.ts b/not-alone-player/src/main.ts new file mode 100644 index 0000000000000000000000000000000000000000..259572eedd53c905c125aa965ab01be9a4ce7f3a --- /dev/null +++ b/not-alone-player/src/main.ts @@ -0,0 +1,17 @@ + +import { ThriftServer } from './thrift/thrift-server'; + +/** + * Port used for local Thrift server. + */ +const LOCAL_PORT = 8090; + +class Main { + private server: ThriftServer; + constructor() { + console.log('Main class'); + this.server = new ThriftServer(LOCAL_PORT); + } +} + +const main: Main = new Main(); diff --git a/not-alone-player/src/player/player-service.ts b/not-alone-player/src/player/player-service.ts new file mode 100644 index 0000000000000000000000000000000000000000..ee1428c4c5c386ce5b813a1ee2928d03c1c3e9ff --- /dev/null +++ b/not-alone-player/src/player/player-service.ts @@ -0,0 +1,6 @@ +export class PlayerService { + + startGame(gameId: number): void { + console.log('Start game', gameId); + } +} diff --git a/not-alone-player/src/thrift/game-proxy.ts b/not-alone-player/src/thrift/game-proxy.ts new file mode 100644 index 0000000000000000000000000000000000000000..30b82bcb6d05482b1130703682db6a1e4aa36aaf --- /dev/null +++ b/not-alone-player/src/thrift/game-proxy.ts @@ -0,0 +1,53 @@ +import { Client } from 'src/codegen/common/GameService'; +import { GameInterface } from '../core/game'; +import { CoreOptions } from 'request'; +import { createHttpClient, ICreateHttpClientOptions } from '@creditkarma/thrift-client'; +import { IJoinRequest, JoinRequest } from '../codegen/common/JoinRequest'; +import { TPlayer, TRoomId, TBoard, TColor, TCard, TDescription, TPhase, TPlacedJeton } from 'src/codegen/common'; + +export class GameProxy implements GameInterface { + private thriftClient: Client; + + constructor(options: ICreateHttpClientOptions) { + this.thriftClient = createHttpClient(Client, options); + } + createRoom(player: TPlayer): Promise { + throw new Error('Method not implemented.'); + } + sendStartGame(player: TPlayer, creatureId: number, board: TBoard, color: TColor, placeCards: TCard[]): Promise { + throw new Error('Method not implemented.'); + } + joinRoom(player: TPlayer, roomId: TRoomId): Promise { + throw new Error('Method not implemented.'); + } + getGameDescription(player: TPlayer): Promise { + throw new Error('Method not implemented.'); + } + sendFinishPhase(player: TPlayer, phase: TPhase): Promise { + throw new Error('Method not implemented.'); + } + sendPlayCards(player: TPlayer, playerCards: TCard[]): Promise { + throw new Error('Method not implemented.'); + } + sendPlaceJetons(player: TPlayer, placedJetons: TPlacedJeton[]): Promise { + throw new Error('Method not implemented.'); + } + sendResist(player: TPlayer, number: number): Promise { + throw new Error('Method not implemented.'); + } + sendGiveUp(player: TPlayer): Promise { + throw new Error('Method not implemented.'); + } + + /* + createGame(numberOfPlayers: number): Promise { + return this.thriftClient.createGame(numberOfPlayers); + } + + join(gameId: number): Promise { + const request: IJoinRequest = new JoinRequest(); + request.name = 'me'; + return this.thriftClient.join(gameId, request); + } + */ +} diff --git a/not-alone-player/src/thrift/thrift-client.ts b/not-alone-player/src/thrift/thrift-client.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4133ebfdcee3305e9b6c92a19c414efc85171e9 --- /dev/null +++ b/not-alone-player/src/thrift/thrift-client.ts @@ -0,0 +1,16 @@ +import { createHttpClient, HttpConnection } from '@creditkarma/thrift-client'; +import * as request from 'request'; +import { CoreOptions } from 'request'; + +import { Client } from '../codegen/common/GameService'; + +const CONFIG = { + hostName: 'localhost', + port: 8045, +}; + +const thriftClient: Client = createHttpClient(Client, CONFIG); + +// const id: Promise = thriftClient.createGame(8); + +export class ThriftClient {} diff --git a/not-alone-player/src/thrift/thrift-server.ts b/not-alone-player/src/thrift/thrift-server.ts new file mode 100644 index 0000000000000000000000000000000000000000..2817a3b51237940bcdb4b47c35859a95bf3e6d12 --- /dev/null +++ b/not-alone-player/src/thrift/thrift-server.ts @@ -0,0 +1,26 @@ + +// import { GameService } from '../codegen/common/'; +import { PlayerService } from '../codegen/common/'; +import { ClientServiceHandler } from '../handler/client-service-handler'; +import * as express from 'express'; +import { createThriftServer } from '@creditkarma/thrift-server-express'; + +const handler: ClientServiceHandler = new ClientServiceHandler(); + + +export class ThriftServer { + private app: express.Application; + constructor(port: number) { + this.app = createThriftServer({ + path: '/thrift', + thriftOptions: { + serviceName: 'calculator-service', + handler: new PlayerService.Processor(handler), + }, + }); + this.app.listen(port, () => { + console.log(`Thrift Express server listening on port: ${port}`); + }); + } +} + diff --git a/not-alone-player/tsconfig.json b/not-alone-player/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..8d1c6e7fea75c09ff00532b3c80ee0446bcc3fe2 --- /dev/null +++ b/not-alone-player/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/", + "sourceMap": true, + "declaration": false, + "module": "CommonJs", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "strict": true, + "target": "ES2017", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2017", + "dom" + ], + "paths": { + "core-js/es7/reflect": [ + "node_modules/core-js/proposals/reflect-metadata" + ] + } + }, + "include": ["target/generated-sources/thrift//**/*", "src/**/*"] +} diff --git a/not-alone-player/tslint.json b/not-alone-player/tslint.json new file mode 100644 index 0000000000000000000000000000000000000000..6ddb6b2931511b11e5d5938f76076fb37e70363e --- /dev/null +++ b/not-alone-player/tslint.json @@ -0,0 +1,131 @@ +{ + "rulesDirectory": [ + "node_modules/codelyzer" + ], + "rules": { + "arrow-return-shorthand": true, + "callable-types": true, + "class-name": true, + "comment-format": [ + true, + "check-space" + ], + "curly": true, + "deprecation": { + "severity": "warn" + }, + "eofline": true, + "forin": true, + "import-blacklist": [ + true, + "rxjs/Rx" + ], + "import-spacing": true, + "indent": [ + true, + "spaces" + ], + "interface-over-type-literal": true, + "label-position": true, + "max-line-length": [ + true, + 140 + ], + "member-access": false, + "member-ordering": [ + true, + { + "order": [ + "static-field", + "instance-field", + "static-method", + "instance-method" + ] + } + ], + "no-arg": true, + "no-bitwise": true, + "no-console": [ + true, + "debug", + "info", + "time", + "timeEnd", + "trace" + ], + "no-construct": true, + "no-debugger": true, + "no-duplicate-super": true, + "no-empty": false, + "no-empty-interface": true, + "no-eval": true, + "no-inferrable-types": [ + true, + "ignore-params" + ], + "no-misused-new": true, + "no-non-null-assertion": true, + "no-redundant-jsdoc": true, + "no-shadowed-variable": true, + "no-string-literal": false, + "no-string-throw": true, + "no-switch-case-fall-through": true, + "no-trailing-whitespace": true, + "no-unnecessary-initializer": true, + "no-unused-expression": true, + "no-use-before-declare": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "one-line": [ + true, + "check-open-brace", + "check-catch", + "check-else", + "check-whitespace" + ], + "prefer-const": true, + "quotemark": [ + true, + "single" + ], + "radix": true, + "semicolon": [ + true, + "always" + ], + "triple-equals": [ + true, + "allow-null-check" + ], + "typedef-whitespace": [ + true, + { + "call-signature": "nospace", + "index-signature": "nospace", + "parameter": "nospace", + "property-declaration": "nospace", + "variable-declaration": "nospace" + } + ], + "unified-signatures": true, + "variable-name": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ], + "no-output-on-prefix": true, + "use-input-property-decorator": true, + "use-output-property-decorator": true, + "use-host-property-decorator": true, + "no-input-rename": true, + "no-output-rename": true, + "use-life-cycle-interface": true, + "use-pipe-transform-interface": true, + "component-class-suffix": true, + "directive-class-suffix": true + } +} diff --git a/not-alone-server/.gitignore b/not-alone-server/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ae3c1726048cd06b9a143e0376ed46dd9b9a8d53 --- /dev/null +++ b/not-alone-server/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/not-alone-server/not-alone-server.iml b/not-alone-server/not-alone-server.iml deleted file mode 100644 index 4a4ce55406053014eaaca4546111548f263f24ed..0000000000000000000000000000000000000000 --- a/not-alone-server/not-alone-server.iml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/not-alone-server/pom.xml b/not-alone-server/pom.xml index 9ced649047d86a2433b631585f3eaeddb74dad02..e32fc10252fba49a5a1c674c6ddd67eec1bbdf7c 100644 --- a/not-alone-server/pom.xml +++ b/not-alone-server/pom.xml @@ -1,13 +1,13 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 org.springframework.boot spring-boot-starter-parent - 2.3.4.RELEASE - + 2.4.0 + fr.univnantes.alma @@ -17,25 +17,48 @@ Spring Boot Not Alone server - 11 + 0.8.5 + + org.mockito + mockito-core + 3.3.3 + test + + + fr.univnantes.alma + not-alone-core + ${project.version} + + org.springframework.boot spring-boot-starter - + + org.springframework.boot + spring-boot-starter-web + + + org.atlanmod.commons + commons-core + 1.0.6 + + + org.springframework.boot + spring-boot-starter-data-jpa + org.springframework.boot spring-boot-starter-test test - - - org.junit.vintage - junit-vintage-engine - - + + + com.h2database + h2 + runtime @@ -45,6 +68,33 @@ org.springframework.boot spring-boot-maven-plugin + + org.apache.maven.plugins + maven-site-plugin + 3.9.1 + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + + prepare-agent-exe + + prepare-agent + + + + + report-exe + pre-site + + report + + + + diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/NotAloneApplication.java b/not-alone-server/src/main/java/fr/univnantes/alma/NotAloneApplication.java deleted file mode 100644 index 6f684090d7250c285a5314f1d59f5c0d88ff14b8..0000000000000000000000000000000000000000 --- a/not-alone-server/src/main/java/fr/univnantes/alma/NotAloneApplication.java +++ /dev/null @@ -1,12 +0,0 @@ -package fr.univnantes.alma; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class NotAloneApplication { - - public static void main(String[] args) { - SpringApplication.run(NotAloneApplication.class, args); - } -} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/common/NotAloneDatabase.java b/not-alone-server/src/main/java/fr/univnantes/alma/common/NotAloneDatabase.java new file mode 100644 index 0000000000000000000000000000000000000000..7a036d55728dde2fb4e74180f676351c64fd94aa --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/common/NotAloneDatabase.java @@ -0,0 +1,32 @@ +package fr.univnantes.alma.common; + +import fr.univnantes.alma.server.game.item.card.CardName; +import fr.univnantes.alma.server.game.item.card.PlaceCard; +import fr.univnantes.alma.server.game.item.card.SurvivalCard; +import fr.univnantes.alma.server.game.item.card.TrackingCard; + +import java.util.List; + +public interface NotAloneDatabase { + + public PlaceCard findPlaceCard(String idCard); + + public List findPlaceCards(List idCards); + + public SurvivalCard findSurvivalCard(String idCard); + + public List findSurvivalCards(List idCards); + + public List findAllSurvivalCard(); + + public TrackingCard findTrackingCard(String idCard); + + public List findTrackingCards(List idCards); + + public List findAllTrackingCard(); + + public List findPowersDescription(String cardNameString); + + public List findPowersDescription(CardName cardName); + +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/common/RoomService.java b/not-alone-server/src/main/java/fr/univnantes/alma/common/RoomService.java new file mode 100644 index 0000000000000000000000000000000000000000..ee23c97298e780b161179edf4bc1a4b1b4b73efe --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/common/RoomService.java @@ -0,0 +1,83 @@ +package fr.univnantes.alma.common; + +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.board.Board; +import fr.univnantes.alma.server.game.item.card.Card; +import fr.univnantes.alma.server.game.item.jeton.PlacedJeton; +import fr.univnantes.alma.server.game.item.planet.Planet; +import fr.univnantes.alma.server.user.User; +import fr.univnantes.alma.thrift.GameNotFound; +import fr.univnantes.alma.thrift.InvalidOperationException; +import fr.univnantes.alma.thrift.Response; +import fr.univnantes.alma.thrift.TDescription; +import org.checkerframework.checker.units.qual.C; + +import java.util.List; + +public interface RoomService { + + /** + * Create a room if the player is not already in a room + * @param user The player + * @return The game id + */ + String createRoom(User user) throws InvalidOperationException; + + /** + * Join the room if it's not full and if the player is not in a room + * @param user The player + * @param roomId The room id + * @return A response + */ + Response joinRoom(User user, String roomId) throws GameNotFound; + + /** + * Start the game where the player is the game creator + * @param user The player + * @param creatureId The in game id of the creature + * @param board The board choose to play + * @param planet The planet used to play + * @return A response + */ + Response startGame(User user, int creatureId, Board board, Planet planet); + + /** + * @param user A user + * @return The description of the user's game + */ + TDescription getGameDescription(User user) throws InvalidOperationException; + + /** + * Send to the room that the user has finished a phase + * @param user The user + * @param phase The phase + */ + void sendFinishPhase(User user, Phase phase) throws InvalidOperationException; + + /** + * Send to the room that the user play cards + * @param user The user + * @param cards The cards + */ + void sendPlayCards(User user, List cards) throws InvalidOperationException; + + /** + * Send to the room that the user place jetons + * @param user The user + * @param placedJetons The placed jetons + */ + void sendPlaceJetons(User user, List placedJetons) throws InvalidOperationException; + + /** + * Send to the room that the user resist of number pawn Willingness + * @param user The user + * @param number The number of pawn Willingness lost + */ + void sendResist(User user, int number) throws InvalidOperationException; + + /** + * Send to the room that the user give up + * @param user The user + */ + void sendGiveUp(User user) throws InvalidOperationException; +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/data/DatabaseFactory.java b/not-alone-server/src/main/java/fr/univnantes/alma/data/DatabaseFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..39556245e362ff7e8d3b351c8c2f1a1445fde5ea --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/data/DatabaseFactory.java @@ -0,0 +1,12 @@ +package fr.univnantes.alma.data; + +import fr.univnantes.alma.common.NotAloneDatabase; + +public class DatabaseFactory { + + private DatabaseFactory(){} + + public static NotAloneDatabase getDatabase(){ + return new DatabaseStub(); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/data/DatabaseStub.java b/not-alone-server/src/main/java/fr/univnantes/alma/data/DatabaseStub.java new file mode 100644 index 0000000000000000000000000000000000000000..2653e47aa7a8bd7d9adc8cbae673406b2d1b4254 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/data/DatabaseStub.java @@ -0,0 +1,266 @@ +package fr.univnantes.alma.data; + +import fr.univnantes.alma.common.NotAloneDatabase; +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.card.CardName; +import fr.univnantes.alma.server.game.item.card.PlaceCard; +import fr.univnantes.alma.server.game.item.card.SurvivalCard; +import fr.univnantes.alma.server.game.item.card.TrackingCard; +import fr.univnantes.alma.server.game.item.jeton.JetonSymbol; + +import java.util.*; + +public class DatabaseStub implements NotAloneDatabase { + + private Map placeCardMap; + private Map survivalCardMap; + private Map trackingCardMap; + + public DatabaseStub() { + initializePlaceCardMap(); + initializeSurvivalCardMap(); + initializeTrackingCardMap(); + } + + private void initializePlaceCardMap(){ + placeCardMap = new HashMap<>(); + placeCardMap.put("ANTRE", new PlaceCard(CardName.ANTRE, "Antre", "Lorem ipsum",1, "/image.png", "#4466bb")); + placeCardMap.put("NEXUS", new PlaceCard(CardName.NEXUS, "Nexus", "Lorem ipsum", 1, "/image.png", "#4466bb")); + placeCardMap.put("JUNGLE", new PlaceCard(CardName.JUNGLE, "Jungle", "Lorem ipsum", 2, "/image.png", "#4466bb")); + placeCardMap.put("OASIS", new PlaceCard(CardName.OASIS, "Oasis", "Lorem ipsum", 2, "/image.png", "#4466bb")); + placeCardMap.put("RIVIERE", new PlaceCard(CardName.RIVIERE, "Rivière", "Lorem ipsum", 3, "/image.png", "#4466bb")); + placeCardMap.put("FJORD", new PlaceCard(CardName.FJORD, "Fjord", "Lorem ipsum", 3, "/image.png", "#4466bb")); + placeCardMap.put("DOME", new PlaceCard(CardName.DOME,"Dôme", "Lorem ipsum", 4, "/image.png", "#4466bb")); + placeCardMap.put("PLAGE", new PlaceCard(CardName.PLAGE,"Plage", "Lorem ipsum", 4, "/image.png", "#4466bb")); + placeCardMap.put("ROVER", new PlaceCard(CardName.ROVER,"Rover", "Lorem ipsum", 5, "/image.png", "#4466bb")); + placeCardMap.put("LABYRINTHE", new PlaceCard(CardName.LABYRINTHE,"Labyrinthe", "Lorem ipsum", 5, "/image.png", "#4466bb")); + placeCardMap.put("MANGROVE", new PlaceCard(CardName.MANGROVE, "Mangrove", "Lorem ipsum", 6, "/image.png", "#4466bb")); + placeCardMap.put("MARAIS", new PlaceCard(CardName.MARAIS, "Marais", "Lorem ipsum", 6, "/image.png", "#4466bb")); + placeCardMap.put("ABRI", new PlaceCard(CardName.ABRI, "Abri", "Lorem ipsum", 7, "/image.png", "#4466bb")); + placeCardMap.put("ARCHIPEL", new PlaceCard(CardName.ARCHIPEL, "Archipel", "Lorem ipsum", 7, "/image.png", "#4466bb")); + placeCardMap.put("EPAVE", new PlaceCard(CardName.EPAVE, "Epave", "Lorem ipsum", 8, "/image.png", "#4466bb")); + placeCardMap.put("POLE", new PlaceCard(CardName.POLE, "Pole", "Lorem ipsum", 8, "/image.png", "#4466bb")); + placeCardMap.put("FUNGI", new PlaceCard(CardName.FUNGI, "Fungi", "Lorem ipsum", 9, "/image.png", "#4466bb")); + placeCardMap.put("SOURCE", new PlaceCard(CardName.SOURCE, "Source", "Lorem ipsum", 9, "/image.png", "#4466bb")); + placeCardMap.put("PORTAIL", new PlaceCard(CardName.PORTAIL, "Portail", "Lorem ipsum", 10, "/image.png", "#4466bb")); + placeCardMap.put("ARTEFACT", new PlaceCard(CardName.ARTEFACT, "Artefact", "Lorem ipsum", 10, "/image.png", "#4466bb")); + } + + private void initializeSurvivalCardMap(){ + survivalCardMap = new HashMap<>(); + survivalCardMap.put("ADRENALINE", new SurvivalCard(CardName.ADRENALINE,"Adrénaline", "Lorem ipsum", Phase.PREPHASE_1)); + survivalCardMap.put("ALERTE", new SurvivalCard(CardName.ALERTE,"Alerte", "Lorem ipsum", Phase.PREPHASE_3)); + survivalCardMap.put("AMPLIFICATEUR", new SurvivalCard(CardName.AMPLIFICATEUR,"Amplificateur", "Lorem ipsum", Phase.PREPHASE_4)); + survivalCardMap.put("BROUILLAGE", new SurvivalCard(CardName.BROUILLAGE,"Brouillage", "Lorem ipsum", Phase.PREPHASE_1)); + survivalCardMap.put("CAVALE", new SurvivalCard(CardName.CAVALE,"Cavale", "Lorem ipsum", Phase.PREPHASE_1)); + survivalCardMap.put("DETECTEUR", new SurvivalCard(CardName.DETECTEUR,"Détecteur", "Lorem ipsum", Phase.PREPHASE_3)); + survivalCardMap.put("DRONE", new SurvivalCard(CardName.DRONE,"Drone", "Lorem ipsum", Phase.PREPHASE_3)); + survivalCardMap.put("ENTRAVE", new SurvivalCard(CardName.ENTRAVE,"Entrave", "Lorem ipsum", Phase.PREPHASE_1)); + survivalCardMap.put("EQUIPEMENT", new SurvivalCard(CardName.EQUIPEMENT,"Equipement", "Lorem ipsum", Phase.PREPHASE_4)); + survivalCardMap.put("ESQUIVE", new SurvivalCard(CardName.ESQUIVE,"Esquive", "Lorem ipsum", Phase.PREPHASE_3)); + survivalCardMap.put("FAUSSE_PISTE", new SurvivalCard(CardName.FAUSSE_PISTE,"Fausse-piste", "Lorem ipsum", Phase.PREPHASE_3)); + survivalCardMap.put("HOLOGRAMME", new SurvivalCard(CardName.HOLOGRAMME,"Hologramme", "Lorem ipsum", Phase.PREPHASE_3)); + survivalCardMap.put("LEURRE", new SurvivalCard(CardName.LEURRE,"Leurre", "Lorem ipsum", Phase.PREPHASE_3)); + survivalCardMap.put("MIMETISME", new SurvivalCard(CardName.MIMETISME,"Mimétisme", "Lorem ipsum", Phase.PREPHASE_1)); + survivalCardMap.put("NAVETTE", new SurvivalCard(CardName.NAVETTE,"Navette", "Lorem ipsum", Phase.PREPHASE_4)); + survivalCardMap.put("PLANQUES", new SurvivalCard(CardName.PLANQUES,"Planques", "Lorem ipsum", Phase.PREPHASE_4)); + survivalCardMap.put("PORTAIL_SURVIVAL", new SurvivalCard(CardName.PORTAIL_SURVIVAL,"Portail", "Lorem ipsum", Phase.PREPHASE_3)); + survivalCardMap.put("RALLIEMENT", new SurvivalCard(CardName.RALLIEMENT,"Ralliement", "Lorem ipsum", Phase.PREPHASE_4)); + survivalCardMap.put("REFUGE", new SurvivalCard(CardName.REFUGE,"Refuge", "Lorem ipsum", Phase.PREPHASE_1)); + survivalCardMap.put("REGENERATION", new SurvivalCard(CardName.REGENERATION,"Régénération", "Lorem ipsum", Phase.PREPHASE_3)); + survivalCardMap.put("RESISTANCE", new SurvivalCard(CardName.RESISTANCE,"Résistance", "Lorem ipsum", Phase.PREPHASE_3)); + survivalCardMap.put("RETRAITE", new SurvivalCard(CardName.RETRAITE,"Retraite", "Lorem ipsum", Phase.PREPHASE_3)); + survivalCardMap.put("RIPOSTE", new SurvivalCard(CardName.RIPOSTE,"Riposte", "Lorem ipsum", Phase.PREPHASE_1)); + survivalCardMap.put("SACRIFICE", new SurvivalCard(CardName.SACRIFICE,"Sacrifice", "Lorem ipsum", Phase.PREPHASE_1)); + survivalCardMap.put("SECOND_SOUFFLE", new SurvivalCard(CardName.SECOND_SOUFFLE,"Second souffle", "Lorem ipsum", Phase.PREPHASE_1)); + survivalCardMap.put("SIXIEME_SENS", new SurvivalCard(CardName.SIXIEME_SENS,"Sixième sens", "Lorem ipsum", Phase.PREPHASE_1)); + survivalCardMap.put("SYSTEME_D", new SurvivalCard(CardName.SYSTEME_D,"Système D", "Lorem ipsum", Phase.PREPHASE_1)); + survivalCardMap.put("TENACITE", new SurvivalCard(CardName.TENACITE,"Ténacité", "Lorem ipsum", Phase.PREPHASE_1)); + survivalCardMap.put("VACCIN", new SurvivalCard(CardName.VACCIN,"Vaccin", "Lorem ipsum", Phase.PREPHASE_1)); + survivalCardMap.put("VOLTE_FACE", new SurvivalCard(CardName.VOLTE_FACE,"Volte-face", "Lorem ipsum", Phase.PREPHASE_4)); + survivalCardMap.put("VORTEX", new SurvivalCard(CardName.VORTEX,"Vortex", "Lorem ipsum", Phase.PREPHASE_2)); + } + + private void initializeTrackingCardMap(){ + trackingCardMap = new HashMap<>(); + trackingCardMap.put("ACHARNEMENT", new TrackingCard(CardName.ACHARNEMENT, "Acharnement", "Lorem ipsum", Phase.PREPHASE_2)); + trackingCardMap.put("ANGOISSE", new TrackingCard(CardName.ANGOISSE, "Angoisse", "Lorem ipsum", Phase.PREPHASE_1, JetonSymbol.ARTEMIA)); + trackingCardMap.put("ANTICIPATION", new TrackingCard(CardName.ANTICIPATION, "Anticipation", "Lorem ipsum", Phase.PREPHASE_2)); + trackingCardMap.put("CATACLYSME", new TrackingCard(CardName.CATACLYSME, "Cataclysme", "Lorem ipsum", Phase.PREPHASE_3)); + trackingCardMap.put("CHAMP_DE_FORCE", new TrackingCard(CardName.CHAMP_DE_FORCE, "Champ de force", "Lorem ipsum", Phase.PREPHASE_1, JetonSymbol.CIBLE)); + trackingCardMap.put("CLONE", new TrackingCard(CardName.CLONE, "Clone", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE)); + trackingCardMap.put("DEPLOIEMENT", new TrackingCard(CardName.DEPLOIEMENT, "Déploiement", "Lorem ipsum", Phase.PREPHASE_3)); + trackingCardMap.put("DESESPOIR", new TrackingCard(CardName.DESESPOIR, "Désespoir", "Lorem ipsum", Phase.PREPHASE_1, JetonSymbol.ARTEMIA)); + trackingCardMap.put("DETOUR", new TrackingCard(CardName.DETOUR, "Détour", "Lorem ipsum", Phase.PREPHASE_3)); + trackingCardMap.put("DOMINATION", new TrackingCard(CardName.DOMINATION, "Domination", "Lorem ipsum", Phase.PREPHASE_2)); + trackingCardMap.put("EFFROI", new TrackingCard(CardName.EFFROI, "Effroi", "Lorem ipsum", Phase.POSTPHASE_1)); + trackingCardMap.put("EMPRISE", new TrackingCard(CardName.EMPRISE, "Emprise", "Lorem ipsum", Phase.PREPHASE_2)); + trackingCardMap.put("EPIDEMIE", new TrackingCard(CardName.EPIDEMIE, "Epidémie", "Lorem ipsum", Phase.PREPHASE_2)); + trackingCardMap.put("FAILLE_TEMPORELLE", new TrackingCard(CardName.FAILLE_TEMPORELLE, "Faille temporelle", "Lorem ipsum", Phase.PREPHASE_2)); + trackingCardMap.put("FLASHBACK", new TrackingCard(CardName.FLASHBACK, "Flashback", "Lorem ipsum", Phase.PREPHASE_1)); + trackingCardMap.put("GARGANTUA", new TrackingCard(CardName.GARGANTUA, "Gargantua", "Lorem ipsum", Phase.PREPHASE_2)); + trackingCardMap.put("HARCELEMENT", new TrackingCard(CardName.HARCELEMENT, "Harcèlements", "Lorem ipsum", Phase.PREPHASE_2)); + trackingCardMap.put("HURLEMENTS", new TrackingCard(CardName.HURLEMENTS, "Hurlements", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE)); + trackingCardMap.put("INERTIE", new TrackingCard(CardName.INERTIE, "Inertie", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE)); + trackingCardMap.put("INTERFERENCES", new TrackingCard(CardName.INTERFERENCES, "Interférences", "Lorem ipsum", Phase.PREPHASE_2)); + trackingCardMap.put("INTUITION", new TrackingCard(CardName.INTUITION, "Intuition", "Lorem ipsum", Phase.PREPHASE_1)); + trackingCardMap.put("MAGNETISME", new TrackingCard(CardName.MAGNETISME, "Magnétisme", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE)); + trackingCardMap.put("MIRAGE", new TrackingCard(CardName.MIRAGE, "Mirage", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE)); + trackingCardMap.put("MUTATION", new TrackingCard(CardName.MUTATION, "Mutation", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.ARTEMIA)); + trackingCardMap.put("PSYCHOSE", new TrackingCard(CardName.PSYCHOSE, "Psychose", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.ARTEMIA)); + trackingCardMap.put("REMINISCENCE", new TrackingCard(CardName.REMINISCENCE, "Réminiscence", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.ARTEMIA)); + trackingCardMap.put("REPERAGE", new TrackingCard(CardName.REPERAGE, "Repérage", "Lorem ipsum", Phase.PREPHASE_4)); + trackingCardMap.put("SABLES_MOUVANTS", new TrackingCard(CardName.SABLES_MOUVANTS, "Sables mouvants", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE)); + trackingCardMap.put("SOIF_DE_SANG", new TrackingCard(CardName.SOIF_DE_SANG, "Soif de sang", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE)); + trackingCardMap.put("STASE", new TrackingCard(CardName.STASE, "Stase", "Lorem ipsum", Phase.PREPHASE_4)); + trackingCardMap.put("TELEPATHIE", new TrackingCard(CardName.TELEPATHIE, "Télépathie", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.ARTEMIA)); + trackingCardMap.put("TORNADE", new TrackingCard(CardName.TORNADE, "Tornade", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.ARTEMIA)); + trackingCardMap.put("TOXINE", new TrackingCard(CardName.TOXINE, "Toxine", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.CIBLE)); + trackingCardMap.put("UBIQUITE", new TrackingCard(CardName.UBIQUITE, "Ubiquité", "Lorem ipsum", Phase.PREPHASE_2, Arrays.asList(JetonSymbol.CIBLE, JetonSymbol.ARTEMIA))); + trackingCardMap.put("VIRUS", new TrackingCard(CardName.VIRUS, "Virus", "Lorem ipsum", Phase.PREPHASE_2, JetonSymbol.ARTEMIA)); + trackingCardMap.put("ZONE_INTERDITE", new TrackingCard(CardName.ZONE_INTERDITE, "Zone interdite", "Lorem ipsum", Phase.PREPHASE_2)); + } + + public PlaceCard findPlaceCard(String idCard) { + return placeCardMap.get(idCard); + } + + @Override + public List findPlaceCards(List idCards) { + List places = new ArrayList<>(); + for(String id : idCards){ + places.add(placeCardMap.get(id)); + } + return places; + } + + @Override + public SurvivalCard findSurvivalCard(String idCard) { + return survivalCardMap.get(idCard); + } + + @Override + public List findSurvivalCards(List idCards) { + List survival = new ArrayList<>(); + for(String id : idCards){ + survival.add(survivalCardMap.get(id)); + } + return survival; + } + + @Override + public List findAllSurvivalCard() { + List survival = new ArrayList<>(); + for(Map.Entry entry : survivalCardMap.entrySet()){ + survival.add((SurvivalCard) entry.getValue()); + } + return survival; + } + + @Override + public TrackingCard findTrackingCard(String idCard) { + return trackingCardMap.get(idCard); + } + + @Override + public List findTrackingCards(List idCards) { + List tracking = new ArrayList<>(); + for(String id : idCards){ + tracking.add(trackingCardMap.get(id)); + } + return tracking; + } + + @Override + public List findAllTrackingCard() { + List tracking = new ArrayList<>(); + for(Map.Entry entry : trackingCardMap.entrySet()){ + tracking.add((TrackingCard) entry.getValue()); + } + return tracking; + } + + @Override + public List findPowersDescription(String cardNameString) { + CardName cardName = null; + try { + cardName = CardName.valueOf(cardNameString); + } + catch (Exception e) { + throw new IllegalArgumentException("Invalid name of card"); + } + return findPowersDescription(cardName); + } + + @Override + public List findPowersDescription(CardName cardName) { + List powersDescription = new ArrayList<>(); + switch (cardName) { + case ANTRE: + powersDescription = Arrays.asList("Reprenez en main les cartes Lieu de votre défausse (mais pas celui-ci)", "Copiez le pouvoir d’un Lieu où le jeton Créature se trouve"); + break; + case JUNGLE: + powersDescription = Arrays.asList("Reprenez en main cette carte Lieu et 1 carte Lieu de votre défausse."); + break; + case RIVIERE: + powersDescription = Arrays.asList("Au prochain tour, jouez 2 cartes Lieu. Avant de révéler, choisissez-en une et reprenez l’autre en main."); + break; + case PLAGE: + powersDescription = Arrays.asList("Placer/Retirer le Pion Balise de la Plage. (Max 1 fois/tour). Si plusieurs Traqués explorent la Plage, l’un d’eux peut utiliser le pouvoir de la Plage et les autres peuvent récupérer 1 carte Lieu de leur défausse. Le pouvoir de la Plage est cumulable avec celui de l’Épave. "); + break; + case ROVER: + powersDescription = Arrays.asList("Prenez de la réserve une carte Lieu que vous ne possédez pas et ajoutez-le à votre main."); + break; + case MARAIS: + powersDescription = Arrays.asList("Reprenez en main cette carte Lieu et 2 cartes Lieu de votre défausse. Si le Marais est révélé grâce au Labyrinthe et que vous l’activez directement, ni le Marais ni le Labyrinthe ne sont repris en main."); + break; + case ABRI: + powersDescription = Arrays.asList("Piochez 2 carte Survie, gardez-en une et défaussez l’autre."); + break; + case EPAVE: + powersDescription = Arrays.asList("Avancez le pion Secours d'1 case (1 fois par tour, quel que soit le nombre de Traqués explorant l’Épave). Si plusieurs Traqués explorent l’Épave, l’un d’eux peut utiliser le pouvoir de l’Épave et les autres peuvent récupérer 1 carte Lieu de leur défausse. Le pouvoir de l’Épave est cumulable avec celui de la Plage."); + break; + case SOURCE: + powersDescription = Arrays.asList("Le Traqué de votre choix (vous ou un autre joueur) récupère 1 Volonté", "Piochez 1 carte Survie."); + break; + case ARTEFACT: + //None description list + break; + case NEXUS: + powersDescription = Arrays.asList("Copiez le pouvoir d'1 Lieu 2à 5. Avancez le pion Assimilation d'1 case supplémentaire si le jeton Créature attrape au moins 1 Traqué sur le Nexus."); + break; + case OASIS: + powersDescription = Arrays.asList("Reprenez en main cette carte Lieu plus 1 carte Lieu de votre défausse par Volonté qu’il vous manque, si possible."); + break; + case FJORD: + powersDescription = Arrays.asList("Lors du prochain tour : En Phase 1 : vous pouvez jouer une 2ème carte Lieu, face visible, de votre défausse, s’il n’y en a. En Phase 3 : résolvez 1 de ces Lieux. En Phase 4 : défaussez ces 2 cartes Lieu."); + break; + case DOME: + powersDescription = Arrays.asList("Déplacez le Bouclier d'1 Lieu vers le Dôme. Si le pion Boucler atteint le Dôme : reculer le pion Assimilation d'1 case et replacer le pion Bouclier sur le Lieu 1 (max 1x/tour)."); + break; + case LABYRINTHE: + powersDescription = Arrays.asList("Révéler un Lieu : retourner, face visible, une des 5 cartes Lieu 6 à 10 de la planète Artemia et activer son pouvoir ou prendre 1 carte Lieu correspondante.", "Prendre de la réserve 1 carte Lieu déjà révélé."); + break; + case MANGROVE: + powersDescription = Arrays.asList("Échanger les cartes Lieu de sa main contre celles de sa défausse. Reprendre cette carte Lieu en main."); + break; + case ARCHIPEL: + powersDescription = Arrays.asList("Piocher 1 carte Survie. S’il vous reste moins de 3 cartes Lieu en main, le Traqué de votre choix récupère 1 Volonté."); + break; + case POLE: + powersDescription = Arrays.asList("Sacrifiez 1 Volonté (même si c’est le dernier), puis avancez le pion Secours de 2 cases. En Phase 4, replacer le pôle dans la réserve, qu’elle ait pu être activée ou non. Le Pôle ne peut être copié (que ce soit par le pouvoir d’un Lieu ou une carte Survie)."); + break; + case FUNGI: + powersDescription = Arrays.asList("Piocher une carte Survie", "Placer jusqu’à 2 pions Volonté (si possible) sur les prochaines cases de la piste Secours. Quand le pion Secours atteint une de ces cases : le Traqué qui a le moins de Pion Volonté récupère le pion Volonté."); + break; + case PORTAIL: + powersDescription = Arrays.asList("Défausser le Portail pour jouer une autre carte Lieu de sa main et la résoudre. Le Portail téléporte le Traqué sur le second lieu joué, ce Traqué est donc susceptible de s’y faire attraper par un jeton Traque et/ou d’y être la cible d’une carte Traque. Le Portail est défaussé en phase 3 et la seconde carte Lieu en phase 4."); + break; + default: + + } + List powers = new ArrayList<>(Collections.singletonList("Reprenez en main une carte Lieu de votre défausse")); + powers.addAll(powersDescription); + return powers; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/NotAloneApplication.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/NotAloneApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..6f31907fa8da4e499340b13bd899fb164c8fb0af --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/NotAloneApplication.java @@ -0,0 +1,35 @@ +package fr.univnantes.alma.server; + +import fr.univnantes.alma.server.handler.GameServiceHandler; +import fr.univnantes.alma.thrift.GameService; +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.protocol.TProtocolFactory; +import org.apache.thrift.server.TServlet; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableAutoConfiguration +@ComponentScan(basePackages = {"fr.univnantes.alma"}) +public class NotAloneApplication { + + public static void main(String[] args) { + SpringApplication.run(NotAloneApplication.class, args); + } + + @Bean + public TProtocolFactory tProtocolFactory() { + return new TBinaryProtocol.Factory(); + } + + @Bean + public ServletRegistrationBean gameServer(TProtocolFactory protocolFactory, GameServiceHandler handler) { + TServlet tServlet = new TServlet(new GameService.Processor(handler), protocolFactory); + + return new ServletRegistrationBean(tServlet, "/api"); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/Game.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/Game.java new file mode 100644 index 0000000000000000000000000000000000000000..fd61a6e8c381288c91b89bc903fc1179ba9c1b63 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/Game.java @@ -0,0 +1,1504 @@ +package fr.univnantes.alma.server.game; + +import fr.univnantes.alma.common.NotAloneDatabase; +import fr.univnantes.alma.data.DatabaseFactory; +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.Reserve; +import fr.univnantes.alma.server.game.item.action.*; +import fr.univnantes.alma.server.game.item.board.Board; +import fr.univnantes.alma.server.game.item.card.*; +import fr.univnantes.alma.server.game.item.jeton.JetonSymbol; +import fr.univnantes.alma.server.game.item.jeton.PlacedJeton; +import fr.univnantes.alma.server.game.item.pioche.Pioche; +import fr.univnantes.alma.server.game.item.planet.Place; +import fr.univnantes.alma.server.game.item.planet.Planet; +import fr.univnantes.alma.server.game.item.player.Creature; +import fr.univnantes.alma.server.game.item.player.Player; +import fr.univnantes.alma.server.game.item.player.Traque; +import fr.univnantes.alma.server.game.item.power.Power; +import fr.univnantes.alma.server.game.item.power.PowerType; +import fr.univnantes.alma.server.game.item.power.modifier.PowerModifier; +import fr.univnantes.alma.server.game.item.power.modifier.PowerModifierType; +import fr.univnantes.alma.server.game.item.power.recurrent.PowerRecurrent; +import fr.univnantes.alma.server.game.utilitary.Conversion; +import fr.univnantes.alma.server.game.utilitary.Pair; +import fr.univnantes.alma.thrift.*; +import org.apache.thrift.TException; + +import java.util.*; +import java.util.stream.Collectors; + +import static fr.univnantes.alma.server.game.PowerApplicator.applyPlayerCard; +import static fr.univnantes.alma.server.game.PowerApplicator.resolvePlace; +import static fr.univnantes.alma.server.game.item.action.ActionType.*; +import static fr.univnantes.alma.server.game.item.jeton.JetonSymbol.ARTEMIA; +import static fr.univnantes.alma.server.game.item.jeton.JetonSymbol.CIBLE; +import static fr.univnantes.alma.server.game.item.player.PlayerTeam.CREATURE; +import static fr.univnantes.alma.server.game.item.player.PlayerTeam.TRAQUE; + +public class Game implements GameInterface { + /** + * The powers of the next round + */ + private List nextRoundPowers; + + /** + * The planet + */ + private Planet planet; + + /** + * The reserve of the game + */ + private Reserve reserve; + + /** + * The "pioche" for survival cards + */ + private Pioche survivalCardPioche; + + /** + * The "pioche" for tracking cards + */ + private Pioche trackingCardPioche; + + /** + * The board of the game, containing the score + */ + private Board board; + + /** + * The database where the data are stored + */ + private NotAloneDatabase database; + + /** + * The creature + */ + private Creature creature; + + /** + * The traques + */ + private List traques; + + /** + * Map of inGameId to players + */ + private Map playersMap; + + /** + * Represents the state of the game + */ + private Phase state; + + /** + * Reference to the room + */ + private Room room; + + /** + * Contains the round variables that may be modified by power + */ + private GameRoundVariables gameRoundVariables; + + public Game(List> players, int creatureId, Planet planet, Board board, Room room) { + if(players.isEmpty() || players.size() > 7) { + throw new IllegalArgumentException("Need between 1 and 7 players"); + } + int playerNumber = players.size(); + this.planet = planet; + this.board = board; + this.board.initializeScore(playerNumber); + this.room = room; + this.database = DatabaseFactory.getDatabase(); + this.nextRoundPowers = new ArrayList<>(); + this.gameRoundVariables = new GameRoundVariables(); + initializePlayer(players, creatureId); + initializeReserve(playerNumber); + initializeSurvivalCardPioche(); + initializeTrackingCardPioche(); + initializeCardsOfPlayers(); + this.state = Phase.PREPHASE_1; + sendFirstRoundStart(); + } + + public Game(Collection playersId, int creatureId, Planet planet, Board board, Room room) { + if(playersId.isEmpty() || playersId.size() > 7) { + throw new IllegalArgumentException("Need between 1 and 7 players"); + } + int playerNumber = playersId.size(); + this.planet = planet; + this.board = board; + this.board.initializeScore(playerNumber); + this.room = room; + this.database = DatabaseFactory.getDatabase(); + this.nextRoundPowers = new ArrayList<>(); + this.gameRoundVariables = new GameRoundVariables(); + initializePlayer(playersId, creatureId); + initializeReserve(playerNumber); + initializeSurvivalCardPioche(); + initializeTrackingCardPioche(); + initializeCardsOfPlayers(); + this.state = Phase.PREPHASE_1; + sendFirstRoundStart(); + } + + /*************************** + * Initialization + **************************/ + + /** + * Initialize Creature, Traques and the playerMap + */ + private void initializePlayer(Collection playersId, int creatureId){ + if(!playersId.contains(creatureId)) { + throw new IllegalArgumentException(creatureId + " doesn't represent a valid in game id"); + } + this.traques = new ArrayList<>(); + this.playersMap = new HashMap<>(); + this.creature = new Creature("Player" + creatureId, creatureId); + this.playersMap.put(creatureId, this.creature); + for(int id : playersId) { + if(id != creatureId) { + Traque traque = new Traque("Player" + id, id); + this.traques.add(traque); + this.playersMap.put(id, traque); + } + } + } + + /** + * Initialize Creature, Traques and the playerMap + */ + private void initializePlayer(List> players, int creatureId){ + List ids = players.stream().map(Pair::getKey).collect(Collectors.toList()); + if(!ids.contains(creatureId)) { + throw new IllegalArgumentException(creatureId + " doesn't represent a valid in game id"); + } + this.traques = new ArrayList<>(); + this.playersMap = new HashMap<>(); + for(Pair pair : players) { + if(pair.getKey() != creatureId) { + Traque traque = new Traque(pair.getValue(), pair.getKey()); + this.traques.add(traque); + this.playersMap.put(pair.getKey(), traque); + } + else { + this.creature = new Creature(pair.getValue(), pair.getKey()); + this.playersMap.put(creatureId, this.creature); + } + } + } + + /** + * Initialize the reserve with placeCards + * @param playerNumber The number of players + */ + private void initializeReserve(int playerNumber){ + List cards = planet.getPlaceCardsInInterval(6, 10); + reserve = new Reserve(cards, playerNumber); + } + + /** + * Initialize the pioche of survival cards + */ + private void initializeSurvivalCardPioche(){ + this.survivalCardPioche = new Pioche<>(database.findAllSurvivalCard()); + } + + /** + * Initialize the pioche of tracking cards + */ + private void initializeTrackingCardPioche(){ + this.trackingCardPioche = new Pioche<>(database.findAllTrackingCard()); + } + + /** + * Initialize the player's place cards, survival cards and tracking cards + */ + private void initializeCardsOfPlayers(){ + for(Traque traque : traques) { + traque.addPlaceCard(planet.getPlaceCardsInInterval(1, 5)); + traque.addSurvivalCard(survivalCardPioche.draw()); + } + creature.addTrackingCard(trackingCardPioche.draw(3)); + } + + /*************************** + * Getters + **************************/ + + public Planet getPlanet() { + return planet; + } + + public Reserve getReserve() { + return reserve; + } + + public Pioche getSurvivalCardPioche() { + return survivalCardPioche; + } + + public Pioche getTrackingCardPioche() { + return trackingCardPioche; + } + + public Board getBoard() { + return board; + } + + public Creature getCreature() { + return creature; + } + + public List getTraques() { + return traques; + } + + public Map getPlayersMap() { + return playersMap; + } + + public Player getPlayer(int idPlayer) {return playersMap.get(idPlayer);} + + public GameRoundVariables getGameRoundVariables() { + return gameRoundVariables; + } + + public Phase getState() { + return state; + } + + public Room getRoom() { + return room; + } + + public boolean isJetonArtemiaIsActive() { + return gameRoundVariables.isJetonArtemiaIsActive(); + } + + public int getNumberWillingnessDecrementByJetonCreature() { + return gameRoundVariables.getNumberWillingnessDecrementByJetonCreature(); + } + + public boolean traqueCanResist() { + return gameRoundVariables.traqueCanResist(); + } + + public int getIdPlayerTargetByTrackingCardAnticipation() { + return gameRoundVariables.getIdPlayerTargetByTrackingCardAnticipation(); + } + + public boolean traqueCanPickSurvivalCards() { + return gameRoundVariables.traqueCanPickSurvivalCards(); + } + + /*************************** + * Setters and modifiers + **************************/ + + public void addPowerForNextRound(Power power) { + this.nextRoundPowers.add(power); + } + + public void disableJetonArtemia() { + gameRoundVariables.disableJetonArtemia(); + } + + public void enableJetonArtemia() { + gameRoundVariables.enableJetonArtemia(); + } + + public void setNumberWillingnessDecrementByJetonCreature(int number) { + gameRoundVariables.setNumberWillingnessDecrementByJetonCreature(number); + } + + public void addNumberWillingnessByJetonCreature() { + gameRoundVariables.addNumberWillingnessByJetonCreature(); + } + public void setTraqueCanResist(boolean traqueCanResist) { + this.gameRoundVariables.setTraqueCanResist(traqueCanResist); + } + + public void setIdPlayerTargetByTrackingCardAnticipation(int idPlayerTargetByJetonCreature) { + this.gameRoundVariables.setIdPlayerTargetByTrackingCardAnticipation(idPlayerTargetByJetonCreature); + } + + public void setTraqueCanPickSurvivalCards(boolean traqueCanPickSurvivalCards) { + gameRoundVariables.setTraqueCanPickSurvivalCards(traqueCanPickSurvivalCards); + } + + /************************************* + * Game Interface Methods + ***********************************/ + + @Override + public boolean isFinish() { + return board.isFinish(); + } + + @Override + public Response playerHasFinished(int playerId, Phase phase) { + Response response; + Player player = playersMap.get(playerId); + if(state.equals(phase)) { + if (player.teamEqualsTo(CREATURE)) { + response = creatureHasFinished((Creature) player, phase); + } else { + response = traqueHasFinished((Traque) player, phase); + + } + } + else { + return new Response(false, "The current phase is " + state); + } + if(response.isState()) { + playerFinishedPhase(player, phase); + } + return response; + } + + public Response creatureHasFinished(Creature creature, Phase phase) { + if (phase.equals(Phase.PHASE_2) && creature.jetonsPlayedIsEmpty()) { + return new Response(false, "You must to place at least one jeton"); + } + else{ + boolean thereIsPowerToApplied = false; + for(TrackingCard card : creature.getTrackingCardToApplied()) { + if(card.getPhaseToApply().equals(phase)) { + thereIsPowerToApplied = true; + } + } + if(thereIsPowerToApplied){ + return new Response(false, "You must to applied card's power"); + } + else { + return new Response(true, ""); + } + } + } + + public Response traqueHasFinished(Traque traque, Phase phase) { + if(phase.equals(Phase.PHASE_1) && traque.placeCardPlayedIsEmpty()) { + return new Response(false, "You must play a place card"); + } + else{ + boolean thereIsPowerToApplied = false; + for(SurvivalCard card : traque.getSurvivalCardsToApplied()) { + if(card.getPhaseToApply().equals(phase)) { + thereIsPowerToApplied = true; + } + } + if(thereIsPowerToApplied){ + return new Response(false, "You must to applied card's power"); + } + else { + return new Response(true, ""); + } + } + } + + public void playerFinishedPhase(Player player, Phase phase) { + player.setCurrentPhase(nextPhase(phase)); + if(allPlayersHasFinishedCurrentPhase()) { + startNextPhase(); + } + } + + @Override + public Response playerPlayCard(int playerId, Card card) { + Response response; + Player player = playersMap.get(playerId); + switch (state) { + case PREPHASE_1: + case POSTPHASE_1: + case PREPHASE_2: + case POSTPHASE_2: + case PREPHASE_3: + case POSTPHASE_3: + case PREPHASE_4: + case POSTPHASE_4: + response = playerPlayPlayerCard(player, card); + break; + case PHASE_1: + if(player.teamEqualsTo(TRAQUE)) { + try { + PlaceCard placeCard = (PlaceCard) card; + Traque traque = (Traque) player; + response = traquePlayPlaceCard(traque, placeCard); + } + catch (Exception e){ + response = new Response(false, "Need a place card"); + } + } + else{ + response = new Response(false, "No card authorize in this phase"); + } + break; + case PHASE_2: + case PHASE_3: + case PHASE_4: + default: + response = new Response(false, "No card authorize in this phase"); + } + return response; + } + + @Override + public Response playerPlayCard(int playerId, List cards) { + Response response; + Player player = playersMap.get(playerId); + switch (state) { + case PHASE_1: + if(player.getTeam().equals(TRAQUE)) { + try { + List placeCards = cards.stream().map(c -> (PlaceCard) c).collect(Collectors.toList()); + Traque traque= (Traque) player; + response = traquePlayPlaceCard(traque, placeCards); + } + catch (Exception e){ + response = new Response(false, "Need only place card"); + } + } + else{ + response = new Response(false, "No card authorize in this phase"); + } + break; + case PREPHASE_1: + case POSTPHASE_1: + case PREPHASE_2: + case POSTPHASE_2: + case PREPHASE_3: + case POSTPHASE_3: + case PREPHASE_4: + case POSTPHASE_4: + response = playerPlayPlayerCard(player, cards); + break; + case PHASE_2: + case PHASE_3: + case PHASE_4: + default: + response = new Response(false, "No card authorize in this phase"); + } + return response; + } + + @Override + public Response playerPlaceJeton(int playerId, PlacedJeton placedJeton) { + Response response; + Player player = playersMap.get(playerId); + if(player.teamEqualsTo(TRAQUE)){ + response = new Response(false, "Only the Creature can played jeton"); + } + else if(! state.equals(Phase.PHASE_2)) { + if(gameRoundVariables.isJetonCibleBlockPlace() && placedJeton.getJetonSymbol().equals(CIBLE)) { + response = creaturePlaceAJeton(creature, placedJeton); + } + else { + response = new Response(false, "You can play jeton only in Phase 2"); + } + } + else if(gameRoundVariables.refugeIsActive() && isJetonCibleOnThisPlace(placedJeton.getPlaces())) { + response = new Response(false, "Can't play JetonCible when Refuge is active"); + } + else{ + response = creaturePlaceAJeton(creature, placedJeton); + } + return response; + } + + @Override + public Response playerPlaceJeton(int playerId, List jetons) { + Player player = playersMap.get(playerId); + Response response; + if(player.teamEqualsTo(TRAQUE)){ + response = new Response(false, "Only the Creature can played jetons"); + } + else { + boolean canPlaceAllJetons = true; + for (PlacedJeton placedJeton : jetons) { + canPlaceAllJetons = canPlaceAllJetons && playerPlaceJeton(playerId, placedJeton).isState(); + } + if (!canPlaceAllJetons) { + creature.initializationJeton(); + response = new Response(false, "Invalid action"); + } + else{ + response = new Response(true, ""); + } + } + return response; + } + + @Override + public Response playerResist(int playerId, int number) { + Player player = playersMap.get(playerId); + Response response; + if(! gameRoundVariables.traqueCanResist()) { + response = new Response(false, "You can't resist for this round"); + } + else if(player.teamEqualsTo(CREATURE)) { + response = new Response(false, "Only traque can resist"); + } + else{ + Traque traque = (Traque) player; + if(number < 1 || number > 2) { + response = new Response(false, "Number must be 1 or 2"); + } + else if(! state.equals(Phase.PHASE_1)){ + response = new Response(false, "Resist is only possible in PHASE_1"); + } + else if(traque.getNumberWillingness() >= number && traque.canResist()) { + traque.subWillingness(number); + int cardsPerWillingness = 2 + traque.getNumberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist(); + int numberCard = Math.min(cardsPerWillingness * number, traque.defausseSize()); + if(numberCard > 0) { + List chosen = choosePlaceCardsAction(playerId, numberCard, traque.getDefausse()); + traque.takeBackPlaceCard(chosen); + } + traque.getRights().setCanGiveUp(false); + traque.getRights().setCanResist(false); + gameRoundVariables.addPlayersWhoHaveResist(traque.getInGameId()); + response = new Response(true, ""); + } + else{ + response = new Response(false, "You can't resist"); + } + } + return response; + } + + @Override + public Response playerGiveUp(int playerId) { + Player player = playersMap.get(playerId); + Response response; + if(player.teamEqualsTo(CREATURE)) { + response = new Response(false, "Only traque can resist"); + } + else{ + Traque traque = (Traque) player; + if(! state.equals(Phase.PHASE_1)){ + response = new Response(false, "Give up is only possible in PHASE_1"); + } + else if(traque.canGiveUp()) { + traque.fillWillingness(); + traque.takeBackAllPlaceCardFromDefausse(); + traque.setCanGiveUp(false); + traque.setCanResist(false); + board.moveForwardCreature(); + response = new Response(true, ""); + } + else{ + response = new Response(false, "You can't resist"); + } + } + return response; + } + + @Override + public Action askAction(int inGameIdPlayer, TAskAction askedAction) { + try{ + return room.askAction(inGameIdPlayer, askedAction); + } + catch (Exception e){ + throw new IllegalArgumentException("Unknown error"); + } + } + + @Override + public void sendAction(int inGameIdPlayer, TAskAction askedAction) { + try { + room.sendAction(inGameIdPlayer, askedAction); + } catch (TException e) { + throw new IllegalArgumentException("Unknown error"); + } + } + + @Override + public void sendFirstRoundStart() { + try { + room.sendFirstRoundStart(); + } catch (TException e) { + throw new IllegalArgumentException("Unknown error"); + } + } + + @Override + public void sendStartPhase() { + for(Integer id : playersMap.keySet()) { + try { + room.sendStartPhase(id, new TPhase(state.toString()),createDescription(id)); + } catch (TException e) { + e.printStackTrace(); + } + } + } + + @Override + public void sendDescription() { + for(Integer id : playersMap.keySet()) { + try { + room.sendDescription(id, createDescription(id)); + } catch (TException e) { + e.printStackTrace(); + } + } + } + + @Override + public void sendGameIsFinished() { + TPlayerTeam winner = new TPlayerTeam(board.winner().toString()); + try { + room.sendGameIsFinished(winner); + } catch (TException e) { + e.printStackTrace(); + } + } + + /************************************* + * Player play card + *************************************/ + + /** + * A player play a survival card or a tracking card + * @param player The player + * @param card The player card + * @return A Response + */ + public Response playerPlayPlayerCard(Player player, Card card) { + Response response; + if(player.teamEqualsTo(TRAQUE)) { + try { + SurvivalCard survivalCard = (SurvivalCard) card; + Traque traque = (Traque) player; + response = traquePlaySurvivalCard(traque, survivalCard); + } + catch (Exception e){ + response = new Response(false, "Need a survival card"); + } + } + else{ + try { + TrackingCard trackingCard = (TrackingCard) card; + response = creaturePlayTrackingCard(creature, trackingCard); + } + catch (Exception e){ + response = new Response(false, "Need a tracking card"); + } + } + return response; + } + + /** + * A player play survival cards or tracking cards + * @param player The player + * @param cards The player cards + * @return A Response + */ + public Response playerPlayPlayerCard(Player player, List cards) { + Response response; + if(player.teamEqualsTo(TRAQUE)) { + try { + List survivalCards = cards.stream().map(c -> (SurvivalCard) c).collect(Collectors.toList()); + Traque traque = (Traque) player; + response = traquePlaySurvivalCard(traque, survivalCards); + } + catch (Exception e){ + response = new Response(false, "Need a survival card"); + } + } + else{ + try { + List trackingCards = cards.stream().map(c -> (TrackingCard) c).collect(Collectors.toList()); + response = creaturePlayTrackingCard(creature, trackingCards); + } + catch (Exception e){ + response = new Response(false, "Need a tracking card"); + } + } + return response; + } + + + /** + * The creature play a tracking card + * @param creature The creature + * @param trackingCard The tracking card + * @return A Response + */ + public Response creaturePlayTrackingCard(Creature creature, TrackingCard trackingCard) { + boolean canPlay = creatureCanPlayThisTrackingCards(creature, trackingCard); + if(canPlay){ + if(creature.getTrackingCardToApplied().contains(trackingCard) + || creature.playTrackingCard(trackingCard)) { + applyCreaturePlayTrackingCard(creature, trackingCard); + return new Response(true, ""); + } + else{ + return new Response(false, "Unable to play this card"); + } + } + else{ + return new Response(false, "Unable to play this card"); + } + } + + /** + * The creature play tracking cards + * @param creature The creature + * @param trackingCards The tracking cards + * @return A Response + */ + public Response creaturePlayTrackingCard(Creature creature, List trackingCards) { + boolean canPlay = creatureCanPlayThisTrackingCards(creature, trackingCards); + if(canPlay) { + for(TrackingCard trackingCard : trackingCards){ + creatureCanPlayThisTrackingCards(creature, trackingCard); + } + return new Response(true, ""); + } + else{ + return new Response(false, "Unable to play this card"); + } + } + + /** + * Play the card and/or apply its power + * @param creature The creature + * @param trackingCard The card + */ + private void applyCreaturePlayTrackingCard(Creature creature, TrackingCard trackingCard) { + Phase toApplied = trackingCard.getPhaseToApply(); + if(toApplied.equals(state)) { + creature.removeTrackingCardToApplied(trackingCard); + applyPlayerCard(this, creature.getInGameId(), trackingCard); + trackingCardPioche.throwAway(trackingCard); + } + else { + creature.addTrackingCardToApplied(trackingCard); + } + } + + public boolean creatureCanPlayThisTrackingCards(Creature creature, TrackingCard trackingCard) { + if(gameRoundVariables.refugeIsActive() && trackingCard.containsSymbol(CIBLE)) { + return false; + } + if(! gameRoundVariables.canPlayTrackingCard()) { + return false; + } + else if(creature.getTrackingCardToApplied().contains(trackingCard) && state.equals(trackingCard.getPhaseToApply())) { + return true; + } + else{ + boolean canPlay = creature.getHand().trackingCardPlayedSize() < creature.getMaxTrackingCardPlayable() + && state.equals(trackingCard.getPhase()); + return canPlay && creature.getTrackingCardHand().contains(trackingCard); + } + } + + public boolean creatureCanPlayThisTrackingCards(Creature creature, List trackingCards) { + if(! gameRoundVariables.canPlayTrackingCard()) { + return false; + } + Iterator iterator = trackingCards.iterator(); + boolean canPlay = true; + List toPlay = new ArrayList<>(); + TrackingCard trackingCard; + while (canPlay && iterator.hasNext()) { + trackingCard = iterator.next(); + if(! creature.getTrackingCardToApplied().contains(trackingCard)) { + toPlay.add(trackingCard); + } + if(! creatureCanPlayThisTrackingCards(creature, trackingCard)) { + canPlay = false; + } + } + canPlay = canPlay && creature.getHand().trackingCardPlayedSize() + toPlay.size() <= creature.getMaxTrackingCardPlayable(); + return canPlay && creature.getTrackingCardHand().containsAll(toPlay); + } + + /** + * A Traque play a SurvivalCard + * @param traque The Traque + * @param survivalCard The SurvivalCard + * @return A Response + */ + public Response traquePlaySurvivalCard(Traque traque, SurvivalCard survivalCard) { + if(traqueCanPlayThisSurvivalCards(traque, survivalCard) && + traque.playSurvivalCard(survivalCard)) { + applyTraquePlaySurvivalCard(traque, survivalCard); + return new Response(true, ""); + } + else{ + return new Response(false, "Unable to play this card"); + } + } + + /** + * A Traque play survival cards + * @param traque The traque + * @param survivalCards The survival cards + * @return A Response + */ + public Response traquePlaySurvivalCard(Traque traque, List survivalCards) { + if(traqueCanPlayThisSurvivalCards(traque, survivalCards) && + traque.playSurvivalCard(survivalCards)) { + for(SurvivalCard survivalCard : survivalCards){ + applyTraquePlaySurvivalCard(traque, survivalCard); + } + return new Response(true, ""); + } + else{ + return new Response(false, "Unable to play this card"); + } + } + + /** + * Play the card and/or apply its power + * @param traque The traque + * @param survivalCard The card + */ + private void applyTraquePlaySurvivalCard(Traque traque, SurvivalCard survivalCard) { + if(playerCardsPlayedPhaseAndAppliedPhaseDifferent(survivalCard)) { + if(state.equals(survivalCard.getPhase())){ + traque.playSurvivalCard(survivalCard); + traque.addSurvivalCardToApplied(survivalCard); + } + else{ + applyPlayerCard(this, traque.getInGameId(), survivalCard); + traque.removeSurvivalCardToApplied(survivalCard); + survivalCardPioche.throwAway(survivalCard); + } + } + else{ + applyPlayerCard(this, traque.getInGameId(), survivalCard); + traque.playSurvivalCard(survivalCard); + survivalCardPioche.throwAway(survivalCard); + } + } + + public boolean traqueCanPlayThisSurvivalCards(Traque traque, SurvivalCard survivalCard) { + //if the card doesn't apply himself in the same phase that it's played + if(playerCardsPlayedPhaseAndAppliedPhaseDifferent(survivalCard)) { + //true if the card can to be played or can to be applied + return (traque.getHand().survivalCardPlayedSize() < traque.getMaxSurvivalCardPlayable() && state.equals(survivalCard.getPhase())) + || (state.equals(survivalCard.getPhaseToApply()) && traque.getSurvivalCardsPlayed().contains(survivalCard)); + } + else{ + //true if the card can to be played + return traque.getHand().survivalCardPlayedSize() < traque.getMaxSurvivalCardPlayable() && state.equals(survivalCard.getPhase()); + } + } + + public boolean traqueCanPlayThisSurvivalCards(Traque traque, List survivalCards) { + int numberCardPlayed = 0; + //Count the number of played cards + for(SurvivalCard survivalCard : survivalCards) { + if(!playerCardsPlayedPhaseAndAppliedPhaseDifferent(survivalCard)) { + ++numberCardPlayed; + } + } + if(traque.getHand().survivalCardPlayedSize() + numberCardPlayed > traque.getMaxSurvivalCardPlayable()){ + return false; + } + boolean aux = true; + for(SurvivalCard survivalCard : survivalCards) { + aux = aux && traqueCanPlayThisSurvivalCards(traque, survivalCard); + } + return aux; + } + + /** + * A traque play a place card + * @param traque The traque + * @param placeCard The place card + * @return A Response + */ + public Response traquePlayPlaceCard(Traque traque, PlaceCard placeCard) { + Response response; + if(!planet.isRevealedPlace(placeCard)) { + response = new Response(false, "The place must be revealed"); + } + else if(planet.isBlockedPlace(placeCard) || + (gameRoundVariables.isJetonCibleBlockPlace() && planet.isJetonSymbolOnPlaceCard(CIBLE, placeCard))) { + response = new Response(false, "The place is blocked"); + } + else if(traque.placeCardPlayedSize() < traque.getMaxPlacesCardChoosable() && traque.playPlaceCard(placeCard)) { + response = new Response(true, ""); + } + else{ + response = new Response(false, "Unable to play this card"); + } + return response; + } + + /** + * A traque play place cards + * @param traque The traque + * @param placeCards The place cards + * @return A Response + */ + public Response traquePlayPlaceCard(Traque traque, List placeCards) { + if(traque.placeCardPlayedSize() + placeCards.size() <= traque.getMaxPlacesCardChoosable() && + traque.playPlaceCard(placeCards)) { + return new Response(true, ""); + } + else{ + return new Response(false, "Unable to play this card"); + } + + } + + public boolean playerCardsPlayedPhaseAndAppliedPhaseDifferent(PlayerCard playerCard) { + return ! playerCard.getPhase().equals(playerCard.getPhaseToApply()); + } + + /************************************* + * Creature place jetons + *************************************/ + + public Response creaturePlaceAJeton(Creature creature, PlacedJeton placedJeton) { + List trackingCards = creature.getTrackingCardsPlayed(); + boolean containsJetonCible = false; + boolean containsJetonArtemia = false; + boolean canPlaceOn6To10 = gameRoundVariables.canPlaceJetonCreatureOnPlaces6To10(); + boolean placeBetween6To10 = false; + + for(TrackingCard trackingCard : trackingCards) { + if(trackingCard.containsSymbol(CIBLE)){ + containsJetonCible = true; + } + if(trackingCard.containsSymbol(ARTEMIA)){ + containsJetonArtemia = true; + } + } + + JetonSymbol symbol = placedJeton.getJetonSymbol(); + + if(placedJeton.getPlaces().size() > 1) { + if(symbol.equals(JetonSymbol.CIBLE) && !gameRoundVariables.jetonCibleCanBeOnTwoAdjacentPlaces()) { + return new Response(false, "JetonCible can't be place on two adjacent places"); + } + else if(symbol.equals(ARTEMIA) && !gameRoundVariables.jetonArtemiaCanBeOnTwoAdjacentPlaces()) { + return new Response(false, "JetonArtemia can't be place on two adjacent places"); + } + else if(symbol.equals(JetonSymbol.CREATURE) && !gameRoundVariables.jetonCreatureCanBeOnTwoAdjacentPlaces()) { + return new Response(false, "JetonCreature can't be place on two adjacent places"); + } + } + for(Place place : placedJeton.getPlaces()) { + if(Planet.placeToNumber(place) >= 6) { + placeBetween6To10 = true; + } + } + if( (symbol.equals(CIBLE) && containsJetonCible) + || (symbol.equals(ARTEMIA) && (containsJetonArtemia || board.isArtemiaSquare())) + || symbol.equals(JetonSymbol.CREATURE) && (canPlaceOn6To10 || !placeBetween6To10)) { + if(planet.placeJeton(placedJeton)) { + creature.playJeton(placedJeton.getJetonSymbol()); + return new Response(true, ""); + } + else { + return new Response(false, "Impossible action"); + } + } + else { + return new Response(false, "Invalid jeton"); + } + } + + /************************************* + * Phase management methods + ***********************************/ + + public Phase nextPhase(Phase phase) { + switch (phase) { + case PREPHASE_1: + return Phase.PHASE_1; + case PHASE_1: + return Phase.POSTPHASE_1; + case POSTPHASE_1: + return Phase.PREPHASE_2; + case PREPHASE_2: + return Phase.PHASE_2; + case PHASE_2: + return Phase.POSTPHASE_2; + case POSTPHASE_2: + return Phase.PREPHASE_3; + case PREPHASE_3: + return Phase.PHASE_3; + case PHASE_3: + return Phase.POSTPHASE_3; + case POSTPHASE_3: + return Phase.PREPHASE_4; + case PREPHASE_4: + return Phase.PHASE_4; + case PHASE_4: + return Phase.POSTPHASE_4; + case POSTPHASE_4: + return Phase.PREPHASE_1; + default: + throw new IllegalArgumentException(phase + " is not a valid phase"); + } + } + + public boolean allPlayersHasFinishedCurrentPhase(){ + boolean res = true; + Phase nextPhase = nextPhase(state); + Iterator> iterator = playersMap.entrySet().iterator(); + while(res && iterator.hasNext()) { + if(! nextPhase.equals(iterator.next().getValue().getCurrentPhase())) { + res = false; + } + } + return res; + } + + public void startNextPhase() { + state = nextPhase(state); + sendStartPhase(); + if(state.equals(Phase.PHASE_3)) { + managePhase3(); + } + else if(state.equals(Phase.PHASE_4)) { + managePhase4(); + } + else if(state.equals(Phase.PREPHASE_1)) { + nextRound(); + } + else if(state.equals(Phase.PREPHASE_3)){ + if(PowerApplicator.checkInertieCondition(this)){ + planet.blockPlaces(Arrays.asList(Place.values())); + } + } + } + + public void managePhase3() { + List chosenPlaceCards; + for(Traque traque : traques) { + chosenPlaceCards = choosePlaceCardsToReveal(traque); + for(PlaceCard placeCard : chosenPlaceCards) { + resolvePlace(this, traque.getInGameId(), placeCard); + } + sendDescription(); + } + } + + private List choosePlaceCardsToReveal(Traque traque) { + List placeCardsPlayed = new ArrayList<>(traque.getPlaceCardsPlayed()); + List chosenPlaceCards = placeCardsPlayed; + //if player plays too many cards + if(placeCardsPlayed.size() > traque.getMaxPlacesCardPlayable()) { + chosenPlaceCards = choosePlaceCardsAction(traque.getInGameId(), traque.getMaxPlacesCardPlayable(), placeCardsPlayed); + for(PlaceCard placeCard : placeCardsPlayed) { + if(! chosenPlaceCards.contains(placeCard)) { + if(gameRoundVariables.getPlayersWhoHavePlayCavale().contains(traque.getInGameId()) + || gameRoundVariables.getplayersWhoUseFjordInPreviousRound().contains(traque.getInGameId())) { + traque.throwAwayPlaceCard(placeCard); + } + else { + //put back non-played cards in the hand + traque.takeBackPlaceCard(placeCard); + } + } + } + } + return chosenPlaceCards; + } + + public void managePhase4() { + for(Traque traque : traques) { + if(gameRoundVariables.getPlayersWhoHavePlayCavale().contains(traque.getInGameId()) + || gameRoundVariables.getPlayersWhoHavePlayVolteFace().contains(traque.getInGameId())) { + traque.takeBackPlayedPlaceCards(); + } + else if(gameRoundVariables.ralliementIsActive() && gameRoundVariables.getPlayersWhoHasCaughtByCreature().contains(traque.getInGameId())) { + List placeCardsWhereIsJetonCreature = planet.findPlaceCardsWhereJetonIs(JetonSymbol.CREATURE); + traque.takeBackPlaceCard(placeCardsWhereIsJetonCreature); + traque.throwAwayPlaceCard(); + } + else{ + traque.throwAwayPlaceCard(); + } + } + creature.initializationJeton(); + int numberTrackingCardToDraw = creature.getMaxTrackingCards() - creature.trackingCardHandSize(); + creature.addTrackingCard(trackingCardPioche.draw(numberTrackingCardToDraw)); + sendDescription(); + } + + public void nextRound() { + if(gameRoundVariables.rescuePawnCanMoveForward()){ + board.moveForwardTraque(gameRoundVariables.getIncrementScoreTraque()); + if(gameRoundVariables.isPawnWillingnessOnBoard()) { + useWillingnessOnBoard(); + } + } + if(isFinish()) { + sendGameIsFinished(); + } + else{ + gameRoundVariables.reset(); + planet.reset(); + for(Traque t : traques) { + t.reset(); + } + creature.reset(); + applyNextRoundPowers(); + gameRoundVariables.resetAfterNextRoundPowersApplication(); + } + } + + /** + * Apply the next round powers and clear them + */ + private void applyNextRoundPowers() { + List newNextRoundPowers = new ArrayList<>(); + for(Power power : nextRoundPowers) { + if(power.getType().equals(PowerType.MODIFICATOR)) { + applyModificatorPower((PowerModifier) power); + } + else if(power.getType().equals(PowerType.RECURRENT)) { + PowerRecurrent powerRecurrent = (PowerRecurrent) power; + if(powerRecurrent.conditionIsTrue(this)) { + newNextRoundPowers.add(power); + powerRecurrent.apply(this); + } + } + } + nextRoundPowers = newNextRoundPowers; + } + + /** + * Apply a power modificator + */ + private void applyModificatorPower(PowerModifier power) { + PowerModifierType type = power.getModificatorType(); + Player player = getPlayer(power.getInGameIdPlayer()); + if(player.getTeam().equals(CREATURE)) { + if(type.equals(PowerModifierType.PLAYABLE_TRACKING_CARD)) { + creature.getRights().setMaxTrackingCardPlayable((int) power.getModifiedValue()); + } + } + else{ + Traque traque = (Traque) player; + switch (type) { + case PLAYABLE_PLACE_CARD: + traque.setMaxPlacesCardPlayable((int)power.getModifiedValue()); + break; + case CHOOSABLE_PLACE_CARD: + traque.setMaxPlacesCardChoosable((int)power.getModifiedValue()); + break; + case CHOOSABLE_VISIBLE_ADDITIONAL_PLACE_CARD: + int tmp = traque.getMaxPlacesCardChoosable() + ((int)power.getModifiedValue()); + traque.setMaxPlacesCardChoosable(tmp); + traque.setPlaceCardsVisible(((int)power.getModifiedValue())); + break; + case USE_FJORD_IN_PREVIOUS_ROUND: + gameRoundVariables.addplayersWhoUseFjordInPreviousRound(traque.getInGameId()); + default: + } + } + } + + /** + * Use willingness on board and give one willingness to the traque with the least willingness + */ + private void useWillingnessOnBoard() { + gameRoundVariables.usePawnWillingnessOnBoard(); + Traque traqueWithTheLeastOfWillingness = traques.get(0); + int minWillingness = traqueWithTheLeastOfWillingness.getNumberWillingness(); + for(Traque traque : traques) { + if(traque.getNumberWillingness() < minWillingness) { + minWillingness = traque.getNumberWillingness(); + traqueWithTheLeastOfWillingness = traque; + } + } + traqueWithTheLeastOfWillingness.addWillingness(1); + } + + /************************************* + * Choose action methods + ***********************************/ + + public List choosePlaceCardsAction(int idPlayer, int max, List placesCards) { + List cardList = new ArrayList<>(placesCards); + List cards = null; + boolean validChoice = false; + do { + try { + cards = chooseCardsAction(idPlayer, max, cardList).stream() + .map(c -> (PlaceCard) c) + .collect(Collectors.toList()); + validChoice = true; + } + catch (Exception e){ + //Bad Card type + } + } + while (!validChoice); + return cards; + } + + public List chooseSurvivalCardsAction(int idPlayer, int max, List survivalCards) { + List cardList = new ArrayList<>(survivalCards); + List cards = null; + boolean validChoice = false; + do { + try { + cards = chooseCardsAction(idPlayer, max, cardList).stream() + .map(c -> (SurvivalCard) c) + .collect(Collectors.toList()); + validChoice = true; + } + catch (Exception e){ + //Bad Card type + } + } + while (!validChoice); + return cards; + } + + public List chooseTrackingCardsAction(int idPlayer, int max, List trackingCards) { + List cardList = new ArrayList<>(trackingCards); + List cards = null; + boolean validChoice = false; + do { + try { + cards = chooseCardsAction(idPlayer, max, cardList).stream() + .map(c -> (TrackingCard) c) + .collect(Collectors.toList()); + validChoice = true; + } + catch (Exception e){ + //Bad Card type + } + } + while (!validChoice); + return cards; + } + + public List chooseCardsAction(int idPlayer, int max, List cardsToChoose) { + TAskAction askAction = createTActionForChooseCardsAction(max, cardsToChoose); + List cards = new ArrayList<>(); + List cardNames; + Action action; + do{ + action = askAction(idPlayer, askAction); + if(action.getActionType().equals(ActionType.CHOOSE_CARD)) { + cardNames = ((ActionChooseCard) action).getCards(); + cards = computeCardListFromCardNames(cardNames, cardsToChoose); + } + } while (cards.isEmpty() || cards.size() > max); + return cards; + } + + private TAskAction createTActionForChooseCardsAction(int max, List cardsToChoose){ + List params = new ArrayList<>(); + params.add(new TPair("number", ""+ max)); + for(int i = 0 ; i < cardsToChoose.size() ; ++i) { + params.add(new TPair("" + (i+1), cardsToChoose.get(i).getCardName().toString())); + } + String message = "Choose a maximum of " + max + "cards"; + return new TAskAction(CHOOSE_CARD.toString(), message, params); + } + public void sendPlaceCardsAction(int idPlayer, List cardsToShow) { + List cards = new ArrayList<>(cardsToShow); + sendCardsAction(idPlayer, cards); + } + + public void sendCardsAction(int idPlayer, List cardsToShow) { + TAskAction askAction = createTActionForSendCardsAction(cardsToShow); + sendAction(idPlayer, askAction); + } + + private TAskAction createTActionForSendCardsAction(List cardsToShow){ + List params = new ArrayList<>(); + for(int i = 0 ; i < cardsToShow.size() ; ++i) { + params.add(new TPair("" + (i+1), cardsToShow.get(i).getCardName().toString())); + } + String message = ""; + return new TAskAction(SHOW_CARD.toString(), message, params); + } + + private List computeCardListFromCardNames(List cardNames, List cardsToChoose){ + List chosenCards = new ArrayList<>(); + for(Card card : cardsToChoose){ + if(cardNames.contains(card.getCardName())){ + chosenCards.add(card); + } + } + return chosenCards; + } + + public int choosePower(int idPlayer, List powersDescription) { + List params = new ArrayList<>(); + String number; + for(int i = 0 ; i < powersDescription.size() ; ++i){ + number = "" + (i+1); + params.add(new TPair(number, powersDescription.get(i))); + } + String message = "Choose a power"; + TAskAction askAction = new TAskAction(CHOOSE_POWER.toString(), message, params); + int idPower = -1; + Action action; + do{ + action = askAction(idPlayer, askAction); + if(action.getActionType().equals(CHOOSE_POWER)) { + idPower = ((ActionChoosePower) action).getIdPowerChosen(); + } + } while (idPower < 0 || idPower >= powersDescription.size()); + return idPower; + } + + public int targetPlayer(int idPlayer) { + String message = "Choose one traque"; + TAskAction askAction = new TAskAction(TARGET_PLAYER.toString(), message, new ArrayList<>()); + int idTargetPlayer = -1; + Action action; + Set playersIdList = playersMap.keySet(); + do{ + action = askAction(idPlayer, askAction); + if(action.getActionType().equals(TARGET_PLAYER)) { + idTargetPlayer = ((ActionTargetPlayer) action).getIdPlayer(); + } + } while(! playersIdList.contains(idTargetPlayer) || creature.getInGameId() == idTargetPlayer); + return idTargetPlayer; + } + + public List choosePlace(int idPlayer, int number) { + String message = number > 1 ? "Choose" + number + " places" : "Choose 1 place"; + return choosePlace(idPlayer, number, message); + } + + public List choosePlace(int idPlayer, int number, String message) { + if(number <= 0 || number > 10) { + throw new IllegalArgumentException("number must be between 1 and 10"); + } + List params = new ArrayList<>(); + params.add(new TPair("number", number+"")); + TAskAction askAction = new TAskAction(CHOOSE_PLACE.toString(), message, params); + List places = new ArrayList<>(); + Action action; + do{ + action = askAction(idPlayer, askAction); + if(action.getActionType().equals(CHOOSE_PLACE)) { + places = ((ActionChoosePlace) action).getPlaces(); + } + } while(places.size() != number); + return places; + } + + public Pair movePlayer(int idPlayer) { + String message = "Move one traque"; + TAskAction askAction = new TAskAction(MOVE_PLAYER.toString(), message, new ArrayList<>()); + int idTargetPlayer = -1; + Place place = null; + Action action; + ActionMovePlayer actionMovePlayer; + Set playersIdList = playersMap.keySet(); + do{ + action = askAction(idPlayer, askAction); + if(action.getActionType().equals(MOVE_PLAYER)) { + actionMovePlayer = (ActionMovePlayer) action; + idTargetPlayer = actionMovePlayer.getIdPlayer(); + place = actionMovePlayer.getPlace(); + } + } while(! playersIdList.contains(idTargetPlayer) && creature.getInGameId() == idTargetPlayer); + return new Pair<>(idTargetPlayer, place); + } + + public Pair swapJetons(int idPlayer) { + TAskAction askAction = new TAskAction(MOVE_PLAYER.toString(), "", new ArrayList<>()); + JetonSymbol symbol1 = null; + JetonSymbol symbol2 = null; + Action action; + ActionSwapJeton actionSwapJeton; + do{ + action = askAction(idPlayer, askAction); + if(action.getActionType().equals(SWAP_JETONS)) { + actionSwapJeton = (ActionSwapJeton) action; + symbol1 = actionSwapJeton.getJetonSymbol1(); + symbol2 = actionSwapJeton.getJetonSymbol2(); + } + } while(symbol1 == null || symbol2 == null || symbol1 == symbol2); + return new Pair<>(symbol1, symbol2); + } + + public Map associateCardNamesToPlaces(int idPlayer, List cardsToAssociate) { + TAskAction askAction = createTActionForAssociateCardNamesToPlaces(cardsToAssociate); + Map cardNamePlaceMap = new HashMap<>(); + Map auxiliaryMap; + Action action; + do{ + action = askAction(idPlayer, askAction); + if(action.getActionType().equals(ActionType.ASSOCIATE_CARDNAMES_TO_PLACES)) { + auxiliaryMap = ((ActionAssociateCardNamesToPlaces) action).getCardNamePlaceMap(); + cardNamePlaceMap = computeMapCardToPlaceFromMapCardNamesToPlace(auxiliaryMap, cardsToAssociate); + } + } while (cardNamePlaceMap.size() != cardsToAssociate.size()); + return cardNamePlaceMap; + } + + private TAskAction createTActionForAssociateCardNamesToPlaces(List cardsToAssociate){ + List params = new ArrayList<>(); + for(int i = 0 ; i < cardsToAssociate.size() ; ++i) { + params.add(new TPair("" + (i+1), cardsToAssociate.get(i).getCardName().toString())); + } + String message = "Place the cards"; + return new TAskAction(ASSOCIATE_CARDNAMES_TO_PLACES.toString(), message, params); + } + + private Map computeMapCardToPlaceFromMapCardNamesToPlace(Map cardNamePlaceMap, List cards) { + Map map = new HashMap<>(); + for(Card card : cards){ + if(cardNamePlaceMap.containsKey(card.getCardName())){ + map.put(card, cardNamePlaceMap.get(card.getCardName())); + } + } + return map; + } + + private boolean isJetonCibleOnThisPlace(List places) { + List jetonCiblePlaces = planet.findPlacesWhereJetonIs(CIBLE); + Iterator iterator = places.iterator(); + boolean isJetonCibleOnThisPlace = false; + while (!isJetonCibleOnThisPlace && iterator.hasNext()) { + if(jetonCiblePlaces.contains(iterator.next())) { + isJetonCibleOnThisPlace = true; + } + } + return isJetonCibleOnThisPlace; + } + + public TDescription createDescription(int playerId) { + Player player = playersMap.getOrDefault(playerId, null); + if(player == null) { + throw new IllegalArgumentException(playerId + " is not a valid id"); + } + TScore tScore = Conversion.toTScore(board); + TPlanet tPlanet = Conversion.toTPlanet(planet); + List reserves = Conversion.toTCardReserveList(reserve); + List variables = Conversion.toTGameVariable(gameRoundVariables); + List traquesInformations; + TCreature creatureInformation = Conversion.toTCreature(creature); + if(state.equals(Phase.PHASE_3)) { + //places cards played became visible + traquesInformations = traques.stream().map(Conversion::toTTraquePlaceCardPlayedVisible).collect(Collectors.toList()); + } + else { + traquesInformations = traques.stream().map(Conversion::toTTraque).collect(Collectors.toList()); + } + THand tHand = Conversion.toTHand(player); + TPlayerTeam tPlayerTeam; + if(player.teamEqualsTo(CREATURE)) { + tPlayerTeam = new TPlayerTeam(CREATURE.toString()); + } + else { + tPlayerTeam = new TPlayerTeam(TRAQUE.toString()); + } + return new TDescription(tPlayerTeam, tHand, tScore, tPlanet, reserves, variables, traquesInformations, creatureInformation); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/GameInterface.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/GameInterface.java new file mode 100644 index 0000000000000000000000000000000000000000..0a554a9101ad7f1b07593bd0fe9a39ec05bf3b4d --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/GameInterface.java @@ -0,0 +1,110 @@ +package fr.univnantes.alma.server.game; + +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.action.Action; +import fr.univnantes.alma.server.game.item.card.Card; +import fr.univnantes.alma.server.game.item.jeton.PlacedJeton; +import fr.univnantes.alma.thrift.Response; +import fr.univnantes.alma.thrift.TAskAction; +import org.apache.thrift.TException; + +import java.util.List; + +public interface GameInterface { + + /** + * Test if the game is finish + * @return True if the game is finish, false otherwise + */ + public boolean isFinish(); + + /** + * Inform the game that the player has finished a phase + * @param playerId The game id of the player + * @param phase The phase finished by the player + * @throws IllegalArgumentException if the player need to play + */ + public Response playerHasFinished(int playerId, Phase phase); + + /** + * Inform the game that the player play a card + * @param playerId The game id of the player + * @param card The card played by the player + * @throws IllegalArgumentException if this action is not valid + */ + public Response playerPlayCard(int playerId, Card card); + + /** + * Inform the game that the player play card + * @param playerId The game id of the player + * @param cards The cards played by the player + * @throws IllegalArgumentException if this action is not valid + */ + public Response playerPlayCard(int playerId, List cards); + + /** + * Inform the game that the player place a jeton + * @param playerId The game id of the player + * @param jeton The jeton placed by the player + * @throws IllegalArgumentException if this action is not valid + */ + public Response playerPlaceJeton(int playerId, PlacedJeton jeton); + + /** + * Inform the game that the player place jetons + * @param playerId The game id of the player + * @param jetons The jetons placed by the player + * @throws IllegalArgumentException if this action is not valid + */ + public Response playerPlaceJeton(int playerId, List jetons); + + /** + * Inform the game that the player resist + * @param playerId The game id of the player + * @param number The number of willingnessPawn lost + * @throws IllegalArgumentException if this action is not valid + */ + public Response playerResist(int playerId, int number); + + /** + * Inform the game that the player give up + * @param playerId The game id of the player + * @throws IllegalArgumentException if this action is not valid + */ + public Response playerGiveUp(int playerId); + + /** + * Ask an action to a client + * @param inGameIdPlayer The id of player + * @param askedAction The asked action + * @return An Action + */ + public Action askAction(int inGameIdPlayer, TAskAction askedAction) throws TException; + + /** + * Send an action to a client + * @param inGameIdPlayer The id of player + * @param askedAction The asked action + */ + public void sendAction(int inGameIdPlayer, TAskAction askedAction); + + /** + * Send that the game start + */ + public void sendFirstRoundStart(); + + /** + * Send that a new phase has started + */ + public void sendStartPhase(); + + /** + * Send the game description + */ + public void sendDescription(); + + /** + * Send that the game is end + */ + public void sendGameIsFinished(); +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/GameRoundVariables.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/GameRoundVariables.java new file mode 100644 index 0000000000000000000000000000000000000000..26c968243d7f9cd105e2dcac863d0636d19a0ca8 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/GameRoundVariables.java @@ -0,0 +1,539 @@ +package fr.univnantes.alma.server.game; + +import fr.univnantes.alma.server.game.item.planet.Place; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; + +public class GameRoundVariables { + //Numbers + private int numberPawnWillingnessOnBoard; + + //Functions + private BiConsumer actionJetonCible; + private BiConsumer actionAdjacentPlaceJetonCible; + + //Modifiers + private int incrementScoreTraque; + private int numberWillingnessDecrementByJetonCreature; + private int numberMaxPlaceCardsGetByPlacePower; + + //Id players + private int idPlayerTargetByTrackingCardAnticipation; + private int idPlayerTargetByTrackingCardDomination; + private int idPlayerTargetByTrackingCardEpidemie; + + //Places + + private Place targetByAlerte; + + //Player ids list + private List playerWhoHaveLostAllWillingness; + private List playersWhoHaveResist; + private List playersCaughtByCreature; + private List playersCaughtByCreatureOnNexus; + private List playersWhoDodgeJetonArtemia; + private List playersWhoDodgeJetonCreature; + private List playersWhoDodgeJetonCible; + private List playersWhoHavePlayCavale; + private List playersWhoHavePlayDrone; + private List playersWhoHavePlayMimetisme; + private List playersWhoHavePlayPortail; + private List playersWhoHavePlayRegeneration; + private List playersWhoIsTargetRetraite; + private List playersWhoHavePlayVolteFace; + private List playersWhoUseFjordInPreviousRound; + + //Conditions + private boolean traqueCanResist; + private boolean traqueCanPickSurvivalCards; + private boolean jetonArtemiaIsActive; + private boolean jetonArtemiaMadeLoseOneWillingness; + private boolean rescuePawnCanMoveForward; + private boolean jetonCibleCanBeOnTwoAdjacentPlaces; + private boolean jetonCreatureCanBeOnTwoAdjacentPlaces; + private boolean jetonArtemiaCanBeOnTwoAdjacentPlaces; + private boolean defaussePlaceCardsAreHidden; + private boolean canPlaceJetonCreatureOnPlaces6To10; + private boolean survivalCardRalliementIsActive; + private boolean survivalCardRefugeIsActive; + private boolean canPlayTrackingCard; + private boolean inertieTrackingCardIsPlayed; + private boolean jetonCibleBlockPlace; + private boolean jetonCibleBlockAdjacentPlace; + private boolean jetonCibleAdjacentPlaceMoveTraque; + private boolean ralliementIsActive; + private boolean refugeIsActive; + + public GameRoundVariables() { + this.numberPawnWillingnessOnBoard = 0; + this.playerWhoHaveLostAllWillingness = new ArrayList<>(); + reset(); + } + + public void reset(){ + //Functions + this.actionJetonCible = (a,b) -> {}; + this.actionAdjacentPlaceJetonCible = (a,b) -> {}; + + //Modifiers + this.incrementScoreTraque = 1; + this.numberWillingnessDecrementByJetonCreature = 1; + this.numberMaxPlaceCardsGetByPlacePower = -1; + + //Id players + this.idPlayerTargetByTrackingCardAnticipation = -1; + this.idPlayerTargetByTrackingCardDomination = -1; + this.idPlayerTargetByTrackingCardEpidemie = -1; + + //Places + this.targetByAlerte = null; + + //Player ids list + this.playersWhoHaveResist = new ArrayList<>(); + this.playersCaughtByCreature = new ArrayList<>(); + this.playersCaughtByCreatureOnNexus = new ArrayList<>(); + this.playersWhoHavePlayCavale = new ArrayList<>(); + this.playersWhoDodgeJetonArtemia = new ArrayList<>(); + this.playersWhoHavePlayDrone = new ArrayList<>(); + this.playersWhoDodgeJetonCreature = new ArrayList<>(); + this.playersWhoHavePlayMimetisme = new ArrayList<>(); + this.playersWhoHavePlayPortail = new ArrayList<>(); + this.playersWhoHavePlayRegeneration = new ArrayList<>(); + this.playersWhoDodgeJetonCible = new ArrayList<>(); + this.playersWhoIsTargetRetraite = new ArrayList<>(); + this.playersWhoHavePlayVolteFace = new ArrayList<>(); + this.playersWhoUseFjordInPreviousRound = new ArrayList<>(); + + //Conditions + this.traqueCanResist = true; + this.traqueCanPickSurvivalCards = true; + this.jetonArtemiaIsActive = true; + this.jetonArtemiaMadeLoseOneWillingness = true; + this.rescuePawnCanMoveForward = true; + this.jetonCibleCanBeOnTwoAdjacentPlaces = false; + this.jetonCreatureCanBeOnTwoAdjacentPlaces = false; + this.jetonArtemiaCanBeOnTwoAdjacentPlaces = false; + this.defaussePlaceCardsAreHidden = false; + this.canPlaceJetonCreatureOnPlaces6To10 = true; + this.survivalCardRalliementIsActive = false; + this.survivalCardRefugeIsActive = false; + this.canPlayTrackingCard = true; + this.inertieTrackingCardIsPlayed = false; + this.jetonCibleBlockPlace = false; + this.jetonCibleBlockAdjacentPlace = false; + this.jetonCibleAdjacentPlaceMoveTraque = false; + + this.ralliementIsActive = false; + this.refugeIsActive = false; + } + + public void resetAfterNextRoundPowersApplication() { + this.playerWhoHaveLostAllWillingness = new ArrayList<>(); + } + + //Number methods + + public void addPawnWillingnessOnBoard(int number) { + numberPawnWillingnessOnBoard += number; + } + + public boolean isPawnWillingnessOnBoard() { + return numberPawnWillingnessOnBoard > 0; + } + + public void usePawnWillingnessOnBoard() { + if(numberPawnWillingnessOnBoard > 0) { + --numberPawnWillingnessOnBoard; + } + } + + public int getNumberPawnWillingnessOnBoard() { + return numberPawnWillingnessOnBoard; + } + + //Functions methods + + public BiConsumer getActionJetonCible() { + return actionJetonCible; + } + + public void setActionJetonCible(BiConsumer actionJetonCible) { + this.actionJetonCible = actionJetonCible; + } + + public BiConsumer getActionAdjacentPlaceJetonCible() { + return actionAdjacentPlaceJetonCible; + } + + public void setActionAdjacentPlaceJetonCible(BiConsumer actionAdjacentPlaceJetonCible) { + this.actionAdjacentPlaceJetonCible = actionAdjacentPlaceJetonCible; + } + + + //Modifiers methods + + public int getIncrementScoreTraque() { + return incrementScoreTraque; + } + + public void setIncrementScoreTraque(int incrementScoreTraque) { + this.incrementScoreTraque = incrementScoreTraque; + } + + public int getNumberWillingnessDecrementByJetonCreature() { + return numberWillingnessDecrementByJetonCreature; + } + + public void setNumberWillingnessDecrementByJetonCreature(int numberWillingnessDecrementByJetonCreature) { + this.numberWillingnessDecrementByJetonCreature = numberWillingnessDecrementByJetonCreature; + } + + public void addNumberWillingnessByJetonCreature() { + ++this.numberWillingnessDecrementByJetonCreature; + } + + public boolean numberMaxPlaceCardsGetByPlacePowerIsLimited() { + return numberMaxPlaceCardsGetByPlacePower != -1; + } + + public int getNumberMaxPlaceCardsGetByPlacePower() { + return numberMaxPlaceCardsGetByPlacePower; + } + + public void setNumberMaxPlaceCardsGetByPlacePower(int numberMaxPlaceCardsGetByPlacePower) { + this.numberMaxPlaceCardsGetByPlacePower = numberMaxPlaceCardsGetByPlacePower; + } + + //Id players + + public void setIdPlayerTargetByTrackingCardAnticipation(int idPlayerTargetByJetonCreature) { + this.idPlayerTargetByTrackingCardAnticipation = idPlayerTargetByJetonCreature; + } + + public int getIdPlayerTargetByTrackingCardAnticipation() { + return idPlayerTargetByTrackingCardAnticipation; + } + + + public boolean playerIsTargetByTrackingCardDomination() { + return idPlayerTargetByTrackingCardDomination != -1; + } + + public boolean playerIsTargetByTrackingCardEpidemie() { + return idPlayerTargetByTrackingCardEpidemie != -1; + } + + public int getIdPlayerTargetByTrackingCardDomination() { + return idPlayerTargetByTrackingCardDomination; + } + + public void setIdPlayerTargetByTrackingCardDomination(int idPlayerTargetByTrackingCardDomination) { + this.idPlayerTargetByTrackingCardDomination = idPlayerTargetByTrackingCardDomination; + } + + public int getIdPlayerTargetByTrackingCardEpidemie() { + return idPlayerTargetByTrackingCardEpidemie; + } + + public void setIdPlayerTargetByTrackingCardEpidemie(int idPlayerTargetByTrackingCardEpidemie) { + this.idPlayerTargetByTrackingCardEpidemie = idPlayerTargetByTrackingCardEpidemie; + } + + //Places + public boolean alerteIsActive() { + return targetByAlerte != null; + } + + public Place getTargetByAlerte() { + return targetByAlerte; + } + + public void setTargetByAlerte(Place targetByAlerte) { + this.targetByAlerte = targetByAlerte; + } + + //Player ids list + + public List getPlayerWhoHaveLostAllWillingness() { + return playerWhoHaveLostAllWillingness; + } + + public void addPlayerWhoHaveLostAllWillingness(Integer idPlayer) { + playerWhoHaveLostAllWillingness.add(idPlayer); + } + + public List getPlayersWhoHaveResist() { + return playersWhoHaveResist; + } + + public void addPlayersWhoHaveResist(Integer idPlayer) { + playersWhoHaveResist.add(idPlayer); + } + + public List getPlayersWhoHasCaughtByCreature() { + return playersCaughtByCreature; + } + + public void addPlayersWhoHasCaughtByCreature(Integer idPlayer) { + playersCaughtByCreature.add(idPlayer); + } + + public List getPlayersWhoHasCaughtByCreatureOnNexus() { + return playersCaughtByCreatureOnNexus; + } + + public void addPlayersWhoHasCaughtByCreatureOnNexus(Integer idPlayer) { + playersCaughtByCreatureOnNexus.add(idPlayer); + } + + public List getPlayersWhoHavePlayCavale() { + return playersWhoHavePlayCavale; + } + + public void addPlayerWhoHavePlayCavale(int idPlayer) { + this.playersWhoHavePlayCavale.add(idPlayer); + } + + public List getPlayersWhoDodgeJetonArtemia() { + return playersWhoDodgeJetonArtemia; + } + + public void addPlayersWhoDodgeJetonArtemia(int idPlayer) { + this.playersWhoDodgeJetonArtemia.add(idPlayer); + } + + public List getPlayersWhoHavePlayDrone() { + return playersWhoHavePlayDrone; + } + + public void addPlayersWhoHavePlayDrone(int idPlayer) { + this.playersWhoHavePlayDrone.add(idPlayer); + } + + public List getPlayersWhoDodgeJetonCreature() { + return playersWhoDodgeJetonCreature; + } + + public void addPlayersWhoDodgeJetonCreature(int idPlayer) { + this.playersWhoDodgeJetonCreature.add(idPlayer); + } + + public List getPlayersWhoHavePlayMimetisme() { + return playersWhoHavePlayMimetisme; + } + + public void addPlayersWhoHavePlayMimetisme(int idPlayer) { + this.playersWhoHavePlayMimetisme.add(idPlayer); + } + + public List getPlayersWhoHavePlayPortail() { + return playersWhoHavePlayPortail; + } + + public void addPlayersWhoHavePlayPortail(int idPlayer) { + this.playersWhoHavePlayPortail.add(idPlayer); + } + + public List getPlayersWhoHavePlayRegeneration() { + return playersWhoHavePlayRegeneration; + } + + public void addPlayersWhoHavePlayRegeneration(int idPlayer) { + this.playersWhoHavePlayRegeneration.add(idPlayer); + } + + public List getPlayersWhoDodgeJetonCible() { + return playersWhoDodgeJetonCible; + } + + public void addPlayersWhoDodgeJetonCible(int idPlayer) { + this.playersWhoDodgeJetonCible.add(idPlayer); + } + + public List getPlayersWhoIsTargetRetraite() { + return playersWhoIsTargetRetraite; + } + + public void addPlayersWhoIsTargetByRetraite(int idPlayer) { + this.playersWhoIsTargetRetraite.add(idPlayer); + } + + public List getPlayersWhoHavePlayVolteFace() { + return playersWhoHavePlayVolteFace; + } + + public void addPlayersWhoHavePlayVolteFace(int idPlayer) { + this.playersWhoHavePlayVolteFace.add(idPlayer); + } + + public List getplayersWhoUseFjordInPreviousRound() { + return playersWhoUseFjordInPreviousRound; + } + + public void addplayersWhoUseFjordInPreviousRound(int idPlayer) { + this.playersWhoUseFjordInPreviousRound.add(idPlayer); + } + + public boolean ralliementIsActive() { + return ralliementIsActive; + } + + public void setRalliementIsActive(boolean ralliementIsActive) { + this.ralliementIsActive = ralliementIsActive; + } + + public boolean refugeIsActive() { + return refugeIsActive; + } + + public void setRefugeIsActive(boolean refugeIsActive) { + this.refugeIsActive = refugeIsActive; + } + + //Conditions + public boolean isJetonArtemiaIsActive() { + return jetonArtemiaIsActive; + } + + public void disableJetonArtemia() { + jetonArtemiaIsActive = false; + } + + public void enableJetonArtemia() { + jetonArtemiaIsActive = true; + } + + public boolean traqueCanResist() { + return traqueCanResist; + } + + public void setTraqueCanResist(boolean traqueCanResist) { + this.traqueCanResist = traqueCanResist; + } + + public boolean traqueCanPickSurvivalCards() { + return traqueCanPickSurvivalCards; + } + + public void setTraqueCanPickSurvivalCards(boolean traqueCanPickSurvivalCards) { + this.traqueCanPickSurvivalCards = traqueCanPickSurvivalCards; + } + + public void setJetonArtemiaIsActive(boolean jetonArtemiaIsActive) { + this.jetonArtemiaIsActive = jetonArtemiaIsActive; + } + + public boolean jetonArtemiaMadeLoseOneWillingness() { + return jetonArtemiaMadeLoseOneWillingness; + } + + public void setJetonArtemiaMadeLoseOneWillingness(boolean jetonArtemiaMadeLoseOneWillingness) { + this.jetonArtemiaMadeLoseOneWillingness = jetonArtemiaMadeLoseOneWillingness; + } + + public boolean rescuePawnCanMoveForward() { + return rescuePawnCanMoveForward; + } + + public void setRescuePawnCanMoveForward(boolean rescuePawnCanMoveForward) { + this.rescuePawnCanMoveForward = rescuePawnCanMoveForward; + } + + public boolean jetonCibleCanBeOnTwoAdjacentPlaces() { + return jetonCibleCanBeOnTwoAdjacentPlaces; + } + + public void setJetonCibleCanBeOnTwoAdjacentPlaces(boolean jetonCibleCanBeOnTwoAdjacentPlaces) { + this.jetonCibleCanBeOnTwoAdjacentPlaces = jetonCibleCanBeOnTwoAdjacentPlaces; + } + + public boolean jetonCreatureCanBeOnTwoAdjacentPlaces() { + return jetonCreatureCanBeOnTwoAdjacentPlaces; + } + + public void setJetonCreatureCanBeOnTwoAdjacentPlaces(boolean jetonCreatureCanBeOnTwoAdjacentPlaces) { + this.jetonCreatureCanBeOnTwoAdjacentPlaces = jetonCreatureCanBeOnTwoAdjacentPlaces; + } + + public boolean jetonArtemiaCanBeOnTwoAdjacentPlaces() { + return jetonArtemiaCanBeOnTwoAdjacentPlaces; + } + + public void jetonArtemiaCanBeOnTwoAdjacentPlaces(boolean jetonArtemiaCanBeOnTwoAdjacentPlaces) { + this.jetonArtemiaCanBeOnTwoAdjacentPlaces = jetonArtemiaCanBeOnTwoAdjacentPlaces; + } + + public boolean defaussePlaceCardsAreHidden() { + return defaussePlaceCardsAreHidden; + } + + public void setDefaussePlaceCardsAreHidden(boolean defaussePlaceCardsAreHidden) { + this.defaussePlaceCardsAreHidden = defaussePlaceCardsAreHidden; + } + + public boolean canPlaceJetonCreatureOnPlaces6To10() { + return canPlaceJetonCreatureOnPlaces6To10; + } + + public void setCanPlaceJetonCreatureOnPlaces6To10(boolean canPlaceJetonCreatureOnPlaces6To10) { + this.canPlaceJetonCreatureOnPlaces6To10 = canPlaceJetonCreatureOnPlaces6To10; + } + + public boolean survivalCardRalliementIsActive() { + return survivalCardRalliementIsActive; + } + + public void setSurvivalCardRalliementIsActive(boolean survivalCardRalliementIsActive) { + this.survivalCardRalliementIsActive = survivalCardRalliementIsActive; + } + + public boolean survivalCardRefugeIsActive() { + return survivalCardRefugeIsActive; + } + + public void setSurvivalCardRefugeIsActive(boolean survivalCardRefugeIsActive) { + this.survivalCardRefugeIsActive = survivalCardRefugeIsActive; + } + + public boolean canPlayTrackingCard() { + return canPlayTrackingCard; + } + + public void setCanPlayTrackingCard(boolean canPlayTrackingCard) { + this.canPlayTrackingCard = canPlayTrackingCard; + } + + public boolean inertieTrackingCardIsPlayed() { + return inertieTrackingCardIsPlayed; + } + + public void setInertieTrackingCardIsPlayed(boolean inertieTrackingCardIsPlayed) { + this.inertieTrackingCardIsPlayed = inertieTrackingCardIsPlayed; + } + + public boolean isJetonCibleBlockPlace() { + return jetonCibleBlockPlace; + } + + public void setJetonCibleBlockPlace(boolean jetonCibleBlockPlace) { + this.jetonCibleBlockPlace = jetonCibleBlockPlace; + } + + public boolean isJetonCibleBlockAdjacentPlace() { + return jetonCibleBlockAdjacentPlace; + } + + public void setJetonCibleBlockAdjacentPlace(boolean jetonCibleBlockAdjacentPlace) { + this.jetonCibleBlockAdjacentPlace = jetonCibleBlockAdjacentPlace; + } + + public boolean isJetonCibleAdjacentPlaceMoveTraque() { + return jetonCibleAdjacentPlaceMoveTraque; + } + + public void setJetonCibleAdjacentPlaceMoveTraque(boolean jetonCibleAdjacentPlaceMoveTraque) { + this.jetonCibleAdjacentPlaceMoveTraque = jetonCibleAdjacentPlaceMoveTraque; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/PowerApplicator.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/PowerApplicator.java new file mode 100644 index 0000000000000000000000000000000000000000..739d2df3117ea3e71b4d22f6e0c8a61769714540 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/PowerApplicator.java @@ -0,0 +1,1936 @@ +package fr.univnantes.alma.server.game; + +import fr.univnantes.alma.data.DatabaseFactory; +import fr.univnantes.alma.common.NotAloneDatabase; +import fr.univnantes.alma.server.game.item.Reserve; +import fr.univnantes.alma.server.game.item.board.Board; +import fr.univnantes.alma.server.game.item.board.BoardColor; +import fr.univnantes.alma.server.game.item.card.*; +import fr.univnantes.alma.server.game.item.jeton.*; +import fr.univnantes.alma.server.game.item.pioche.Pioche; +import fr.univnantes.alma.server.game.item.planet.PawnType; +import fr.univnantes.alma.server.game.item.planet.Place; +import fr.univnantes.alma.server.game.item.planet.Planet; +import fr.univnantes.alma.server.game.item.player.Creature; +import fr.univnantes.alma.server.game.item.player.Player; +import fr.univnantes.alma.server.game.item.player.PlayerTeam; +import fr.univnantes.alma.server.game.item.player.Traque; +import fr.univnantes.alma.server.game.item.power.Power; +import fr.univnantes.alma.server.game.item.power.modifier.PowerModifier; +import fr.univnantes.alma.server.game.item.power.modifier.PowerModifierType; +import fr.univnantes.alma.server.game.item.power.recurrent.PowerRecurrent; +import fr.univnantes.alma.server.game.utilitary.Pair; + +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.BiPredicate; +import java.util.stream.Collectors; + +import static fr.univnantes.alma.server.game.item.card.CardName.*; + +public class PowerApplicator { + + private static final NotAloneDatabase database = DatabaseFactory.getDatabase(); + + private PowerApplicator(){} + + /** + * Apply the power of a PlayerCard on the player + * @param game The game + * @param idPlayer The id of the player + * @param playerCard The player card + */ + public static void applyPlayerCard(Game game, int idPlayer, PlayerCard playerCard){ + if(playerCard.getType().equals(Card.CardType.TRACKING)) { + applyTrackingCardPower(game, idPlayer, playerCard.getCardName()); + } + else{ + applySurvivalCardPower(game, idPlayer, playerCard.getCardName()); + } + } + + /** + * A traque resolve a PlaceCard + * @param game The game + * @param idPlayer The id of the traque + * @param placeCard The place card + */ + public static void resolvePlace(Game game, int idPlayer, PlaceCard placeCard) { + if(filterSpecialCaseBlockPlace(game, idPlayer, placeCard)) { + return; + } + if(filterJetonBlockPlace(game, idPlayer, placeCard)) { + return; + } + if(! isABlockedPlaceCard(game, placeCard)){ + if(game.getGameRoundVariables().getPlayersWhoHavePlayDrone().contains(idPlayer)) { + chooseCardFromReserve(game, idPlayer); + } + else if(game.getGameRoundVariables().getPlayersWhoHavePlayPortail().contains(idPlayer)) { + copyPowerOfOneAdjacentCard(game, idPlayer, placeCard); + } + else if(game.getGameRoundVariables().getPlayersWhoHavePlayRegeneration().contains(idPlayer)) { + copyPowerOfOneCardInDefausse(game, idPlayer); + } + else{ + if(game.getPlanet().isASurvivalCardOnPlace(placeCard)) { + Traque traque = (Traque) game.getPlayer(idPlayer); + traque.addSurvivalCard(game.getPlanet().takeSurvivalCardOnPlace(placeCard)); + } + applyPlaceCardPower(game, idPlayer, placeCard.getCardName()); + } + + } + } + + /** + * Apply the special case power and return true if place can't be resolved, false otherwise + * @param game The game + * @param idPlayer The id of player + * @param placeCard The place card resolve + * @return true if place can't be resolved, false otherwise + */ + private static boolean filterSpecialCaseBlockPlace(Game game, int idPlayer, PlaceCard placeCard) { + Planet planet = game.getPlanet(); + GameRoundVariables variables = game.getGameRoundVariables(); + if(variables.getPlayersWhoIsTargetRetraite().contains(idPlayer)) { + return true; + } + if(checkEpidemieCondition(game, placeCard)){ + if(idPlayer != variables.getIdPlayerTargetByTrackingCardEpidemie()){ + subWillingness(game, idPlayer, 1); + } + return true; + } + //Case where the SurvivalCard Alerte was played + Place place = planet.getPlaceDistribution().placeCardToPlace(placeCard); + if(checkAlerteCondition(variables, place)) { + //Do nothing + return true; + } + + if(checkIfAdjacentToJetonCible(game, placeCard)) { + if(variables.isJetonCibleAdjacentPlaceMoveTraque()) { + PlaceCard newPlaceCard = findPlaceCardWhereTheJetonCibleIsAndAdjacent(game, placeCard); + resolvePlace(game, idPlayer, newPlaceCard); + return true; + } + else{ + variables.getActionAdjacentPlaceJetonCible().accept(idPlayer, game); + } + } + return false; + } + + /** + * Check if a jeton is applied on the place card and return true if place can't be resolved, false otherwise + * @param game The game + * @param idPlayer The id of player + * @param placeCard The place card resolve + * @return true if place can't be resolve, false otherwise + */ + private static boolean filterJetonBlockPlace(Game game, int idPlayer, PlaceCard placeCard) { + Planet planet = game.getPlanet(); + GameRoundVariables variables = game.getGameRoundVariables(); + List jetonSymbols = planet.findJetonsSymbolsOnCard(placeCard); + + boolean canApplyArtemiaOnThisPlace = jetonSymbols.contains(JetonSymbol.ARTEMIA) && game.isJetonArtemiaIsActive(); + boolean canApplyCreatureOnThisPlace = jetonSymbols.contains(JetonSymbol.CREATURE); + boolean canApplyCibleOnThisPlace = jetonSymbols.contains(JetonSymbol.CIBLE); + + boolean blockPlace = false; + + //Jeton Artemia + if(canApplyArtemiaOnThisPlace && ! variables.getPlayersWhoDodgeJetonArtemia().contains(idPlayer)) { + applyJetonArtemia(game, idPlayer); + blockPlace = true; + } + + //Jeton Creature + if(canApplyCreatureOnThisPlace && ! variables.getPlayersWhoDodgeJetonCreature().contains(idPlayer)) { + if(variables.getPlayersWhoHavePlayMimetisme().contains(idPlayer)) { + game.getBoard().moveForwardTraque(); + } + else{ + applyJetonCreature(game, idPlayer, placeCard); + blockPlace = true; + } + } + + //Jeton Cible + if(canApplyCibleOnThisPlace && ! variables.getPlayersWhoDodgeJetonCible().contains(idPlayer)) { + applyJetonCible(game, idPlayer); + if(variables.isJetonCibleBlockPlace()) { + blockPlace = true; + } + } + return blockPlace; + } + + /** + * A traque apply the power of one place + * @param game The game + * @param idPlayer The id of the traque + * @param cardName The card name + */ + public static void applyPlaceCardPower(Game game, int idPlayer, CardName cardName) { + switch (cardName) { + case ANTRE: + applyPlaceAntre(game, idPlayer); + break; + case JUNGLE: + applyPlaceJungle(game, idPlayer); + break; + case RIVIERE: + applyPlaceRiviere(game, idPlayer); + break; + case PLAGE: + applyPlacePlage(game, idPlayer); + break; + case ROVER: + applyPlaceRover(game, idPlayer); + break; + case MARAIS: + applyPlaceMarais(game, idPlayer); + break; + case ABRI: + applyPlaceAbri(game, idPlayer); + break; + case EPAVE: + applyPlaceEpave(game, idPlayer); + break; + case SOURCE: + applyPlaceSource(game, idPlayer); + break; + case ARTEFACT: + applyPlaceArtefact(game, idPlayer); + break; + case NEXUS: + applyPlaceNexus(game, idPlayer); + break; + case OASIS: + applyPlaceOasis(game, idPlayer); + break; + case FJORD: + applyPlaceFjord(game, idPlayer); + break; + case DOME: + applyPlaceDome(game, idPlayer); + break; + case LABYRINTHE: + applyPlaceLabyrinthe(game, idPlayer); + break; + case MANGROVE: + applyPlaceMangrove(game, idPlayer); + break; + case ARCHIPEL: + applyPlaceArchipel(game, idPlayer); + break; + case POLE: + applyPlacePole(game, idPlayer); + break; + case FUNGI: + applyPlaceFungi(game, idPlayer); + break; + case PORTAIL: + applyPlacePortail(game, idPlayer); + break; + default: + throw new IllegalArgumentException(cardName + " is not a PlaceCard name"); + } + } + + public static void applyTrackingCardPower(Game game, int idPlayer, CardName cardName) { + switch (cardName) { + case ACHARNEMENT: + applyTrackingAcharnement(game); + break; + case ANGOISSE: + applyTrackingAngoisse(game); + break; + case ANTICIPATION: + applyTrackingAnticipation(game, idPlayer); + break; + case CATACLYSME: + applyTrackingCataclysme(game, idPlayer); + break; + case CHAMP_DE_FORCE: + applyTrackingChampDeForce(game); + break; + case CLONE: + applyTrackingClone(game); + break; + case DEPLOIEMENT: + applyTrackingDeploiement(game, idPlayer); + break; + case DESESPOIR: + applyTrackingDesespoir(game); + break; + case DETOUR: + applyTrackingDetour(game, idPlayer); + break; + case DOMINATION: + applyTrackingDomination(game, idPlayer); + break; + case EFFROI: + applyTrackingEffroi(game, idPlayer); + break; + case EMPRISE: + applyTrackingEmprise(game, idPlayer); + break; + case EPIDEMIE: + applyTrackingEpidemie(game, idPlayer); + break; + case FAILLE_TEMPORELLE: + applyTrackingFailleTemporelle(game); + break; + case FLASHBACK: + applyTrackingFlashback(game); + break; + case GARGANTUA: + applyTrackingGargantua(game); + break; + case HARCELEMENT: + applyTrackingHarcelement(game); + break; + case HURLEMENTS: + applyTrackingHurlement(game); + break; + case INERTIE: + applyTrackingInertie(game); + break; + case INTERFERENCES: + applyTrackingInterference(game); + break; + case INTUITION: + applyTrackingIntuition(game, idPlayer); + break; + case MAGNETISME: + applyTrackingMagnetisme(game); + break; + case MIRAGE: + applyTrackingMirage(game); + break; + case MUTATION: + applyTrackingMutation(game); + break; + case PSYCHOSE: + applyTrackingPsychose(game, idPlayer); + break; + case REMINISCENCE: + applyTrackingReminiscence(game, idPlayer); + break; + case REPERAGE: + applyTrackingReperage(game, idPlayer); + break; + case SABLES_MOUVANTS: + applyTrackingSablesMouvants(game); + break; + case SOIF_DE_SANG: + applyTrackingSoifDeSang(game); + break; + case STASE: + applyTrackingStase(game); + break; + case TELEPATHIE: + applyTrackingTelepathie(game, idPlayer); + break; + case TORNADE: + applyTrackingTornade(game, idPlayer); + break; + case TOXINE: + applyTrackingToxine(game); + break; + case UBIQUITE: + applyTrackingUbiquite(game, idPlayer); + break; + case VIRUS: + applyTrackingVirus(game); + break; + case ZONE_INTERDITE: + applyTrackingZoneInterdite(game); + break; + default: + throw new IllegalArgumentException(cardName + " is not a TrackingCard name"); + } + } + + public static void applySurvivalCardPower(Game game, int idPlayer, CardName cardName) { + switch (cardName) { + case ADRENALINE: + applySurvivalAdrenaline(game, idPlayer); + break; + case ALERTE: + applySurvivalAlerte(game, idPlayer); + break; + case AMPLIFICATEUR: + applySurvivalAmplificateur(game); + break; + case BROUILLAGE: + applySurvivalBrouillage(game); + break; + case CAVALE: + applySurvivalCavale(game, idPlayer); + break; + case DETECTEUR: + applySurvivalDetecteur(game, idPlayer); + break; + case DRONE: + applySurvivalDrone(game, idPlayer); + break; + case ENTRAVE: + applySurvivalEntrave(game); + break; + case EQUIPEMENT: + applySurvivalEquipement(game, idPlayer); + break; + case ESQUIVE: + applySurvivalEsquive(game, idPlayer); + break; + case FAUSSE_PISTE: + applySurvivalFaussePiste(game, idPlayer); + break; + case HOLOGRAMME: + applySurvivalHologramme(game, idPlayer); + break; + case LEURRE: + applySurvivalLeurre(game, idPlayer); + break; + case MIMETISME: + applySurvivalMimetisme(game, idPlayer); + break; + case NAVETTE: + applySurvivalNavette(game); + break; + case PLANQUES: + applySurvivalPlanques(game, idPlayer); + break; + case PORTAIL_SURVIVAL: + applySurvivalPortail(game, idPlayer); + break; + case RALLIEMENT: + applySurvivalRalliement(game); + break; + case REFUGE: + applySurvivalRefuge(game, idPlayer); + break; + case REGENERATION: + applySurvivalRegeneration(game, idPlayer); + break; + case RESISTANCE: + applySurvivalResistance(game, idPlayer); + break; + case RETRAITE: + applySurvivalRetraite(game, idPlayer); + break; + case RIPOSTE: + applySurvivalRiposte(game); + break; + case SACRIFICE: + applySurvivalSacrifice(game, idPlayer); + break; + case SECOND_SOUFFLE: + applySurvivalSecondSouffle(game, idPlayer); + break; + case SIXIEME_SENS: + applySurvivalSixiemeSens(game, idPlayer); + break; + case SYSTEME_D: + applySurvivalSystemeD(game); + break; + case TENACITE: + applySurvivalTenacite(game, idPlayer); + break; + case VACCIN: + applySurvivalVaccin(game); + break; + case VOLTE_FACE: + applySurvivalVolteFace(game, idPlayer); + break; + case VORTEX: + applySurvivalVortex(game, idPlayer); + break; + default: + throw new IllegalArgumentException(cardName + " is not a SurvivalCard name"); + } + } + + /** + * Apply the power of Jeton Artemia on the player + * @param game The game + * @param idPlayer The id of the player + */ + public static void applyJetonArtemia(Game game, int idPlayer) { + throwAwayPlaceCards(game, idPlayer, 1); + if(game.getGameRoundVariables().jetonArtemiaMadeLoseOneWillingness()) { + subWillingness(game, idPlayer, 1); + } + } + + /** + * Apply the power of Jeton Creature on the player + * @param game The game + * @param idPlayer The id of the player + * @param placeCard The placeCard where the traque was caught + */ + public static void applyJetonCreature(Game game, int idPlayer, PlaceCard placeCard) { + GameRoundVariables variables = game.getGameRoundVariables(); + variables.addPlayersWhoHasCaughtByCreature(idPlayer); + int numberWillingnessDecrement = game.getNumberWillingnessDecrementByJetonCreature(); + + if(placeCard.getCardName().equals(ANTRE)) { + ++numberWillingnessDecrement; + } + else if(placeCard.getCardName().equals(NEXUS)) { + variables.addPlayersWhoHasCaughtByCreatureOnNexus(idPlayer); + } + int numberTraqueCaught = variables.getPlayersWhoHasCaughtByCreature().size(); + int numberTraqueCaughtOnNexus = variables.getPlayersWhoHasCaughtByCreatureOnNexus().size(); + if(numberTraqueCaught <= 1) { + game.getBoard().moveForwardCreature(); + } + if(placeCard.getCardName().equals(NEXUS) && numberTraqueCaughtOnNexus <= 1) { + game.getBoard().moveForwardCreature(); + } + if(game.getIdPlayerTargetByTrackingCardAnticipation() == idPlayer) { + game.getBoard().moveForwardCreature(); + } + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + subWillingness(game, traque, numberWillingnessDecrement); + } + + /** + * Apply the power of Jeton Cible on the player + * @param game The game + * @param idPlayer The id of the player + */ + public static void applyJetonCible(Game game, int idPlayer) { + //Apply the jeton cible's power + game.getGameRoundVariables().getActionJetonCible().accept(idPlayer, game); + } + + /************************************* + * Apply places + ***********************************/ + + private static void applyPlaceAntre(Game game, int idPlayer) { + GameRoundVariables variables = game.getGameRoundVariables(); + boolean isLimited = variables.numberMaxPlaceCardsGetByPlacePowerIsLimited(); + List powersDescription = database.findPowersDescription(CardName.ANTRE); + int idPower = game.choosePower(idPlayer, powersDescription); + + if(!isLimited && idPower == 0) { + takeBackAllCardsFromDefausse(game, idPlayer); + } + //Copy Power is always the second power + else if (idPower == 1) { + copyPowerWhereJetonCreatureIs(game, idPlayer); + } + //Third power when no isLimited or first power when isLimited + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceJungle(Game game, int idPlayer) { + GameRoundVariables variables = game.getGameRoundVariables(); + boolean isLimited = variables.numberMaxPlaceCardsGetByPlacePowerIsLimited(); + List powersDescription = database.findPowersDescription(JUNGLE); + int idPower = game.choosePower(idPlayer, powersDescription); + if(idPower == 0) { + if(! isLimited + || game.getGameRoundVariables().getNumberMaxPlaceCardsGetByPlacePower() >= 2){ + takeBackCardsFromDefausse(game, idPlayer, 1); + } + takeBackCard(game, idPlayer, JUNGLE); + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceRiviere(Game game, int idPlayer) { + List powersDescription = database.findPowersDescription(RIVIERE); + int idPower = game.choosePower(idPlayer, powersDescription); + if(idPower == 0) { + Power power = new PowerModifier(idPlayer, PowerModifierType.CHOOSABLE_PLACE_CARD, 2); + game.addPowerForNextRound(power); + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlacePlage(Game game, int idPlayer) { + List powersDescription = database.findPowersDescription(PLAGE); + Planet planet = game.getPlanet(); + if(planet.canMovePlanetPawn()) { + int idPower = game.choosePower(idPlayer, powersDescription); + if(idPower == 0) { + planet.movePlanetPawn(); + if(planet.planetPawnIsActive()) { + applyPlanetPawn(game); + } + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + else{ + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceRover(Game game, int idPlayer) { + List powersDescription = database.findPowersDescription(ROVER); + Reserve reserve = game.getReserve(); + if(reserve.isNotEmpty()) { + int idPower = game.choosePower(idPlayer, powersDescription); + if(idPower == 0) { + chooseCardFromReserve(game, idPlayer); + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + else{ + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceMarais(Game game, int idPlayer) { + GameRoundVariables variables = game.getGameRoundVariables(); + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + List cardNames = traque.getPlaceCardsPlayed().stream().map(Card::getCardName).collect(Collectors.toList()); + boolean canTakeBackMarais = ! cardNames.contains(LABYRINTHE) || cardNames.contains(MARAIS); + int maxCardsToTakeBack = variables.numberMaxPlaceCardsGetByPlacePowerIsLimited() ? + variables.getNumberMaxPlaceCardsGetByPlacePower() - 1 : 2; + List powersDescription = maxCardsToTakeBack > 0 ? database.findPowersDescription(MARAIS) + : new ArrayList<>(Arrays.asList("Reprenez le marais", "Reprenez une carte de la défausse")); + int idPower = game.choosePower(idPlayer, powersDescription); + if(idPower == 0){ + if(canTakeBackMarais) { + traque.takeBackPlaceCard(database.findPlaceCard(MARAIS.toString())); + } + if(maxCardsToTakeBack > 0) { + takeBackCardsFromDefausse(game, idPlayer, maxCardsToTakeBack); + } + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceAbri(Game game, int idPlayer) { + if(game.getGameRoundVariables().traqueCanPickSurvivalCards()) { + List powersDescription = database.findPowersDescription(ABRI); + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + pickSurvivalCards(game, idPlayer, 2, 1); + } else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceEpave(Game game, int idPlayer) { + List powersDescription = database.findPowersDescription(EPAVE); + Planet planet = game.getPlanet(); + if(planet.canUseEpavePower()) { + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + planet.setEpavePowerToUsed(); + game.getBoard().moveForwardTraque(); + } else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceSource(Game game, int idPlayer) { + List powersDescription = database.findPowersDescription(SOURCE); + if(game.getGameRoundVariables().traqueCanPickSurvivalCards()) { + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + addWillingnessToAPlayer(game, idPlayer, 1); + } else if (idPower == 1) { + pickSurvivalCards(game, idPlayer, 1, 1); + } else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + else{ + powersDescription.remove(1); + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + addWillingnessToAPlayer(game, idPlayer, 1); + } else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + } + + private static void applyPlaceArtefact(Game game, int idPlayer) { + BoardColor color = game.getBoard().getBoardColor(); + List powersDescription = new ArrayList<>(); + switch (color) { + case BLUE: + powersDescription.add("Au prochain tour, jouez 2 cartes Lieu. Résolvez les deux Lieu individuellement dans l’ordre de votre choix en respectant les règles de la Phase 3."); + break; + case GREEN: + powersDescription.add("Défaussez 1 carte Lieu et déplacez 1 Traqué de votre choix sur un Lieu adjacent."); + break; + case RED: + powersDescription.add("Copiez les effets d'1 carte Lieu de votre défausse."); + break; + case YELLOW: + powersDescription = new ArrayList<>(Arrays.asList("Annulez les effets du jeton Artemia", "Récupérez 2 cartes Lieu de votre défausse.")); + break; + } + powersDescription.add("Récupérez 1 carte de votre défausse"); + switch (color) { + case BLUE: + applyPlaceBlueArtefact(game, idPlayer, powersDescription); + break; + case GREEN: + applyPlaceGreenArtefact(game, idPlayer, powersDescription); + break; + case RED: + applyPlaceRedArtefact(game, idPlayer, powersDescription); + break; + case YELLOW: + applyPlaceYellowArtefact(game, idPlayer, powersDescription); + break; + } + } + + private static void applyPlaceBlueArtefact(Game game, int idPlayer, List powersDescription) { + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + Power power1 = new PowerModifier(idPlayer, PowerModifierType.CHOOSABLE_PLACE_CARD, 2); + Power power2 = new PowerModifier(idPlayer, PowerModifierType.PLAYABLE_PLACE_CARD, 2); + game.addPowerForNextRound(power1); + game.addPowerForNextRound(power2); + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceGreenArtefact(Game game, int idPlayer, List powersDescription) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + if (!traque.getPlaceCards().isEmpty()) { + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + throwAwayPlaceCards(game, idPlayer, 1); + moveTraqueOnAdjacentPlace(game, idPlayer); + } else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + else{ + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceRedArtefact(Game game, int idPlayer, List powersDescription) { + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + copyPowerOfOneCardInDefausse(game, idPlayer); + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceYellowArtefact(Game game, int idPlayer, List powersDescription) { + GameRoundVariables variables = game.getGameRoundVariables(); + boolean isLimited = variables.numberMaxPlaceCardsGetByPlacePowerIsLimited(); + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + game.disableJetonArtemia(); + } + else if(idPower == 1 && (! isLimited || variables.getNumberMaxPlaceCardsGetByPlacePower() >= 2)) { + takeBackCardsFromDefausse(game, idPlayer, 2); + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceNexus(Game game, int idPlayer) { + List powersDescription = database.findPowersDescription(NEXUS); + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + copyPowerOfOneCardInInterval(game, idPlayer, 2, 5); + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceOasis(Game game, int idPlayer) { + GameRoundVariables variables = game.getGameRoundVariables(); + boolean isLimited = variables.numberMaxPlaceCardsGetByPlacePowerIsLimited(); + List powersDescription = database.findPowersDescription(OASIS); + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + traque.takeBackPlaceCard(database.findPlaceCard(OASIS.toString())); + int numberToTakeBack = traque.getMaxWillingness() - traque.getNumberWillingness(); + if(isLimited) { + numberToTakeBack = Math.min(variables.getNumberMaxPlaceCardsGetByPlacePower()-1, numberToTakeBack); + } + if(numberToTakeBack > 0){ + takeBackCardsFromDefausse(game, idPlayer, numberToTakeBack); + } + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceFjord(Game game, int idPlayer) { + List powersDescription = database.findPowersDescription(FJORD); + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + Power power = new PowerModifier(idPlayer, PowerModifierType.CHOOSABLE_VISIBLE_ADDITIONAL_PLACE_CARD, 1); + game.addPowerForNextRound(power); + power = new PowerModifier(idPlayer, PowerModifierType.USE_FJORD_IN_PREVIOUS_ROUND, null); + game.addPowerForNextRound(power); + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceDome(Game game, int idPlayer) { + List powersDescription = database.findPowersDescription(DOME); + Planet planet = game.getPlanet(); + if(planet.canMovePlanetPawn()) { + int idPower = game.choosePower(idPlayer, powersDescription); + if(idPower == 0) { + planet.movePlanetPawn(); + if(planet.planetPawnIsActive()) { + applyPlanetPawn(game); + } + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + else{ + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceLabyrinthe(Game game, int idPlayer) { + Planet planet = game.getPlanet(); + + //there is hidden cards and revealed card (between 6-10) + if(planet.isHiddenCards()) { + applyPlaceLabyrintheNotAllRevealed(game, idPlayer); + } + //all places are revealed + else{ + applyPlaceLabyrintheAllRevealed(game, idPlayer); + } + } + + private static void applyPlaceLabyrintheNotAllRevealed(Game game, int idPlayer) { + List powersDescription = Arrays.asList("Révéler un Lieu : retourner, face visible, une des 5 cartes Lieu 6 à 10 de la planète Artemia et activer son pouvoir","Prendre une carte Lieu de la réserve", "Récupérez 1 carte de votre défausse"); + int idPower = game.choosePower(idPlayer, powersDescription); + //reveal a place + if (idPower == 0) { + revealAHiddenPlaceAndApplyItsPower(game, idPlayer); + } + //take a non-revealed place + else if(idPower == 1){ + chooseCardFromReserve(game, idPlayer); + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceLabyrintheAllRevealed(Game game, int idPlayer) { + List powersDescription = Arrays.asList("Prendre une carte Lieu de la réserve", "Récupérez 1 carte de votre défausse"); + int idPower = game.choosePower(idPlayer, powersDescription); + if(idPower == 0){ + chooseCardFromReserve(game, idPlayer); + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceMangrove(Game game, int idPlayer) { + List powersDescription = database.findPowersDescription(MANGROVE); + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0 && ! game.getGameRoundVariables().numberMaxPlaceCardsGetByPlacePowerIsLimited()) { + swapHandAndDefaussePlaceCard(game, idPlayer); + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + traque.takeBackPlaceCard(database.findPlaceCard(MANGROVE.toString())); + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlaceArchipel(Game game, int idPlayer) { + if(game.getGameRoundVariables().traqueCanPickSurvivalCards()) { + List powersDescription = database.findPowersDescription(ARCHIPEL); + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + pickSurvivalCards(game, idPlayer, 1, 1); + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + if (traque.getPlaceCards().size() < 3) { + addWillingnessToAPlayer(game, idPlayer, 1); + } + } else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + private static void applyPlacePole(Game game, int idPlayer) { + List powersDescription = database.findPowersDescription(POLE); + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + Board board = game.getBoard(); + board.moveForwardTraque(2); + subWillingness(game, traque, 1); + List playedCards = traque.getPlaceCardsPlayed(); + PlaceCard pole = database.findPlaceCard(POLE.toString()); + playedCards.remove(pole); + game.getReserve().add(pole); + + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + + private static void applyPlaceFungi(Game game, int idPlayer) { + List powersDescription = database.findPowersDescription(FUNGI); + if(game.getGameRoundVariables().traqueCanPickSurvivalCards()) { + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + pickSurvivalCards(game, idPlayer, 1, 1); + } else if (idPower == 1) { + game.getGameRoundVariables().addPawnWillingnessOnBoard(2); + } else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + else{ + powersDescription.remove(0); + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + game.getGameRoundVariables().addPawnWillingnessOnBoard(2); + } else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + } + + private static void applyPlacePortail(Game game, int idPlayer) { + List powersDescription = database.findPowersDescription(PORTAIL); + int idPower = game.choosePower(idPlayer, powersDescription); + if (idPower == 0) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + traque.throwAwayPlaceCard(database.findPlaceCard(PORTAIL.toString())); + playNewPlaceCard(game, idPlayer); + } + else { + takeBackCardsFromDefausse(game, idPlayer, 1); + } + } + + /************************************* + * Apply tracking card + ***********************************/ + + private static void applyTrackingAcharnement(Game game) { + game.addNumberWillingnessByJetonCreature(); + } + + private static void applyTrackingAngoisse(Game game) { + game.setTraqueCanResist(false); + } + + private static void applyTrackingAnticipation(Game game, int idPlayer) { + int idTarget = game.targetPlayer(idPlayer); + game.setIdPlayerTargetByTrackingCardAnticipation(idTarget); + } + + private static void applyTrackingCataclysme(Game game, int idPlayer) { + Place place = game.choosePlace(idPlayer, 1).get(0); + game.getPlanet().blockPlaces(place); + } + + private static void applyTrackingChampDeForce(Game game) { + game.getGameRoundVariables().setJetonCibleBlockPlace(true); + game.getGameRoundVariables().setJetonCibleCanBeOnTwoAdjacentPlaces(true); + } + + private static void applyTrackingClone(Game game) { + BiConsumer action = (Integer id, Game g) -> { + Traque traque = (Traque) g.getPlayer(id); + List placeCards = traque.getPlaceCardsPlayed(); + List jetonCiblePlaces = g.getPlanet().findPlaceCardsWhereJetonIs(JetonSymbol.CIBLE); + PlaceCard card = null; + PlaceCard aux; + //Find the placeCard who the player has been caught + Iterator iterator = placeCards.iterator(); + while(card == null && iterator.hasNext()) { + aux = iterator.next(); + if(jetonCiblePlaces.contains(aux)){ + card = aux; + } + } + if(card != null){ + applyJetonCreature(g, id, card); + } + }; + game.getGameRoundVariables().setJetonCibleBlockPlace(true); + game.getGameRoundVariables().setActionJetonCible(action); + } + + private static void applyTrackingDeploiement(Game game, int idPlayer) { + game.getBoard().moveBackCreature(); + moveJetonOnAdjacentPlace(game, idPlayer, JetonSymbol.CREATURE); + } + + private static void applyTrackingDesespoir(Game game) { + game.setTraqueCanPickSurvivalCards(false); + } + + private static void applyTrackingDetour(Game game, int idPlayer) { + moveTraqueOnAdjacentPlace(game, idPlayer); + } + + private static void applyTrackingDomination(Game game, int idPlayer) { + int targetPlayer = game.targetPlayer(idPlayer); + BiConsumer action = (Integer id, Game g) -> throwAwayPlaceCards(g, id, 1); + + BiPredicate condition = (Integer id, Game g) -> { + GameRoundVariables variables = game.getGameRoundVariables(); + return ! variables.getPlayerWhoHaveLostAllWillingness().contains(id); + }; + + Power powerRecurrent = new PowerRecurrent(targetPlayer, action, condition); + game.addPowerForNextRound(powerRecurrent); + } + + private static void applyTrackingEffroi(Game game, int idPlayer) { + GameRoundVariables variables = game.getGameRoundVariables(); + List haveResistPlayers = variables.getPlayersWhoHaveResist(); + if(! haveResistPlayers.isEmpty()){ + int targetPlayer; + do{ + targetPlayer = game.targetPlayer(idPlayer); + } + while (! haveResistPlayers.contains(targetPlayer)); + checkPlayerIsNotCreature(game, targetPlayer); + Traque traque = (Traque) game.getPlayer(targetPlayer); + traque.fillWillingness(); + traque.takeBackAllPlaceCardFromDefausse(); + game.getBoard().moveForwardCreature(); + } + } + + private static void applyTrackingEmprise(Game game, int idPlayer) { + int targetPlayer = game.targetPlayer(idPlayer); + Traque traque = (Traque) game.getPlayersMap().get(targetPlayer); + int numberToThrowAway = traque.getPlaceCards().size() - 2; + if(numberToThrowAway > 0) { + throwAwayPlaceCards(game, targetPlayer, numberToThrowAway); + } + } + + private static void applyTrackingEpidemie(Game game, int idPlayer) { + int targetPlayer = game.targetPlayer(idPlayer); + game.getGameRoundVariables().setIdPlayerTargetByTrackingCardEpidemie(targetPlayer); + } + + private static void applyTrackingFailleTemporelle(Game game) { + BiConsumer action = (Integer id, Game g) -> { + game.getBoard().moveForwardCreature(); + game.getBoard().moveForwardTraque(); + }; + game.getGameRoundVariables().setActionJetonCible(action); + } + + private static void applyTrackingFlashback(Game game) { + Creature creature = game.getCreature(); + if(game.getTrackingCardPioche().getTrash().isEmpty()) { + return; + } + TrackingCard lastCardPlayed = game.getTrackingCardPioche().drawLastTrashCards(1).get(0); + creature.addTrackingCardToApplied(lastCardPlayed); + creature.addTrackingCard(lastCardPlayed); + creature.playTrackingCard(lastCardPlayed); + } + + private static void applyTrackingGargantua(Game game) { + game.getGameRoundVariables().setJetonCreatureCanBeOnTwoAdjacentPlaces(true); + } + + private static void applyTrackingHarcelement(Game game) { + game.getGameRoundVariables().setNumberMaxPlaceCardsGetByPlacePower(1); + } + + private static void applyTrackingHurlement(Game game) { + BiConsumer action = (Integer id, Game g) -> { + int chosenAction = g.choosePower(id, Arrays.asList("Défaussez 2 cartes", "Perdre 1 volonté")); + if(chosenAction == 0) { + throwAwayPlaceCards(game, id, 2); + } + else { + subWillingness(g, id, 1); + } + }; + game.getGameRoundVariables().setActionJetonCible(action); + } + + private static void applyTrackingInertie(Game game) { + game.getGameRoundVariables().setInertieTrackingCardIsPlayed(true); + } + + private static void applyTrackingInterference(Game game) { + Planet planet = game.getPlanet(); + if(planet.getPlaceDistribution().useCardDome()) { + planet.moveBackPlanetPawn(); + } + else{ + planet.blockPlaces(database.findPlaceCard(PLAGE.toString())); + if(!planet.getPlaceDistribution().useCardPole()){ + planet.blockPlaces(database.findPlaceCard(EPAVE.toString())); + } + } + } + + private static void applyTrackingIntuition(Game game, int idPlayer) { + Pioche pioche = game.getTrackingCardPioche(); + List cards = pioche.draw(3); + TrackingCard trackingCard = game.chooseTrackingCardsAction(idPlayer, 1, cards).get(0); + cards.remove(trackingCard); + pioche.throwAway(cards); + Creature creature = game.getCreature(); + creature.addTrackingCardToApplied(trackingCard); + creature.addTrackingCard(trackingCard); + creature.playTrackingCard(trackingCard); + } + + private static void applyTrackingMagnetisme(Game game) { + game.getGameRoundVariables().setJetonCibleAdjacentPlaceMoveTraque(true); + } + + private static void applyTrackingMirage(Game game) { + GameRoundVariables variables = game.getGameRoundVariables(); + variables.setJetonCibleCanBeOnTwoAdjacentPlaces(true); + variables.setJetonCibleBlockPlace(true); + } + + private static void applyTrackingMutation(Game game) { + game.getGameRoundVariables().setJetonArtemiaMadeLoseOneWillingness(true); + } + + private static void applyTrackingPsychose(Game game, int idPlayer) { + int targetPlayer = game.targetPlayer(idPlayer); + Traque traque = (Traque) game.getPlayer(targetPlayer); + List allCards = traque.getPlaceCards(); + int number = allCards.size() - 2; + List showed = new ArrayList<>(); + if(number > 0){ + showed = game.choosePlaceCardsAction(targetPlayer, number, allCards); + } + game.sendPlaceCardsAction(idPlayer, showed); + } + + private static void applyTrackingReminiscence(Game game, int idPlayer) { + List trash = game.getTrackingCardPioche().getTrash(); + TrackingCard card = game.chooseTrackingCardsAction(idPlayer, 1, trash).get(0); + Creature creature = game.getCreature(); + creature.addTrackingCard(card); + } + + private static void applyTrackingReperage(Game game, int idPlayer) { + Power power = new PowerModifier(idPlayer, PowerModifierType.PLAYABLE_TRACKING_CARD, 2); + game.addPowerForNextRound(power); + } + + private static void applyTrackingSablesMouvants(Game game) { + BiConsumer action = (Integer id, Game g) -> { + Traque traque = (Traque) g.getPlayer(id); + int number = traque.placeCardHandSize() - 2; + if(number > 0){ + throwAwayPlaceCards(g, id, number); + } + }; + game.getGameRoundVariables().setActionJetonCible(action); + } + + private static void applyTrackingSoifDeSang(Game game) { + BiConsumer action = (Integer id, Game g) -> { + Traque traque = (Traque) g.getPlayer(id); + traque.addWillingness(1); + }; + BiConsumer actionAdjacent = (Integer id, Game g) -> subWillingness(g, id, 1); + game.getGameRoundVariables().setActionJetonCible(action); + game.getGameRoundVariables().setActionAdjacentPlaceJetonCible(actionAdjacent); + } + + private static void applyTrackingStase(Game game) { + game.getGameRoundVariables().setRescuePawnCanMoveForward(false); + } + + private static void applyTrackingTelepathie(Game game, int idPlayer) { + PlaceCard placeCard = game.choosePlaceCardsAction(idPlayer, 1, game.getPlanet().getPlaceCardsInInterval(1, 10)).get(0); + int targetPlayer = game.targetPlayer(idPlayer); + Traque traque = (Traque) game.getPlayer(targetPlayer); + if(traque.placeCardHandSize() > 1) { + List hand = traque.getPlaceCards(); + int indice = new Random().nextInt(hand.size()); + PlaceCard randomCard = hand.get(indice); + traque.throwAwayPlaceCard(randomCard); + if(randomCard.equals(placeCard)) { + game.getBoard().moveForwardCreature(); + } + } + } + + private static void applyTrackingTornade(Game game, int idPlayer) { + moveJetonOnAdjacentPlace(game, idPlayer, JetonSymbol.ARTEMIA); + } + + private static void applyTrackingToxine(Game game) { + BiConsumer action = (Integer id, Game g) -> throwAwaySurvivalCards(g, id, 1); + GameRoundVariables variables = game.getGameRoundVariables(); + variables.setActionJetonCible(action); + variables.setJetonCibleBlockPlace(true); + } + + private static void applyTrackingUbiquite(Game game, int idPlayer) { + Pair pair = game.swapJetons(idPlayer); + game.getPlanet().swapJeton(pair.getKey(), pair.getValue()); + } + + private static void applyTrackingVirus(Game game) { + game.getGameRoundVariables().jetonArtemiaCanBeOnTwoAdjacentPlaces(true); + } + + private static void applyTrackingZoneInterdite(Game game) { + for(Traque traque : game.getTraques()) { + throwAwayPlaceCards(game, traque.getInGameId(), 1); + } + } + + /************************************* + * Apply survival card + ***********************************/ + + private static void applySurvivalAdrenaline(Game game, int idPlayer) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + traque.incrementWillingness(); + } + + private static void applySurvivalAlerte(Game game, int idPlayer) { + Place place = game.choosePlace(idPlayer, 1).get(0); + game.getGameRoundVariables().setTargetByAlerte(place); + } + + private static void applySurvivalAmplificateur(Game game) { + Planet planet = game.getPlanet(); + if(planet.getPlanetPawnType().equals(PawnType.BEACON)) { + if(! planet.planetPawnIsActive()) { + planet.forceMovePlanetPawn(); + game.getBoard().moveForwardTraque(); + } + } + else { + planet.movePlanetPawn(); + if(planet.planetPawnIsActive()) { + applyShieldPawn(game); + } + } + } + + private static void applySurvivalBrouillage(Game game) { + game.getGameRoundVariables().setDefaussePlaceCardsAreHidden(true); + } + + private static void applySurvivalCavale(Game game, int idPlayer) { + game.getGameRoundVariables().addPlayerWhoHavePlayCavale(idPlayer); + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + traque.setMaxPlacesCardChoosable(3); + } + + private static void applySurvivalDetecteur(Game game, int idPlayer) { + game.getGameRoundVariables().addPlayersWhoDodgeJetonArtemia(idPlayer); + } + + private static void applySurvivalDrone(Game game, int idPlayer) { + game.getGameRoundVariables().addPlayersWhoHavePlayDrone(idPlayer); + } + + private static void applySurvivalEntrave(Game game) { + game.getGameRoundVariables().setCanPlaceJetonCreatureOnPlaces6To10(false); + } + + private static void applySurvivalEquipement(Game game, int idPlayer) { + if(! game.getGameRoundVariables().traqueCanPickSurvivalCards()) { + return; + } + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + int power = 0; + Pioche pioche = game.getSurvivalCardPioche(); + if(! pioche.getTrash().isEmpty()) { + power = game.choosePower(idPlayer, Arrays.asList("Piochez une carte Survie", "Prenez la dernière carte survie défaussée")); + } + if(power == 0) { + traque.addSurvivalCard(pioche.draw()); + } + else { + traque.addSurvivalCard(pioche.drawLastTrashCards(1)); + } + } + + private static void applySurvivalEsquive(Game game, int idPlayer) { + game.getGameRoundVariables().addPlayersWhoDodgeJetonCreature(idPlayer); + } + + private static void applySurvivalFaussePiste(Game game, int idPlayer) { + moveJetonOnAdjacentPlace(game, idPlayer, JetonSymbol.CREATURE); + } + + private static void applySurvivalHologramme(Game game, int idPlayer) { + moveJetonOnAdjacentPlace(game, idPlayer, JetonSymbol.ARTEMIA); + } + + private static void applySurvivalLeurre(Game game, int idPlayer) { + Pair pair = game.swapJetons(idPlayer); + game.getPlanet().swapJeton(pair.getKey(), pair.getValue()); + takeBackCardsFromDefausse(game, idPlayer, 1); + } + + private static void applySurvivalMimetisme(Game game, int idPlayer) { + game.getGameRoundVariables().addPlayersWhoHavePlayMimetisme(idPlayer); + } + + private static void applySurvivalNavette(Game game) { + int scoreTraque = game.getBoard().getScore().getScoreTraque(); + if(scoreTraque == 1) { + game.getBoard().moveForwardTraque(); + } + } + + private static void applySurvivalPlanques(Game game, int idPlayer) { + List places = game.choosePlace(idPlayer, 2); + List survivalCards = game.getSurvivalCardPioche().draw(2); + Pair pair1 = new Pair<>(places.get(0), survivalCards.get(0)); + Pair pair2 = new Pair<>(places.get(1), survivalCards.get(1)); + game.getPlanet().putSurvivalCardOnPlace(Arrays.asList(pair1, pair2)); + } + + private static void applySurvivalPortail(Game game, int idPlayer) { + game.getGameRoundVariables().addPlayersWhoHavePlayPortail(idPlayer); + } + + private static void applySurvivalRalliement(Game game) { + game.getGameRoundVariables().setRalliementIsActive(true); + } + + private static void applySurvivalRefuge(Game game, int idPlayer) { + game.getGameRoundVariables().setRefugeIsActive(true); + Pair pair = chooseTwoAdjacentPlace(game, idPlayer); + PlacedJeton jetonCible = new PlacedJeton(JetonSymbol.CIBLE, Arrays.asList(pair.getKey(), pair.getValue())); + game.getPlanet().placeJeton(jetonCible); + game.getCreature().playJeton(JetonSymbol.CIBLE); + } + + private static void applySurvivalRegeneration(Game game, int idPlayer) { + game.getGameRoundVariables().addPlayersWhoHavePlayRegeneration(idPlayer); + } + + private static void applySurvivalResistance(Game game, int idPlayer) { + game.getGameRoundVariables().addPlayersWhoDodgeJetonCible(idPlayer); + } + + private static void applySurvivalRetraite(Game game, int idPlayer) { + moveTraqueOnAdjacentPlaceAndAddHimToRetraiteList(game, idPlayer); + } + + private static void applySurvivalRiposte(Game game) { + List trackingCards = game.getCreature().getTrackingCardHand(); + int maxToThrowAway = Math.min(2, trackingCards.size()); + List trashCards = new ArrayList<>(); + for(int i = 1 ; i <= maxToThrowAway ; ++i) { + trashCards.add(trackingCards.get(i)); + } + game.getCreature().removeTrackingCard(trashCards); + game.getTrackingCardPioche().throwAway(trashCards); + } + + private static void applySurvivalSacrifice(Game game, int idPlayer) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + if(!traque.getPlaceCards().isEmpty()) { + throwAwayPlaceCards(game, idPlayer, 1); + game.getGameRoundVariables().setCanPlayTrackingCard(false); + } + } + + private static void applySurvivalSecondSouffle(Game game, int idPlayer) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + if(traque.getPlaceCards().size() == 1) { + traque.takeBackAllPlaceCardFromDefausse(); + } + } + + private static void applySurvivalSixiemeSens(Game game, int idPlayer) { + takeBackCardsFromDefausse(game, idPlayer, 2); + } + + private static void applySurvivalSystemeD(Game game) { + Planet planet = game.getPlanet(); + if(!planet.planetPawnIsActive()) { + planet.forceMovePlanetPawn(); + } + } + + private static void applySurvivalTenacite(Game game, int idPlayer) { + Traque traque = (Traque) game.getPlayer(idPlayer); + traque.getRights().setNumberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist(1); + } + + private static void applySurvivalVaccin(Game game) { + game.getBoard().moveBackCreature(); + } + + private static void applySurvivalVolteFace(Game game, int idPlayer) { + game.getGameRoundVariables().addPlayersWhoHavePlayVolteFace(idPlayer); + } + + private static void applySurvivalVortex(Game game, int idPlayer) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + PlaceCard placeCard = game.choosePlaceCardsAction(idPlayer, 1, traque.getDefausse()).get(0); + traque.takeBackPlayedPlaceCards(); + traque.takeBackPlaceCard(placeCard); + traque.playPlaceCard(placeCard); + } + + /************************************* + * Powers + ***********************************/ + + /** + * Traque play a new place card + * @param game The game + * @param idPlayer The id of the traque + */ + public static void playNewPlaceCard(Game game, int idPlayer) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + List placeCards = traque.getPlaceCards(); + PlaceCard playedCard = game.choosePlaceCardsAction(idPlayer, 1, placeCards).get(0); + traque.playPlaceCard(playedCard); + resolvePlace(game, idPlayer, playedCard); + } + + /** + * Swap the defausse and the place cards in the hand of the traque + * @param game The game + * @param idPlayer The id of the traque + */ + public static void swapHandAndDefaussePlaceCard(Game game, int idPlayer) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + List newDefausse = traque.getPlaceCards(); + List newHand = traque.getDefausse(); + traque.setPlaceCards(newHand); + traque.setDefausse(newDefausse); + } + + /** + * Reveal a hidden place from the Reserve and apply its power + * @param game The game + * @param idPlayer The id of the traque + */ + public static void revealAHiddenPlaceAndApplyItsPower(Game game, int idPlayer) { + Planet planet = game.getPlanet(); + if(! planet.isHiddenCards()) { + return; + } + List hiddenPlaces = planet.getHiddenPlaces(); + Place revealedPlace; + do{ + revealedPlace = game.choosePlace(idPlayer, 1, "Choississez un lieu à révéler").get(0); + } + while (revealedPlace == null || ! hiddenPlaces.contains(revealedPlace)); + planet.revealPlace(revealedPlace); + PlaceCard placeCard = planet.placeToPlaceCard(revealedPlace); + applyPlaceCardPower(game, idPlayer, placeCard.getCardName()); + } + + /** + * Traque choose a traque and add them willingness + * @param game The game + * @param idPlayer Id of the traque + */ + public static void addWillingnessToAPlayer(Game game, int idPlayer, int numberWillingness) { + int idTargetPlayer = game.targetPlayer(idPlayer); + checkPlayerIsNotCreature(game, idTargetPlayer); + Traque traque = (Traque) game.getPlayer(idTargetPlayer); + traque.addWillingness(numberWillingness); + } + + /** + * Traque choose a not owned card from reserve + * @param game The game + * @param idPlayer Id of the traque + */ + public static void chooseCardFromReserve(Game game, int idPlayer) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + List reserveCards = game.getReserve().getNotEmptyPlaceCard(); + //remove all cards owned by the player + reserveCards.removeAll(traque.getPlaceCards()); + reserveCards.removeAll(traque.getDefausse()); + reserveCards.removeAll(traque.getPlaceCardsPlayed()); + //add the card + traque.addPlaceCard(game.choosePlaceCardsAction(idPlayer, 1, reserveCards)); + } + + /** + * Traque take back all this cards from defausse + * @param game The game + * @param idPlayer Id of the traque + */ + public static void takeBackAllCardsFromDefausse(Game game, int idPlayer) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + traque.takeBackAllPlaceCardFromDefausse(); + } + + /** + * Traque take back some cards from his defausse + * @param game The game + * @param idPlayer The id of the traque + * @param numberCards The number of cards to take back + */ + public static void takeBackCardsFromDefausse(Game game, int idPlayer, int numberCards) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + List placeCards = traque.getDefausse(); + if(! placeCards.isEmpty()) { + if(placeCards.size() <= numberCards) { + traque.takeBackAllPlaceCardFromDefausse(); + } + else { + List cardsTakeBack = game.choosePlaceCardsAction(idPlayer, numberCards, placeCards); + traque.takeBackPlaceCard(cardsTakeBack); + } + } + } + + /** + * Traque take back one card + * @param game The game + * @param idPlayer The id of the traque + * @param cardName The name of the card + */ + public static void takeBackCard(Game game, int idPlayer, CardName cardName) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + List placeCards = traque.getPlaceCardsPlayed(); + placeCards.addAll(traque.getDefausse()); + PlaceCard cardToTakeBack = null; + for(PlaceCard placeCard : placeCards) { + if(placeCard.getCardName().equals(cardName)) { + cardToTakeBack = placeCard; + } + } + if(cardToTakeBack != null) { + traque.takeBackPlaceCard(cardToTakeBack); + } + } + + /** + * Copy the power where the jeton Creature is + * @param game The game + * @param idPlayer The id of the traque + */ + public static void copyPowerWhereJetonCreatureIs(Game game, int idPlayer) { + List placeCards = game.getPlanet().placesWhereJetonCreatureIs(); + if(placeCards.isEmpty()) { + return; + } + else if(placeCards.size() > 1) { + placeCards = game.choosePlaceCardsAction(idPlayer, 1, placeCards); + } + PlaceCard card = placeCards.get(0); + if(card.getCardName() != ARTEFACT) { + applyPlaceCardPower(game, idPlayer, card.getCardName()); + } + } + + /** + * Copy the power of one chosen card in the player's defausse + * @param game The game + * @param idPlayer The id of the traque + */ + public static void copyPowerOfOneCardInDefausse(Game game, int idPlayer) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + List placeCards = traque.getDefausse(); + PlaceCard placeCard = game.choosePlaceCardsAction(idPlayer, 1, placeCards).get(0); + applyPlaceCardPower(game, idPlayer, placeCard.getCardName()); + } + + /** + * Copy the power of one chosen card between a and b + * @param game The game + * @param idPlayer The id of the traque + * @param a The start of interval + * @param b The end of interval + */ + public static void copyPowerOfOneCardInInterval(Game game, int idPlayer, int a, int b) { + List choosableCards = game.getPlanet().getPlaceCardsInInterval(a, b); + PlaceCard placeCard = game.choosePlaceCardsAction(idPlayer, 1, choosableCards).get(0); + applyPlaceCardPower(game, idPlayer, placeCard.getCardName()); + } + + /** + * Copy the power of one chosen card adjacent to place card + * @param game The game + * @param idPlayer The id of the traque + */ + public static void copyPowerOfOneAdjacentCard(Game game, int idPlayer, PlaceCard placeCard) { + Planet planet = game.getPlanet(); + List placeCards = game.getPlanet().getPlaceCardsInInterval(1, 10); + List choosableCards = new ArrayList<>(); + for(PlaceCard pc : placeCards){ + if(planet.isAdjacentPlaces(pc, placeCard) && ! pc.getCardName().equals(POLE)) { + choosableCards.add(pc); + } + } + PlaceCard copiedCard = game.choosePlaceCardsAction(idPlayer, 1, choosableCards).get(0); + applyPlaceCardPower(game, idPlayer, copiedCard.getCardName()); + } + + /** + * The traque pick survival cards + * @param game The game + * @param idPlayer The id of the traque + * @param numberCardsToPick The number of card to pick + * @param numberCardToKeep The number of card to keep + */ + public static void pickSurvivalCards(Game game, int idPlayer, int numberCardsToPick, int numberCardToKeep) { + if(!game.traqueCanPickSurvivalCards()){ + return; + } + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + List survivalCards = game.getSurvivalCardPioche().draw(numberCardsToPick); + if(numberCardToKeep > numberCardsToPick) { + throw new IllegalArgumentException("Number cards to keep must be greater than the number cards to pick"); + } + else if(numberCardsToPick == numberCardToKeep) { + traque.addSurvivalCard(survivalCards); + } + else{ + traque.addSurvivalCard(game.chooseSurvivalCardsAction(idPlayer, numberCardToKeep, survivalCards)); + } + } + + /** + * The traque must to throw away place cards + * @param game The game + * @param idPlayer The id of the traque + * @param numberCardsToThrowAway The number of cards to throw away + */ + public static void throwAwayPlaceCards(Game game, int idPlayer, int numberCardsToThrowAway) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + List placeCards = traque.getPlaceCards(); + numberCardsToThrowAway = Math.min(numberCardsToThrowAway, placeCards.size()); + List throwAwayCards = game.choosePlaceCardsAction(idPlayer, numberCardsToThrowAway, placeCards); + traque.throwAwayPlaceCard(throwAwayCards); + } + + /** + * The traque must to throw away survival cards + * @param game The game + * @param idPlayer The id of the traque + * @param numberCardsToThrowAway The number of cards to throw away + */ + public static void throwAwaySurvivalCards(Game game, int idPlayer, int numberCardsToThrowAway) { + checkPlayerIsNotCreature(game, idPlayer); + Traque traque = (Traque) game.getPlayer(idPlayer); + List survivalCards = traque.getSurvivalCardsHand(); + numberCardsToThrowAway = Math.min(numberCardsToThrowAway, survivalCards.size()); + List throwAwayCards = game.chooseSurvivalCardsAction(idPlayer, numberCardsToThrowAway, survivalCards); + traque.removeSurvivalCard(throwAwayCards); + } + + /** + * The traque move one traque on an adjacent place + * @param game The game + * @param idPlayer The id of the player + */ + public static void moveTraqueOnAdjacentPlace(Game game, int idPlayer) { + Pair pair; + Traque traque; + boolean isAdjacentPlace = false; + Planet planet = game.getPlanet(); + List placeCardsPlayed; + PlaceCard adjacent = null; + do{ + pair = game.movePlayer(idPlayer); + checkPlayerIsNotCreature(game, pair.getKey()); + traque = (Traque) game.getPlayer(pair.getKey()); + placeCardsPlayed = traque.getPlaceCardsPlayed(); + for(PlaceCard placeCard : placeCardsPlayed) { + if(planet.isAdjacentPlaces(placeCard, pair.getValue())) { + adjacent = placeCard; + isAdjacentPlace = true; + } + } + } + while (! isAdjacentPlace); + + List placeCardsAfterMoving = new ArrayList<>(placeCardsPlayed); + placeCardsAfterMoving.remove(adjacent); + placeCardsAfterMoving.add(planet.placeToPlaceCard(pair.getValue())); + traque.addPlaceCardsAfterMoving(placeCardsAfterMoving); + } + + /** + * The traque move one traque on an adjacent place and add him to the target list of Retraite + * @param game The game + * @param idPlayer The id of the player + */ + public static void moveTraqueOnAdjacentPlaceAndAddHimToRetraiteList(Game game, int idPlayer) { + Pair playerAndPlace; + Traque traque; + boolean isAdjacentPlace = false; + Planet planet = game.getPlanet(); + List placeCardsPlayed; + PlaceCard placeCardPlayedAndAdjacentToMovingPlace = null; + do{ + playerAndPlace = game.movePlayer(idPlayer); + checkPlayerIsNotCreature(game, idPlayer); + traque = (Traque) game.getPlayer(idPlayer); + placeCardsPlayed = traque.getPlaceCardsPlayed(); + for(PlaceCard placeCard : placeCardsPlayed) { + if(planet.isAdjacentPlaces(placeCard, playerAndPlace.getValue())) { + placeCardPlayedAndAdjacentToMovingPlace = placeCard; + isAdjacentPlace = true; + } + } + } + while (! isAdjacentPlace); + + List placeCardsAfterMoving = new ArrayList<>(placeCardsPlayed); + placeCardsAfterMoving.remove(placeCardPlayedAndAdjacentToMovingPlace); + placeCardsAfterMoving.add(planet.placeToPlaceCard(playerAndPlace.getValue())); + traque.addPlaceCardsAfterMoving(placeCardsAfterMoving); + game.getGameRoundVariables().addPlayersWhoIsTargetByRetraite(traque.getInGameId()); + } + + /** + * Move one Jeton on an adjacent place + * @param game The game + * @param idPlayer The id of the player + * @param symbol The symbol of the jeton + */ + public static void moveJetonOnAdjacentPlace(Game game, int idPlayer, JetonSymbol symbol) { + boolean isAdjacentPlace = false; + Planet planet = game.getPlanet(); + List places = planet.findPlacesWhereJetonIs(symbol); + Place adjacent; + do{ + adjacent = game.choosePlace(idPlayer, 1, "Choose place adjacent to JetonCreature").get(0); + for(Place place : places) { + isAdjacentPlace = isAdjacentPlace || Planet.isAdjacentPlaces(place, adjacent); + } + } + while (! isAdjacentPlace); + planet.removeJeton(symbol); + planet.placeJeton(new PlacedJeton(symbol, adjacent)); + } + + /** + * Traque choose two adjacent places + * @param game The game + * @param idPlayer The id of the player + */ + public static Pair chooseTwoAdjacentPlace(Game game, int idPlayer) { + boolean isAdjacentPlace; + List places; + Pair pair; + do{ + places = game.choosePlace(idPlayer, 2, "Choose two adjacent places"); + pair = new Pair<>(places.get(0), places.get(1)); + isAdjacentPlace = Planet.isAdjacentPlaces(pair.getKey(), pair.getValue()); + } + while (! isAdjacentPlace); + return pair; + } + + /************************************* + * Planet pawn + ***********************************/ + + /** + * Apply the power of game's planet pawn + * @param game The game + */ + public static void applyPlanetPawn(Game game) { + PawnType pawnType = game.getPlanet().getPlanetPawnType(); + switch (pawnType) { + case SHIELD: + applyShieldPawn(game); + break; + case BEACON: + applyBeaconPawn(game); + break; + default: + } + } + + public static void applyBeaconPawn(Game game) { + Board board = game.getBoard(); + board.moveForwardTraque(); + } + + public static void applyShieldPawn(Game game) { + Board board = game.getBoard(); + board.moveBackCreature(); + game.getPlanet().resetPawn(); + } + + /************************************* + * Auxiliaries + ***********************************/ + + public static void checkPlayerIsNotCreature(Game game, int idPlayer) { + Player player = game.getPlayer(idPlayer); + checkPlayerIsNotCreature(player); + } + + public static void checkPlayerIsNotCreature(Player player) { + if(player.getTeam().equals(PlayerTeam.CREATURE)) { + throw new IllegalArgumentException("Player must be a Traque"); + } + } + + public static boolean checkEpidemieCondition(Game game, PlaceCard placeCard) { + GameRoundVariables variables = game.getGameRoundVariables(); + if(variables.playerIsTargetByTrackingCardEpidemie()) { + Traque traque = (Traque) game.getPlayer(variables.getIdPlayerTargetByTrackingCardEpidemie()); + return traque.getPlaceCardsPlayed().contains(placeCard); + } + else{ + return false; + } + } + + public static boolean checkInertieCondition(Game game) { + GameRoundVariables variables = game.getGameRoundVariables(); + Planet planet = game.getPlanet(); + if(variables.inertieTrackingCardIsPlayed()) { + boolean isTraqueOnThePlaces = false; + List cardsTargetByJetonCible = planet.findPlaceCardsWhereJetonIs(JetonSymbol.CIBLE); + Iterator iteratorTraque = game.getTraques().iterator(); + while(!isTraqueOnThePlaces && iteratorTraque.hasNext()) { + Traque traque = iteratorTraque.next(); + List placeCardsPlayed = traque.getPlaceCardsPlayed(); + Iterator iteratorPlayed = placeCardsPlayed.iterator(); + while(!isTraqueOnThePlaces && iteratorPlayed.hasNext()) { + if(cardsTargetByJetonCible.contains(iteratorPlayed.next())) { + isTraqueOnThePlaces = true; + } + } + } + return isTraqueOnThePlaces; + } + else{ + return false; + } + } + + public static boolean checkAlerteCondition(GameRoundVariables variables, Place place) { + return variables.alerteIsActive() && variables.getTargetByAlerte().equals(place); + } + + public static boolean isABlockedPlaceCard(Game game, PlaceCard placeCard) { + Planet planet = game.getPlanet(); + return planet.isBlockedPlace(placeCard) || + checkEpidemieCondition(game, placeCard); + } + + public static boolean checkIfAdjacentToJetonCible(Game game, PlaceCard placeCard) { + Planet planet = game.getPlanet(); + List placesWhereJetonIs = planet.findPlacesWhereJetonIs(JetonSymbol.CIBLE); + boolean isAdjacent = false; + for(Place jetonPlace : placesWhereJetonIs){ + if(planet.isAdjacentPlaces(placeCard, jetonPlace)){ + isAdjacent = true; + } + } + return isAdjacent; + } + + public static PlaceCard findPlaceCardWhereTheJetonCibleIsAndAdjacent(Game game, PlaceCard placeCard) { + Planet planet = game.getPlanet(); + List placesWhereJetonIs = planet.findPlacesWhereJetonIs(JetonSymbol.CIBLE); + PlaceCard jetonCiblePlaceCard = null; + for(Place jetonPlace : placesWhereJetonIs){ + if(planet.isAdjacentPlaces(placeCard, jetonPlace)){ + jetonCiblePlaceCard = planet.placeToPlaceCard(jetonPlace); + } + } + return jetonCiblePlaceCard; + } + + public static void subWillingness(Game game, Traque traque, int numberWillingnessDecrement) { + traque.subWillingness(numberWillingnessDecrement); + if(traque.getNumberWillingness() <= 0) { + game.getGameRoundVariables().addPlayerWhoHaveLostAllWillingness(traque.getInGameId()); + traque.fillWillingness(); + game.getBoard().moveForwardCreature(); + } + } + + public static void subWillingness(Game game, int idTraque, int numberWillingnessDecrement) { + Traque traque = (Traque) game.getPlayer(idTraque); + subWillingness(game, traque, numberWillingnessDecrement); + } + +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/Room.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/Room.java new file mode 100644 index 0000000000000000000000000000000000000000..2c8c72cbfa644a737cf86f9580750d9866e0082e --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/Room.java @@ -0,0 +1,352 @@ +package fr.univnantes.alma.server.game; + +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.action.Action; +import fr.univnantes.alma.server.game.item.board.Board; +import fr.univnantes.alma.server.game.item.card.Card; +import fr.univnantes.alma.server.game.item.jeton.PlacedJeton; +import fr.univnantes.alma.server.game.item.planet.Planet; +import fr.univnantes.alma.server.game.utilitary.Pair; +import fr.univnantes.alma.server.game.utilitary.request.*; +import fr.univnantes.alma.server.user.User; +import fr.univnantes.alma.thrift.*; +import org.apache.thrift.TException; +import org.atlanmod.commons.log.Log; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import static fr.univnantes.alma.server.game.utilitary.Conversion.toAction; + +public class Room { + /** + * Stores arriving registrations. + */ + private final BlockingQueue requests; + + /** + * Counter used to increment player identifications. + */ + private final AtomicInteger playersCounter; + + /** + * Representes the maximum number of players + */ + private static final int MAX_PLAYERS = 7; + + /** + * Representes the minimum number of players + */ + private static final int MIN_PLAYERS = 2; + + /** + * The game id + */ + private String roomId; + + /** + * The creator of the the game + */ + private User creator; + + /** + * Stores the players id to their in game id. + */ + private final Map players; + + /** + * Stores the in game id to the user + */ + private final Map users; + + /** + * True if the game is start + */ + private boolean isStart; + + /** + * True if the game is close (ie : game creator stop the game) + */ + private boolean isClose; + + /** + * Thread use to manage the game + */ + private Thread play; + + /** + * The game + */ + private Game game; + + public Room(String roomId, User creator) { + this.requests = new ArrayBlockingQueue<>(MAX_PLAYERS); + this.playersCounter = new AtomicInteger(1); + this.creator = creator; + this.roomId = roomId; + + this.players = new HashMap<>(); + this.players.put(creator.getId(), 1); + this.users = new HashMap<>(); + this.users.put(1, creator); + this.isStart = false; + this.isClose = false; + this.play = new Thread(this::requestManagement); + this.play.start(); + } + + public String getRoomId() { + return roomId; + } + + public int getNumberPlayers() { + return users.size(); + } + + /** + * Set the game, usefull for tests + * @param game The game + */ + public void setGame(Game game) { + this.game = game; + } + + public boolean isCreator(User user){ + return this.creator.equals(user); + } + + public Response join(User user) { + int currentNumber = playersCounter.getAndIncrement(); + Response response; + if(isStart){ + response = new Response(false, "Game has started"); + } + else if(currentNumber + 1 <= MAX_PLAYERS){ + if(requests.offer(new GameJoinRequest(user, currentNumber+1))){ + response = new Response(true, "Join the game"); + } + else{ + response = new Response(false, "Unknown error. Please retry."); + } + } + else{ + response = new Response(false, "Room is full"); + } + return response; + } + + public Response start(User user, int creatureId, Board board, Planet planet) { + Response response; + if(!isCreator(user)) { + response = new Response(false, "Only the room creator can start the game"); + } + else if(players.size() < MIN_PLAYERS) { + response = new Response(false, "Need " + MIN_PLAYERS + " players"); + } + else if(!users.containsKey(creatureId)) { + response = new Response(false, creatureId + " is not a valid id"); + } + else{ + isStart = true; + this.game = new Game(playersToIdNamePairList(), creatureId, planet, board, this); + response = new Response(true, "Game start"); + } + return response; + } + + public TDescription getGameDescription(User user) { + return game.createDescription(userToInGameId(user)); + } + + public Response addRequest(GameRequest request) { + if(!userIsInRoom(request.getUser())) { + return new Response(false, "You must be in the room"); + } + else if(requests.offer(request)) { + return new Response(true, "Request sent"); + } + else { + return new Response(false, "Unable to offer this request"); + } + } + + private void requestManagement(){ + while(!isClose){ + try { + GameRequest request = requests.take(); + handleRequest(request); + } + catch (InterruptedException e) { + Log.error(e); + } + } + } + + private void handleRequest(GameRequest request) { + User user; + switch (request.getType()){ + case JOIN: + GameJoinRequest gameJoinRequest = (GameJoinRequest) request; + int inGameId = gameJoinRequest.getInGameId(); + user = gameJoinRequest.getUser(); + players.put(user.getId(), inGameId); + users.put(inGameId, user); + break; + case FINISH_PHASE: + GameFinishPhaseRequest gameFinishPhaseRequest = (GameFinishPhaseRequest) request; + user = gameFinishPhaseRequest.getUser(); + Phase phase = gameFinishPhaseRequest.getPhase(); + sendFinishPhase(user, phase); + break; + case PLAY_CARDS: + GamePlayCardsRequest gamePlayCardsRequest = (GamePlayCardsRequest) request; + user = gamePlayCardsRequest.getUser(); + List cards = gamePlayCardsRequest.getCards(); + sendPlayCards(user, cards); + break; + case PLACE_JETONS: + GamePlaceJetonsRequest gamePlaceJetonsRequest = (GamePlaceJetonsRequest) request; + user = gamePlaceJetonsRequest.getUser(); + List jetonList = gamePlaceJetonsRequest.getJetonList(); + sendPlaceJetons(user, jetonList); + break; + case RESIST: + GameResistRequest gameResistRequest = (GameResistRequest) request; + user = gameResistRequest.getUser(); + int number = gameResistRequest.getNumber(); + sendResist(user, number); + break; + case GIVE_UP: + GameGiveUpRequest gameGiveUpRequest = (GameGiveUpRequest) request; + user = gameGiveUpRequest.getUser(); + sendGiveUp(user); + break; + } + } + + /**************************** + * Game methods + ***************************/ + + public void sendFinishPhase(User user, Phase phase) { + int inGameId = userToInGameId(user); + Response response = game.playerHasFinished(inGameId, phase); + try { + user.sendResponse(response); + } catch (TException e) { + e.printStackTrace(); + } + } + + public void sendPlayCards(User user, List playerCards) { + int inGameId = userToInGameId(user); + Response response = game.playerPlayCard(inGameId, playerCards); + try { + user.sendResponse(response); + } catch (TException e) { + e.printStackTrace(); + } + } + + public void sendPlaceJetons(User user, List placedJetons) { + int inGameId = userToInGameId(user); + Response response = game.playerPlaceJeton(inGameId, placedJetons); + try { + user.sendResponse(response); + } catch (TException e) { + e.printStackTrace(); + } + } + + public void sendResist(User user, int number) { + int inGameId = userToInGameId(user); + Response response = game.playerResist(inGameId, number); + try { + user.sendResponse(response); + } catch (TException e) { + e.printStackTrace(); + } + } + + public void sendGiveUp(User user) { + int inGameId = userToInGameId(user); + Response response = game.playerGiveUp(inGameId); + try { + user.sendResponse(response); + } catch (TException e) { + e.printStackTrace(); + } + } + + /**************************** + * Players methods + ***************************/ + + public Action askAction(int inGameIdPlayer, TAskAction askedAction) throws TException { + User user = inGameIdToUser(inGameIdPlayer); + return toAction(user.askAction(askedAction)); + } + + public void sendAction(int inGameIdPlayer, TAskAction askedAction) throws TException { + User user = inGameIdToUser(inGameIdPlayer); + user.sendAction(askedAction); + } + + public void sendFirstRoundStart() throws TException { + for(User user : users.values()) { + user.sendFirstRoundStart(); + } + } + + public void sendStartPhase(int idPlayer, TPhase tPhase, TDescription description) throws TException { + users.get(idPlayer).sendStartPhase(tPhase, description); + } + + public void sendDescription(int idPlayer, TDescription description) throws TException { + users.get(idPlayer).sendGameDescription(description); + } + + public void sendGameIsFinished(TPlayerTeam winner) throws TException { + for(User user : users.values()) { + user.sendGameIsFinished(winner); + } + } + + /**************************** + * Auxiliaries methods + ***************************/ + + private User inGameIdToUser(int id) { + User user = users.getOrDefault(id, null); + if(user != null) { + return user; + } + else { + throw new IllegalArgumentException("Invalid in game id"); + } + } + + private int userToInGameId(User user) { + return players.get(user.getId()); + } + + private List> playersToIdNamePairList() { + return users.keySet().stream() + .map(this::playerToIdNamePair).collect(Collectors.toList()); + } + + private Pair playerToIdNamePair(int inGameId) { + String name = users.get(inGameId).getName(); + return new Pair<>(inGameId, name); + } + + private boolean userIsInRoom(User user) { + return players.containsKey(user.getId()); + } + +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/RoomFactory.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/RoomFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..d2e2bbf72b03ef42775879dc04a3dff3dac0715b --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/RoomFactory.java @@ -0,0 +1,25 @@ +package fr.univnantes.alma.server.game; + +import fr.univnantes.alma.server.user.User; + +import java.util.concurrent.atomic.AtomicInteger; + +public class RoomFactory { + + private RoomFactory(){} + + /** + * Counter used to increment room identifiers. + */ + private static final AtomicInteger idCounter = new AtomicInteger(1000); + + /** + * Create a game with unique id + * @param user The player + * @return The game + */ + public static Room createRoom(User user){ + String roomId = "" + idCounter.getAndIncrement(); + return new Room(roomId, user); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/RoomServiceController.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/RoomServiceController.java new file mode 100644 index 0000000000000000000000000000000000000000..da60bb17784168503aeda0aaf9d55f0e4c197019 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/RoomServiceController.java @@ -0,0 +1,144 @@ +package fr.univnantes.alma.server.game; + + +import fr.univnantes.alma.common.RoomService; +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.board.Board; +import fr.univnantes.alma.server.game.item.card.Card; +import fr.univnantes.alma.server.game.item.jeton.PlacedJeton; +import fr.univnantes.alma.server.game.item.planet.Planet; +import fr.univnantes.alma.server.game.utilitary.request.*; +import fr.univnantes.alma.server.user.User; +import fr.univnantes.alma.thrift.GameNotFound; +import fr.univnantes.alma.thrift.InvalidOperationException; +import fr.univnantes.alma.thrift.Response; +import fr.univnantes.alma.thrift.TDescription; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +public class RoomServiceController implements RoomService { + + private final Map rooms = new HashMap<>(); + private final Map players = new HashMap<>(); + + public Map getRooms() { + return rooms; + } + + public Map getPlayers() { + return players; + } + + public boolean addRoom(Room room) { + String roomId = room.getRoomId(); + if(rooms.containsKey(roomId)) { + return false; + } + else{ + rooms.put(roomId, room); + return true; + } + } + + @Override + public String createRoom(User user) throws InvalidOperationException { + if(players.containsKey(user)){ + throw new InvalidOperationException(300, "Player is already in a room"); + } + Room room = RoomFactory.createRoom(user); + String roomId = room.getRoomId(); + players.put(user, roomId); + this.rooms.put(roomId, room); + return roomId; + } + + @Override + public Response joinRoom(User user, String roomId) throws GameNotFound { + if(players.containsKey(user)){ + return new Response(false, "Player already in a room"); + } + Room room = this.rooms.get(roomId); + if(room == null) { + throw new GameNotFound(404, "Game " + roomId + " is inexistant"); + } + Response response = room.join(user); + if(response.state){ + players.put(user, roomId); + } + return response; + } + + @Override + public Response startGame(User user, int creatureId, Board board, Planet planet) { + if(! players.containsKey(user)){ + return new Response(false, "Player is not in a room"); + } + Room room = this.rooms.get(players.get(user)); + return room.start(user, creatureId, board, planet); + } + + @Override + public TDescription getGameDescription(User user) throws InvalidOperationException { + if(! players.containsKey(user)){ + throw new InvalidOperationException(200, "Player is not in a room"); + } + Room room = this.rooms.get(players.get(user)); + return room.getGameDescription(user); + } + + @Override + public void sendFinishPhase(User user, Phase phase) throws InvalidOperationException { + if(! players.containsKey(user)){ + throw new InvalidOperationException(200, "Player is not in a room"); + } + Room room = this.rooms.get(players.get(user)); + GameRequest request = new GameFinishPhaseRequest(user, phase); + room.addRequest(request); + } + + @Override + public void sendPlayCards(User user, List cards) throws InvalidOperationException { + if(! players.containsKey(user)){ + throw new InvalidOperationException(200, "Player is not in a room"); + } + Room room = this.rooms.get(players.get(user)); + GameRequest request = new GamePlayCardsRequest(user, cards); + room.addRequest(request); + } + + @Override + public void sendPlaceJetons(User user, List placedJetons) throws InvalidOperationException { + if(! players.containsKey(user)){ + throw new InvalidOperationException(200, "Player is not in a room"); + } + Room room = this.rooms.get(players.get(user)); + GameRequest request = new GamePlaceJetonsRequest(user, placedJetons); + room.addRequest(request); + } + + @Override + public void sendResist(User user, int number) throws InvalidOperationException { + if(! players.containsKey(user)){ + throw new InvalidOperationException(200, "Player is not in a room"); + } + Room room = this.rooms.get(players.get(user)); + GameRequest request = new GameResistRequest(user, number); + room.addRequest(request); + } + + @Override + public void sendGiveUp(User user) throws InvalidOperationException { + if(! players.containsKey(user)){ + throw new InvalidOperationException(200, "Player is not in a room"); + } + Room room = this.rooms.get(players.get(user)); + GameRequest request = new GameGiveUpRequest(user); + room.addRequest(request); + } + + +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/Phase.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/Phase.java new file mode 100644 index 0000000000000000000000000000000000000000..03ed67f57ccfd652a6f4d2bcf265af901eb8698f --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/Phase.java @@ -0,0 +1,16 @@ +package fr.univnantes.alma.server.game.item; + +public enum Phase { + PREPHASE_1, + PHASE_1, + POSTPHASE_1, + PREPHASE_2, + PHASE_2, + POSTPHASE_2, + PREPHASE_3, + PHASE_3, + POSTPHASE_3, + PREPHASE_4, + PHASE_4, + POSTPHASE_4, +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/Reserve.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/Reserve.java new file mode 100644 index 0000000000000000000000000000000000000000..61e199a32a014a03bfa588e0dab9ccc297dc2a59 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/Reserve.java @@ -0,0 +1,151 @@ +package fr.univnantes.alma.server.game.item; + +import fr.univnantes.alma.server.game.item.card.CardName; +import fr.univnantes.alma.server.game.item.card.PlaceCard; +import fr.univnantes.alma.server.game.utilitary.Pair; +import javassist.NotFoundException; + +import java.util.*; + +public class Reserve { + private final Map> placeCards; + + public Reserve(List cards, int playerNumber) { + placeCards = new HashMap<>(); + if(cards.size() != 5){ + throw new IllegalArgumentException("Need 5 cards"); + } + int number = copiesNumber(playerNumber); + for(PlaceCard c : cards){ + if((c.getNumber() < 6 && c.getNumber() > 10) || placeCards.containsKey(c.getNumber())){ + throw new IllegalArgumentException("Need each number once (6-10)"); + } + if (c.getCardName().equals(CardName.POLE)){ + placeCards.put(c.getNumber(), new Pair<>(c, 1)); + } + else { + placeCards.put(c.getNumber(), new Pair<>(c, number)); + } + } + } + + public Map> getPlaceCards() { + return placeCards; + } + + /** + * A List containing the list of PlaceCard with copies number greater than 0 + * @return + */ + public List getNotEmptyPlaceCard() { + Iterator iterator = placeCards.keySet().iterator(); + List list = new ArrayList<>(); + Pair pair; + while(iterator.hasNext()) { + pair = placeCards.get(iterator.next()); + if(pair.getValue() > 0) { + list.add(pair.getKey()); + } + } + return list; + } + + private int copiesNumber(int numberPlayer){ + if(numberPlayer >= 5){ + return 3; + } + else if(numberPlayer >= 3){ + return 2; + } + else{ + return 1; + } + } + + /** + * Test if Reserve contains place cards + * @return true if there is PlaceCard (cardNumber), false otherwise + */ + public boolean isNotEmpty(){ + Iterator iterator = placeCards.keySet().iterator(); + boolean response = false; + int copiesNumber; + while(!response && iterator.hasNext()) { + copiesNumber = placeCards.get(iterator.next()).getValue(); + response = response || copiesNumber > 0; + } + return response; + } + + /** + * Test if Reserve contains copies of the PlaceCard + * @param cardNumber The card number + * @return true if there is PlaceCard (cardNumber), false otherwise + */ + public boolean notEmpty(int cardNumber){ + if(cardNumber < 6 || cardNumber > 10){ + throw new IllegalArgumentException("CardNumber must be between 6 and 10"); + } + return placeCards.containsKey(cardNumber) && placeCards.get(cardNumber).getValue() > 0; + } + + /** + * Return an exemplar of place card + * @param cardNumber The card number + * @return A PlaceCard + * @throws NotFoundException if the PlaceCard (cardNumber) is empty + */ + public PlaceCard pick(int cardNumber) throws NotFoundException { + if(cardNumber < 6 || cardNumber > 10){ + throw new IllegalArgumentException("CardNumber must be between 6 and 10"); + } + if(placeCards.get(cardNumber).getValue() == 0){ + throw new NotFoundException("CardNumber is empty"); + } + else{ + int newNumber = placeCards.get(cardNumber).getValue() -1; + PlaceCard placeCard = placeCards.get(cardNumber).getKey(); + placeCards.replace(cardNumber, new Pair<>(placeCard, newNumber)); + return placeCard; + } + } + + public void add(PlaceCard placeCard) { + int cardNumber = placeCard.getNumber(); + if(cardNumber<= 5 || cardNumber > 10) { + throw new IllegalArgumentException("PlaceCard in reserve are place cards 6 to 10"); + } + int number = placeCards.get(cardNumber).getValue() + 1; + placeCards.put(cardNumber, new Pair<>(placeCard, number)); + } + + + @Override + public boolean equals(Object obj) { + if(obj == this){ + return true; + } + if(obj == null || ! (obj instanceof Reserve)){ + return false; + } + System.out.println("ok"); + Reserve reserve = (Reserve) obj; + return placeCards.equals(reserve.getPlaceCards()); + } + + @Override + public String toString() { + String res = "Reserve("; + Iterator>> iterator = placeCards.entrySet().iterator(); + Map.Entry> aux; + while (iterator.hasNext()) { + aux = iterator.next(); + res += aux.getValue().getKey() + "(" + aux.getValue().getValue() + ")"; + if(iterator.hasNext()) { + res += ", "; + } + } + res += ")"; + return res; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/Action.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/Action.java new file mode 100644 index 0000000000000000000000000000000000000000..afe37a286507e66cfece65bc20a8835ff237c3fd --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/Action.java @@ -0,0 +1,10 @@ +package fr.univnantes.alma.server.game.item.action; + +/** + * Represents all secondaries actions that a player can do + */ +public abstract class Action { + + public abstract ActionType getActionType(); + +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionAssociateCardNamesToPlaces.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionAssociateCardNamesToPlaces.java new file mode 100644 index 0000000000000000000000000000000000000000..cd89b331bb268b75f03ad33b544ef434e7bee7e7 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionAssociateCardNamesToPlaces.java @@ -0,0 +1,71 @@ +package fr.univnantes.alma.server.game.item.action; + +import fr.univnantes.alma.server.game.item.card.CardName; +import fr.univnantes.alma.server.game.item.planet.Place; +import fr.univnantes.alma.server.game.utilitary.Pair; +import fr.univnantes.alma.thrift.TPair; + +import java.util.*; + +import static fr.univnantes.alma.server.game.utilitary.Conversion.*; + +public class ActionAssociateCardNamesToPlaces extends Action { + private Map cardNamePlaceMap; + + public ActionAssociateCardNamesToPlaces(Map map){ + this.cardNamePlaceMap = map; + } + + public ActionAssociateCardNamesToPlaces(List params) { + this.cardNamePlaceMap = new HashMap<>(); + if(params.size() % 2 != 0){ + throw new IllegalArgumentException("Need a number pair of arguments"); + } + CardName cardName; + Place place; + try { + for(int i = 0 ; i < params.size() ; i = i+2) { + if(toTPairType(params.get(i).getKey()).equals(TPairType.PLACE) + && toTPairType(params.get(i+1).getKey()).equals(TPairType.CARD)){ + place = toPlace(params.get(i).getValue()); + cardName = toCardName(params.get(i+1).getValue()); + this.cardNamePlaceMap.put(cardName, place); + } + else if(toTPairType(params.get(i).getKey()).equals(TPairType.CARD) + && toTPairType(params.get(i+1).getKey()).equals(TPairType.PLACE)){ + cardName = toCardName(params.get(i).getValue()); + place = toPlace(params.get(i+1).getValue()); + this.cardNamePlaceMap.put(cardName, place); + } + else{ + throw new IllegalArgumentException("Need only places and cards (alternate)"); + } + } + } + catch (Exception e){ + throw new IllegalArgumentException("Need only places"); + } + + } + + public Map getCardNamePlaceMap() { + return cardNamePlaceMap; + } + + @Override + public ActionType getActionType() { + return ActionType.ASSOCIATE_CARDNAMES_TO_PLACES; + } + + @Override + public boolean equals(Object obj) { + if(obj == this){ + return true; + } + if(!(obj instanceof ActionAssociateCardNamesToPlaces)){ + return false; + } + ActionAssociateCardNamesToPlaces action = (ActionAssociateCardNamesToPlaces) obj; + return cardNamePlaceMap.equals(action.getCardNamePlaceMap()) && action.getActionType().equals(ActionType.ASSOCIATE_CARDNAMES_TO_PLACES); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionChooseCard.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionChooseCard.java new file mode 100644 index 0000000000000000000000000000000000000000..82dfeab0d01881412a1e34a7e29c2c84a3fed866 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionChooseCard.java @@ -0,0 +1,55 @@ +package fr.univnantes.alma.server.game.item.action; + +import fr.univnantes.alma.server.game.item.card.CardName; +import fr.univnantes.alma.thrift.TPair; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static fr.univnantes.alma.server.game.utilitary.Conversion.*; + +public class ActionChooseCard extends Action { + private List cards; + + public ActionChooseCard(List list){ + this.cards = list; + } + + public ActionChooseCard(Collection params) { + this.cards = new ArrayList<>(); + try { + for(TPair pair : params) { + if(!toTPairType(pair.getKey()).equals(TPairType.CARD)){ + throw new IllegalArgumentException("Need only cards"); + } + this.cards.add(toCardName(pair.getValue())); + } + } + catch (Exception e){ + throw new IllegalArgumentException("Need only cards"); + } + + } + + public List getCards() { + return cards; + } + + @Override + public ActionType getActionType() { + return ActionType.CHOOSE_CARD; + } + + @Override + public boolean equals(Object obj) { + if(obj == this){ + return true; + } + if(!(obj instanceof ActionChooseCard)){ + return false; + } + ActionChooseCard action = (ActionChooseCard) obj; + return cards.equals(action.getCards()) && action.getActionType().equals(ActionType.CHOOSE_CARD); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionChoosePlace.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionChoosePlace.java new file mode 100644 index 0000000000000000000000000000000000000000..64d1f3030d7c80f7ee457312eb54a5c596cda5ed --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionChoosePlace.java @@ -0,0 +1,56 @@ +package fr.univnantes.alma.server.game.item.action; + +import fr.univnantes.alma.server.game.item.planet.Place; +import fr.univnantes.alma.thrift.TPair; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import static fr.univnantes.alma.server.game.utilitary.Conversion.*; + +public class ActionChoosePlace extends Action { + private List places; + + public ActionChoosePlace(List list){ + this.places = list; + } + + public ActionChoosePlace(Collection params) { + this.places = new ArrayList<>(); + try { + for(TPair pair : params) { + if(!toTPairType(pair.getKey()).equals(TPairType.PLACE)){ + throw new IllegalArgumentException("Need only places"); + } + this.places.add(toPlace(pair.getValue())); + } + } + catch (Exception e){ + throw new IllegalArgumentException("Need only places"); + } + + } + + + public List getPlaces() { + return places; + } + + @Override + public ActionType getActionType() { + return ActionType.CHOOSE_PLACE; + } + + @Override + public boolean equals(Object obj) { + if(obj == this){ + return true; + } + if(!(obj instanceof ActionChoosePlace)){ + return false; + } + ActionChoosePlace action = (ActionChoosePlace) obj; + return places.equals(action.getPlaces()) && action.getActionType().equals(ActionType.CHOOSE_PLACE); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionChoosePower.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionChoosePower.java new file mode 100644 index 0000000000000000000000000000000000000000..26ef9dde575060420ba71067fcc6ba2cd656bb95 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionChoosePower.java @@ -0,0 +1,60 @@ +package fr.univnantes.alma.server.game.item.action; + +import fr.univnantes.alma.thrift.TPair; + +import java.util.List; + +import static fr.univnantes.alma.server.game.utilitary.Conversion.toTPairType; + +public class ActionChoosePower extends Action{ + private int idPowerChosen; + + public ActionChoosePower(int id){ + this.idPowerChosen = id; + } + + public ActionChoosePower(List params) { + boolean invalid = false; + if(params.size() != 1) { + invalid = true; + } + else{ + try{ + TPairType type = toTPairType(params.get(0).getKey()); + if(type.equals(TPairType.NUMBER)) { + this.idPowerChosen = Integer.parseInt(params.get(0).getValue()); + } + else{ + invalid = true; + } + } + catch (Exception e){ + invalid = true; + } + } + if(invalid){ + throw new IllegalArgumentException("ActionChoosePower need one number (integer)"); + } + } + + public int getIdPowerChosen() { + return idPowerChosen; + } + + @Override + public ActionType getActionType() { + return ActionType.CHOOSE_POWER; + } + + @Override + public boolean equals(Object obj) { + if(obj == this){ + return true; + } + if(!(obj instanceof ActionChoosePower)){ + return false; + } + ActionChoosePower action = (ActionChoosePower) obj; + return idPowerChosen == action.getIdPowerChosen() && action.getActionType().equals(ActionType.CHOOSE_POWER); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionMovePlayer.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionMovePlayer.java new file mode 100644 index 0000000000000000000000000000000000000000..16d40bba5f9082f89943f276635ceb21f98b6c2a --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionMovePlayer.java @@ -0,0 +1,74 @@ +package fr.univnantes.alma.server.game.item.action; + +import fr.univnantes.alma.server.game.item.planet.Place; +import fr.univnantes.alma.thrift.TPair; + +import java.util.List; + +import static fr.univnantes.alma.server.game.utilitary.Conversion.toPlace; +import static fr.univnantes.alma.server.game.utilitary.Conversion.toTPairType; + +public class ActionMovePlayer extends Action { + private int idPlayer; + private Place place; + + public ActionMovePlayer(int idPlayer, Place place) { + this.place = place; + this.idPlayer = idPlayer; + } + + public ActionMovePlayer(List params) { + boolean invalid = false; + if(params.size() != 2) { + invalid = true; + } + else{ + try{ + TPairType type1 = toTPairType(params.get(0).getKey()); + TPairType type2 = toTPairType(params.get(1).getKey()); + if(type1.equals(TPairType.PLAYER) && type2.equals(TPairType.PLACE)) { + this.idPlayer = Integer.parseInt(params.get(0).getValue()); + this.place = toPlace(params.get(1).getValue()); + } + else if(type1.equals(TPairType.PLACE) && type2.equals(TPairType.PLAYER)) { + this.place = toPlace(params.get(0).getValue()); + this.idPlayer = Integer.parseInt(params.get(1).getValue()); + } + else{ + invalid = true; + } + } + catch (Exception e){ + invalid = true; + } + } + if(invalid){ + throw new IllegalArgumentException("ActionTargetPlayer need one player id (integer)"); + } + } + + public int getIdPlayer() { + return idPlayer; + } + + public Place getPlace() { + return place; + } + + @Override + public ActionType getActionType() { + return ActionType.MOVE_PLAYER; + } + + @Override + public boolean equals(Object obj) { + if(obj == this){ + return true; + } + if(!(obj instanceof ActionMovePlayer)){ + return false; + } + ActionMovePlayer action = (ActionMovePlayer) obj; + return idPlayer == action.getIdPlayer() && place.equals(action.getPlace()) && action.getActionType().equals(ActionType.MOVE_PLAYER); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionSwapJeton.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionSwapJeton.java new file mode 100644 index 0000000000000000000000000000000000000000..e9fb6a1eeed150e9dafa8ab44b83d6331a73f0c2 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionSwapJeton.java @@ -0,0 +1,72 @@ +package fr.univnantes.alma.server.game.item.action; + +import fr.univnantes.alma.server.game.item.jeton.JetonSymbol; +import fr.univnantes.alma.thrift.TPair; + +import java.util.List; + +import static fr.univnantes.alma.server.game.utilitary.Conversion.*; + +public class ActionSwapJeton extends Action { + private JetonSymbol jetonSymbol1; + private JetonSymbol jetonSymbol2; + + public ActionSwapJeton(JetonSymbol j1, JetonSymbol j2){ + this.jetonSymbol1 = j1; + this.jetonSymbol2 = j2; + } + + public ActionSwapJeton(List params) { + boolean invalid = false; + if(params.size() != 2) { + invalid = true; + } + else{ + try{ + TPairType type1 = toTPairType(params.get(0).getKey()); + TPairType type2 = toTPairType(params.get(1).getKey()); + if(type1.equals(TPairType.JETON) && type2.equals(TPairType.JETON)) { + this.jetonSymbol1 = toJetonSymbol(params.get(0).getValue()); + this.jetonSymbol2 = toJetonSymbol(params.get(1).getValue()); + } + else{ + invalid = true; + } + } + catch (Exception e){ + invalid = true; + } + } + if(invalid){ + throw new IllegalArgumentException("ActionTargetPlayer need one player id (integer)"); + } + } + + public JetonSymbol getJetonSymbol1() { + return jetonSymbol1; + } + + public JetonSymbol getJetonSymbol2() { + return jetonSymbol2; + } + + @Override + public ActionType getActionType() { + return ActionType.SWAP_JETONS; + } + + @Override + public boolean equals(Object obj) { + if(obj == this){ + return true; + } + if(!(obj instanceof ActionSwapJeton)){ + return false; + } + ActionSwapJeton action = (ActionSwapJeton) obj; + JetonSymbol s1 = action.getJetonSymbol1(); + JetonSymbol s2 = action.getJetonSymbol2(); + boolean equals = (jetonSymbol1.equals(s1) && jetonSymbol2.equals(s2)) || (jetonSymbol1.equals(s2) && jetonSymbol2.equals(s1)); + return equals && action.getActionType().equals(ActionType.SWAP_JETONS); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionTargetPlayer.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionTargetPlayer.java new file mode 100644 index 0000000000000000000000000000000000000000..dcd9ce965b88dbd37f048f2ee7625f9486db7485 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionTargetPlayer.java @@ -0,0 +1,60 @@ +package fr.univnantes.alma.server.game.item.action; + +import fr.univnantes.alma.thrift.TPair; + +import java.util.List; + +import static fr.univnantes.alma.server.game.utilitary.Conversion.toTPairType; + +public class ActionTargetPlayer extends Action { + private int idPlayer; + + public ActionTargetPlayer(int id){ + this.idPlayer = id; + } + + public ActionTargetPlayer(List params) { + boolean invalid = false; + if(params.size() != 1) { + invalid = true; + } + else{ + try{ + TPairType type = toTPairType(params.get(0).getKey()); + if(type.equals(TPairType.PLAYER)) { + this.idPlayer = Integer.parseInt(params.get(0).getValue()); + } + else{ + invalid = true; + } + } + catch (Exception e){ + invalid = true; + } + } + if(invalid){ + throw new IllegalArgumentException("ActionTargetPlayer need one player id (integer)"); + } + } + + public int getIdPlayer() { + return idPlayer; + } + + @Override + public ActionType getActionType() { + return ActionType.TARGET_PLAYER; + } + + @Override + public boolean equals(Object obj) { + if(obj == this){ + return true; + } + if(!(obj instanceof ActionTargetPlayer)){ + return false; + } + ActionTargetPlayer action = (ActionTargetPlayer) obj; + return idPlayer == action.getIdPlayer() && action.getActionType().equals(ActionType.TARGET_PLAYER); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionType.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionType.java new file mode 100644 index 0000000000000000000000000000000000000000..73dce7b05218677c269ee1f6c83bf743fb79061d --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/ActionType.java @@ -0,0 +1,5 @@ +package fr.univnantes.alma.server.game.item.action; + +public enum ActionType{ + CHOOSE_POWER, TARGET_PLAYER, MOVE_PLAYER, CHOOSE_CARD, CHOOSE_PLACE, SWAP_JETONS, ASSOCIATE_CARDNAMES_TO_PLACES, SHOW_CARD +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/TPairType.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/TPairType.java new file mode 100644 index 0000000000000000000000000000000000000000..475f603e42efb78ad9d3298d374b79c5016e5868 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/action/TPairType.java @@ -0,0 +1,5 @@ +package fr.univnantes.alma.server.game.item.action; + +public enum TPairType { + NUMBER, CARD, PLACE, JETON, PLAYER +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/board/Board.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/board/Board.java new file mode 100644 index 0000000000000000000000000000000000000000..59e2b2ce75981341c89df888e27100d2d74ccb0b --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/board/Board.java @@ -0,0 +1,164 @@ +package fr.univnantes.alma.server.game.item.board; + +import fr.univnantes.alma.server.game.item.player.PlayerTeam; + +/** + * Represents the board of the game. + * Contains the score, the distribution of Artemia squares and the color chosen for the game + */ +public class Board { + /** + * The score + */ + private Score score; + + /** + * The distribution of Artemia squares + */ + private BoardDistribution boardDistribution; + + /** + * The color chosen for the game + */ + private BoardColor boardColor; + + public Board(BoardDistribution boardDistribution, BoardColor boardColor){ + this.boardColor = boardColor; + this.boardDistribution = boardDistribution; + this.score = new Score(); + } + + public Board(BoardDistribution boardDistribution, BoardColor boardColor, Score score){ + this.boardColor = boardColor; + this.boardDistribution = boardDistribution; + this.score = score; + } + + public Score getScore() { + return score; + } + + public BoardDistribution getBoardDistribution() { + return boardDistribution; + } + + public BoardColor getBoardColor() { + return boardColor; + } + + /** + * Test if the rescue pawn is on Artemia square + * @return True if the rescue pawn is on Artemia square, false otherwise + */ + public boolean isArtemiaSquare(){ + switch (boardDistribution){ + case FRONT: + return score.scoreTraqueGreaterThanBase() && score.getScoreTraque()%2 == 1; + case BACK: + return 0 < score.getScoreTraque() && score.getScoreTraque() <= 6; + default: + return false; + } + } + + @Override + public String toString() { + return "Score(Traque : " + getScoreTraque() + " ; Creature : " + getScoreCreature() + ")"; + } + + /*********************************** + * Score methods + ************************************/ + + /** + * Initialize the score in function of playerNumber + * @param playerNumber The number of players + */ + public void initializeScore(int playerNumber){ + this.score = new Score(playerNumber); + } + + /** + * Test if one team has the maximum score + * @return true if one team has the maximum score, else false + */ + public boolean isFinish(){ + return score.isFinish(); + } + + public int getScoreTraque() { + return score.getScoreTraque(); + } + + public int getScoreCreature() { + return score.getScoreCreature(); + } + + /** + * @return the team closest to victory + */ + public PlayerTeam actualBestTeam(){ + return score.actualBestTeam(); + } + + public PlayerTeam winner(){ + return score.winner(); + } + + /** + * Move forward the score of Traque of delta square + */ + public void moveForwardTraque(int delta){ + score.moveForwardTraque(delta); + } + + /** + * Move forward the score of Traque of one square + */ + public void moveForwardTraque(){ + score.moveForwardTraque(1); + } + + + /** + * Move back the score of Traque of delta square + */ + public void moveBackTraque(int delta){ + score.moveBackTraque(delta); + } + + /** + * Move back the score of Traque of one square + */ + public void moveBackTraque(){ + score.moveBackTraque(1); + } + + /** + * Move forward the score of Traque of delta square + */ + public void moveForwardCreature(int delta){ + score.moveForwardCreature(delta); + } + + /** + * Move forward the score of Traque of one square + */ + public void moveForwardCreature(){ + score.moveForwardCreature(1); + } + + /** + * Move back the score of Traque of delta square + */ + public void moveBackCreature(int delta){ + score.moveBackCreature(delta); + } + + /** + * Move back the score of Traque of one square + */ + public void moveBackCreature(){ + score.moveBackCreature(1); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/board/BoardColor.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/board/BoardColor.java new file mode 100644 index 0000000000000000000000000000000000000000..67f8d1899784f78c449e19ee93f9bc48c89feee7 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/board/BoardColor.java @@ -0,0 +1,8 @@ +package fr.univnantes.alma.server.game.item.board; + +public enum BoardColor { + BLUE, + GREEN, + RED, + YELLOW +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/board/BoardDistribution.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/board/BoardDistribution.java new file mode 100644 index 0000000000000000000000000000000000000000..4fd6dd5c7923ebce4dd6f71e35821498dddc32e9 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/board/BoardDistribution.java @@ -0,0 +1,6 @@ +package fr.univnantes.alma.server.game.item.board; + +public enum BoardDistribution { + FRONT, + BACK +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/board/Score.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/board/Score.java new file mode 100644 index 0000000000000000000000000000000000000000..3bc9b2d427d8a54995dfcc26c75a636ab3631888 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/board/Score.java @@ -0,0 +1,143 @@ +package fr.univnantes.alma.server.game.item.board; + + +import fr.univnantes.alma.server.game.item.player.PlayerTeam; + +public class Score { + + private static final int BASE_TRAQUE = 13; + private static final int BASE_CREATURE = 7; + + private int scoreTraque; + private int scoreCreature; + private PlayerTeam winner; + + public Score(){ + this.scoreCreature = 0; + this.scoreTraque = 0; + this.winner = null; + } + + public Score(int playerNumber){ + playerNumber -= 2; //delta score + this.scoreCreature = BASE_CREATURE + playerNumber; + this.scoreTraque = BASE_TRAQUE + playerNumber; + this.winner = null; + } + + public Score(int scoreCreature, int scoreTraque){ + this.scoreCreature = scoreCreature; + this.scoreTraque = scoreTraque; + this.winner = null; + } + + public int getScoreTraque() { + return scoreTraque; + } + + public int getScoreCreature() { + return scoreCreature; + } + + /** + * Test if one team has the maximum score + * @return true if one team has the maximum score, else false + */ + public boolean isFinish(){ + return scoreCreature <= 0 || scoreTraque <= 0; + } + + /** + * @return the team closest to victory + */ + public PlayerTeam actualBestTeam(){ + if(scoreTraque < scoreCreature){ + return PlayerTeam.TRAQUE; + } + else{ + return PlayerTeam.CREATURE; + } + } + + /** + * @return the team closest to victory + */ + public PlayerTeam winner(){ + return winner; + } + + /** + * @return true if the score of creature is greater than the base + */ + public boolean scoreCreatureGreaterThanBase(){ + //lower because score is represented by a decremental counter + return scoreCreature < BASE_CREATURE; + } + + /** + * @return true if the score of traque is greater than the base + */ + public boolean scoreTraqueGreaterThanBase(){ + //lower because score is represented by a decremental counter + return scoreTraque < BASE_TRAQUE; + } + + /** + * Move forward the score of Traque + */ + public void moveForwardTraque(int delta){ + //decrement because score is represented by a decremental counter + if(!isFinish()) { + scoreTraque -= delta; + } + if(scoreTraque <= 0){ + winner = PlayerTeam.TRAQUE; + } + } + + /** + * Move back the score of Traque + */ + public void moveBackTraque(int delta){ + //increment because score is represented by a decremental counter + scoreTraque += delta; + } + + /** + * Move forward the score of Traque + */ + public void moveForwardCreature(int delta){ + //decrement because score is represented by a decremental counter + if(!isFinish()) { + scoreCreature -= delta; + } + if(scoreCreature <= 0){ + winner = PlayerTeam.CREATURE; + } + } + + /** + * Move back the score of Traque + */ + public void moveBackCreature(int delta){ + //increment because score is represented by a decremental counter + scoreCreature += delta; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || obj.getClass() != this.getClass()) { + return false; + } + Score score = (Score) obj; + return (score.getScoreTraque() == this.scoreTraque && score.getScoreCreature() == this.scoreCreature); + } + + @Override + public String toString() { + return "Score{Creature : " + scoreCreature + " ; Traques : " + scoreTraque + "}"; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/Card.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/Card.java new file mode 100644 index 0000000000000000000000000000000000000000..5b63fb45079d2032ad3e9803c8d764e16424938e --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/Card.java @@ -0,0 +1,51 @@ +package fr.univnantes.alma.server.game.item.card; + + +public abstract class Card { + public enum CardType {SURVIVAL, PLACE, TRACKING} + protected CardName cardName; + protected String name; + protected String description; + + public Card(CardName cardName, String name, String description) { + this.name = name; + this.cardName = cardName; + this.description = description; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public CardName getCardName() { + return cardName; + } + + public abstract CardType getType(); + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || obj.getClass() != this.getClass()) { + return false; + } + Card card = (Card) obj; + return card.getCardName().equals(this.cardName); + } + + @Override + public String toString() { + return cardName.toString(); + } + + @Override + public int hashCode() { + return cardName.hashCode(); + } +} \ No newline at end of file diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/CardName.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/CardName.java new file mode 100644 index 0000000000000000000000000000000000000000..fb853f8bffc2c7c6704bc440755acdfb3bad3f65 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/CardName.java @@ -0,0 +1,17 @@ +package fr.univnantes.alma.server.game.item.card; + +public enum CardName { + //PlaceCard + ANTRE, JUNGLE, RIVIERE, PLAGE, ROVER, MARAIS, ABRI, EPAVE, SOURCE, ARTEFACT, + NEXUS, OASIS, FJORD, DOME, LABYRINTHE, MANGROVE, ARCHIPEL, POLE, FUNGI, PORTAIL, + //TrackingCard + ACHARNEMENT, ANGOISSE, ANTICIPATION, CATACLYSME, CHAMP_DE_FORCE, CLONE, DEPLOIEMENT, DESESPOIR, DETOUR, DOMINATION, EFFROI, + EMPRISE, EPIDEMIE, FAILLE_TEMPORELLE, FLASHBACK, GARGANTUA, HARCELEMENT, HURLEMENTS, INERTIE, INTERFERENCES, INTUITION, + MAGNETISME, MIRAGE, MUTATION, PSYCHOSE, REMINISCENCE, REPERAGE, SABLES_MOUVANTS, SOIF_DE_SANG, STASE, TELEPATHIE, + TORNADE, TOXINE, UBIQUITE, VIRUS, ZONE_INTERDITE, + //SURVIVAL_CARD + ADRENALINE, ALERTE, AMPLIFICATEUR, BROUILLAGE, CAVALE, DETECTEUR, DRONE, ENTRAVE, EQUIPEMENT, ESQUIVE, + FAUSSE_PISTE, HOLOGRAMME, LEURRE, MIMETISME, NAVETTE, PLANQUES, PORTAIL_SURVIVAL, RALLIEMENT, REFUGE, REGENERATION, + RESISTANCE, RETRAITE, RIPOSTE, SACRIFICE, SECOND_SOUFFLE, SIXIEME_SENS, SYSTEME_D, TENACITE, VACCIN, VOLTE_FACE, + VORTEX +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/PlaceCard.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/PlaceCard.java new file mode 100644 index 0000000000000000000000000000000000000000..0cbc24a1d417a7552dbc3b34654952aa4a0acbc9 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/PlaceCard.java @@ -0,0 +1,31 @@ +package fr.univnantes.alma.server.game.item.card; + +public class PlaceCard extends Card { + private int number; + private String imageUrl; + private String color; + + public PlaceCard(CardName cardName, String name, String description, int number, String imageUrl, String color){ + super(cardName, name, description); + this.number = number; + this.color = color; + this.imageUrl = imageUrl; + } + + public int getNumber() { + return number; + } + + public String getImageUrl() { + return imageUrl; + } + + public String getColor() { + return color; + } + + @Override + public CardType getType() { + return CardType.PLACE; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/PlayerCard.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/PlayerCard.java new file mode 100644 index 0000000000000000000000000000000000000000..e38925f44057b6391f7d3a455e912025103d445c --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/PlayerCard.java @@ -0,0 +1,28 @@ +package fr.univnantes.alma.server.game.item.card; + +import fr.univnantes.alma.server.game.item.Phase; + +public abstract class PlayerCard extends Card { + protected Phase phase; + protected Phase phaseToApply; + + public PlayerCard(CardName cardName, String name, String description, Phase phase){ + super(cardName, name, description); + this.phase = phase; + this.phaseToApply = phase; + } + + public PlayerCard(CardName cardName, String name, String description, Phase phase, Phase phaseToApply){ + super(cardName, name, description); + this.phase = phase; + this.phaseToApply = phaseToApply; + } + + public Phase getPhase() { + return phase; + } + + public Phase getPhaseToApply() { + return phaseToApply; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/SurvivalCard.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/SurvivalCard.java new file mode 100644 index 0000000000000000000000000000000000000000..b387efcddd49dc96ec693c78a90bb073adf552d8 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/SurvivalCard.java @@ -0,0 +1,15 @@ +package fr.univnantes.alma.server.game.item.card; + +import fr.univnantes.alma.server.game.item.Phase; + +public class SurvivalCard extends PlayerCard { + + public SurvivalCard(CardName cardName, String name, String description, Phase phase){ + super(cardName, name, description, phase); + } + + @Override + public CardType getType() { + return CardType.SURVIVAL; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/TrackingCard.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/TrackingCard.java new file mode 100644 index 0000000000000000000000000000000000000000..563aa9e467a7b91d64c997db0db5a39edb774fe3 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/card/TrackingCard.java @@ -0,0 +1,63 @@ +package fr.univnantes.alma.server.game.item.card; + +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.jeton.JetonSymbol; + +import java.util.ArrayList; +import java.util.List; + +public class TrackingCard extends PlayerCard { + + private List symbols; + + public TrackingCard(CardName cardName, String name, String description, Phase phase){ + super(cardName, name, description, phase); + this.symbols = new ArrayList<>(); + } + + public TrackingCard(CardName cardName, String name, String description, Phase phase, JetonSymbol symbol){ + super(cardName, name, description, phase); + this.symbols = new ArrayList<>(); + this.symbols.add(symbol); + } + + public TrackingCard(CardName cardName, String name, String description, Phase phase, List symbols){ + super(cardName, name, description, phase); + this.symbols = symbols; + } + + public TrackingCard(CardName cardName, String name, String description, Phase phase, Phase phaseToApply){ + super(cardName, name, description, phase, phaseToApply); + this.symbols = new ArrayList<>(); + } + + public TrackingCard(CardName cardName, String name, String description, Phase phase, Phase phaseToApply, JetonSymbol symbol){ + super(cardName, name, description, phase, phaseToApply); + this.symbols = new ArrayList<>(); + this.symbols.add(symbol); + } + + public TrackingCard(CardName cardName, String name, String description, Phase phase, Phase phaseToApply, List symbols){ + super(cardName, name, description, phase, phaseToApply); + this.symbols = symbols; + } + + public List getJetons() { + return symbols; + } + + @Override + public CardType getType() { + return CardType.TRACKING; + } + + public boolean containsSymbol(JetonSymbol type) { + boolean res = false; + for(JetonSymbol symbol : symbols) { + if(type.equals(symbol)){ + res = true; + } + } + return res; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/jeton/JetonSymbol.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/jeton/JetonSymbol.java new file mode 100644 index 0000000000000000000000000000000000000000..b6fdf5342bba472d8ab68178b845da07638a1885 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/jeton/JetonSymbol.java @@ -0,0 +1,3 @@ +package fr.univnantes.alma.server.game.item.jeton; + +public enum JetonSymbol {CIBLE, ARTEMIA, CREATURE} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/jeton/PlacedJeton.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/jeton/PlacedJeton.java new file mode 100644 index 0000000000000000000000000000000000000000..992d9f42f81637c577c03f521627ce4bd1a50187 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/jeton/PlacedJeton.java @@ -0,0 +1,45 @@ +package fr.univnantes.alma.server.game.item.jeton; + +import fr.univnantes.alma.server.game.item.action.ActionTargetPlayer; +import fr.univnantes.alma.server.game.item.action.ActionType; +import fr.univnantes.alma.server.game.item.planet.Place; + +import java.util.ArrayList; +import java.util.List; + +public class PlacedJeton { + private JetonSymbol jetonSymbol; + private List places; + + public PlacedJeton(JetonSymbol symbol, Place place) { + this.places = new ArrayList<>(); + this.places.add(place); + this.jetonSymbol = symbol; + } + + public PlacedJeton(JetonSymbol symbol, List places) { + this.places = places; + this.jetonSymbol = symbol; + } + + + public JetonSymbol getJetonSymbol() { + return jetonSymbol; + } + + public List getPlaces() { + return places; + } + @Override + public boolean equals(Object obj) { + if(obj == this){ + return true; + } + if(!(obj instanceof PlacedJeton)){ + return false; + } + PlacedJeton placedJeton = (PlacedJeton) obj; + return jetonSymbol.equals(placedJeton.getJetonSymbol()) && places.equals(placedJeton.getPlaces()); + } + +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/pioche/Pioche.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/pioche/Pioche.java new file mode 100644 index 0000000000000000000000000000000000000000..76d97b799ed240ece7f94736a34318b2eaea60b8 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/pioche/Pioche.java @@ -0,0 +1,108 @@ +package fr.univnantes.alma.server.game.item.pioche; + +import fr.univnantes.alma.server.game.item.card.PlayerCard; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; + +public class Pioche{ + private List cards; + private List trash; + private Random random; + + public Pioche(List cards){ + this.cards = cards; + this.trash = new ArrayList<>(); + this.random = new Random(); + mix(); + } + + public Pioche(List cards, Random random){ + this.cards = cards; + this.trash = new ArrayList<>(); + this.random = random; + mix(); + } + + /** + * Put the trash in the "pioche", mix it and clear trash + */ + public void mix(){ + cards.addAll(trash); + trash = new ArrayList<>(); + Collections.shuffle(cards,random); + } + + /** + * Draw the first card + * @return A Card + */ + public T draw(){ + if(cards.isEmpty()) { + mix(); + } + T c = cards.get(0); + cards.remove(c); + return c; + } + + /** + * Draw the "number" first card + * @param number The number of cards to draw + * @return A list of Card + */ + public List draw(int number){ + if(number > trash.size() + cards.size()) { + throw new IllegalArgumentException("Number must be lower than the number of cards in the pioche"); + } + if(cards.size() < number) { + mix(); + } + List c = new ArrayList<>(); + for(int i = 1 ; i <= number ; ++i) { + c.add(draw()); + } + return c; + } + + /** + * Throw away (put in trash) the cards + * @param cards The list of cards + */ + public void throwAway(List cards) { + trash.addAll(cards); + } + + /** + * Throw away (put in trash) the card + * @param card The card + */ + public void throwAway(T card) { + trash.add(card); + } + + /** + * Return the n last discarded cards + * @param number The number of cards + * @return A list of card + */ + public List drawLastTrashCards(int number) { + number = Math.min(trash.size(), number); + List cards = new ArrayList<>(); + for(int i = 1 ; i <= number ; ++i) { + cards.add(trash.get(trash.size()-i)); + } + trash.removeAll(cards); + return cards; + } + + public List getTrash() { + return trash; + } + + public List getCards() { + return cards; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/BeaconPawn.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/BeaconPawn.java new file mode 100644 index 0000000000000000000000000000000000000000..30cae5db268d3f788318597ab7d21a8f3b13e0c6 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/BeaconPawn.java @@ -0,0 +1,40 @@ +package fr.univnantes.alma.server.game.item.planet; + +public class BeaconPawn extends PlanetPawn{ + + private int state; + + public BeaconPawn(){ + state = 0; + } + + @Override + public void nextState() { + if(state < 2) { + ++state; + } + else{ + state = 1; + } + } + + @Override + public boolean isActive() { + return state == 2; + } + + @Override + public PawnType getType() { + return PawnType.BEACON; + } + + @Override + public int maxMovesInOneRound() { + return 1; + } + + @Override + public int stateToInt() { + return state; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/PawnType.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/PawnType.java new file mode 100644 index 0000000000000000000000000000000000000000..4ba83bf3e1449768e8de3a6831a6c5f1f7b2aad3 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/PawnType.java @@ -0,0 +1,5 @@ +package fr.univnantes.alma.server.game.item.planet; + +public enum PawnType { + SHIELD, BEACON +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/Place.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/Place.java new file mode 100644 index 0000000000000000000000000000000000000000..d1cb6900731fa740898e0790a1d0f2a3b1ccfefa --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/Place.java @@ -0,0 +1,7 @@ +package fr.univnantes.alma.server.game.item.planet; + +public enum Place{ + PLACE_ONE, PLACE_TWO, PLACE_THREE, PLACE_FOUR, PLACE_FIVE, + PLACE_SIX, PLACE_SEVEN, PLACE_EIGHT, PLACE_NINE, PLACE_TEN +} + diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/PlaceDistribution.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/PlaceDistribution.java new file mode 100644 index 0000000000000000000000000000000000000000..f94228fc962f28749898af2bfb3649f3cec3e1cd --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/PlaceDistribution.java @@ -0,0 +1,245 @@ +package fr.univnantes.alma.server.game.item.planet; + +import fr.univnantes.alma.server.game.item.card.CardName; +import fr.univnantes.alma.server.game.item.card.PlaceCard; + +import java.util.*; +import java.util.List; +import java.util.stream.Collectors; + +import static fr.univnantes.alma.server.game.item.planet.Planet.*; +import static java.util.Collections.shuffle; + +public class PlaceDistribution { + /** + * The card number to the place card uses + */ + private Map mapCardNumberToPlaceCard; + + /** + * The place card to the place + */ + private Map mapPlaceCardToPlace; + + /** + * True if the place is hidden, false otherwise + */ + private Map placeIsHidden; + + public PlaceDistribution(List placeCards){ + placeIsHidden = new HashMap<>(); + mapCardNumberToPlaceCard = new HashMap<>(); + mapPlaceCardToPlace = new HashMap<>(); + initialization(placeCards); + } + + /*************************** + * Initialization + **************************/ + + private void initialization(List placeCards){ + //Verify there is 10 place cards + if(placeCards.size() != 10){ + throw new IllegalArgumentException("Needs 10 places cards"); + } + List numbers = placeCards.stream() + .map(PlaceCard::getNumber) + .collect(Collectors.toList()); + //Verify that there is all card number (1 to 10) once + for(PlaceCard card : placeCards) { + if(Collections.frequency(numbers, card.getNumber()) != 1){ + throw new IllegalArgumentException("Number " + card.getNumber() + " is twice in the list"); + } + else{ + mapCardNumberToPlaceCard.put(card.getNumber(), card); + } + } + initializePlaceCardsVisibility(); + initializePlaces(); + + } + private void initializePlaceCardsVisibility(){ + boolean useLabyrinthe = useCardLabyrinthe(); + //only the last five place card are hidden + for(int number = 1 ; number <= 10 ; ++number){ + placeIsHidden.put(numberToPlace(number), (useLabyrinthe && number > 5)); + } + } + + private void initializePlaces(){ + //the five first places are always in the good order + for(int number = 1 ; number <= 5 ; ++number){ + mapPlaceCardToPlace.put(mapCardNumberToPlaceCard.get(number), numberToPlace(number)); + } + List placeCardsOrders = Arrays.asList(6,7,8,9,10); + //if card Labyrinthe is used, we randomize the places + if(useCardLabyrinthe()){ + shuffle(placeCardsOrders); + } + Iterator iteratorPlaceCardsNumber = placeCardsOrders.iterator(); + for(int i = 6 ; i <= 10 ; ++i){ + mapPlaceCardToPlace.put(mapCardNumberToPlaceCard.get(iteratorPlaceCardsNumber.next()), numberToPlace(i)); + } + } + + public Map getMapCardNumberToPlaceCard() { + return mapCardNumberToPlaceCard; + } + + public Map getMapPlaceCardToPlace() { + return mapPlaceCardToPlace; + } + + /** + * Create a pawn depending of the place cards use (Shield or Beacon) + * @return A PlanetPawn + */ + public PlanetPawn createPawn(){ + if(useCardDome()){ + return new ShieldPawn(); + } + else{ + return new BeaconPawn(); + } + } + + /** + * Verify if the places are valid places for a jeton + * @param adjacentPlaces The places + * @return True if adjacentPlaces is a valid list of places + */ + public boolean isValidPlacesForJeton(List adjacentPlaces){ + if(adjacentPlaces.isEmpty() || adjacentPlaces.size() > 2){ + throw new IllegalArgumentException("Need 1 or 2 places"); + } + return adjacentPlaces.size() == 1 || isAdjacentPlaces(adjacentPlaces.get(0), adjacentPlaces.get(1)); + } + + /** + * Convert the place card to a place + * @param card The card + * @return A place + */ + public Place placeCardToPlace(PlaceCard card){ + Place place = mapPlaceCardToPlace.get(card); + return place; + } + + /** + * Convert the place to a place card + * @param place The place + * @return A place + */ + public PlaceCard placeToPlaceCard(Place place){ + Iterator iterator = mapPlaceCardToPlace.keySet().iterator(); + PlaceCard placeCard = null; + boolean find = false; + while(! find && iterator.hasNext()) { + placeCard = iterator.next(); + find = mapPlaceCardToPlace.get(placeCard).equals(place); + } + return find ? placeCard : null; + } + + /** + * Test if the card "Labyrinthe" is used + * @return True if the "Labyrinthe" is used, false otherwise + */ + public boolean useCardLabyrinthe(){ + return mapCardNumberToPlaceCard.get(LABYRINTHE_NUMBER).getCardName().equals(CardName.LABYRINTHE); + } + + /** + * Test if the card "Dome" is used + * @return True if the "Dome" is used, false otherwise + */ + public boolean useCardDome(){ + return mapCardNumberToPlaceCard.get(DOME_NUMBER).getCardName().equals(CardName.DOME); + } + + /** + * Test if the card "Pole" is used + * @return True if the "Pole" is used, false otherwise + */ + public boolean useCardPole(){ + return mapCardNumberToPlaceCard.get(POLE_NUMBER).getCardName().equals(CardName.POLE); + } + + /** + * Return a list of place card number a to number b + * @param a The start of the interval (include) + * @param b The end of the interval (include) + * @return A list of PlaceCard + */ + public List getPlaceCardsInInterval(int a, int b){ + if(a > b){ + throw new IllegalArgumentException("b must be greater than a"); + } + else if(a < 1 || a > 10 || b > 10){ + throw new IllegalArgumentException("a and b must be between 1 and 10"); + } + List placeCards = new ArrayList<>(); + for(int i = a ; i <= b ; ++i){ + placeCards.add(mapCardNumberToPlaceCard.get(i)); + } + return placeCards; + } + + public List getPlaceCards(){ + return getPlaceCardsInInterval(1, 10); + } + + /** + * Test if there is PlaceCard hidden + * @return + */ + public boolean isHiddenCards() { + return placeIsHidden.containsValue(true); + } + + /** + * Return the list oh hidden PlaceCard + * @return + */ + public List getHiddenCards() { + List placeCards = new ArrayList<>(); + for(Place place : placeIsHidden.keySet()){ + if(placeIsHidden.get(place)){ + placeCards.add(placeToPlaceCard(place)); + } + } + return placeCards; + } + + /** + * Return the list oh hidden place + * @return + */ + public List getHiddenPlaces() { + List places = new ArrayList<>(); + for(Place place : placeIsHidden.keySet()){ + if(placeIsHidden.get(place)){ + places.add(place); + } + } + return places; + } + + public void revealPlace(Place place) { + placeIsHidden.put(place, false); + } + + public void revealPlace(PlaceCard placeCard) { + Place place = mapPlaceCardToPlace.get(placeCard); + revealPlace(place); + } + + public boolean isRevealedPlace(Place place) { + return ! placeIsHidden.get(place); + } + + public boolean isRevealedPlace(PlaceCard placeCard) { + Place place = mapPlaceCardToPlace.get(placeCard); + return isRevealedPlace(place); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/Planet.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/Planet.java new file mode 100644 index 0000000000000000000000000000000000000000..291cf605b6849217495c0d2fa20a7b485a445cf3 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/Planet.java @@ -0,0 +1,476 @@ +package fr.univnantes.alma.server.game.item.planet; + +import fr.univnantes.alma.server.game.item.card.PlaceCard; +import fr.univnantes.alma.server.game.item.card.SurvivalCard; +import fr.univnantes.alma.server.game.item.jeton.*; +import fr.univnantes.alma.server.game.utilitary.Pair; +import sun.awt.Symbol; + +import java.util.*; +import java.util.stream.Collectors; + +import static fr.univnantes.alma.server.game.item.planet.Place.*; +import static fr.univnantes.alma.server.game.item.planet.Place.PLACE_TEN; + +public class Planet { + + public static final int LABYRINTHE_NUMBER = 5; + public static final int DOME_NUMBER = 4; + public static final int POLE_NUMBER = 8; + + + private Map> mapPlaceToJetons; + private Map blockedPlaces; + private Map> placeSurvivalCardMap; + private int numberMovesAllowInRound; + private PlaceDistribution placeDistribution; + private PlanetPawn planetPawn; + private boolean epaveUsedInTheRound; + + public Planet(List placeCards){ + this.mapPlaceToJetons = new EnumMap<>(Place.class); + this.blockedPlaces = new EnumMap<>(Place.class); + this.placeDistribution = new PlaceDistribution(placeCards); + this.planetPawn = this.placeDistribution.createPawn(); + this.numberMovesAllowInRound = planetPawn.maxMovesInOneRound(); + this.epaveUsedInTheRound = false; + this.placeSurvivalCardMap = new EnumMap<>(Place.class); + } + + public PlaceDistribution getPlaceDistribution() { + return placeDistribution; + } + + + public Map> getMapPlaceToJetons() { + return mapPlaceToJetons; + } + + /** + * Convert and return the map Place to Jetons in PlacedJetonList + * @return A list of PlacedJeton + */ + public List getPlacedJetons() { + List placedJetons = new ArrayList<>(); + Map> revert = new EnumMap<>(JetonSymbol.class); + List symbols; + for(Map.Entry> entry : mapPlaceToJetons.entrySet()) { + symbols = entry.getValue(); + for(JetonSymbol symbol : symbols) { + revert.putIfAbsent(symbol, new ArrayList<>()); + revert.get(symbol).add(entry.getKey()); + } + } + for(Map.Entry> entry : revert.entrySet()) { + placedJetons.add(new PlacedJeton(entry.getKey(), entry.getValue())); + } + return placedJetons; + } + + + + public void reset(){ + mapPlaceToJetons = new EnumMap<>(Place.class); + blockedPlaces = new EnumMap<>(Place.class); + epaveUsedInTheRound = false; + resetPawn(); + this.numberMovesAllowInRound = planetPawn.maxMovesInOneRound(); + } + + public boolean placeJeton(PlacedJeton placedJeton) { + if(placeDistribution.isValidPlacesForJeton(placedJeton.getPlaces())){ + Place p; + for(Place place : placedJeton.getPlaces()){ + if(! mapPlaceToJetons.containsKey(place)){ + mapPlaceToJetons.put(place, new ArrayList<>()); + } + mapPlaceToJetons.get(place).add(placedJeton.getJetonSymbol()); + } + return true; + } + else{ + return false; + } + } + + public List findPlacesWhereJetonIs(JetonSymbol symbol) { + List places = new ArrayList<>(); + List jetonsAux; + for(Place place : mapPlaceToJetons.keySet()) { + jetonsAux = mapPlaceToJetons.get(place); + for(JetonSymbol jetonSymbol : jetonsAux) { + if(jetonSymbol.equals(symbol)) { + places.add(place); + } + } + } + return places; + } + + public List findPlaceCardsWhereJetonIs(JetonSymbol symbol) { + return findPlacesWhereJetonIs(symbol).stream() + .map(this::placeToPlaceCard).collect(Collectors.toList()); + } + + public void removeJeton(JetonSymbol symbol) { + List places = new ArrayList<>(); + List jetonsAux; + for(Place place : mapPlaceToJetons.keySet()) { + jetonsAux = mapPlaceToJetons.get(place); + for(JetonSymbol jetonSymbol : jetonsAux) { + if(jetonSymbol.equals(symbol)) { + places.add(place); + } + } + } + for(Place place : places) { + mapPlaceToJetons.remove(place); + } + } + + public void blockPlaces(List places){ + for(Place p : places){ + blockedPlaces.put(p, true); + } + } + + public void blockPlaces(Place place){ + blockedPlaces.put(place, true); + } + + public void blockPlaces(Collection placeCards){ + for(PlaceCard p : placeCards){ + blockedPlaces.put(placeDistribution.placeCardToPlace(p), true); + } + } + + public void blockPlaces(PlaceCard placeCard){ + Place place = placeDistribution.placeCardToPlace(placeCard); + blockedPlaces.put(place, true); + } + + public boolean isBlockedPlace(PlaceCard card){ + Place place = placeDistribution.placeCardToPlace(card); + return blockedPlaces.containsKey(place) && blockedPlaces.get(place); + } + + public boolean isJetonOnPlace(Place place){ + return mapPlaceToJetons.containsKey(place); + } + + public boolean isJetonOnPlace(PlaceCard placeCard){ + return isJetonOnPlace(placeDistribution.placeCardToPlace(placeCard)); + } + + public List findJetonsSymbolsOnCard(PlaceCard placeCard){ + if(isJetonOnPlace(placeCard)){ + return mapPlaceToJetons.get(placeDistribution.placeCardToPlace(placeCard)); + } + else{ + return new ArrayList<>(); + } + } + + public boolean isJetonSymbolOnPlaceCard(JetonSymbol symbol, PlaceCard placeCard) { + return findJetonsSymbolsOnCard(placeCard).contains(symbol); + } + + public PlanetPawn getPlanetPawn() { + return planetPawn; + } + + public boolean canMovePlanetPawn() { + return numberMovesAllowInRound > 0; + } + + public boolean movePlanetPawn(){ + if(canMovePlanetPawn()){ + planetPawn.nextState(); + --numberMovesAllowInRound; + return true; + } + else{ + return false; + } + } + + public void forceMovePlanetPawn(){ + planetPawn.nextState(); + } + + public void moveBackPlanetPawn(){ + if(planetPawn.getType().equals(PawnType.SHIELD)) { + planetPawn.previousState(); + ++numberMovesAllowInRound; + } + } + + public void resetPawn(){ + planetPawn.reset(); + } + + public List placesWhereJetonCreatureIs() { + List placeCards = new ArrayList<>(); + for(Map.Entry> entry : mapPlaceToJetons.entrySet()){ + for(JetonSymbol jetonSymbol : entry.getValue()) { + if(jetonSymbol.equals(JetonSymbol.CREATURE)) { + placeCards.add(placeDistribution.placeToPlaceCard(entry.getKey())); + } + } + } + return placeCards; + } + + public List getPlaceCardsInInterval(int a, int b){ + return this.placeDistribution.getPlaceCardsInInterval(a, b); + } + + public boolean planetPawnIsActive(){ + return planetPawn.isActive(); + } + + public PawnType getPlanetPawnType(){ + return planetPawn.getType(); + } + + public boolean canUseEpavePower() { + return ! epaveUsedInTheRound; + } + + public void setEpavePowerToUsed() { + epaveUsedInTheRound = true; + } + + /** + * Convert the place to a place card + * @param place The place + * @return A place + */ + public PlaceCard placeToPlaceCard(Place place){ + return placeDistribution.placeToPlaceCard(place); + } + + + public boolean isASurvivalCardOnPlace(Place place) { + return placeSurvivalCardMap.containsKey(place); + } + + public boolean isASurvivalCardOnPlace(PlaceCard placeCard) { + return isASurvivalCardOnPlace(placeDistribution.placeCardToPlace(placeCard)); + } + + public SurvivalCard takeSurvivalCardOnPlace(Place place) { + List survivalCards = placeSurvivalCardMap.getOrDefault(place, null); + SurvivalCard cardCaught = null; + if(survivalCards != null) { + if(!survivalCards.isEmpty()) { + cardCaught = survivalCards.get(0); + survivalCards.remove(cardCaught); + } + if(survivalCards.isEmpty()) { + placeSurvivalCardMap.remove(place); + } + } + return cardCaught; + } + + public SurvivalCard takeSurvivalCardOnPlace(PlaceCard placeCard) { + return takeSurvivalCardOnPlace(placeDistribution.placeCardToPlace(placeCard)); + } + + + public void putSurvivalCardOnPlace(Pair pair) { + placeSurvivalCardMap.putIfAbsent(pair.getKey(), new ArrayList<>()); + placeSurvivalCardMap.get(pair.getKey()).add(pair.getValue()); + } + + public void putSurvivalCardOnPlace(List> pairs) { + for(Pair pair : pairs) { + putSurvivalCardOnPlace(pair); + } + } + + /******************************** + * Auxiliaries methods + * *****************************/ + + /** + * Convert a Place in a integer (PLACE_ONE -> 1, ... PLACE_10 -> 10) + * Usefull to compute the adjacence of two places + * @return A integer + */ + public static Integer placeToNumber(Place place){ + switch (place){ + case PLACE_ONE: + return 1; + case PLACE_TWO: + return 2; + case PLACE_THREE: + return 3; + case PLACE_FOUR: + return 4; + case PLACE_FIVE: + return 5; + case PLACE_SIX: + return 6; + case PLACE_SEVEN: + return 7; + case PLACE_EIGHT: + return 8; + case PLACE_NINE: + return 9; + case PLACE_TEN: + return 10; + default: + throw new IllegalArgumentException("This place is not valid"); + } + } + + /** + * Convert a number in a Place (1 -> PLACE_ONE, ... 10 -> PLACE_10) + * @return A Place + */ + public static Place numberToPlace(int number){ + switch (number){ + case 1: + return PLACE_ONE; + case 2: + return PLACE_TWO; + case 3: + return PLACE_THREE; + case 4: + return PLACE_FOUR; + case 5: + return PLACE_FIVE; + case 6: + return PLACE_SIX; + case 7: + return PLACE_SEVEN; + case 8: + return PLACE_EIGHT; + case 9: + return PLACE_NINE; + case 10: + return PLACE_TEN; + default: + throw new IllegalArgumentException("This number must be between 1 and 10"); + } + } + + /** + * Test if the two places are adjacent + * @param place1 The place 1 + * @param place2 The place 2 + * @return True if the place are adjacent, false otherwise + */ + public static boolean isAdjacentPlaces(int place1, int place2){ + if(place1 > place2){ + //swap the place + int temp = place1; + place1 = place2; + place2 = temp; + + } + if(place1 == 5 && place2 == 6){ + return false; + } + else if(place1 + 1 == place2 || place1 + 5 == place2){ + return true; + } + else{ + return false; + } + } + + /** + * Test if the the placeCard and the place are adjacent + * @param placeCard The place card + * @param place The place + * @return True if the place are adjacent, false otherwise + */ + public boolean isAdjacentPlaces(PlaceCard placeCard, Place place){ + int numberPlaceCard = placeToNumber(placeDistribution.placeCardToPlace(placeCard)); + return isAdjacentPlaces(numberPlaceCard, placeToNumber(place)); + } + + /** + * Test if the two place cards are adjacent + * @param placeCard1 The place card 1 + * @param placeCard2 The place card 2 + * @return True if the place are adjacent, false otherwise + */ + public boolean isAdjacentPlaces(PlaceCard placeCard1, PlaceCard placeCard2){ + int numberPlaceCard1 = placeToNumber(placeDistribution.placeCardToPlace(placeCard1)); + int numberPlaceCard2 = placeToNumber(placeDistribution.placeCardToPlace(placeCard2)); + return isAdjacentPlaces(numberPlaceCard1, numberPlaceCard2); + } + + /** + * Test if the two places are adjacent + * @param place1 The place 1 + * @param place2 The place 2 + * @return True if the place are adjacent, false otherwise + */ + public static boolean isAdjacentPlaces(Place place1, Place place2){ + return isAdjacentPlaces(placeToNumber(place1), placeToNumber(place2)); + } + + /** + * Test if there is PlaceCard hidden + * @return + */ + public boolean isHiddenCards() { + return placeDistribution.isHiddenCards(); + } + + /** + * Return the list oh hidden PlaceCard + * @return + */ + public List getHiddenCards() { + return placeDistribution.getHiddenCards(); + } + + /** + * Return the list oh hidden place + * @return + */ + public List getHiddenPlaces() { + return placeDistribution.getHiddenPlaces(); + } + + public void revealPlace(Place place) { + placeDistribution.revealPlace(place); + } + + public void revealPlace(PlaceCard placeCard) { + placeDistribution.revealPlace(placeCard); + } + + public boolean isRevealedPlace(Place place) { + return placeDistribution.isRevealedPlace(place); + } + + public boolean isRevealedPlace(PlaceCard placeCard) { + return placeDistribution.isRevealedPlace(placeCard); + } + + public void swapJeton(JetonSymbol symbol1, JetonSymbol symbol2) { + Map> newMap = new HashMap<>(); + for(Place place : mapPlaceToJetons.keySet()) { + for(JetonSymbol jeton : mapPlaceToJetons.get(place)) { + newMap.putIfAbsent(place, new ArrayList<>()); + if(jeton.equals(symbol1)){ + newMap.get(place).add(symbol2); + } + else if(jeton.equals(symbol2)) { + newMap.get(place).add(symbol1); + } + else{ + newMap.get(place).add(jeton); + } + } + } + mapPlaceToJetons = newMap; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/PlanetPawn.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/PlanetPawn.java new file mode 100644 index 0000000000000000000000000000000000000000..a2e360f368dfae0e9b1f6af9b10e51e4d1f79646 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/PlanetPawn.java @@ -0,0 +1,25 @@ +package fr.univnantes.alma.server.game.item.planet; + +public abstract class PlanetPawn { + + public PlanetPawn(){} + + public abstract PawnType getType(); + + public abstract void nextState(); + + public void previousState(){}; + + public abstract boolean isActive(); + + public abstract int maxMovesInOneRound(); + + public void reset(){} + + /** + * Convert the state of the Pawn in a int. + * Usefull to conversion + * @return a int describing the state + */ + public abstract int stateToInt(); +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/ShieldPawn.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/ShieldPawn.java new file mode 100644 index 0000000000000000000000000000000000000000..f92aba050123268a35a19800760871014829a38c --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/planet/ShieldPawn.java @@ -0,0 +1,59 @@ +package fr.univnantes.alma.server.game.item.planet; + +import static fr.univnantes.alma.server.game.item.planet.Planet.DOME_NUMBER; + +public class ShieldPawn extends PlanetPawn{ + + private int location; + private boolean hasReachDome; + + public ShieldPawn() { + location = 1; + hasReachDome = false; + } + + public int getLocation() { + return location; + } + + @Override + public void nextState() { + ++location; + if(location == DOME_NUMBER) { + hasReachDome = true; + location = 1; + } + } + + @Override + public void previousState() { + location = location > 1 ? location - 1 : 1; + } + + @Override + public boolean isActive() { + return hasReachDome; + } + + @Override + public PawnType getType() { + return PawnType.SHIELD; + } + + @Override + public int maxMovesInOneRound() { + //DOME_NUMBER - location to reach the DOME + //DOME_NUMBER - 2 to reach the place before the DOME + return DOME_NUMBER - location + DOME_NUMBER -2; + } + + @Override + public void reset() { + hasReachDome = false; + } + + @Override + public int stateToInt() { + return location; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/Creature.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/Creature.java new file mode 100644 index 0000000000000000000000000000000000000000..4cd6065eada6ce5adec1fc93933c51571f0d2c96 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/Creature.java @@ -0,0 +1,175 @@ +package fr.univnantes.alma.server.game.item.player; + +import fr.univnantes.alma.server.game.item.card.TrackingCard; +import fr.univnantes.alma.server.game.item.jeton.JetonSymbol; +import fr.univnantes.alma.server.game.item.player.hand.HandCreature; +import fr.univnantes.alma.server.game.item.player.rights.CreatureRight; + +import java.util.List; + +public class Creature extends Player { + + /** + * The hand of the Creature + */ + private HandCreature hand; + + /** + * The rights of the Creature + */ + private CreatureRight rights; + + public Creature(int inGameId){ + super(inGameId); + this.hand = new HandCreature(); + this.rights = new CreatureRight(); + } + + public Creature(String name, int inGameId){ + super(name, inGameId); + this.hand = new HandCreature(); + this.rights = new CreatureRight(); + } + + public HandCreature getHand(){ + return hand; + } + + public CreatureRight getRights() { + return rights; + } + + @Override + public PlayerTeam getTeam() { + return PlayerTeam.CREATURE; + } + + public void reset() { + hand.clearTrackingCardPlayed(); + rights.reset(); + } + + /****************************** + * Hand methods + *****************************/ + + public void initializationJeton(){ + hand.initializationJeton(); + } + + public int jetonsSize(){ + return hand.jetonsSize(); + } + + public int jetonsPlayedSize(){ + return hand.jetonsPlayedSize(); + } + + public boolean jetonsIsEmpty(){ + return hand.jetonsIsEmpty(); + } + + public List getJetons(){ + return hand.getJetonSymbols(); + } + + public boolean playJeton(JetonSymbol jeton){ + return hand.playJeton(jeton); + } + + public boolean playJeton(List jetons){ + return hand.playJeton(jetons); + } + + public boolean jetonsPlayedIsEmpty(){ + return hand.jetonsPlayedIsEmpty(); + } + + public int getMaxTrackingCards() { + return hand.getMaxTrackingCards(); + } + + public List getTrackingCardHand(){ + return hand.getTrackingCardHand(); + } + + public List getTrackingCardsPlayed() { + return hand.getTrackingCardsPlayed(); + } + + public int trackingCardHandSize(){ + return hand.trackingCardHandSize(); + } + + public int trackingCardPlayedSize(){ + return hand.trackingCardPlayedSize(); + } + + public boolean trackingCardIsEmpty(){ + return hand.trackingCardIsEmpty(); + } + + public boolean trackingCardPlayedIsEmpty(){ + return hand.trackingCardPlayedIsEmpty(); + } + + + public void clearTrackingCardPlayed() { + hand.clearTrackingCardPlayed(); + } + + public boolean addTrackingCard(TrackingCard trackingCard){ + return hand.addTrackingCard(trackingCard); + } + + public boolean addTrackingCard(List trackingCards){ + return hand.addTrackingCard(trackingCards); + } + + public boolean removeTrackingCard(TrackingCard trackingCard){ + return hand.removeTrackingCard(trackingCard); + } + + public boolean removeTrackingCard(List trackingCards){ + return hand.removeTrackingCard(trackingCards); + } + + public boolean playTrackingCard(TrackingCard trackingCard){ + return hand.playTrackingCard(trackingCard); + } + + public boolean playTrackingCard(List trackingCards){ + return hand.playTrackingCard(trackingCards); + } + + public void addTrackingCardToApplied(TrackingCard trackingCard) { + hand.addTrackingCardToApplied(trackingCard); + } + + public void addTrackingCardToApplied(List trackingCards) { + hand.addTrackingCardToApplied(trackingCards); + } + + public void removeTrackingCardToApplied(TrackingCard trackingCard) { + hand.removeTrackingCardToApplied(trackingCard); + } + + public void removeTrackingCardToApplied(List trackingCards) { + hand.removeTrackingCardToApplied(trackingCards); + } + + public List getTrackingCardToApplied() { + return hand.getTrackingCardToApplied(); + } + /******************************** + * Rights methods + *******************************/ + + public void setMaxTrackingCardPlayable(int maxTrackingCardPlayable) { + rights.setMaxTrackingCardPlayable(maxTrackingCardPlayable); + } + + public int getMaxTrackingCardPlayable(){ + return rights.getMaxTrackingCardPlayable(); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/Player.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/Player.java new file mode 100644 index 0000000000000000000000000000000000000000..2db0ad8b13c86e5e32acb69255e1fe9a97025d97 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/Player.java @@ -0,0 +1,46 @@ +package fr.univnantes.alma.server.game.item.player; + +import fr.univnantes.alma.server.game.item.Phase; + +public abstract class Player { + + protected String name; + protected int inGameId; + + /** + * The current phase where is the player + */ + protected Phase currentPhase; + + public Player(int inGameId){ + this.name = "Player" + inGameId; + this.inGameId = inGameId; + } + + public Player(String name, int inGameId){ + this.name = name; + this.inGameId = inGameId; + } + + public String getName() { + return name; + } + + public int getInGameId() { + return inGameId; + } + + public Phase getCurrentPhase() { + return currentPhase; + } + + public abstract PlayerTeam getTeam(); + + public void setCurrentPhase(Phase currentPhase) { + this.currentPhase = currentPhase; + } + + public boolean teamEqualsTo(PlayerTeam team) { + return team.equals(getTeam()); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/PlayerTeam.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/PlayerTeam.java new file mode 100644 index 0000000000000000000000000000000000000000..1aa3b8b42be641e68454ea60a9bbc7c7116173d7 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/PlayerTeam.java @@ -0,0 +1,3 @@ +package fr.univnantes.alma.server.game.item.player; + +public enum PlayerTeam {CREATURE, TRAQUE} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/Traque.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/Traque.java new file mode 100644 index 0000000000000000000000000000000000000000..572c7d0fbfb45fbdc42332fe08d53e12fcee686f --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/Traque.java @@ -0,0 +1,402 @@ +package fr.univnantes.alma.server.game.item.player; + +import fr.univnantes.alma.server.game.item.card.PlaceCard; +import fr.univnantes.alma.server.game.item.card.SurvivalCard; +import fr.univnantes.alma.server.game.item.player.hand.HandTraque; +import fr.univnantes.alma.server.game.item.player.rights.TraqueRight; + +import java.util.ArrayList; +import java.util.List; + +public class Traque extends Player { + private static final int MAX_WILLINGNESS = 3; + + private int numberWillingness; + private HandTraque hand; + private TraqueRight rights; + private List placeCardsPlayedAfterMoving; + private List placeCardsPlayedAndVisible; + + public Traque(int inGameId){ + super(inGameId); + numberWillingness = MAX_WILLINGNESS; + hand = new HandTraque(); + rights = new TraqueRight(); + placeCardsPlayedAfterMoving = new ArrayList<>(); + placeCardsPlayedAndVisible = new ArrayList<>(); + } + + public Traque(int inGameId, int numberWillingness){ + super(inGameId); + this.numberWillingness = numberWillingness; + hand = new HandTraque(); + rights = new TraqueRight(); + placeCardsPlayedAfterMoving = new ArrayList<>(); + placeCardsPlayedAndVisible = new ArrayList<>(); + } + + public Traque(String name, int inGameId){ + super(name, inGameId); + numberWillingness = MAX_WILLINGNESS; + hand = new HandTraque(); + rights = new TraqueRight(); + placeCardsPlayedAfterMoving = new ArrayList<>(); + placeCardsPlayedAndVisible = new ArrayList<>(); + } + + public Traque(String name, int inGameId, int numberWillingness){ + super(name, inGameId); + this.numberWillingness = numberWillingness; + hand = new HandTraque(); + rights = new TraqueRight(); + placeCardsPlayedAfterMoving = new ArrayList<>(); + placeCardsPlayedAndVisible = new ArrayList<>(); + } + + public int getNumberWillingness() { + return numberWillingness; + } + + public int getMaxWillingness() { + return MAX_WILLINGNESS; + } + + public HandTraque getHand() { + return hand; + } + + public TraqueRight getRights() { + return rights; + } + + public void addWillingness(int delta){ + numberWillingness += delta; + if(numberWillingness > MAX_WILLINGNESS){ + numberWillingness = MAX_WILLINGNESS; + } + } + + public void subWillingness(int delta){ + numberWillingness -= delta; + if(numberWillingness < 0){ + numberWillingness = 0; + } + } + + public void incrementWillingness(){ + addWillingness(1); + } + + public void decrementWillingness(){ + subWillingness(1); + } + + public void fillWillingness() { + numberWillingness = MAX_WILLINGNESS; + } + + public void addPlaceCardsAfterMoving(PlaceCard placeCard) { + placeCardsPlayedAfterMoving.add(placeCard); + } + + public void addPlaceCardsAfterMoving(List placeCards) { + placeCardsPlayedAfterMoving.addAll(placeCards); + } + + public List getPlaceCardsPlayedAndVisible() { + return placeCardsPlayedAndVisible; + } + + public void addPlaceCardsPlayedAndVisible(PlaceCard placeCard) { + placeCardsPlayedAndVisible.add(placeCard); + } + + public void addPlaceCardsPlayedAndVisible(List placeCards) { + placeCardsPlayedAndVisible.addAll(placeCards); + } + + + public void reset() { + resetRight(); + hand.clearSurvivalCardPlayed(); + placeCardsPlayedAfterMoving = new ArrayList<>(); + placeCardsPlayedAndVisible = new ArrayList<>(); + } + + @Override + public PlayerTeam getTeam() { + return PlayerTeam.TRAQUE; + } + + /**************************** + * Hand methods + ****************************/ + + public List getPlaceCards() { + return hand.getPlaceCards(); + } + + public List getPlaceCardsPlayed() { + if(! placeCardsPlayedAfterMoving.isEmpty()) { + return placeCardsPlayedAfterMoving; + } + else{ + return hand.getPlaceCardsPlayed(); + } + } + + public List getDefausse() { + return hand.getDefausse(); + } + + public void setPlaceCards(List placeCards) { + hand.setPlaceCards(placeCards); + } + + public void setDefausse(List placeCards) { + hand.setDefausse(placeCards); + } + + public int placeCardHandSize(){ + return hand.placeCardHandSize(); + } + + public boolean placeCardIsEmpty(){ + return hand.placeCardIsEmpty(); + } + + public int defausseSize(){ + return hand.defausseSize(); + } + + public boolean defausseIsEmpty(){ + return hand.defausseIsEmpty(); + } + + public int placeCardPlayedSize(){ + return hand.placeCardPlayedSize(); + } + + public boolean placeCardPlayedIsEmpty() { + return hand.placeCardPlayedIsEmpty(); + } + + /** + * Put the played cards in the "defausse" + * @return true is the operation is a succeed, else otherwise + */ + public boolean throwAwayPlaceCard(){ + return hand.throwAwayPlaceCard(); + } + + /** + * Put the card in the "defausse" + * @param placeCard The card + * @return true is the operation is a succeed, else otherwise + */ + public boolean throwAwayPlaceCard(PlaceCard placeCard){ + return hand.throwAwayPlaceCard(placeCard); + } + + /** + * Put the cards in the "defausse" + * @param placeCards The cards + * @return true is the operation is a succeed, else otherwise + */ + public boolean throwAwayPlaceCard(List placeCards){ + return hand.throwAwayPlaceCard(placeCards); + } + + /** + * Put back the card in the hand + * @param placeCard The card + * @return true is the operation is a succeed, else otherwise + */ + public boolean takeBackPlaceCard(PlaceCard placeCard){ + return hand.takeBackPlaceCard(placeCard); + } + + public void takeBackPlayedPlaceCards() { + hand.takeBackPlayedPlaceCards(); + } + + /** + * Put back the cards in the hand + * @param placeCards The cards + * @return true is the operation is a succeed, else otherwise + */ + public boolean takeBackPlaceCard(List placeCards){ + return hand.takeBackPlaceCard(placeCards); + } + + /** + * Move all the cards from defausse to the hand + */ + public void takeBackAllPlaceCardFromDefausse() { + hand.takeBackAllPlaceCardFromDefausse(); + } + + public boolean addPlaceCard(PlaceCard placeCard){ + return hand.addPlaceCard(placeCard); + } + + public boolean addPlaceCard(List placeCards){ + return hand.addPlaceCard(placeCards); + } + + public boolean addPlaceCardInDefausse(PlaceCard placeCard){ + return hand.addPlaceCardInDefausse(placeCard); + } + + public boolean addPlaceCardInDefausse(List placeCards){ + return hand.addPlaceCardInDefausse(placeCards); + } + + public boolean playPlaceCard(PlaceCard placeCard){ + return hand.playPlaceCard(placeCard); + } + + public boolean playPlaceCard(List placeCards){ + return hand.playPlaceCard(placeCards); + } + + public List getSurvivalCardsHand() { + return hand.getSurvivalCardsHand(); + } + + public List getSurvivalCardsPlayed() { + return hand.getSurvivalCardsPlayed(); + } + + public int survivalCardHandSize(){ + return hand.survivalCardHandSize(); + } + + public int survivalCardPlayedSize(){ + return this.hand.survivalCardPlayedSize(); + } + + + public boolean survivalCardIsEmpty(){ + return hand.survivalCardIsEmpty(); + } + + public boolean survivalCardPlayedIsEmpty(){ + return hand.survivalCardPlayedIsEmpty(); + } + + public void clearSurvivalCardPlayed() { + hand.clearSurvivalCardPlayed(); + } + + public boolean addSurvivalCard(SurvivalCard survivalCard){ + return hand.addSurvivalCard(survivalCard); + } + + public boolean addSurvivalCard(List cardList){ + return hand.addSurvivalCard(cardList); + } + + public boolean removeSurvivalCard(SurvivalCard survivalCard){ + return hand.removeSurvivalCard(survivalCard); + } + + public boolean removeSurvivalCard(List cardList){ + return hand.removeSurvivalCard(cardList); + } + + public boolean playSurvivalCard(SurvivalCard survivalCard){ + return hand.playSurvivalCard(survivalCard); + } + + public boolean playSurvivalCard(List cardList){ + return hand.playSurvivalCard(cardList); + } + + public void addSurvivalCardToApplied(SurvivalCard survivalCard) { + hand.addSurvivalCardToApplied(survivalCard); + } + + public void addSurvivalCardToApplied(List survivalCards) { + hand.addSurvivalCardToApplied(survivalCards); + } + + + public void removeSurvivalCardToApplied(SurvivalCard survivalCard) { + hand.removeSurvivalCardToApplied(survivalCard); + } + + public void removeSurvivalCardToApplied(List survivalCards) { + hand.removeSurvivalCardToApplied(survivalCards); + } + + public List getSurvivalCardsToApplied() { + return hand.getSurvivalCardsToApplied(); + } + + /******************************** + * Rights methods + *******************************/ + + public void resetRight(){ + rights.reset(); + } + + public int getMaxPlacesCardChoosable() { + return rights.getMaxPlacesCardChoosable(); + } + + public void setMaxPlacesCardChoosable(int maxPlacesCardChoosable) { + rights.setMaxPlacesCardChoosable(maxPlacesCardChoosable); + } + + public int getMaxPlacesCardPlayable() { + return rights.getMaxPlacesCardPlayable(); + } + + public void setMaxPlacesCardPlayable(int maxPlacesCardPlayable) { + rights.setMaxPlacesCardPlayable(maxPlacesCardPlayable); + } + + public int getMaxSurvivalCardPlayable() { + return rights.getMaxSurvivalCardPlayable(); + } + + public void setMaxSurvivalCardPlayable(int maxSurvivalCardPlayable) { + rights.setMaxSurvivalCardPlayable(maxSurvivalCardPlayable); + } + + public boolean canResist() { + return rights.canResist(); + } + + public void setCanResist(boolean canResist) { + rights.setCanResist(canResist); + } + + public boolean canGiveUp() { + return rights.canGiveUp(); + } + + public void setCanGiveUp(boolean canGiveUp) { + rights.setCanGiveUp(canGiveUp); + } + + + public int getPlaceCardsVisible() { + return rights.getPlaceCardsVisible(); + } + + public void setPlaceCardsVisible(int placeCardsVisible) { + rights.setPlaceCardsVisible(placeCardsVisible); + } + + public int getNumberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist() { + return rights.getNumberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist(); + } + + public void setNumberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist(int number) { + rights.setNumberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist(number); + } + +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/hand/Deck.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/hand/Deck.java new file mode 100644 index 0000000000000000000000000000000000000000..0e528c4cb33fcc54ad6ebb506227e411cc487d5a --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/hand/Deck.java @@ -0,0 +1,117 @@ +package fr.univnantes.alma.server.game.item.player.hand; + +import fr.univnantes.alma.server.game.item.card.PlayerCard; + +import java.util.ArrayList; +import java.util.List; + +public class Deck { + private List cards; + private List playedCards; + private int maxCards; + + public Deck(){ + cards = new ArrayList<>(); + playedCards = new ArrayList<>(); + maxCards = -1; + } + + public Deck(int maxCards){ + cards = new ArrayList<>(); + playedCards = new ArrayList<>(); + this.maxCards = maxCards; + } + + public Deck(List cards){ + this.cards = cards; + playedCards = new ArrayList<>(); + maxCards = -1; + } + + public Deck(List cards, int maxCards){ + this.cards = cards; + playedCards = new ArrayList<>(); + this.maxCards = maxCards; + } + + public int getMaxCards() { + return maxCards; + } + + public List getCards() { + return cards; + } + + public List getPlayedCards() { + return playedCards; + } + + public void clear() { + playedCards = new ArrayList<>(); + } + + public boolean add(T card){ + if(maxCards == -1 || cards.size() + 1 <= maxCards){ + return cards.add(card); + } + else{ + return false; + } + } + + public boolean add(List cardList){ + if(maxCards == -1 || cards.size() + cardList.size() <= maxCards){ + return cards.addAll(cardList); + } + else{ + return false; + } + } + + public boolean remove(T card){ + return cards.remove(card); + } + + public boolean remove(List cardList){ + return cards.removeAll(cardList); + } + + public boolean play(T card){ + if(cards.contains(card)){ + playedCards.add(card); + cards.remove(card); + return true; + } + else{ + return false; + } + } + + public boolean play(List cardList){ + if(cards.containsAll(cardList)){ + cards.removeAll(cardList); + playedCards.addAll(cardList); + return true; + } + else{ + return false; + } + } + + public int handSize() { + return this.cards.size(); + } + + public boolean handIsEmpty(){ + return this.cards.isEmpty(); + } + + public int playedCardSize(){ + return playedCards.size(); + } + + public boolean playedCardIsEmpty(){ + return playedCards.isEmpty(); + } + +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/hand/HandCreature.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/hand/HandCreature.java new file mode 100644 index 0000000000000000000000000000000000000000..afdc20b1c50593cf4204dfeda8dfcf077b615717 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/hand/HandCreature.java @@ -0,0 +1,171 @@ +package fr.univnantes.alma.server.game.item.player.hand; + +import fr.univnantes.alma.server.game.item.card.TrackingCard; +import fr.univnantes.alma.server.game.item.jeton.JetonSymbol; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class HandCreature { + + private Deck trackingCards; + private List jetonSymbols; + private List trackingCardsToApplied; + /** + * The jetons played by the player in the current round + */ + private List jetonSymbolsPlayed; + + public HandCreature(){ + this.trackingCards = new Deck<>(3); + this.trackingCardsToApplied = new ArrayList<>(); + initializationJeton(); + } + + public HandCreature(List trackingCards){ + this.trackingCards = new Deck<>(trackingCards, 3); + this.trackingCardsToApplied = new ArrayList<>(); + initializationJeton(); + } + + public void addTrackingCardToApplied(TrackingCard trackingCard) { + trackingCardsToApplied.add(trackingCard); + } + + public void addTrackingCardToApplied(List trackingCards) { + trackingCardsToApplied.addAll(trackingCards); + } + + public void removeTrackingCardToApplied(TrackingCard trackingCard) { + trackingCardsToApplied.remove(trackingCard); + } + + public void removeTrackingCardToApplied(List trackingCards) { + trackingCardsToApplied.removeAll(trackingCards); + } + + public List getTrackingCardToApplied() { + return trackingCardsToApplied; + } + + /******************************** + * Jeton methods + *******************************/ + public void initializationJeton(){ + jetonSymbols = new ArrayList<>(Arrays.asList(JetonSymbol.CIBLE, JetonSymbol.CREATURE, JetonSymbol.ARTEMIA)); + jetonSymbolsPlayed = new ArrayList<>(); + } + + public List getJetonSymbolsPlayed() { + return jetonSymbolsPlayed; + } + + public List getJetonSymbols(){ + return jetonSymbols; + } + + public boolean playJeton(JetonSymbol jeton){ + if(jetonSymbols.contains(jeton)){ + jetonSymbols.remove(jeton); + jetonSymbolsPlayed.add(jeton); + return true; + } + else{ + return false; + } + } + + public boolean playJeton(List jetons){ + if(this.jetonSymbols.containsAll(jetons)){ + this.jetonSymbols.removeAll(jetons); + jetonSymbolsPlayed.addAll(jetons); + return true; + } + else{ + return false; + } + } + + public int jetonsSize(){ + return jetonSymbols.size(); + } + + public int jetonsPlayedSize(){ + return jetonSymbolsPlayed.size(); + } + + public boolean jetonsIsEmpty(){ + return jetonSymbols.isEmpty(); + } + + public boolean jetonsPlayedIsEmpty(){ + return jetonSymbolsPlayed.isEmpty(); + } + + /******************************** + * Tracking card methods + *******************************/ + + public int getMaxTrackingCards() { + return trackingCards.getMaxCards(); + } + + public Deck getTrackingCardsDeck(){ + return trackingCards; + } + + public List getTrackingCardHand(){ + return trackingCards.getCards(); + } + + public List getTrackingCardsPlayed() { + return trackingCards.getPlayedCards(); + } + + public int trackingCardHandSize(){ + return trackingCards.handSize(); + } + + public int trackingCardPlayedSize(){ + return trackingCards.playedCardSize(); + } + + public boolean trackingCardIsEmpty(){ + return trackingCards.handIsEmpty(); + } + + public boolean trackingCardPlayedIsEmpty(){ + return trackingCards.playedCardIsEmpty(); + } + + public void clearTrackingCardPlayed() { + trackingCards.clear(); + } + + public boolean addTrackingCard(TrackingCard trackingCard){ + return trackingCards.add(trackingCard); + } + + public boolean addTrackingCard(List cardList){ + return trackingCards.add(cardList); + } + + public boolean removeTrackingCard(TrackingCard trackingCard){ + return trackingCards.remove(trackingCard); + } + + public boolean removeTrackingCard(List cardList){ + return trackingCards.remove(cardList); + } + + + public boolean playTrackingCard(TrackingCard trackingCard){ + return trackingCards.play(trackingCard); + } + + public boolean playTrackingCard(List cardList){ + return trackingCards.play(cardList); + } + +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/hand/HandTraque.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/hand/HandTraque.java new file mode 100644 index 0000000000000000000000000000000000000000..01b5d806a5b6857a91a0edfba650196342801789 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/hand/HandTraque.java @@ -0,0 +1,242 @@ +package fr.univnantes.alma.server.game.item.player.hand; +import fr.univnantes.alma.server.game.item.card.PlaceCard; +import fr.univnantes.alma.server.game.item.card.SurvivalCard; + +import java.util.ArrayList; +import java.util.List; + +public class HandTraque { + private Deck survivalCards; + private PlaceCardDeck placeCards; + private List survivalCardsToApplied; + + public HandTraque(){ + survivalCards = new Deck<>(); + placeCards = new PlaceCardDeck(); + survivalCardsToApplied = new ArrayList<>(); + } + + public HandTraque(List placeCards){ + this.placeCards = new PlaceCardDeck(placeCards); + this.survivalCards = new Deck<>(); + this.survivalCardsToApplied = new ArrayList<>(); + } + + public HandTraque(List placeCards, List survivalCards){ + this.placeCards = new PlaceCardDeck(placeCards); + this.survivalCards = new Deck<>(survivalCards); + this.survivalCardsToApplied = new ArrayList<>(); + } + + public void addSurvivalCardToApplied(SurvivalCard survivalCard) { + survivalCardsToApplied.add(survivalCard); + } + + public void addSurvivalCardToApplied(List survivalCards) { + survivalCardsToApplied.addAll(survivalCards); + } + + + public void removeSurvivalCardToApplied(SurvivalCard survivalCard) { + survivalCardsToApplied.remove(survivalCard); + } + + public void removeSurvivalCardToApplied(List survivalCards) { + survivalCardsToApplied.removeAll(survivalCards); + } + + public List getSurvivalCardsToApplied() { + return survivalCardsToApplied; + } + + /********************************** + * PlaceCardDeck methods + **********************************/ + + public List getPlaceCards() { + return placeCards.getPlaceCards(); + } + + public List getPlaceCardsPlayed() { + return placeCards.getPlayedCards(); + } + + public List getDefausse() { + return placeCards.getDefausse(); + } + + public void setPlaceCards(List placeCards) { + this.placeCards.setPlaceCards(placeCards); + } + + public void setDefausse(List placeCards) { + this.placeCards.setDefausse(placeCards); + } + + public PlaceCardDeck getPlaceCardsDeck(){ + return placeCards; + } + + public int placeCardHandSize(){ + return placeCards.handSize(); + } + + public boolean placeCardIsEmpty(){ + return placeCards.handIsEmpty(); + } + + public int defausseSize(){ + return placeCards.defausseSize(); + } + + public boolean defausseIsEmpty(){ + return placeCards.defausseIsEmpty(); + } + + public int placeCardPlayedSize(){ + return placeCards.playedCardSize(); + } + + public boolean placeCardPlayedIsEmpty() { + return placeCards.playedCardIsEmpty(); + } + + /** + * Put the played cards in the "defausse" + * @return true is the operation is a succeed, else otherwise + */ + public boolean throwAwayPlaceCard(){ + return placeCards.throwAway(); + } + + /** + * Put the card in the "defausse" + * @param card The card + * @return true is the operation is a succeed, else otherwise + */ + public boolean throwAwayPlaceCard(PlaceCard card){ + return placeCards.throwAway(card); + } + + /** + * Put the cards in the "defausse" + * @param cards The cards + * @return true is the operation is a succeed, else otherwise + */ + public boolean throwAwayPlaceCard(List cards){ + return placeCards.throwAway(cards); + } + + /** + * Put back the card in the hand + * @param card The card + * @return true is the operation is a succeed, else otherwise + */ + public boolean takeBackPlaceCard(PlaceCard card){ + return placeCards.takeBack(card); + } + + /** + * Put back the cards in the hand + * @param cards The cards + * @return true is the operation is a succeed, else otherwise + */ + public boolean takeBackPlaceCard(List cards){ + return placeCards.takeBack(cards); + } + + public void takeBackPlayedPlaceCards() { + placeCards.takeBackPlayedPlaceCards(); + } + + /** + * Move all the cards from defausse to the hand + */ + public void takeBackAllPlaceCardFromDefausse() { + placeCards.takeBackAllFromDefausse(); + } + + public boolean addPlaceCard(PlaceCard card){ + return placeCards.add(card); + } + + public boolean addPlaceCard(List cards){ + return placeCards.add(cards); + } + + public boolean addPlaceCardInDefausse(PlaceCard card){ + return placeCards.addInDefausse(card); + } + + public boolean addPlaceCardInDefausse(List cards){ + return placeCards.addInDefausse(cards); + } + + public boolean playPlaceCard(PlaceCard card){ + return placeCards.play(card); + } + + public boolean playPlaceCard(List cards){ + return placeCards.play(cards); + } + + /********************************** + * SurvivalCardDeck methods + **********************************/ + + public Deck getSurvivalCardsDeck(){ + return survivalCards; + } + + public List getSurvivalCardsHand() { + return survivalCards.getCards(); + } + + public List getSurvivalCardsPlayed() { + return survivalCards.getPlayedCards(); + } + + public int survivalCardHandSize(){ + return survivalCards.handSize(); + } + + public int survivalCardPlayedSize(){ + return this.survivalCards.playedCardSize(); + } + + public boolean survivalCardIsEmpty(){ + return survivalCards.handIsEmpty(); + } + + public boolean survivalCardPlayedIsEmpty(){ + return survivalCards.playedCardIsEmpty(); + } + + public void clearSurvivalCardPlayed() { + survivalCards.clear(); + } + + public boolean addSurvivalCard(SurvivalCard card){ + return survivalCards.add(card); + } + + public boolean addSurvivalCard(List cardList){ + return survivalCards.add(cardList); + } + + public boolean removeSurvivalCard(SurvivalCard card){ + return survivalCards.remove(card); + } + + public boolean removeSurvivalCard(List cardList){ + return survivalCards.remove(cardList); + } + + public boolean playSurvivalCard(SurvivalCard card){ + return survivalCards.play(card); + } + + public boolean playSurvivalCard(List cardList){ + return survivalCards.play(cardList); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/hand/PlaceCardDeck.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/hand/PlaceCardDeck.java new file mode 100644 index 0000000000000000000000000000000000000000..31052101564b0e2d953a5fe1b7dd049060c9d9b5 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/hand/PlaceCardDeck.java @@ -0,0 +1,229 @@ +package fr.univnantes.alma.server.game.item.player.hand; + +import fr.univnantes.alma.server.game.item.card.PlaceCard; + +import java.util.ArrayList; +import java.util.List; + +public class PlaceCardDeck { + private List placeCards; + private List defausse; + private List playedCards; + + public PlaceCardDeck(){ + this.defausse = new ArrayList<>(); + this.placeCards = new ArrayList<>(); + this.playedCards = new ArrayList<>(); + } + + public PlaceCardDeck(List cards){ + this.placeCards = cards; + this.defausse = new ArrayList<>(); + this.playedCards = new ArrayList<>(); + } + + public List getPlayedCards() { + return playedCards; + } + + public List getPlaceCards() { + return placeCards; + } + + public List getDefausse() { + return defausse; + } + + + public void setPlaceCards(List placeCards) { + this.placeCards = placeCards; + } + + public void setDefausse(List defausse) { + this.defausse = defausse; + } + + public void setPlayedCards(List playedCards) { + this.playedCards = playedCards; + } + + /** + * Put the played cards in the "defausse" + * @return true is the operation is a succeed, else otherwise + */ + public boolean throwAway(){ + boolean ok = defausse.addAll(playedCards); + playedCards.clear(); + return ok; + } + + /** + * Put the card in the "defausse" + * @param card The card + * @return true is the operation is a succeed, else otherwise + */ + public boolean throwAway(PlaceCard card){ + if(placeCards.contains(card) || playedCards.contains(card)){ + placeCards.remove(card); + playedCards.remove(card); + defausse.add(card); + return true; + } + else{ + return false; + } + } + + /** + * Put the cards in the "defausse" + * @param cards The cards + * @return true is the operation is a succeed, else otherwise + */ + public boolean throwAway(List cards){ + List aux = new ArrayList<>(); + aux.addAll(placeCards); + aux.addAll(playedCards); + if(aux.containsAll(cards)){ + placeCards.removeAll(cards); + playedCards.removeAll(cards); + defausse.addAll(cards); + return true; + } + else{ + return false; + } + } + + /** + * Put back the card in the hand + * @param card The card + * @return true is the operation is a succeed, else otherwise + */ + public boolean takeBack(PlaceCard card){ + if(defausse.contains(card) || playedCards.contains(card)){ + defausse.remove(card); + playedCards.remove(card); + placeCards.add(card); + return true; + } + else{ + return false; + } + } + + /** + * Put back the cards in the hand + * @param cards The cards + * @return true is the operation is a succeed, else otherwise + */ + public boolean takeBack(List cards){ + List aux = new ArrayList<>(); + aux.addAll(defausse); + aux.addAll(playedCards); + if(aux.containsAll(cards)){ + defausse.removeAll(cards); + playedCards.removeAll(cards); + placeCards.addAll(cards); + return true; + } + else{ + return false; + } + } + + /** + * Move all the cards in defausse to the hand + */ + public void takeBackAllFromDefausse() { + placeCards.addAll(defausse); + defausse.clear(); + } + + public void takeBackPlayedPlaceCards() { + placeCards.addAll(playedCards); + playedCards = new ArrayList<>(); + } + + public boolean add(PlaceCard card){ + if(!placeCards.contains(card) && !defausse.contains(card)){ + return placeCards.add(card); + } + else{ + return false; + } + } + + public boolean add(List cards){ + if(!placeCards.containsAll(cards) && !defausse.containsAll(cards)){ + return placeCards.addAll(cards); + } + else{ + return false; + } + } + + public boolean addInDefausse(PlaceCard card){ + if(!placeCards.contains(card) && !defausse.contains(card)){ + return defausse.add(card); + } + else{ + return false; + } + } + + public boolean addInDefausse(List cards){ + if(!placeCards.containsAll(cards) && !defausse.containsAll(cards)){ + return defausse.addAll(cards); + } + else{ + return false; + } + } + + public boolean play(PlaceCard card){ + if(placeCards.contains(card)){ + playedCards.add(card); + placeCards.remove(card); + return true; + } + else { + throw new IllegalArgumentException("The played card must be in the hand."); + } + } + + public boolean play(List cards){ + if(placeCards.containsAll(cards)){ + playedCards.addAll(cards); + placeCards.removeAll(cards); + return true; + } + else { + throw new IllegalArgumentException("The played cards must be in the hand."); + } + } + + + public int handSize(){ + return placeCards.size(); + } + + public boolean handIsEmpty(){ + return placeCards.isEmpty(); + } + + public int defausseSize(){ + return defausse.size(); + } + + public boolean defausseIsEmpty(){ + return defausse.isEmpty(); + } + + public int playedCardSize(){ + return playedCards.size(); + } + + public boolean playedCardIsEmpty(){ + return playedCards.isEmpty(); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/rights/CreatureRight.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/rights/CreatureRight.java new file mode 100644 index 0000000000000000000000000000000000000000..57c279fe81af63d036b4a4726d7d8243a136a211 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/rights/CreatureRight.java @@ -0,0 +1,21 @@ +package fr.univnantes.alma.server.game.item.player.rights; + +public class CreatureRight { + private int maxTrackingCardPlayable; + + public CreatureRight() { + this.maxTrackingCardPlayable = 1; + } + + public void reset() { + this.maxTrackingCardPlayable = 1; + } + + public int getMaxTrackingCardPlayable() { + return maxTrackingCardPlayable; + } + + public void setMaxTrackingCardPlayable(int maxTrackingCardPlayable) { + this.maxTrackingCardPlayable = maxTrackingCardPlayable; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/rights/TraqueRight.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/rights/TraqueRight.java new file mode 100644 index 0000000000000000000000000000000000000000..aa8de4c9cd2968a6a6a9540008a5a87ee7105369 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/player/rights/TraqueRight.java @@ -0,0 +1,87 @@ +package fr.univnantes.alma.server.game.item.player.rights; + +public class TraqueRight { + private int maxPlacesCardChoosable; + private int placeCardsVisible; + private int maxPlacesCardPlayable; + private int maxSurvivalCardPlayable; + private boolean canResist; + private boolean canGiveUp; + private int numberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist; + + public TraqueRight() { + this.maxPlacesCardChoosable = 1; + this.maxPlacesCardPlayable = 1; + this.maxSurvivalCardPlayable = 1; + this.canResist = true; + this.canGiveUp = true; + this.placeCardsVisible = 0; + this.numberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist = 0; + } + + public void reset(){ + this.maxPlacesCardChoosable = 1; + this.maxPlacesCardPlayable = 1; + this.maxSurvivalCardPlayable = 1; + this.canResist = true; + this.canGiveUp = true; + this.placeCardsVisible = 0; + this.numberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist = 0; + } + + public int getMaxPlacesCardChoosable() { + return maxPlacesCardChoosable; + } + + public void setMaxPlacesCardChoosable(int maxPlacesCardChoosable) { + this.maxPlacesCardChoosable = maxPlacesCardChoosable; + } + + public int getMaxPlacesCardPlayable() { + return maxPlacesCardPlayable; + } + + public void setMaxPlacesCardPlayable(int maxPlacesCardPlayable) { + this.maxPlacesCardPlayable = maxPlacesCardPlayable; + } + + public int getMaxSurvivalCardPlayable() { + return maxSurvivalCardPlayable; + } + + public void setMaxSurvivalCardPlayable(int maxSurvivalCardPlayable) { + this.maxSurvivalCardPlayable = maxSurvivalCardPlayable; + } + + public boolean canResist() { + return canResist; + } + + public void setCanResist(boolean canResist) { + this.canResist = canResist; + } + + public boolean canGiveUp() { + return canGiveUp; + } + + public void setCanGiveUp(boolean canGiveUp) { + this.canGiveUp = canGiveUp; + } + + public int getPlaceCardsVisible() { + return placeCardsVisible; + } + + public void setPlaceCardsVisible(int placeCardsVisible) { + this.placeCardsVisible = placeCardsVisible; + } + + public int getNumberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist() { + return numberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist; + } + + public void setNumberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist(int number) { + this.numberOfAdditionalCardsTakeBackPerPawnWillingnessLostWithResist = number; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/power/Power.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/power/Power.java new file mode 100644 index 0000000000000000000000000000000000000000..c093ef93c261c2c69d7e8d20b49d21ffeeec35b8 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/power/Power.java @@ -0,0 +1,15 @@ +package fr.univnantes.alma.server.game.item.power; + +public abstract class Power { + protected int inGameIdPlayer; + + public Power(int inGameIdPlayer) { + this.inGameIdPlayer = inGameIdPlayer; + } + + public int getInGameIdPlayer() { + return inGameIdPlayer; + } + + public abstract PowerType getType(); +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/power/PowerType.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/power/PowerType.java new file mode 100644 index 0000000000000000000000000000000000000000..8cbd71b716ac204c6268f95affdbc2dd65c7f81f --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/power/PowerType.java @@ -0,0 +1,5 @@ +package fr.univnantes.alma.server.game.item.power; + +public enum PowerType { + MODIFICATOR, RECURRENT +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/power/modifier/PowerModifier.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/power/modifier/PowerModifier.java new file mode 100644 index 0000000000000000000000000000000000000000..b02f6793146b99fe33c7c170870039490acb5f9f --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/power/modifier/PowerModifier.java @@ -0,0 +1,29 @@ +package fr.univnantes.alma.server.game.item.power.modifier; + +import fr.univnantes.alma.server.game.item.power.Power; +import fr.univnantes.alma.server.game.item.power.PowerType; + +public class PowerModifier extends Power { + + private PowerModifierType modificatorType; + private Object modifiedValue; + + public PowerModifier(int playerId, PowerModifierType modificatorType, Object modifiedValue) { + super(playerId); + this.modificatorType = modificatorType; + this.modifiedValue = modifiedValue; + } + + public PowerModifierType getModificatorType() { + return modificatorType; + } + + public Object getModifiedValue() { + return modifiedValue; + } + + @Override + public PowerType getType() { + return PowerType.MODIFICATOR; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/power/modifier/PowerModifierType.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/power/modifier/PowerModifierType.java new file mode 100644 index 0000000000000000000000000000000000000000..33c1de0ccca7b43c7b14e4c84cc76588ea0e8111 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/power/modifier/PowerModifierType.java @@ -0,0 +1,6 @@ +package fr.univnantes.alma.server.game.item.power.modifier; + +public enum PowerModifierType { + CHOOSABLE_PLACE_CARD, PLAYABLE_PLACE_CARD, CHOOSABLE_VISIBLE_ADDITIONAL_PLACE_CARD, PLAYABLE_TRACKING_CARD, + USE_FJORD_IN_PREVIOUS_ROUND +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/power/recurrent/PowerRecurrent.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/power/recurrent/PowerRecurrent.java new file mode 100644 index 0000000000000000000000000000000000000000..59a527a76c8cf33f96cff1e57d453a2404798837 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/item/power/recurrent/PowerRecurrent.java @@ -0,0 +1,33 @@ +package fr.univnantes.alma.server.game.item.power.recurrent; + +import fr.univnantes.alma.server.game.Game; +import fr.univnantes.alma.server.game.item.power.Power; +import fr.univnantes.alma.server.game.item.power.PowerType; + +import java.util.function.BiConsumer; +import java.util.function.BiPredicate; + +public class PowerRecurrent extends Power { + + private final BiConsumer action; + private final BiPredicate condition; + + public PowerRecurrent(int inGameIdPlayer, BiConsumer action, BiPredicate condition) { + super(inGameIdPlayer); + this.action = action; + this.condition = condition; + } + + public void apply(Game game) { + action.accept(inGameIdPlayer, game); + } + + public boolean conditionIsTrue(Game game) { + return condition.test(inGameIdPlayer, game); + } + + @Override + public PowerType getType() { + return PowerType.RECURRENT; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/Conversion.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/Conversion.java new file mode 100644 index 0000000000000000000000000000000000000000..f0d8a1ca3da896fe8c88ada473f8ecb44577f936 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/Conversion.java @@ -0,0 +1,542 @@ +package fr.univnantes.alma.server.game.utilitary; + +import fr.univnantes.alma.data.DatabaseFactory; +import fr.univnantes.alma.common.NotAloneDatabase; +import fr.univnantes.alma.server.game.GameRoundVariables; +import fr.univnantes.alma.server.game.item.Reserve; +import fr.univnantes.alma.server.game.item.action.*; +import fr.univnantes.alma.server.game.item.board.Board; +import fr.univnantes.alma.server.game.item.board.BoardColor; +import fr.univnantes.alma.server.game.item.board.BoardDistribution; +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.card.*; +import fr.univnantes.alma.server.game.item.jeton.*; +import fr.univnantes.alma.server.game.item.planet.Place; +import fr.univnantes.alma.server.game.item.planet.PlaceDistribution; +import fr.univnantes.alma.server.game.item.planet.Planet; +import fr.univnantes.alma.server.game.item.planet.PlanetPawn; +import fr.univnantes.alma.server.game.item.player.Creature; +import fr.univnantes.alma.server.game.item.player.Player; +import fr.univnantes.alma.server.game.item.player.PlayerTeam; +import fr.univnantes.alma.server.game.item.player.Traque; +import fr.univnantes.alma.server.user.User; +import fr.univnantes.alma.thrift.*; + +import java.util.*; +import java.util.stream.Collectors; + +import static fr.univnantes.alma.server.game.item.card.Card.CardType; + +/** + * Allows to convert Thrift type into object + */ +public class Conversion { + + private static final NotAloneDatabase DATABASE = DatabaseFactory.getDatabase(); + + private Conversion(){} + + /************************************* + * Phase + ***********************************/ + + /** + * Convert a string describing a phase in a Phase + * @param s The string + * @return A phase corresponding to s + * @throws IllegalArgumentException if s doesn't represent a phase + */ + public static Phase toPhase(String s) { + try{ + return Phase.valueOf(s); + } + catch(Exception e){ + throw new IllegalArgumentException(s + " is not a valid phase"); + } + } + + /** + * Convert a TPhaseId in a Phase + * @param tphase The tphase + * @return A Phase + * @throws IllegalArgumentException if tphase doesn't represent a phase + */ + public static Phase toPhase(TPhase tphase) { + return toPhase(tphase.getName()); + } + + /************************************* + * Board + ***********************************/ + + /** + * Convert a string describing a color in a BoardColor + * @param s The string + * @return A board color + * @throws IllegalArgumentException if s doesn't represent a valid color + */ + public static BoardColor toBoardColor(String s) { + try { + return BoardColor.valueOf(s); + } + catch (Exception e) { + throw new IllegalArgumentException(s + " is not a valid board color"); + } + } + + /** + * Convert a TColor in a BoardColor + * @param color The TColor + * @return a BoardColor + * @throws IllegalArgumentException if TColor doesn't represent a valid color + */ + public static BoardColor toBoardColor(TColor color) { + return toBoardColor(color.getColor()); + } + + /** + * Convert a string describing a board distribution in a BoardDistribution + * @param s The string + * @return A board distribution + * @throws IllegalArgumentException if s doesn't represent a valid board distribution + */ + public static BoardDistribution toBoardDistribution(String s) { + try { + return BoardDistribution.valueOf(s); + } + catch (Exception e){ + throw new IllegalArgumentException(s + " doesn't represent a valid board distribution"); + } + } + + /** + * Convert a TBoard in a BoardDistribution + * @param tBoard The TBoard + * @return a BoardDistribution + * @throws IllegalArgumentException if tBoard is not a valid board distribution + */ + public static BoardDistribution toBoardDistribution(TBoard tBoard){ + return toBoardDistribution(tBoard.getBoard()); + } + + /************************************* + * Card + ***********************************/ + + /** + * Convert a String in a CardType + * @param tCardType The string + * @return a CardType + * @throws IllegalArgumentException if the string is not a valid card type + */ + public static CardType toCardType(String tCardType){ + try { + return CardType.valueOf(tCardType); + } + catch (Exception e){ + throw new IllegalArgumentException(tCardType + " doesn't represent a valid card type"); + } + } + + /** + * Convert a TCard in a Card + * @param tCard the TCard + * @return a Card + * @throws IllegalArgumentException if the TCard is not valid + */ + public static Card toCard(TCard tCard){ + CardType type = toCardType(tCard.getCardType()); + Card card; + switch (type){ + case PLACE: + card = DATABASE.findPlaceCard(tCard.getCardName()); + break; + case SURVIVAL: + card = DATABASE.findSurvivalCard(tCard.getCardName()); + break; + case TRACKING: + default: + card = DATABASE.findTrackingCard(tCard.getCardName()); + break; + } + if(card == null){ + throw new IllegalArgumentException("Card not found"); + } + return card; + } + + /** + * Convert a list of t cards in a list of cards + * @param tCards The list of TCard + * @return A list of Card + */ + public static List toCardList(List tCards){ + List cards = new ArrayList<>(); + for (TCard tc : tCards){ + cards.add(toCard(tc)); + } + return cards; + } + + /** + * Convert a list of t place cards in a list of place cards + * @param tPlaceCards The list of TCard + * @return A list of PlaceCard + * @throws IllegalArgumentException if the list doesn't represent a correct place cards list + */ + public static List toPlaceCardList(List tPlaceCards) { + List placeCards = new ArrayList<>(); + Card temp; + PlaceCard card; + for(TCard tCard : tPlaceCards){ + temp = toCard(tCard); + if(! temp.getType().equals(CardType.PLACE)){ + throw new IllegalArgumentException(tCard.getCardName() + " is not a place card"); + } + card = (PlaceCard) temp; + placeCards.add(card); + } + return placeCards; + } + + public static CardName toCardName(String name) { + try { + return CardName.valueOf(name); + } + catch (Exception e){ + throw new IllegalArgumentException(name + " doesn't represent a valid card name"); + } + } + + public static TCard toTCard(PlaceCard card) { + List attributes = new ArrayList<>(); + attributes.add(new TPair("NAME", card.getName())); + attributes.add(new TPair("DESCRIPTION", card.getDescription())); + attributes.add(new TPair("COLOR", card.getColor())); + attributes.add(new TPair("IMAGE", card.getImageUrl())); + attributes.add(new TPair("NUMBER", card.getNumber()+"")); + return new TCard("PLACE", card.getCardName().toString(), attributes); + } + + public static TCard toTCard(SurvivalCard card) { + List attributes = new ArrayList<>(); + attributes.add(new TPair("NAME", card.getName())); + attributes.add(new TPair("DESCRIPTION", card.getDescription())); + attributes.add(new TPair("PHASE", card.getPhase().toString())); + return new TCard("SURVIVAL", card.getCardName().toString(), attributes); + } + + public static TCard toTCard(TrackingCard card) { + List attributes = new ArrayList<>(); + attributes.add(new TPair("NAME", card.getName())); + attributes.add(new TPair("DESCRIPTION", card.getDescription())); + attributes.add(new TPair("PHASE", card.getPhase().toString())); + for(JetonSymbol symbol : card.getJetons()) { + attributes.add(new TPair("SYMBOL", symbol.toString())); + } + return new TCard("TRACKING", card.getCardName().toString(), attributes); + } + + public static TCard toTCard(Card card) { + if(card.getType().equals(CardType.PLACE)) { + PlaceCard placeCard = (PlaceCard) card; + return toTCard(placeCard); + } + else if(card.getType().equals(CardType.SURVIVAL)) { + SurvivalCard survivalCard = (SurvivalCard) card; + return toTCard(survivalCard); + } + else if(card.getType().equals(CardType.TRACKING)){ + TrackingCard trackingCard = (TrackingCard) card; + return toTCard(trackingCard); + } + else { + throw new IllegalArgumentException(card.getType() + " doesn t represent a valid CardType"); + } + } + + /************************************* + * Jeton + ***********************************/ + + /** + * Convert a String in a Jeton + * @param s + * @return + */ + public static JetonSymbol toJetonSymbol(String s){ + try { + return JetonSymbol.valueOf(s); + } + catch (Exception e){ + throw new IllegalArgumentException(s + " doesn't represent a valid JetonSymbol"); + } + } + + /** + * Convert a TPlacedJeton in a Jeton + * @param tPlacedJeton + * @return + */ + public static PlacedJeton toPlacedJeton(TPlacedJeton tPlacedJeton){ + return new PlacedJeton(toJetonSymbol(tPlacedJeton.getJeton().getSymbol()), toPlaceList(tPlacedJeton.position)); + } + + /** + * Convert a list of TPlacedJeton in a list of Jeton + * @param tPlacedJetons + * @return + */ + public static List toPlacedJetonList(List tPlacedJetons){ + List placedJetons = new ArrayList<>(); + for(TPlacedJeton tpj : tPlacedJetons){ + placedJetons.add(toPlacedJeton(tpj)); + } + return placedJetons; + } + + public static TPlacedJeton toTPlacedJeton(PlacedJeton placedJeton) { + TPositionJeton tPositionJeton = new TPositionJeton(placedJeton.getPlaces().stream().map(Place::toString).collect(Collectors.toList())); + return new TPlacedJeton(new TJeton(placedJeton.getJetonSymbol().toString()), tPositionJeton); + } + + /************************************* + * Place + ***********************************/ + + /** + * Convert a string into a Place + * @param s The String + * @return A Place + */ + public static Place toPlace(String s){ + try { + return Place.valueOf(s); + } + catch (Exception e){ + throw new IllegalArgumentException(s + " does't represent a valid Place"); + } + } + + /** + * Convert a TPositionJeton in a list of Place + * @param positionJeton + * @return + */ + public static List toPlaceList(TPositionJeton positionJeton){ + List places = new ArrayList<>(); + for(String s : positionJeton.position){ + places.add(toPlace(s)); + } + return places; + } + + /** + * Convert a list of string in a list of Place + * @param strings + * @return + */ + public static List toPlaceList(List strings){ + List places = new ArrayList<>(); + for(String s : strings){ + places.add(toPlace(s)); + } + return places; + } + + /************************************* + * Action + ***********************************/ + + public static TPairType toTPairType(String name) { + try { + return TPairType.valueOf(name); + } + catch (Exception e){ + throw new IllegalArgumentException(name + " doesn't a valid TPairTypeName"); + } + } + + public static Action toAction(TAction tAction){ + ActionType type; + try { + type = ActionType.valueOf(tAction.getType()); + } + catch (Exception e){ + throw new IllegalArgumentException(tAction.getType() + " doesn't represent a valid ActionType"); + } + switch (type){ + case CHOOSE_POWER: + return new ActionChoosePower(tAction.getParams()); + case TARGET_PLAYER: + return new ActionTargetPlayer(tAction.getParams()); + case MOVE_PLAYER: + return new ActionMovePlayer(tAction.getParams()); + case CHOOSE_CARD: + return new ActionChooseCard(tAction.getParams()); + case CHOOSE_PLACE: + return new ActionChoosePlace(tAction.getParams()); + case SWAP_JETONS: + return new ActionSwapJeton(tAction.getParams()); + case ASSOCIATE_CARDNAMES_TO_PLACES: + default: + return new ActionAssociateCardNamesToPlaces(tAction.getParams()); + } + } + + public static User toUser(TPlayer tPlayer) { + return new User(tPlayer.getToken(), tPlayer.getName(), tPlayer.getAddress(), tPlayer.getPort()); + } + + /************************************* + * Score + ***********************************/ + + public static TScore toTScore(Board board) { + return new TScore( + board.getScoreTraque(), + board.getScoreCreature(), + new TBoard(board.getBoardDistribution().toString()), + new TColor(board.getBoardColor().toString())); + } + + /************************************* + * Planet + ***********************************/ + + public static TPlacedCard toTPlacedCard(PlaceCard placeCard, Place place) { + return new TPlacedCard(toTCard(placeCard), place.toString()); + } + + public static List toTPlacedJetonList(List placedJetons) { + List tPlacedJetons = new ArrayList<>(); + TJeton tJeton; + TPositionJeton tPositionJeton; + for(PlacedJeton placedJeton : placedJetons) { + tJeton = toTJeton(placedJeton.getJetonSymbol()); + tPositionJeton = new TPositionJeton(placedJeton.getPlaces().stream().map(Place::toString).collect(Collectors.toList())); + tPlacedJetons.add(new TPlacedJeton(tJeton, tPositionJeton)); + } + return tPlacedJetons; + } + + public static TJeton toTJeton(JetonSymbol symbol) { + return new TJeton(symbol.toString()); + } + + public static TBalise toTBalise(PlanetPawn planetPawn) { + return new TBalise(planetPawn.getType().toString(), planetPawn.stateToInt()); + } + + public static TPlanet toTPlanet(Planet planet) { + PlaceDistribution placeDistribution = planet.getPlaceDistribution(); + Map mapCardNumberToPlaceCard = placeDistribution.getMapCardNumberToPlaceCard(); + Map placeCardPlaceMap = placeDistribution.getMapPlaceCardToPlace(); + List tPlacedCards = new ArrayList<>(); + PlaceCard card; + Place place; + for(int i = 1 ; i <= 10 ; ++i) { + card = mapCardNumberToPlaceCard.get(i); + place = placeCardPlaceMap.get(card); + if(planet.isRevealedPlace(card)) { + tPlacedCards.add(toTPlacedCard(card, place)); + } + else { + tPlacedCards.add( + new TPlacedCard(new TCard("PLACE", "HIDDEN", new ArrayList<>()), + place.toString())); + } + } + List tPlacedJetons = toTPlacedJetonList(planet.getPlacedJetons()); + TBalise tBalise = toTBalise(planet.getPlanetPawn()); + return new TPlanet(tPlacedCards, tPlacedJetons, tBalise); + } + + /************************************* + * Reserve + ***********************************/ + + public static TCardReserve toTCardReserve(Pair pair) { + return new TCardReserve(toTCard(pair.getKey()), pair.getValue()); + } + + public static List toTCardReserveList(Reserve reserve) { + Map> map = reserve.getPlaceCards(); + List tCardReserves = new ArrayList<>(); + for(int i = 6 ; i <= 10 ; ++i) { + tCardReserves.add(toTCardReserve(map.get(i))); + } + return tCardReserves; + } + + /************************************* + * Game variable + ***********************************/ + + public static List toTGameVariable(GameRoundVariables variables) { + List tGameVariables = new ArrayList<>(); + tGameVariables.add(new TGameVariable("NUMBER_PAWN_WILLINGNESS_ON_BOARD", Collections.singletonList(new TPair("NUMBER", variables.getNumberPawnWillingnessOnBoard() + "")))); + return tGameVariables; + } + + public static TCreature toTCreature(Creature creature) { + List trackingCards = new ArrayList<>(creature.getTrackingCardsPlayed()); + List visible = trackingCards.stream().map(Conversion::toTCard).collect(Collectors.toList()); + List tJetons = creature.getJetons().stream().map(Conversion::toTJeton).collect(Collectors.toList()); + return new TCreature(creature.getName(), visible, creature.getTrackingCardHand().size(), tJetons); + } + + public static TTraque toTTraque(Traque traque) { + String name = traque.getName(); + int hiddenPlaceCardNumber = traque.getPlaceCards().size(); + int hiddenSurvivalCardNumber = traque.getSurvivalCardsHand().size(); + List defausse = traque.getDefausse().stream().map(Conversion::toTCard).collect(Collectors.toList()); + List survivalCards = traque.getSurvivalCardsPlayed().stream().map(Conversion::toTCard).collect(Collectors.toList()); + int numberPawnWillingness = traque.getNumberWillingness(); + return new TTraque(name, survivalCards, hiddenPlaceCardNumber, defausse, hiddenSurvivalCardNumber, numberPawnWillingness); + } + + public static TTraque toTTraquePlaceCardPlayedVisible(Traque traque) { + String name = traque.getName(); + int hiddenPlaceCardNumber = traque.getPlaceCards().size(); + int hiddenSurvivalCardNumber = traque.getSurvivalCardsHand().size(); + List defausse = traque.getDefausse().stream().map(Conversion::toTCard).collect(Collectors.toList()); + List survivalCardsPlayed = traque.getSurvivalCardsPlayed().stream().map(Conversion::toTCard).collect(Collectors.toList()); + List placeCardsPlayed = traque.getPlaceCardsPlayed().stream().map(Conversion::toTCard).collect(Collectors.toList()); + List visible = new ArrayList<>(survivalCardsPlayed); + visible.addAll(placeCardsPlayed); + int numberPawnWillingness = traque.getNumberWillingness(); + return new TTraque(name, visible, hiddenPlaceCardNumber, defausse, hiddenSurvivalCardNumber, numberPawnWillingness); + } + + public static THand toTHand(Traque traque) { + List tCards = new ArrayList<>(); + tCards.addAll(traque.getPlaceCards().stream().map(Conversion::toTCard).collect(Collectors.toList())); + tCards.addAll(traque.getSurvivalCardsHand().stream().map(Conversion::toTCard).collect(Collectors.toList())); + List tCardsPlayed = new ArrayList<>(); + tCardsPlayed.addAll(traque.getPlaceCardsPlayed().stream().map(Conversion::toTCard).collect(Collectors.toList())); + tCardsPlayed.addAll(traque.getSurvivalCardsPlayed().stream().map(Conversion::toTCard).collect(Collectors.toList())); + List tCardsDefausse = new ArrayList<>(); + tCardsPlayed.addAll(traque.getDefausse().stream().map(Conversion::toTCard).collect(Collectors.toList())); + int numberPawnWillingness = traque.getNumberWillingness(); + return new THand(tCards, tCardsPlayed, new ArrayList<>(), numberPawnWillingness, tCardsDefausse); + } + + public static THand toTHand(Creature creature) { + List tCards = creature.getTrackingCardHand().stream().map(Conversion::toTCard).collect(Collectors.toList()); + List tCardsPlayed = creature.getTrackingCardsPlayed().stream().map(Conversion::toTCard).collect(Collectors.toList()); + List tJetons = creature.getJetons().stream().map(Conversion::toTJeton).collect(Collectors.toList()); + return new THand(tCards, tCardsPlayed, tJetons, -1, new ArrayList<>()); + } + + public static THand toTHand(Player player) { + if(player.getTeam().equals(PlayerTeam.CREATURE)) { + Creature creature = (Creature) player; + return toTHand(creature); + } + else { + Traque traque = (Traque) player; + return toTHand(traque); + } + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/Pair.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/Pair.java new file mode 100644 index 0000000000000000000000000000000000000000..ef95623c74284713af8569286b454caa5382e983 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/Pair.java @@ -0,0 +1,37 @@ +package fr.univnantes.alma.server.game.utilitary; + +public class Pair { + private T key; + private U value; + + public Pair(T key, U value) { + this.key = key; + this.value = value; + } + + public T getKey() { + return key; + } + + public U getValue() { + return value; + } + + @Override + public boolean equals(Object obj) { + if(obj == this){ + return true; + } + if(obj == null || ! (obj instanceof Pair)){ + return false; + } + + Pair pair = (Pair) obj; + return key.equals(pair.getKey()) && value.equals(pair.getValue()); + } + + @Override + public String toString() { + return "Pair(" + key + ", " + value + ")"; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GameFinishPhaseRequest.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GameFinishPhaseRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..7933ee8b8e1df60c1b30b0a5d6991c188e40f33b --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GameFinishPhaseRequest.java @@ -0,0 +1,31 @@ +package fr.univnantes.alma.server.game.utilitary.request; + +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.user.User; + +public class GameFinishPhaseRequest extends GameRequest{ + private Phase phase; + + public GameFinishPhaseRequest(User user, Phase phase) { + super(user); + this.phase = phase; + } + + public Phase getPhase() { + return phase; + } + + @Override + public GameRequestType getType() { + return GameRequestType.FINISH_PHASE; + } + + @Override + public boolean equals(Object obj) { + if(!super.equals(obj)) { + return false; + } + GameFinishPhaseRequest gameFinishPhaseRequest = (GameFinishPhaseRequest) obj; + return phase.equals(gameFinishPhaseRequest.getPhase()); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GameGiveUpRequest.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GameGiveUpRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..26b8395cf11847fdbc6366a34252045cc0c93cfd --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GameGiveUpRequest.java @@ -0,0 +1,15 @@ +package fr.univnantes.alma.server.game.utilitary.request; + +import fr.univnantes.alma.server.user.User; + +public class GameGiveUpRequest extends GameRequest { + + public GameGiveUpRequest(User user) { + super(user); + } + + @Override + public GameRequestType getType() { + return GameRequestType.GIVE_UP; + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GameJoinRequest.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GameJoinRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..65ca7184176e0fc2bac8850a1ccc28cc7734b3c5 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GameJoinRequest.java @@ -0,0 +1,31 @@ +package fr.univnantes.alma.server.game.utilitary.request; + +import fr.univnantes.alma.server.user.User; + +public class GameJoinRequest extends GameRequest { + + private int inGameId; + + public GameJoinRequest(User user, int id){ + super(user); + this.inGameId = id; + } + + public int getInGameId() { + return inGameId; + } + + @Override + public GameRequestType getType() { + return GameRequestType.JOIN; + } + + @Override + public boolean equals(Object obj) { + if(!super.equals(obj)) { + return false; + } + GameJoinRequest gameJoinRequest = (GameJoinRequest) obj; + return inGameId == gameJoinRequest.getInGameId(); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GamePlaceJetonsRequest.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GamePlaceJetonsRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..26e561c20256944d4af556e35dd1b98d2d150de1 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GamePlaceJetonsRequest.java @@ -0,0 +1,33 @@ +package fr.univnantes.alma.server.game.utilitary.request; + +import fr.univnantes.alma.server.game.item.jeton.PlacedJeton; +import fr.univnantes.alma.server.user.User; + +import java.util.List; + +public class GamePlaceJetonsRequest extends GameRequest{ + private List jetonList; + + public GamePlaceJetonsRequest(User user, List jetonList) { + super(user); + this.jetonList = jetonList; + } + + public List getJetonList() { + return jetonList; + } + + @Override + public GameRequestType getType() { + return GameRequestType.PLACE_JETONS; + } + + @Override + public boolean equals(Object obj) { + if(!super.equals(obj)) { + return false; + } + GamePlaceJetonsRequest gamePlaceJetonsRequest = (GamePlaceJetonsRequest) obj; + return jetonList.equals(gamePlaceJetonsRequest.getJetonList()); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GamePlayCardsRequest.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GamePlayCardsRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..d2975ac2fa9f9f620914d9a588315c7903182438 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GamePlayCardsRequest.java @@ -0,0 +1,34 @@ +package fr.univnantes.alma.server.game.utilitary.request; + +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.card.Card; +import fr.univnantes.alma.server.user.User; + +import java.util.List; + +public class GamePlayCardsRequest extends GameRequest { + private List cards; + + public GamePlayCardsRequest(User user, List cards) { + super(user); + this.cards = cards; + } + + public List getCards() { + return cards; + } + + @Override + public GameRequest.GameRequestType getType() { + return GameRequest.GameRequestType.PLAY_CARDS; + } + + @Override + public boolean equals(Object obj) { + if(!super.equals(obj)) { + return false; + } + GamePlayCardsRequest gamePlayCardsRequest = (GamePlayCardsRequest) obj; + return cards.equals(gamePlayCardsRequest.getCards()); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GameRequest.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GameRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..5cb22671fb5a688026c27e706e2891dcc6ac020b --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GameRequest.java @@ -0,0 +1,32 @@ +package fr.univnantes.alma.server.game.utilitary.request; + +import fr.univnantes.alma.server.game.item.card.Card; +import fr.univnantes.alma.server.user.User; + +public abstract class GameRequest { + public enum GameRequestType{JOIN, FINISH_PHASE, PLAY_CARDS, PLACE_JETONS, RESIST, GIVE_UP} + + protected User user; + + protected GameRequest(User user) { + this.user = user; + } + + public User getUser() { + return user; + } + + public abstract GameRequestType getType(); + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || obj.getClass() != this.getClass()) { + return false; + } + GameRequest gameRequest = (GameRequest) obj; + return gameRequest.getUser().equals(this.user) && getType().equals(gameRequest.getType()); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GameResistRequest.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GameResistRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..0e64d94635307e857348ab0e0442a4eb2a6e5de1 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/game/utilitary/request/GameResistRequest.java @@ -0,0 +1,30 @@ +package fr.univnantes.alma.server.game.utilitary.request; + +import fr.univnantes.alma.server.user.User; + +public class GameResistRequest extends GameRequest { + private int number; + + public GameResistRequest(User user, int number) { + super(user); + this.number = number; + } + + public int getNumber() { + return number; + } + + @Override + public GameRequestType getType() { + return GameRequestType.RESIST; + } + + @Override + public boolean equals(Object obj) { + if(!super.equals(obj)) { + return false; + } + GameResistRequest gameResistRequest = (GameResistRequest) obj; + return number == gameResistRequest.getNumber(); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/handler/GameServiceHandler.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/handler/GameServiceHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..27515051bf14802d5903bf91995d3878a085b67b --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/handler/GameServiceHandler.java @@ -0,0 +1,96 @@ +package fr.univnantes.alma.server.handler; + +import fr.univnantes.alma.common.RoomService; +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.board.Board; +import fr.univnantes.alma.server.game.item.board.BoardColor; +import fr.univnantes.alma.server.game.item.board.BoardDistribution; +import fr.univnantes.alma.server.game.item.card.Card; +import fr.univnantes.alma.server.game.item.card.PlaceCard; +import fr.univnantes.alma.server.game.item.jeton.PlacedJeton; +import fr.univnantes.alma.server.game.item.planet.Planet; +import fr.univnantes.alma.server.game.utilitary.Conversion; +import fr.univnantes.alma.server.user.User; +import fr.univnantes.alma.thrift.*; +import org.apache.thrift.TException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +import static fr.univnantes.alma.server.game.utilitary.Conversion.toUser; + +@Component +public class GameServiceHandler implements GameService.Iface { + @Autowired + RoomService service; + + @Override + public TRoomId createRoom(TPlayer tPlayer) throws TException { + User player = toUser(tPlayer); + try{ + String gameId = service.createRoom(player); + return new TRoomId(gameId); + } + catch (Exception e){ + e.printStackTrace(); + throw new InvalidOperationException(300, e.getMessage()); + } + } + + @Override + public Response sendStartGame(TPlayer tPlayer, int idCreature,TBoard board, TColor color, List tPlaceCards) { + User player = toUser(tPlayer); + BoardDistribution boardDistribution = Conversion.toBoardDistribution(board); + BoardColor boardColor = Conversion.toBoardColor(color); + List placeCard = Conversion.toPlaceCardList(tPlaceCards); + Planet planet = new Planet(placeCard); + return service.startGame(player, idCreature, new Board(boardDistribution, boardColor), planet); + } + + @Override + public Response joinRoom(TPlayer tPlayer, TRoomId roomId) throws TException { + User player = toUser(tPlayer); + String game = roomId.getToken(); + return service.joinRoom(player, game); + } + + @Override + public TDescription getGameDescription(TPlayer tPlayer) throws TException { + User player = toUser(tPlayer); + return service.getGameDescription(player); + } + + @Override + public void sendFinishPhase(TPlayer tPlayer, TPhase tPhase) throws TException { + User player = toUser(tPlayer); + Phase phase = Conversion.toPhase(tPhase); + service.sendFinishPhase(player, phase); + } + + @Override + public void sendPlayCards(TPlayer tPlayer, List playerCards) throws TException { + User player = toUser(tPlayer); + List cards = Conversion.toCardList(playerCards); + service.sendPlayCards(player, cards); + } + + @Override + public void sendPlaceJetons(TPlayer tPlayer, List placedJetons) throws TException { + User player = toUser(tPlayer); + List jetons = Conversion.toPlacedJetonList(placedJetons); + service.sendPlaceJetons(player, jetons); + } + + @Override + public void sendResist(TPlayer tPlayer, int number) throws TException { + User player = toUser(tPlayer); + service.sendResist(player, number); + } + + @Override + public void sendGiveUp(TPlayer tPlayer) throws TException { + User player = toUser(tPlayer); + service.sendGiveUp(player); + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/user/PlayerInterface.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/user/PlayerInterface.java new file mode 100644 index 0000000000000000000000000000000000000000..1c2a6b471c1c8e3484a273fa2e305c3ea13e6eed --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/user/PlayerInterface.java @@ -0,0 +1,22 @@ +package fr.univnantes.alma.server.user; + +import fr.univnantes.alma.thrift.*; + +public interface PlayerInterface { + + public void sendGameDescription(TDescription gameDescription); + + public void sendGameStart(); + + public void sendGameIsFinished(TPlayerTeam winner); + + public void sendFirstRoundStart(); + + public void sendStartPhase(TPhase phase, TDescription gameDescription); + + public TAction askAction(TAskAction askedAction); + + public void sendAction(TAskAction askedAction); + + public void sendResponse(Response response); +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/user/PlayerProxy.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/user/PlayerProxy.java new file mode 100644 index 0000000000000000000000000000000000000000..892b9a0c2335cfc4a2ea488646b1d54f081ffd18 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/user/PlayerProxy.java @@ -0,0 +1,102 @@ +package fr.univnantes.alma.server.user; + +import fr.univnantes.alma.thrift.*; +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.transport.TSocket; +import org.apache.thrift.transport.TTransport; + +import java.util.List; + +public class PlayerProxy implements PlayerInterface { + private PlayerService.Client client; + + public PlayerProxy(String address, int port) { + TTransport transport = new TSocket(address, port); + TProtocol protocol = new TBinaryProtocol(transport); + client = new PlayerService.Client(protocol); + } + + /** + * Is usefull ? + * @return + * @throws InvalidOperationException + * @throws TException + */ + public boolean ping() throws TException { + return client.ping(); + } + + @Override + public void sendGameDescription(TDescription gameDescription) { + try { + client.sendGameDescription(gameDescription); + } catch (TException e) { + throw new IllegalArgumentException("Thrift error : " + e.getMessage()); + } + } + + @Override + public void sendGameStart() { + try { + client.sendGameStart(); + } catch (TException e) { + throw new IllegalArgumentException("Thrift error : " + e.getMessage()); + } + } + + @Override + public void sendGameIsFinished(TPlayerTeam winner) { + try { + client.sendGameIsFinished(winner); + } catch (TException e) { + throw new IllegalArgumentException("Thrift error : " + e.getMessage()); + } + } + + @Override + public void sendFirstRoundStart() { + try { + client.sendFirstRoundStart(); + } catch (TException e) { + throw new IllegalArgumentException("Thrift error : " + e.getMessage()); + } + } + + @Override + public void sendStartPhase(TPhase phase, TDescription gameDescription) { + try { + client.sendStartPhase(phase, gameDescription); + } catch (TException e) { + throw new IllegalArgumentException("Thrift error : " + e.getMessage()); + } + } + + @Override + public TAction askAction(TAskAction askedAction) { + try { + return client.askAction(askedAction); + } catch (TException e) { + throw new IllegalArgumentException("Thrift error : " + e.getMessage()); + } + } + + @Override + public void sendAction(TAskAction askedAction) { + try { + client.sendAction(askedAction); + } catch (TException e) { + throw new IllegalArgumentException("Thrift error : " + e.getMessage()); + } + } + + @Override + public void sendResponse(Response response) { + try { + client.sendResponse(response); + } catch (TException e) { + throw new IllegalArgumentException("Thrift error : " + e.getMessage()); + } + } +} diff --git a/not-alone-server/src/main/java/fr/univnantes/alma/server/user/User.java b/not-alone-server/src/main/java/fr/univnantes/alma/server/user/User.java new file mode 100644 index 0000000000000000000000000000000000000000..4de7899ec78cf71628887dabbd3d1508ca9ebf37 --- /dev/null +++ b/not-alone-server/src/main/java/fr/univnantes/alma/server/user/User.java @@ -0,0 +1,87 @@ +package fr.univnantes.alma.server.user; + +import fr.univnantes.alma.thrift.*; +import org.apache.thrift.TException; + +public class User { + private String id; + private String name; + private PlayerProxy service; + + public User(String id, String name, PlayerProxy service) { + this.id = id; + this.name = name; + this.service = service; + } + + public User(String id, String name, String adress, int port) { + this.id = id; + this.name = name; + this.service = new PlayerProxy(adress, port); + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public PlayerProxy getService() { + return service; + } + + public boolean ping() throws TException { + return service.ping(); + } + + public void sendGameDescription(TDescription gameDescription) throws TException { + service.sendGameDescription(gameDescription); + } + + public void sendGameStart() throws TException { + service.sendGameStart(); + } + + public void sendFirstRoundStart() throws TException { + service.sendFirstRoundStart(); + } + + public void sendStartPhase(TPhase phase, TDescription gameDescription) throws TException { + service.sendStartPhase(phase, gameDescription); + } + + public TAction askAction(TAskAction askedAction) throws TException { + return service.askAction(askedAction); + } + + public void sendAction(TAskAction askedAction) throws TException { + service.sendAction(askedAction); + } + + public void sendGameIsFinished(TPlayerTeam winner) throws TException { + service.sendGameIsFinished(winner); + } + + public void sendResponse(Response response) throws TException { + service.sendResponse(response); + } + + @Override + public boolean equals(Object obj) { + if(obj == this){ + return true; + } + if(!(obj instanceof User)){ + return false; + } + User user = (User) obj; + return user.getId().equals(id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } +} diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/GameTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/GameTest.java new file mode 100644 index 0000000000000000000000000000000000000000..de96e56eb5eabfa21ca54fd35f90df81cc413a28 --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/GameTest.java @@ -0,0 +1,839 @@ +package fr.univnantes.alma.server.game; + +import fr.univnantes.alma.common.NotAloneDatabase; +import fr.univnantes.alma.data.DatabaseFactory; +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.Reserve; +import fr.univnantes.alma.server.game.item.action.Action; +import fr.univnantes.alma.server.game.item.action.ActionChoosePower; +import fr.univnantes.alma.server.game.item.action.ActionMovePlayer; +import fr.univnantes.alma.server.game.item.action.ActionTargetPlayer; +import fr.univnantes.alma.server.game.item.board.Board; +import fr.univnantes.alma.server.game.item.board.BoardColor; +import fr.univnantes.alma.server.game.item.board.BoardDistribution; +import fr.univnantes.alma.server.game.item.board.Score; +import fr.univnantes.alma.server.game.item.card.PlaceCard; +import fr.univnantes.alma.server.game.item.card.SurvivalCard; +import fr.univnantes.alma.server.game.item.card.TrackingCard; +import fr.univnantes.alma.server.game.item.jeton.JetonSymbol; +import fr.univnantes.alma.server.game.item.jeton.PlacedJeton; +import fr.univnantes.alma.server.game.item.pioche.Pioche; +import fr.univnantes.alma.server.game.item.planet.Place; +import fr.univnantes.alma.server.game.item.planet.Planet; +import fr.univnantes.alma.server.game.item.power.Power; +import fr.univnantes.alma.server.game.item.power.modifier.PowerModifier; +import fr.univnantes.alma.server.game.item.power.modifier.PowerModifierType; +import fr.univnantes.alma.server.game.utilitary.Pair; +import fr.univnantes.alma.thrift.Response; +import fr.univnantes.alma.thrift.TAskAction; +import org.apache.thrift.TException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static fr.univnantes.alma.server.game.item.card.CardName.*; +import static fr.univnantes.alma.server.game.item.power.modifier.PowerModifierType.PLAYABLE_TRACKING_CARD; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class GameTest { + NotAloneDatabase database = DatabaseFactory.getDatabase(); + + Planet planet; + Board board; + + final PlaceCard antre = database.findPlaceCard(ANTRE.toString()); + final PlaceCard jungle = database.findPlaceCard(JUNGLE.toString()); + final PlaceCard riviere = database.findPlaceCard(RIVIERE.toString()); + final PlaceCard plage = database.findPlaceCard(PLAGE.toString()); + final PlaceCard rover = database.findPlaceCard(ROVER.toString()); + final PlaceCard marais = database.findPlaceCard(MARAIS.toString()); + final PlaceCard abri = database.findPlaceCard(ABRI.toString()); + final PlaceCard epave = database.findPlaceCard(EPAVE.toString()); + final PlaceCard source = database.findPlaceCard(SOURCE.toString()); + final PlaceCard artefact = database.findPlaceCard(ARTEFACT.toString()); + final PlaceCard nexus = database.findPlaceCard(NEXUS.toString()); + final PlaceCard oasis = database.findPlaceCard(OASIS.toString()); + final PlaceCard fjord = database.findPlaceCard(FJORD.toString()); + final PlaceCard dome = database.findPlaceCard(DOME.toString()); + final PlaceCard labyrinthe = database.findPlaceCard(LABYRINTHE.toString()); + final PlaceCard mangrove = database.findPlaceCard(MANGROVE.toString()); + final PlaceCard archipel = database.findPlaceCard(ARCHIPEL.toString()); + final PlaceCard pole = database.findPlaceCard(POLE.toString()); + final PlaceCard fungi = database.findPlaceCard(FUNGI.toString()); + final PlaceCard portail = database.findPlaceCard(PORTAIL.toString()); + final TrackingCard acharnement = database.findTrackingCard(ACHARNEMENT.toString()); + final TrackingCard angoisse = database.findTrackingCard(ANGOISSE.toString()); + final TrackingCard mutation = database.findTrackingCard(MUTATION.toString()); + final TrackingCard flashBack = database.findTrackingCard(FLASHBACK.toString()); + final TrackingCard anticipation = database.findTrackingCard(ANTICIPATION.toString()); + final TrackingCard virus = database.findTrackingCard(VIRUS.toString()); + final SurvivalCard adrenaline = database.findSurvivalCard(ADRENALINE.toString()); + final SurvivalCard alerte = database.findSurvivalCard(ALERTE.toString()); + final SurvivalCard vaccin = database.findSurvivalCard(VACCIN.toString()); + final SurvivalCard sixieme_sens = database.findSurvivalCard(SIXIEME_SENS.toString()); + final SurvivalCard riposte = database.findSurvivalCard(RIPOSTE.toString()); + final SurvivalCard hologramme = database.findSurvivalCard(HOLOGRAMME.toString()); + final SurvivalCard retraite = database.findSurvivalCard(RETRAITE.toString()); + final PowerModifierType playableTrackingCard = PLAYABLE_TRACKING_CARD; + + + + @BeforeEach + public void setUp() { + List placeCards = new ArrayList<>(); + placeCards.add(database.findPlaceCard(ANTRE.toString())); + placeCards.add(database.findPlaceCard(JUNGLE.toString())); + placeCards.add(database.findPlaceCard(RIVIERE.toString())); + placeCards.add(database.findPlaceCard(PLAGE.toString())); + placeCards.add(database.findPlaceCard(ROVER.toString())); + placeCards.add(database.findPlaceCard(MARAIS.toString())); + placeCards.add(database.findPlaceCard(ABRI.toString())); + placeCards.add(database.findPlaceCard(EPAVE.toString())); + placeCards.add(database.findPlaceCard(SOURCE.toString())); + placeCards.add(database.findPlaceCard(ARTEFACT.toString())); + planet = new Planet(placeCards); + board = new Board(BoardDistribution.FRONT, BoardColor.BLUE); + } + + @Test + void testCreateGameConstructorCollection_moreThan7Players() { + Room room = mock(Room.class); + List list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8)); + assertThrows(IllegalArgumentException.class, () -> new Game(list, 1, planet, board, room)); + } + + @Test + void testCreateGameConstructorCollection_noPlayers() { + Room room = mock(Room.class); + List list = new ArrayList<>(); + assertThrows(IllegalArgumentException.class, () -> new Game(list, 1, planet, board, room)); + } + + @Test + void testCreateGameConstructorCollection_badIdCreature() { + Room room = mock(Room.class); + List list = new ArrayList<>(Arrays.asList(1, 2)); + assertThrows(IllegalArgumentException.class, () -> new Game(list, 3, planet, board, room)); + } + + @Test + void testCreateGameConstructorPairList_moreThan7Players() { + Room room = mock(Room.class); + List> list = new ArrayList<>(); + list.add(new Pair<>(1, "Nathan")); + list.add(new Pair<>(2, "Odile")); + list.add(new Pair<>(3, "Tom tom")); + list.add(new Pair<>(4, "Alban")); + list.add(new Pair<>(5, "Luna")); + list.add(new Pair<>(6, "Oriane")); + list.add(new Pair<>(7, "Nana")); + list.add(new Pair<>(8, "Emilie")); + assertThrows(IllegalArgumentException.class, () -> new Game(list, 1, planet, board, room)); + } + + @Test + void testCreateGameConstructorPairList_noPLayers() { + Room room = mock(Room.class); + List> list = new ArrayList<>(); + assertThrows(IllegalArgumentException.class, () -> new Game(list, 1, planet, board, room)); + } + + @Test + void testCreateGameConstructorPairList_badIdCreature() { + Room room = mock(Room.class); + List> list = new ArrayList<>(); + list.add(new Pair<>(1, "Nathan")); + list.add(new Pair<>(2, "Odile")); + assertThrows(IllegalArgumentException.class, () -> new Game(list, 3, planet, board, room)); + } + + @Test + void testEnableJetonArtemia() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + assertTrue(game.isJetonArtemiaIsActive()); + game.disableJetonArtemia(); + game.enableJetonArtemia(); + assertTrue(game.isJetonArtemiaIsActive()); + + } + + @Test + void testDisableJetonArtemia() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + assertTrue(game.isJetonArtemiaIsActive()); + game.disableJetonArtemia(); + assertFalse(game.isJetonArtemiaIsActive()); + } + + @Test + void testGetCreature() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + assertEquals(1, game.getCreature().getInGameId()); + assertEquals("Nathan", game.getCreature().getName()); + } + + @Test + void testGetTraque() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + assertEquals(2, game.getTraques().get(0).getInGameId()); + assertEquals("Odile", game.getTraques().get(0).getName()); + } + + @Test + void testGetPlayerMap() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + assertEquals(2, game.getPlayersMap().size()); + } + + @Test + void testGetPlayer() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + assertEquals("Nathan", game.getPlayer(1).getName()); + } + + @Test + void testGetRoom() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + assertSame(room, game.getRoom()); + } + + @Test + void testGetReserve() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + List placeCards = new ArrayList<>(Arrays.asList(marais, abri, epave, source, artefact)); + assertEquals(new Reserve(placeCards, 2), game.getReserve()); + } + + @Test + void testTraqueCanResist() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + assertTrue(game.traqueCanResist()); + game.getGameRoundVariables().setTraqueCanResist(false); + assertFalse(game.traqueCanResist()); + game.setTraqueCanResist(true); + assertTrue(game.traqueCanResist()); + + } + + + @Test + void testTraqueCanPickSurvivalCards() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + assertTrue(game.traqueCanPickSurvivalCards()); + game.getGameRoundVariables().setTraqueCanPickSurvivalCards(false); + assertFalse(game.traqueCanPickSurvivalCards()); + game.setTraqueCanPickSurvivalCards(true); + assertTrue(game.traqueCanPickSurvivalCards()); + + } + + @Test + void testPlayTrackingCard_creatureCantPlayCards() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + Response response = new Response(false, "Unable to play this card"); + assertEquals(response, game.creaturePlayTrackingCard(game.getCreature(), acharnement)); + } + + @Test + void testCanPlayTrackingCard_badPhase() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + game.getCreature().getTrackingCardHand().clear(); + game.getCreature().getTrackingCardHand().add(acharnement); + assertFalse(game.creatureCanPlayThisTrackingCards(game.getCreature(), Collections.singletonList(acharnement))); + } + + @Test + void testCanPlaySurvivalCard_badPhase() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + game.getTraques().get(0).addSurvivalCard(alerte); + assertFalse(game.traqueCanPlayThisSurvivalCards(game.getTraques().get(0), Collections.singletonList(alerte))); + } + + @Test + void testCanPlayTrackingCard_true() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + game.getCreature().getTrackingCardHand().clear(); + game.getCreature().getTrackingCardHand().addAll(Arrays.asList(acharnement, mutation)); + + //Start phase 1 + game.startNextPhase(); + //Start postphase 1 + game.startNextPhase(); + //Start prephase 2 + game.startNextPhase(); + + assertTrue(game.creatureCanPlayThisTrackingCards(game.getCreature(), acharnement)); + assertFalse(game.creatureCanPlayThisTrackingCards(game.getCreature(), Arrays.asList(acharnement, mutation))); + } + + @Test + void testPlayerResist_numberPawnWillingnessToLoseGreaterThan2() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + Response response = new Response(false, "Number must be 1 or 2"); + assertEquals(response, game.playerResist(2, 3)); + } + + @Test + void testPlayerResist_falsePhase2() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + + //Start phase 1 + game.startNextPhase(); + //Start postphase 1 + game.startNextPhase(); + //Start prephase 2 + game.startNextPhase(); + //Start phase 2 + game.startNextPhase(); + + Response response = new Response(false, "Resist is only possible in PHASE_1"); + assertEquals(response, game.playerResist(2, 2)); + } + @Test + void testPlayerResist_falseCreature() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + //Start phase 1 + game.startNextPhase(); + Response response = new Response(false, "Only traque can resist"); + assertEquals(response, game.playerResist(1, 2)); + } + @Test + void testPlayerResist_falseCantResistThisRound() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + game.getCreature().getTrackingCardHand().clear(); + game.getCreature().getTrackingCardHand().add(angoisse); + Response response = new Response(true, ""); + assertTrue(game.creatureCanPlayThisTrackingCards(game.getCreature(), angoisse)); + assertEquals(response, game.creaturePlayTrackingCard(game.getCreature(),angoisse)); + + game.startNextPhase(); + + Response response2 = new Response(false, "You can't resist for this round"); + assertEquals(response2, game.playerResist(2, 2)); + } + + @Test + void testPlayerResist_false() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + //Start phase 1 + game.startNextPhase(); + game.getTraques().get(0).setCanResist(false); + Response response = new Response(false, "You can't resist"); + assertEquals(response, game.playerResist(2, 2)); + } + @Test + void testPlayerResist_true() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + //Start phase 1 + game.startNextPhase(); + Response response = new Response(true, ""); + assertEquals(response, game.playerResist(2, 2)); + } + + @Test + void testCanPlaySurvivalCard_true() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + game.getTraques().get(0).getSurvivalCardsHand().add(vaccin); + assertTrue(game.traqueCanPlayThisSurvivalCards(game.getTraques().get(0), vaccin)); + } + + @Test + void testPlayerPlayCard_traquePlayPlaceCardInPrephase() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + //Start phase 1 + game.startNextPhase(); + //Start postphase 1 + game.startNextPhase(); + //Start prephase 2 + game.startNextPhase(); + //Start phase 2 + game.startNextPhase(); + Response response = new Response(false, "No card authorize in this phase"); + assertEquals(response, game.playerPlayCard(2, riviere)); + } + + @Test + void testApplyTraquePlaySurvivalCard_true() { + Room room = mock(Room.class); + List> a = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(a, 1, planet, board, room); + game.getTraques().get(0).getSurvivalCardsHand().add(vaccin); + int currentCreatureScore = game.getBoard().getScore().getScoreCreature(); + assertTrue(game.traquePlaySurvivalCard(game.getTraques().get(0), vaccin).state); + assertEquals(currentCreatureScore+1,game.getBoard().getScoreCreature()); + + } + @Test + void testApplyTraquePlaySurvivalCard_false() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + game.getTraques().get(0).getSurvivalCardsHand().addAll(Arrays.asList(retraite, hologramme)); + + Response response = new Response(false, "Unable to play this card"); + assertEquals(response, game.traquePlaySurvivalCard(game.getTraques().get(0), hologramme)); + assertEquals(response, game.traquePlaySurvivalCard(game.getTraques().get(0), Arrays.asList(hologramme,retraite))); + } + + @Test + void testGameScenario_2() throws TException { + Room room = mock(Room.class); + List> a = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(a, 1, planet, board, room); + game.getPlanet().forceMovePlanetPawn(); + Board board = game.getBoard(); + + assertEquals(new Score(7, 13), board.getScore()); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(new ActionChoosePower(0)); + + } + @Test + void testPlayerPlayCard_traquePlaySurvivalCardInPhase1() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + game.getTraques().get(0).getSurvivalCardsHand().add(vaccin); + //Start phase1 + game.startNextPhase(); + Response response = new Response(false, "Need a place card"); + assertEquals(response,game.playerPlayCard(2, vaccin)); + } + + @Test + void testPlayerPlayCard_creaturePlayTrackingCardInPhase1() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + game.getCreature().getTrackingCardHand().clear(); + game.getCreature().getTrackingCardHand().addAll(Arrays.asList(acharnement, mutation)); + //Start phase1 + game.startNextPhase(); + Response response = new Response(false, "No card authorize in this phase"); + assertEquals(response,game.playerPlayCard(1, acharnement)); + } + + @Test + void testPlayerPlayCard_traquePlayPlaceCardInPhase1() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + //Start phase1 + game.startNextPhase(); + Response response = new Response(true, ""); + assertEquals(response,game.playerPlayCard(2, plage)); + assertTrue(game.playerHasFinished(2, Phase.PHASE_1).state); + } + + @Test + void testPlayerPlayCardList_traquePlaySurvivalAndPlaceCardInPhase1() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + //Start phase1 + game.startNextPhase(); + game.getTraques().get(0).getSurvivalCardsHand().add(vaccin); + Response response = new Response(false, "Need only place card"); + assertEquals(response,game.playerPlayCard(2, Arrays.asList(plage,vaccin))); + } + + @Test + void testTraquePlayPlaceCard_traquePlaceTwoPlaceCard() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + //Start phase1 + game.startNextPhase(); + game.traquePlayPlaceCard(game.getTraques().get(0), plage); + Response response = new Response(false, "Unable to play this card"); + assertEquals(response,game.traquePlayPlaceCard(game.getTraques().get(0), riviere)); + } + @Test + void testPlayerGiveUp_errorCreature() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + //Start phase1 + game.startNextPhase(); + Response response = new Response(false, "Only traque can resist"); + assertEquals(response,game.playerGiveUp(1)); + } + + @Test + void testPlayerGiveUp_errorBadPhase() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + //Start phase1 + game.startNextPhase(); + game.startNextPhase(); + game.startNextPhase(); + //Start phase2 + game.startNextPhase(); + assertEquals(Phase.PHASE_2,game.getState()); + Response response = new Response(false, "Give up is only possible in PHASE_1"); + assertEquals(response,game.playerGiveUp(2)); + } + @Test + void testPlayerGiveUp_true() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + //Start phase1 + game.startNextPhase(); + + Response response = new Response(true, ""); + assertEquals(response,game.playerGiveUp(2)); + } + @Test + void testPlayerGiveUp_falseCantGiveUp() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + //Start phase1 + game.startNextPhase(); + game.getTraques().get(0).setCanGiveUp(false); + Response response = new Response(false, "You can't resist"); + assertEquals(response,game.playerGiveUp(2)); + } + @Test + void testPlayerPlayPlayerCard_falseNeedSurvivalCard() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + //Start phase1 + game.startNextPhase(); + game.getTraques().get(0).getSurvivalCardsHand().add(vaccin); + + game.getTraques().get(0).setCanGiveUp(false); + Response response = new Response(false, "Need a survival card"); + assertEquals(response,game.playerPlayPlayerCard(game.getPlayer(2),acharnement)); + } @Test + void testPlayerPlayPlayerCard_falseNeedTrackingCard() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + //Start phase1 + game.startNextPhase(); + game.getTraques().get(0).getSurvivalCardsHand().add(vaccin); + + game.getTraques().get(0).setCanGiveUp(false); + Response response = new Response(false, "Need a tracking card"); + assertEquals(response,game.playerPlayPlayerCard(game.getPlayer(1),vaccin)); + } + @Test + void testPlayerPlayPlayerCard_falseNeedSurvivalCardList() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + //Start phase1 + game.startNextPhase(); + game.getTraques().get(0).getSurvivalCardsHand().add(vaccin); + + game.getTraques().get(0).setCanGiveUp(false); + Response response = new Response(false, "Need a survival card"); + assertEquals(response,game.playerPlayPlayerCard(game.getPlayer(2),Arrays.asList(acharnement))); + } + @Test + void testPlayerPlayPlayerCard_falseNeedTrackingCardList() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + //Start phase1 + game.startNextPhase(); + game.getTraques().get(0).getSurvivalCardsHand().add(vaccin); + + game.getTraques().get(0).setCanGiveUp(false); + Response response = new Response(false, "Need a tracking card"); + assertEquals(response,game.playerPlayPlayerCard(game.getPlayer(1),Arrays.asList(vaccin))); + } + @Test + void testGetTrackingCardPioche_true() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + game.getTrackingCardPioche().getCards().clear(); + game.getTrackingCardPioche().getCards().add(acharnement); + Pioche response = new Pioche(Arrays.asList(acharnement)); + assertEquals(response.getCards(),game.getTrackingCardPioche().getCards()); + } + @Test + void testGetSurvivalCardPioche_true() { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + game.getSurvivalCardPioche().getCards().clear(); + game.getSurvivalCardPioche().getCards().add(adrenaline); + Pioche response = new Pioche(Arrays.asList(adrenaline)); + assertEquals(response.getCards(),game.getSurvivalCardPioche().getCards()); + } + @Test + void testGetNumberWillingnessDecrementByJetonCreature_false() throws TException { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + game.getCreature().getTrackingCardHand().clear(); + game.getCreature().getTrackingCardHand().addAll(Arrays.asList(acharnement, mutation, virus)); + + + PowerModifier powerModifier = new PowerModifier(1, playableTrackingCard, 2); + assertEquals(Phase.PREPHASE_1, game.getState()); + game.addPowerForNextRound(powerModifier); + //Start phase 1 + game.startNextPhase(); + //Start postphase 1 + game.startNextPhase(); + //Start prephase 2 + game.startNextPhase(); + + assertTrue(game.creatureCanPlayThisTrackingCards(game.getCreature(), acharnement)); + assertTrue(game.creatureCanPlayThisTrackingCards(game.getCreature(), mutation)); + game.creaturePlayTrackingCard(game.getCreature(), acharnement); + assertEquals(2, game.getNumberWillingnessDecrementByJetonCreature()); + + game.setNumberWillingnessDecrementByJetonCreature(3); + assertEquals(3, game.getNumberWillingnessDecrementByJetonCreature()); + game.setNumberWillingnessDecrementByJetonCreature(2); + assertEquals(2, game.getNumberWillingnessDecrementByJetonCreature()); + } + @Test + void testPowerScenario_false() throws TException { + Room room = mock(Room.class); + List> list = new ArrayList<>(Arrays.asList(new Pair<>(1, "Nathan"), new Pair<>(2, "Odile"))); + Game game = new Game(list, 1, planet, board, room); + game.getCreature().getTrackingCardHand().clear(); + game.getCreature().getTrackingCardHand().addAll(Arrays.asList(acharnement, mutation,virus)); + + + PowerModifier powerModifier = new PowerModifier(1,playableTrackingCard,2); + assertEquals(Phase.PREPHASE_1,game.getState()); + game.addPowerForNextRound(powerModifier); + //Start phase 1 + game.startNextPhase(); + //Start postphase 1 + game.startNextPhase(); + //Start prephase 2 + game.startNextPhase(); + + assertTrue(game.creatureCanPlayThisTrackingCards(game.getCreature(), acharnement)); + assertTrue(game.creatureCanPlayThisTrackingCards(game.getCreature(), mutation)); + game.creaturePlayTrackingCard(game.getCreature(),acharnement); + assertEquals(2,game.getNumberWillingnessDecrementByJetonCreature()); + + assertFalse(game.creatureCanPlayThisTrackingCards(game.getCreature(), mutation)); + //Start Phase 2 + game.startNextPhase(); + //Start Post phase 2 + game.startNextPhase(); + assertEquals(Phase.POSTPHASE_2,game.getState()); + //Start Pre Phase 3 + game.startNextPhase(); + //Start Phase 3 + game.startNextPhase(); + //Start Post Phase 3 + game.startNextPhase(); + assertEquals(Phase.POSTPHASE_3,game.getState()); + //Start Pre Phase 4 + game.startNextPhase(); + //Start Phase 4 + game.startNextPhase(); + //Start Post Phase 4 + game.startNextPhase(); + assertFalse(game.isFinish()); + //Start Pre Phase 1 + game.startNextPhase(); + assertEquals(Phase.PREPHASE_1,game.getState()); + //Start Phase 1 + game.startNextPhase(); + //Start Post Phase 1 + game.startNextPhase(); + //Start Pre Phase 2 + game.startNextPhase(); + assertEquals(Phase.PREPHASE_2,game.getState()); + + assertFalse(game.creatureCanPlayThisTrackingCards(game.getCreature(), acharnement)); + assertTrue(game.creatureCanPlayThisTrackingCards(game.getCreature(), mutation)); + assertTrue(game.creatureCanPlayThisTrackingCards(game.getCreature(), virus)); + game.creaturePlayTrackingCard(game.getCreature(),virus); + assertFalse(game.creatureCanPlayThisTrackingCards(game.getCreature(), acharnement)); + assertFalse(game.creatureCanPlayThisTrackingCards(game.getCreature(), virus)); + assertTrue(game.creatureCanPlayThisTrackingCards(game.getCreature(), mutation)); + game.creaturePlayTrackingCard(game.getCreature(),mutation); + + + } + @Test + void testGetIdPlayerTargetByTrackingCardAnticipation() throws TException { + Room room = mock(Room.class); + Game game = new Game(Arrays.asList(1, 2), 1, planet, board, room); + Board board = game.getBoard(); + Action targetPlayer = new ActionTargetPlayer(2); + + game.getCreature().getTrackingCardHand().clear(); + game.getCreature().getTrackingCardHand().addAll(Arrays.asList(anticipation)); + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(targetPlayer); + assertEquals(Phase.PREPHASE_1, game.getState()); + assertTrue(game.playerHasFinished(1, Phase.PREPHASE_1).state); + assertTrue(game.playerHasFinished(2, Phase.PREPHASE_1).state); + + assertTrue(game.playerHasFinished(1, Phase.PHASE_1).state); + assertTrue(game.playerPlayCard(2, Collections.singletonList(plage)).state); + assertTrue(game.playerHasFinished(2, Phase.PHASE_1).state); + + assertTrue(game.playerHasFinished(1, Phase.POSTPHASE_1).state); + assertTrue(game.playerHasFinished(2, Phase.POSTPHASE_1).state); + assertTrue(game.creatureCanPlayThisTrackingCards(game.getCreature(), anticipation)); + game.creaturePlayTrackingCard(game.getCreature(),anticipation); + + assertTrue(game.playerHasFinished(1, Phase.PREPHASE_2).state); + assertTrue(game.playerHasFinished(2, Phase.PREPHASE_2).state); + assertTrue(game.playerPlaceJeton(1, Collections.singletonList(new PlacedJeton(JetonSymbol.CREATURE, Collections.singletonList(Place.PLACE_FOUR)))).state); + assertEquals(2,game.getIdPlayerTargetByTrackingCardAnticipation()); + } + @Test + void testGameScenario() throws TException { + Room room = mock(Room.class); + Game game = new Game(Arrays.asList(1, 2), 1, planet, board, room); + game.getPlanet().forceMovePlanetPawn(); + Board board = game.getBoard(); + assertEquals(new Score(7, 13), board.getScore()); + board.moveForwardTraque(11); + board.moveForwardCreature(6); + assertEquals(new Score(1, 2), board.getScore()); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(new ActionChoosePower(0)); + assertEquals(Phase.PREPHASE_1,game.getState()); + assertTrue(game.playerHasFinished(1, Phase.PREPHASE_1).state); + assertTrue(game.playerHasFinished(2, Phase.PREPHASE_1).state); + + assertTrue(game.playerHasFinished(1, Phase.PHASE_1).state); + assertFalse(game.playerHasFinished(2, Phase.PHASE_1).state); + assertTrue(game.playerPlayCard(2, Collections.singletonList(plage)).state); + assertTrue(game.playerHasFinished(2, Phase.PHASE_1).state); + + assertTrue(game.playerHasFinished(1, Phase.POSTPHASE_1).state); + assertTrue(game.playerHasFinished(2, Phase.POSTPHASE_1).state); + + assertTrue(game.playerHasFinished(1, Phase.PREPHASE_2).state); + assertTrue(game.playerHasFinished(2, Phase.PREPHASE_2).state); + + assertFalse(game.playerHasFinished(1, Phase.PHASE_2).state); + assertTrue(game.playerPlaceJeton(1, Collections.singletonList(new PlacedJeton(JetonSymbol.CREATURE, Collections.singletonList(Place.PLACE_ONE)))).state); + assertTrue(game.playerHasFinished(1, Phase.PHASE_2).state); + assertTrue(game.playerHasFinished(2, Phase.PHASE_2).state); + + assertTrue(game.playerHasFinished(1, Phase.POSTPHASE_2).state); + assertTrue(game.playerHasFinished(2, Phase.POSTPHASE_2).state); + + assertTrue(game.playerHasFinished(1, Phase.PREPHASE_3).state); + assertTrue(game.playerHasFinished(2, Phase.PREPHASE_3).state); + /// + + assertTrue(game.playerHasFinished(1, Phase.PHASE_3).state); + assertTrue(game.playerHasFinished(2, Phase.PHASE_3).state); + + assertTrue(game.playerHasFinished(1, Phase.POSTPHASE_3).state); + assertTrue(game.playerHasFinished(2, Phase.POSTPHASE_3).state); + + assertTrue(game.playerHasFinished(1, Phase.PREPHASE_4).state); + assertTrue(game.playerHasFinished(2, Phase.PREPHASE_4).state); + + assertTrue(game.playerHasFinished(1, Phase.PHASE_4).state); + assertTrue(game.playerHasFinished(2, Phase.PHASE_4).state); + assertTrue(game.playerHasFinished(1, Phase.POSTPHASE_4).state); + assertTrue(game.playerHasFinished(2, Phase.POSTPHASE_4).state); + assertTrue(game.isFinish()); + } + @Test + void testMovePlayer() throws TException { + Room room = mock(Room.class); + Game game = new Game(Arrays.asList(1, 2), 1, planet, board, room); + Board board = game.getBoard(); + game.getTraques().get(0).getSurvivalCardsHand().clear(); + game.getTraques().get(0).getSurvivalCardsHand().add(retraite); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(new ActionMovePlayer(2, Place.PLACE_THREE)); + assertEquals(Phase.PREPHASE_1,game.getState()); + assertTrue(game.playerHasFinished(1, Phase.PREPHASE_1).state); + assertTrue(game.playerHasFinished(2, Phase.PREPHASE_1).state); + + assertTrue(game.playerHasFinished(1, Phase.PHASE_1).state); + assertFalse(game.playerHasFinished(2, Phase.PHASE_1).state); + assertTrue(game.playerPlayCard(2, Collections.singletonList(plage)).state); + assertTrue(game.playerHasFinished(2, Phase.PHASE_1).state); + + assertTrue(game.playerHasFinished(1, Phase.POSTPHASE_1).state); + assertTrue(game.playerHasFinished(2, Phase.POSTPHASE_1).state); + + assertTrue(game.playerHasFinished(1, Phase.PREPHASE_2).state); + assertTrue(game.playerHasFinished(2, Phase.PREPHASE_2).state); + + assertFalse(game.playerHasFinished(1, Phase.PHASE_2).state); + assertTrue(game.playerPlaceJeton(1, Collections.singletonList(new PlacedJeton(JetonSymbol.CREATURE, Collections.singletonList(Place.PLACE_ONE)))).state); + assertTrue(game.playerHasFinished(1, Phase.PHASE_2).state); + assertTrue(game.playerHasFinished(2, Phase.PHASE_2).state); + + assertTrue(game.playerHasFinished(1, Phase.POSTPHASE_2).state); + assertTrue(game.playerHasFinished(2, Phase.POSTPHASE_2).state); + Response response = new Response(true, ""); + assertEquals(response, game.traquePlaySurvivalCard(game.getTraques().get(0), retraite)); + Pair response1 = new Pair(2, Place.PLACE_THREE ); + assertEquals(response1,game.movePlayer(2)); + + } +} diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/NotAloneApplicationTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/NotAloneApplicationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b3b8034bbf6e5119ceaca3a741ff157bce5246fc --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/NotAloneApplicationTest.java @@ -0,0 +1,106 @@ +package fr.univnantes.alma.server.game; + +import fr.univnantes.alma.server.NotAloneApplication; +import fr.univnantes.alma.server.user.User; +import fr.univnantes.alma.thrift.*; +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TProtocol; +import org.apache.thrift.protocol.TProtocolFactory; +import org.apache.thrift.transport.THttpClient; +import org.apache.thrift.transport.TTransport; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.web.server.LocalServerPort; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = NotAloneApplication.class) +class NotAloneApplicationTest { + @Autowired + protected TProtocolFactory protocolFactory; + + @LocalServerPort + protected int port; + + protected GameService.Iface client; + + protected List tCardList; + + @BeforeEach + public void setUp() throws Exception { + TTransport transport = new THttpClient("http://localhost:" + port + "/api"); + + TProtocol protocol = protocolFactory.getProtocol(transport); + + client = new GameService.Client(protocol); + + tCardList = new ArrayList<>(); + tCardList.add(new TCard("PLACE","NEXUS", new ArrayList<>())); + tCardList.add(new TCard("PLACE","JUNGLE", new ArrayList<>())); + tCardList.add(new TCard("PLACE","RIVIERE", new ArrayList<>())); + tCardList.add(new TCard("PLACE","DOME", new ArrayList<>())); + tCardList.add(new TCard("PLACE","ROVER", new ArrayList<>())); + tCardList.add(new TCard("PLACE","MANGROVE", new ArrayList<>())); + tCardList.add(new TCard("PLACE","ABRI", new ArrayList<>())); + tCardList.add(new TCard("PLACE","EPAVE", new ArrayList<>())); + tCardList.add(new TCard("PLACE","FUNGI", new ArrayList<>())); + tCardList.add(new TCard("PLACE","PORTAIL", new ArrayList<>())); + } + + @Test + void testCreateRoom_allIsTrue() throws TException { + TRoomId id = client.createRoom(new TPlayer("5", "Name", "192.168.1.1", 8080)); + assertThat(Integer.parseInt(id.getToken())).isGreaterThanOrEqualTo(1000); + } + + @Test + void testJoinRoom() throws TException, InterruptedException { + TRoomId id = client.createRoom(new TPlayer("join1", "Name", "192.168.1.1", 8080)); + + Response response = client.joinRoom(new TPlayer("join2", "Name", "192.168.1.1", 8080), id); + assertTrue(response.state); + response = client.joinRoom(new TPlayer("join3", "Name", "192.168.1.1", 8080), id); + assertTrue(response.state); + response = client.joinRoom(new TPlayer("join4", "Name", "192.168.1.1", 8080), id); + assertTrue(response.state); + response = client.joinRoom(new TPlayer("join5", "Name", "192.168.1.1", 8080), id); + assertTrue(response.state); + response = client.joinRoom(new TPlayer("join6", "Name", "192.168.1.1", 8080), id); + assertTrue(response.state); + response = client.joinRoom(new TPlayer("join7", "Name", "192.168.1.1", 8080), id); + assertTrue(response.state); + + response = client.joinRoom(new TPlayer("join8", "Name", "192.168.1.1", 8080), id); + assertFalse(response.state); + + Thread.sleep(1000); + } + + @Test + void testStartGame() throws TException, InterruptedException { + /* + TPlayer creator = new TPlayer("start1", "Name", "192.168.1.1", 8080); + TRoomId id = client.createRoom(creator); + + Response response = client.sendStartGame(creator, 1, new TBoard("BACK"), new TColor("RED"), tCardList); + assertFalse(response.state); + + response = client.joinRoom(new TPlayer("start2", "Name", "192.168.1.1", 8080), id); + assertTrue(response.state); + + Thread.sleep(1000); + + response = client.sendStartGame(creator, 1, new TBoard("BACK"), new TColor("RED"), tCardList); + assertTrue(response.state); + + response = client.joinRoom(new TPlayer("start3", "Name", "192.168.1.1", 8080), id); + assertFalse(response.state); + */ + } +} diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/PowerApplicatorTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/PowerApplicatorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..138efdb42a5f7820e9ec420505a0ee12ebd93574 --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/PowerApplicatorTest.java @@ -0,0 +1,4290 @@ +package fr.univnantes.alma.server.game; + +import fr.univnantes.alma.common.NotAloneDatabase; +import fr.univnantes.alma.data.DatabaseFactory; +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.Reserve; +import fr.univnantes.alma.server.game.item.action.*; +import fr.univnantes.alma.server.game.item.board.Board; +import fr.univnantes.alma.server.game.item.board.BoardColor; +import fr.univnantes.alma.server.game.item.board.BoardDistribution; +import fr.univnantes.alma.server.game.item.board.Score; +import fr.univnantes.alma.server.game.item.card.Card; +import fr.univnantes.alma.server.game.item.card.PlaceCard; +import fr.univnantes.alma.server.game.item.card.SurvivalCard; +import fr.univnantes.alma.server.game.item.card.TrackingCard; +import fr.univnantes.alma.server.game.item.jeton.JetonSymbol; +import fr.univnantes.alma.server.game.item.jeton.PlacedJeton; +import fr.univnantes.alma.server.game.item.pioche.Pioche; +import fr.univnantes.alma.server.game.item.planet.Place; +import fr.univnantes.alma.server.game.item.planet.Planet; +import fr.univnantes.alma.server.game.item.planet.ShieldPawn; +import fr.univnantes.alma.server.game.item.player.Creature; +import fr.univnantes.alma.server.game.item.player.PlayerTeam; +import fr.univnantes.alma.server.game.item.player.Traque; +import fr.univnantes.alma.thrift.TAskAction; +import javassist.NotFoundException; +import org.apache.thrift.TException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static fr.univnantes.alma.server.game.item.card.CardName.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class PowerApplicatorTest { + + NotAloneDatabase database = DatabaseFactory.getDatabase(); + + final PlaceCard antre = database.findPlaceCard(ANTRE.toString()); + final PlaceCard jungle = database.findPlaceCard(JUNGLE.toString()); + final PlaceCard riviere = database.findPlaceCard(RIVIERE.toString()); + final PlaceCard plage = database.findPlaceCard(PLAGE.toString()); + final PlaceCard rover = database.findPlaceCard(ROVER.toString()); + final PlaceCard marais = database.findPlaceCard(MARAIS.toString()); + final PlaceCard abri = database.findPlaceCard(ABRI.toString()); + final PlaceCard epave = database.findPlaceCard(EPAVE.toString()); + final PlaceCard source = database.findPlaceCard(SOURCE.toString()); + final PlaceCard artefact = database.findPlaceCard(ARTEFACT.toString()); + final PlaceCard nexus = database.findPlaceCard(NEXUS.toString()); + final PlaceCard oasis = database.findPlaceCard(OASIS.toString()); + final PlaceCard fjord = database.findPlaceCard(FJORD.toString()); + final PlaceCard dome = database.findPlaceCard(DOME.toString()); + final PlaceCard labyrinthe = database.findPlaceCard(LABYRINTHE.toString()); + final PlaceCard mangrove = database.findPlaceCard(MANGROVE.toString()); + final PlaceCard archipel = database.findPlaceCard(ARCHIPEL.toString()); + final PlaceCard pole = database.findPlaceCard(POLE.toString()); + final PlaceCard fungi = database.findPlaceCard(FUNGI.toString()); + final PlaceCard portail = database.findPlaceCard(PORTAIL.toString()); + + Room room; + Planet planet; + Planet planetExtension; + Board board; + List placeCards; + List placeCardsExtension; + Action chooseFirstPower; + Action chooseSecondPower; + Action chooseThirdPower; + + @BeforeEach + public void setUp() { + placeCards = new ArrayList(); + placeCards.add(antre); + placeCards.add(jungle); + placeCards.add(riviere); + placeCards.add(plage); + placeCards.add(rover); + placeCards.add(marais); + placeCards.add(abri); + placeCards.add(epave); + placeCards.add(source); + placeCards.add(artefact); + + placeCardsExtension = new ArrayList<>(); + placeCardsExtension.add(nexus); + placeCardsExtension.add(oasis); + placeCardsExtension.add(fjord); + placeCardsExtension.add(dome); + placeCardsExtension.add(labyrinthe); + placeCardsExtension.add(mangrove); + placeCardsExtension.add(archipel); + placeCardsExtension.add(pole); + placeCardsExtension.add(fungi); + placeCardsExtension.add(portail); + + + room = null; + planet = new Planet(placeCards); + planetExtension = new Planet(placeCardsExtension); + + board = new Board(BoardDistribution.FRONT, BoardColor.BLUE); + + chooseFirstPower = new ActionChoosePower(0); + chooseSecondPower = new ActionChoosePower(1); + chooseThirdPower = new ActionChoosePower(2); + + room = mock(Room.class); + } + + @Test + void testResolvePlace_antreWithoutJetonAndFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(antre); + PowerApplicator.resolvePlace(game, traque.getInGameId(), antre); + + //Verify that traque has all the cards except the Antre + assertTrue(traque.getPlaceCards().containsAll(throwAwayCards)); + } + + @Test + void testResolvePlace_antreWithJetonCreatureAndFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(antre); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_ONE); + planet.placeJeton(placedJeton); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), antre); + + //Verify that traque has none cards + assertTrue(traque.getPlaceCards().isEmpty()); + //Verify that traque lose 2 Willingness + assertEquals(1, traque.getNumberWillingness()); + } + + @Test + void testResolvePlace_antreWithoutJetonAndSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(PLAGE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseFirstPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(antre); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_TWO); + planet.placeJeton(placedJeton); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), antre); + + //Verify that traque has Jungle and Plage + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(jungle, plage))); + } + + @Test + void testResolvePlace_antreJetonOnTwoPlacesAndSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseCard = new ActionChooseCard(Collections.singletonList(JUNGLE)); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(PLAGE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseCard) + .thenReturn(chooseFirstPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(antre); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Arrays.asList(Place.PLACE_THREE, Place.PLACE_TWO)); + planet.placeJeton(placedJeton); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), antre); + + //Verify that traque has Jungle and Plage + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(jungle, plage))); + } + + @Test + void testResolvePlace_antreWithoutJetonAndThirdPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(JUNGLE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseThirdPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(antre); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), antre); + + //Verify that traque has only the Jungle + assertEquals(Collections.singletonList(jungle), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_jungleFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(PLAGE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(jungle); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), jungle); + + //Verify that traque has Jungle and Plage + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(jungle, plage))); + } + + @Test + void testResolvePlace_jungleSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(PLAGE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(jungle); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), jungle); + + //Verify that traque has Plage + assertTrue(traque.getPlaceCards().contains(plage)); + } + + @Test + void testResolvePlace_riviereFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseAPlaceCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseAPlaceCard) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + traque.playPlaceCard(riviere); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), riviere); + + //Verify that traque has all cards except riviere + List cards = Arrays.asList(antre, jungle, plage, rover); + assertTrue(traque.getPlaceCards().containsAll(cards)); + + game.managePhase4(); + game.nextRound(); + //Start phase 1 + game.startNextPhase(); + traque.setCurrentPhase(Phase.PHASE_1); + + List chosenCards = new ArrayList<>(Arrays.asList(antre, jungle)); + assertTrue(game.playerPlayCard(2, chosenCards).state); + + //Start postphase 1 + game.startNextPhase(); + //Start prephase 2 + game.startNextPhase(); + //Start phase 2 + game.startNextPhase(); + //Start postphase 2 + game.startNextPhase(); + //Start prephase 3 + game.startNextPhase(); + //Start phase 3 + game.startNextPhase(); + + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(jungle, riviere, plage, rover))); + } + + @Test + void testResolvePlace_riviereSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(PLAGE)); + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(riviere); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), riviere); + + //Verify that traque has only Plage + assertEquals(Collections.singletonList(plage), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_plageFirstPowerAndBeaconIsNotOnPlage() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + game.getPlanet().forceMovePlanetPawn(); + + //Verify that the Beacon Pawn is not active + assertFalse(planet.planetPawnIsActive()); + + traque.playPlaceCard(plage); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + + //Verify that the Beacon Pawn is active + assertTrue(planet.planetPawnIsActive()); + + //Verify that the score of traque has changed + Score score = new Score(2); + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testResolvePlace_plageFirstPowerAndBeaconIsOnPlage() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + game.getPlanet().forceMovePlanetPawn(); + game.getPlanet().forceMovePlanetPawn(); + + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + //Verify that the Beacon Pawn is active + assertTrue(planet.planetPawnIsActive()); + + traque.playPlaceCard(plage); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + + //Verify that the Beacon Pawn is not active + assertFalse(planet.planetPawnIsActive()); + + //Verify that the score of traque hasn't changed + Score score = new Score(2); + assertEquals(score, game.getBoard().getScore()); + + //Verify that traque has none cards + assertTrue(traque.getPlaceCards().isEmpty()); + } + + @Test + void testResolvePlace_plageAPlayerAlreadyMoveTheBeacon() throws TException { + Game game = new Game(Arrays.asList(1,2, 3), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + game.getPlanet().forceMovePlanetPawn(); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + //Verify that the Beacon Pawn is not active + assertFalse(planet.planetPawnIsActive()); + + //First player move the beacon + PowerApplicator.resolvePlace(game, 3, plage); + + //Verify that the Beacon Pawn is active + assertTrue(planet.planetPawnIsActive()); + + traque.playPlaceCard(plage); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + + //Verify that the Beacon Pawn is active + assertTrue(planet.planetPawnIsActive()); + + //Verify that the score of traque has changed + Score score = new Score(3); + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + + //Verify that traque has only Antre + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_plageAndSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(plage); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + + //Verify that traque has only Antre + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_roverFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseAReserveCard = new ActionChooseCard(Collections.singletonList(MARAIS)); + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseAReserveCard); + + + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(rover); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), rover); + + //Verify that traque has only Marais + assertEquals(Collections.singletonList(marais), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_roverSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(rover); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), rover); + + //Verify that traque has only Antre + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_roverFirstPowerEmptyReserve() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage); + traque.throwAwayPlaceCard(throwAwayCards); + + Reserve reserve = game.getReserve(); + for(int number = 6 ; number <= 10 ; ++number) { + try { + reserve.pick(number); + } catch (NotFoundException ignored) { + } + } + + traque.playPlaceCard(rover); + PowerApplicator.resolvePlace(game, traque.getInGameId(), rover); + + //Verify that traque has only Antre + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + } + + + @Test + void testResolvePlace_maraisFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Arrays.asList(ANTRE, JUNGLE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(marais); + traque.playPlaceCard(marais); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), marais); + + //Verify that traque has Antre, Jungle and Marais + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(antre, jungle, marais))); + } + + @Test + void testResolvePlace_maraisSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(marais); + traque.playPlaceCard(marais); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), marais); + + //Verify that traque has only Antre + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + } + + + @Test + void testResolvePlace_abriFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + SurvivalCard chosen = game.getSurvivalCardPioche().getCards().get(0); + Action chooseASurvivalCard = new ActionChooseCard(Collections.singletonList(chosen.getCardName())); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseASurvivalCard); + + Traque traque = (Traque) game.getPlayer(2); + + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(abri); + traque.playPlaceCard(abri); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), abri); + + //Verify that traque has none cards and has pick the first SurvivalCard of the pioche + assertTrue(traque.getPlaceCards().isEmpty()); + assertEquals(2, traque.getSurvivalCardsHand().size()); + assertTrue(traque.getSurvivalCardsHand().contains(chosen)); + } + + @Test + void testResolvePlace_abriSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseADefausseCard); + + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(abri); + traque.playPlaceCard(abri); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), abri); + + //Verify that traque has only Antre + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_abriFirstPowerCantPickSurvivalCard() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseADefausseCard); + + game.getGameRoundVariables().setTraqueCanPickSurvivalCards(false); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(abri); + traque.playPlaceCard(abri); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), abri); + + //Verify that traque has only Antre + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_epaveFirstPower() throws TException { + //Initialization + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + traque.addPlaceCard(epave); + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + List cardsInitial = Arrays.asList(jungle, riviere, plage, rover, antre, epave); + //Verify that traque has all the initial cards + assertTrue(traque.getPlaceCards().containsAll(cardsInitial)); + + traque.throwAwayPlaceCard(throwAwayCards); + + //Verify that traque has only the epave + assertEquals(Collections.singletonList(epave), traque.getPlaceCards()); + traque.playPlaceCard(epave); + PowerApplicator.resolvePlace(game, traque.getInGameId(), epave); + + Score score = new Score(2); + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + + //Verify that traque has none cards + assertTrue(traque.getPlaceCards().isEmpty()); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testResolvePlace_epaveAPlayerAlreadyUseTheFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2, 3), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseFirstPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + //Another player play Epave before + PowerApplicator.resolvePlace(game, 3, epave); + + traque.addPlaceCard(epave); + traque.playPlaceCard(epave); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), epave); + + Score score = new Score(3); + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + + //Verify that traque has only Antre + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testResolvePlace_epaveAndSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseADefausseCard); + + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(epave); + traque.playPlaceCard(epave); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), epave); + + //Verify that traque has only Antre + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_sourceFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action choosePlayer = new ActionTargetPlayer(2); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(choosePlayer); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.subWillingness(1); + traque.addPlaceCard(source); + traque.playPlaceCard(source); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), source); + + //Verify that traque has none cards and has one more willingness + assertTrue(traque.getPlaceCards().isEmpty()); + assertEquals(3, traque.getNumberWillingness()); + } + + @Test + void testResolvePlace_sourceSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + SurvivalCard chosen = game.getSurvivalCardPioche().getCards().get(0); + traque.addPlaceCard(source); + traque.playPlaceCard(source); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), source); + + //Verify that traque has none cards and has pick the first SurvivalCard of the pioche + assertTrue(traque.getPlaceCards().isEmpty()); + assertEquals(2, traque.getSurvivalCardsHand().size()); + assertTrue(traque.getSurvivalCardsHand().contains(chosen)); + } + + @Test + void testResolvePlace_sourceThirdPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseThirdPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(source); + traque.playPlaceCard(source); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), source); + + //Verify that traque has only Antre + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_sourceFirstPowerCantPickSurvivalCard() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action choosePlayer = new ActionTargetPlayer(2); + + game.getGameRoundVariables().setTraqueCanPickSurvivalCards(false); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(choosePlayer); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.subWillingness(1); + traque.addPlaceCard(source); + traque.playPlaceCard(source); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), source); + + //Verify that traque has none cards and has one more willingness + assertTrue(traque.getPlaceCards().isEmpty()); + assertEquals(3, traque.getNumberWillingness()); + } + + @Test + void testResolvePlace_sourceSecondPowerCantPickSurvivalCard() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseADefausseCard); + + game.getGameRoundVariables().setTraqueCanPickSurvivalCards(false); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(source); + traque.playPlaceCard(source); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), source); + + //Verify that traque has only Antre + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_artefactFirstPowerBlue() throws TException { + Board board = new Board(BoardDistribution.FRONT, BoardColor.BLUE); + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + planet.forceMovePlanetPawn(); + + List throwAwayCards = Arrays.asList(jungle, riviere, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(artefact); + traque.playPlaceCard(artefact); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), artefact); + + game.managePhase4(); + game.nextRound(); + Score score = new Score(2); + score.moveForwardTraque(1); + + //Start phase 1 + game.startNextPhase(); + traque.setCurrentPhase(Phase.PHASE_1); + + List chosenCards = new ArrayList<>(Arrays.asList(antre, plage)); + + assertTrue(game.playerPlayCard(2, chosenCards).state); + + //Start postphase 1 + game.startNextPhase(); + //Start prephase 2 + game.startNextPhase(); + //Start phase 2 + game.startNextPhase(); + //Start postphase 2 + game.startNextPhase(); + //Start prephase 3 + game.startNextPhase(); + //Start phase 3 + game.startNextPhase(); + + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(jungle, riviere, artefact, rover))); + + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testResolvePlace_artefactFirstPowerRed() throws TException { + Board board = new Board(BoardDistribution.FRONT, BoardColor.RED); + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseADefausseCard) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(artefact); + traque.playPlaceCard(artefact); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), artefact); + + //Verify that traque has all cards except artefact + assertTrue(traque.getPlaceCards().containsAll(throwAwayCards)); + } + + @Test + void testResolvePlace_artefactFirstPowerGreen() throws TException { + Board board = new Board(BoardDistribution.FRONT, BoardColor.GREEN); + Game game = new Game(Arrays.asList(1,2, 3), 1, planet, board, room); + + Action chooseACardToThrowAway = new ActionChooseCard(Collections.singletonList(JUNGLE)); + + Action movePlayer = new ActionMovePlayer(3, Place.PLACE_ONE); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseACardToThrowAway) + .thenReturn(movePlayer); + + //The moved player play Jungle + Traque movedTraque = (Traque) game.getPlayer(3); + movedTraque.playPlaceCard(jungle); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(artefact); + traque.playPlaceCard(artefact); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), artefact); + + //Verify that other traque has move + assertEquals(Collections.singletonList(antre), movedTraque.getPlaceCardsPlayed()); + } + + @Test + void testResolvePlace_artefactFirstPowerYellow() throws TException { + Board board = new Board(BoardDistribution.FRONT, BoardColor.YELLOW); + Game game = new Game(Arrays.asList(1,2, 3), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(artefact); + traque.playPlaceCard(artefact); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), artefact); + + //Verify that the artemia pawn is inefficient + assertFalse(game.getGameRoundVariables().isJetonArtemiaIsActive()); + } + + + @Test + void testResolvePlace_artefactSecondPowerYellow() throws TException { + Board board = new Board(BoardDistribution.FRONT, BoardColor.YELLOW); + Game game = new Game(Arrays.asList(1,2, 3), 1, planet, board, room); + + Action chooseDefausseCard = new ActionChooseCard(Arrays.asList(ANTRE, JUNGLE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseDefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(artefact); + traque.playPlaceCard(artefact); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), artefact); + + //Verify that the traque has Antre and Jungle + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(antre, jungle))); + } + + @Test + void testResolvePlace_artefactLastPowerBlue() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(artefact); + traque.playPlaceCard(artefact); + PowerApplicator.resolvePlace(game, traque.getInGameId(), artefact); + + //Verify that traque has only Antre + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_artefactLastPowerGreen() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, new Board(BoardDistribution.BACK, BoardColor.GREEN), room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(artefact); + traque.playPlaceCard(artefact); + PowerApplicator.resolvePlace(game, traque.getInGameId(), artefact); + + //Verify that traque has only Antre + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_artefactLastPowerGreenNotEmptyPlaceCards() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, new Board(BoardDistribution.BACK, BoardColor.GREEN), room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(artefact); + traque.playPlaceCard(artefact); + PowerApplicator.resolvePlace(game, traque.getInGameId(), artefact); + + //Verify that traque has only Antre + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(antre, rover))); + } + + + @Test + void testResolvePlace_artefactLastPowerRed() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, new Board(BoardDistribution.BACK, BoardColor.RED), room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(artefact); + traque.playPlaceCard(artefact); + PowerApplicator.resolvePlace(game, traque.getInGameId(), artefact); + + //Verify that traque has only Antre + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_artefactLastPowerYellow() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, new Board(BoardDistribution.BACK, BoardColor.YELLOW), room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseThirdPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(antre, jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(artefact); + traque.playPlaceCard(artefact); + PowerApplicator.resolvePlace(game, traque.getInGameId(), artefact); + + //Verify that traque has only Antre + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_nexusFirstPowerWithoutJetonCreature() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseCopyCard = new ActionChooseCard(Collections.singletonList(OASIS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseCopyCard) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(nexus); + PowerApplicator.resolvePlace(game, traque.getInGameId(), nexus); + + //Verify that traque has only Oasis + assertEquals(Collections.singletonList(oasis), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_nexusWithJetonCreature() { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Traque traque = (Traque) game.getPlayer(2); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_ONE); + planetExtension.placeJeton(placedJeton); + + traque.playPlaceCard(nexus); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), nexus); + + Score score = new Score(2); + score.moveForwardCreature(2); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testResolvePlace_nexusSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(OASIS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(nexus); + PowerApplicator.resolvePlace(game, traque.getInGameId(), nexus); + + //Verify that traque has only Oasis + assertEquals(Collections.singletonList(oasis), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_oasisFirstPowerFullWillingness() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(oasis); + PowerApplicator.resolvePlace(game, traque.getInGameId(), oasis); + + //Verify that traque has only Oasis + assertEquals(Collections.singletonList(oasis), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_oasisFirstPowerOneWillingness() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseDefausseCard = new ActionChooseCard(Arrays.asList(NEXUS, FJORD)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseDefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + traque.subWillingness(2); + + List throwAwayCards = Arrays.asList(nexus, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(oasis); + PowerApplicator.resolvePlace(game, traque.getInGameId(), oasis); + + //Verify that traque has Oasis, Nexus and Fjord + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(oasis, fjord, nexus))); + } + + @Test + void testResolvePlace_oasisFirstPowerOneWillingnessAndLimitedNumberToTakeBack() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + + Action chooseDefausseCard = new ActionChooseCard(Collections.singletonList(NEXUS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseDefausseCard); + + game.getGameRoundVariables().setNumberMaxPlaceCardsGetByPlacePower(2); + + Traque traque = (Traque) game.getPlayer(2); + traque.subWillingness(2); + + List throwAwayCards = Arrays.asList(nexus, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(oasis); + PowerApplicator.resolvePlace(game, traque.getInGameId(), oasis); + + //Verify that traque has Oasis, Nexus and Fjord + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(oasis, nexus))); + } + + @Test + void testResolvePlace_oasisSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseDefausseCard = new ActionChooseCard(Collections.singletonList(NEXUS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseDefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(oasis); + PowerApplicator.resolvePlace(game, traque.getInGameId(), oasis); + + //Verify that traque has only nexus + assertEquals(Collections.singletonList(nexus), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_fjordFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseThePlayedCard = new ActionChooseCard(Collections.singletonList(NEXUS)); + Action chooseACopyCard = new ActionChooseCard(Collections.singletonList(DOME)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseThePlayedCard) + .thenReturn(chooseFirstPower) + .thenReturn(chooseACopyCard) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), fjord); + traque.throwAwayPlaceCard(fjord); + + planetExtension.movePlanetPawn(); + planetExtension.movePlanetPawn(); + + game.nextRound(); + Score score = new Score(2); + score.moveForwardTraque(1); + //Start phase 1 + game.startNextPhase(); + + assertTrue(game.playerPlayCard(2, Arrays.asList(nexus, oasis)).state); + + //Start postphase 1 + game.startNextPhase(); + //Start prephase 2 + game.startNextPhase(); + //Start phase 2 + game.startNextPhase(); + //Start postphase 2 + game.startNextPhase(); + //Start prephase 3 + game.startNextPhase(); + //Start phase 3 + game.startNextPhase(); + //Start postphase 3 + game.startNextPhase(); + //Start prephase 4 + game.startNextPhase(); + //Start phase 4 + game.startNextPhase(); + //Start postphase 4 + game.startNextPhase(); + + assertTrue(traque.getPlaceCards().isEmpty()); + score.moveBackCreature(1); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testResolvePlace_fjordSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseDefausseCard = new ActionChooseCard(Collections.singletonList(NEXUS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseDefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(fjord); + PowerApplicator.resolvePlace(game, traque.getInGameId(), fjord); + + //Verify that traque has only nexus + assertEquals(Collections.singletonList(nexus), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_domeFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + //move ShieldPawn on Fjord + planetExtension.movePlanetPawn(); + planetExtension.movePlanetPawn(); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(dome); + PowerApplicator.resolvePlace(game, traque.getInGameId(), dome); + + //Verify that the pawn Assimilation has move back + Score score = new Score(2); + score.moveBackCreature(1); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testResolvePlace_domeSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseDefausseCard = new ActionChooseCard(Collections.singletonList(NEXUS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseDefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(dome); + PowerApplicator.resolvePlace(game, traque.getInGameId(), dome); + + //Verify that traque has only nexus + assertEquals(Collections.singletonList(nexus), traque.getPlaceCards()); + } + + + @Test + void testResolvePlace_domeCantMoveTheDome() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseDefausseCard = new ActionChooseCard(Collections.singletonList(NEXUS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseDefausseCard); + + planetExtension.movePlanetPawn(); + planetExtension.movePlanetPawn(); + planetExtension.movePlanetPawn(); + planetExtension.movePlanetPawn(); + planetExtension.movePlanetPawn(); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(dome); + PowerApplicator.resolvePlace(game, traque.getInGameId(), dome); + + //Verify that traque has only nexus + assertEquals(Collections.singletonList(nexus), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_labyrintheFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Place placeMangrove = planetExtension.getPlaceDistribution().placeCardToPlace(mangrove); + Action chooseAPlace = new ActionChoosePlace(Collections.singletonList(placeMangrove)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseAPlace) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(labyrinthe); + PowerApplicator.resolvePlace(game, traque.getInGameId(), labyrinthe); + + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(nexus, oasis, fjord))); + assertTrue(traque.getDefausse().contains(dome)); + planetExtension.isRevealedPlace(mangrove); + assertTrue(planetExtension.isRevealedPlace(mangrove)); + } + + @Test + void testResolvePlace_labyrintheSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseAReserveCard = new ActionChooseCard(Collections.singletonList(MANGROVE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseAReserveCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(labyrinthe); + PowerApplicator.resolvePlace(game, traque.getInGameId(), labyrinthe); + + //Verify that traque has only mangrove + assertEquals(Collections.singletonList(mangrove), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_labyrintheThirdPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseDefausseCard = new ActionChooseCard(Collections.singletonList(NEXUS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseThirdPower) + .thenReturn(chooseDefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(labyrinthe); + PowerApplicator.resolvePlace(game, traque.getInGameId(), labyrinthe); + + //Verify that traque has only Nexus + assertEquals(Collections.singletonList(nexus), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_labyrintheAllRevealFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseAReserveCard = new ActionChooseCard(Collections.singletonList(MANGROVE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseAReserveCard); + + Traque traque = (Traque) game.getPlayer(2); + + List placeCards = planetExtension.getPlaceCardsInInterval(6, 10); + for(PlaceCard placeCard : placeCards){ + planetExtension.revealPlace(placeCard); + } + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(labyrinthe); + PowerApplicator.resolvePlace(game, traque.getInGameId(), labyrinthe); + + //Verify that traque has only mangrove + assertEquals(Collections.singletonList(mangrove), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_labyrintheAllRevealSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseDefausseCard = new ActionChooseCard(Collections.singletonList(NEXUS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseDefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List placeCards = planetExtension.getPlaceCardsInInterval(6, 10); + for(PlaceCard placeCard : placeCards){ + planetExtension.revealPlace(placeCard); + } + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(labyrinthe); + PowerApplicator.resolvePlace(game, traque.getInGameId(), labyrinthe); + + //Verify that traque has only Nexus + assertEquals(Collections.singletonList(nexus), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_mangroveFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(mangrove); + traque.playPlaceCard(mangrove); + PowerApplicator.resolvePlace(game, traque.getInGameId(), mangrove); + + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(nexus, oasis, fjord, mangrove))); + assertTrue(traque.getDefausse().containsAll(Arrays.asList(dome, labyrinthe))); + } + + @Test + void testResolvePlace_mangroveSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseDefausseCard = new ActionChooseCard(Collections.singletonList(NEXUS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseDefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(mangrove); + traque.playPlaceCard(mangrove); + PowerApplicator.resolvePlace(game, traque.getInGameId(), mangrove); + + //Verify that traque has only Nexus + assertEquals(Collections.singletonList(nexus), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_archipelFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseAPlayer = new ActionTargetPlayer(2); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseAPlayer); + + Traque traque = (Traque) game.getPlayer(2); + traque.subWillingness(2); + SurvivalCard pick = game.getSurvivalCardPioche().getCards().get(0); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(archipel); + traque.playPlaceCard(archipel); + PowerApplicator.resolvePlace(game, traque.getInGameId(), archipel); + + assertEquals(2, traque.getNumberWillingness()); + assertTrue(traque.getSurvivalCardsHand().contains(pick)); + } + + @Test + void testResolvePlace_archipelSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseDefausseCard = new ActionChooseCard(Collections.singletonList(NEXUS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseDefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(archipel); + traque.playPlaceCard(archipel); + PowerApplicator.resolvePlace(game, traque.getInGameId(), archipel); + + //Verify that traque has only Nexus + assertEquals(Collections.singletonList(nexus), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_archipelCantPickSurvivalCard() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + game.setTraqueCanPickSurvivalCards(false); + + Action chooseDefausseCard = new ActionChooseCard(Collections.singletonList(NEXUS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseDefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(archipel); + traque.playPlaceCard(archipel); + PowerApplicator.resolvePlace(game, traque.getInGameId(), archipel); + + //Verify that traque has only Nexus + assertEquals(Collections.singletonList(nexus), traque.getPlaceCards()); + } + + + @Test + void testResolvePlace_poleFirstPower() throws TException, NotFoundException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + Reserve reserve = game.getReserve(); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + reserve.pick(8); + assertFalse(reserve.notEmpty(8)); + traque.addPlaceCard(pole); + traque.playPlaceCard(pole); + PowerApplicator.resolvePlace(game, traque.getInGameId(), pole); + + Score score = new Score(2); + score.moveForwardTraque(2); + assertEquals(score, game.getBoard().getScore()); + assertFalse(traque.getPlaceCards().contains(pole)); + assertFalse(traque.getPlaceCardsPlayed().contains(pole)); + assertFalse(traque.getDefausse().contains(pole)); + assertTrue(reserve.notEmpty(8)); + } + + @Test + void testResolvePlace_poleSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseDefausseCard = new ActionChooseCard(Collections.singletonList(NEXUS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseDefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(pole); + traque.playPlaceCard(pole); + PowerApplicator.resolvePlace(game, traque.getInGameId(), pole); + + //Verify that traque has only Nexus + assertEquals(Collections.singletonList(nexus), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_fungiFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + SurvivalCard pick = game.getSurvivalCardPioche().getCards().get(0); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(fungi); + traque.playPlaceCard(fungi); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), fungi); + + assertTrue(traque.getSurvivalCardsHand().contains(pick)); + } + + @Test + void testResolvePlace_fungiSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower); + + Traque traque = (Traque) game.getPlayer(2); + traque.subWillingness(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(fungi); + traque.playPlaceCard(fungi); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), fungi); + + assertTrue(game.getGameRoundVariables().isPawnWillingnessOnBoard()); + + game.nextRound(); + + assertEquals(2, traque.getNumberWillingness()); + assertTrue(game.getGameRoundVariables().isPawnWillingnessOnBoard()); + + game.nextRound(); + + assertEquals(3, traque.getNumberWillingness()); + assertFalse(game.getGameRoundVariables().isPawnWillingnessOnBoard()); + } + + @Test + void testResolvePlace_FungiThirdPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseDefausseCard = new ActionChooseCard(Collections.singletonList(NEXUS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseThirdPower) + .thenReturn(chooseDefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(fungi); + traque.playPlaceCard(fungi); + PowerApplicator.resolvePlace(game, traque.getInGameId(), fungi); + + //Verify that traque has only Nexus + assertEquals(Collections.singletonList(nexus), traque.getPlaceCards()); + } + + @Test + void testResolvePlace_fungiFistPowerCantPickSurvival() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + game.setTraqueCanPickSurvivalCards(false); + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + traque.subWillingness(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(fungi); + traque.playPlaceCard(fungi); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), fungi); + + assertTrue(game.getGameRoundVariables().isPawnWillingnessOnBoard()); + + game.nextRound(); + + assertEquals(2, traque.getNumberWillingness()); + assertTrue(game.getGameRoundVariables().isPawnWillingnessOnBoard()); + + game.nextRound(); + + assertEquals(3, traque.getNumberWillingness()); + assertFalse(game.getGameRoundVariables().isPawnWillingnessOnBoard()); + } + + @Test + void testResolvePlace_fungiSecondPowerCantPickSurvival() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + game.setTraqueCanPickSurvivalCards(false); + + Action chooseDefausseCard = new ActionChooseCard(Collections.singletonList(NEXUS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseDefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(fungi); + traque.playPlaceCard(fungi); + PowerApplicator.resolvePlace(game, traque.getInGameId(), fungi); + + //Verify that traque has only Nexus + assertEquals(Collections.singletonList(nexus), traque.getPlaceCards()); + } + + + @Test + void testResolvePlace_PortailFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseACard = new ActionChooseCard(Collections.singletonList(NEXUS)); + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(OASIS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseACard) + .thenReturn(chooseSecondPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(portail); + traque.playPlaceCard(portail); + PowerApplicator.resolvePlace(game, traque.getInGameId(), portail); + + assertTrue(traque.getPlaceCards().contains(oasis)); + assertEquals(Collections.singletonList(nexus), traque.getPlaceCardsPlayed()); + assertTrue(traque.getDefausse().containsAll(Arrays.asList(fjord, dome, labyrinthe, portail))); + } + + @Test + void testResolvePlace_PortailFirstPowerAndJetonCreatureOnNewPlace() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseACard = new ActionChooseCard(Collections.singletonList(NEXUS)); + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(OASIS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseACard) + .thenReturn(chooseSecondPower) + .thenReturn(chooseADefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_ONE); + planetExtension.placeJeton(placedJeton); + + List throwAwayCards = Arrays.asList(oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(portail); + traque.playPlaceCard(portail); + PowerApplicator.resolvePlace(game, traque.getInGameId(), portail); + + assertEquals(Collections.singletonList(nexus), traque.getPlaceCardsPlayed()); + assertTrue(traque.getDefausse().containsAll(Arrays.asList(fjord, dome, labyrinthe, portail, oasis))); + Score score = new Score(2); + score.moveForwardCreature(2); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testResolvePlace_PortailSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Action chooseDefausseCard = new ActionChooseCard(Collections.singletonList(NEXUS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseDefausseCard); + + Traque traque = (Traque) game.getPlayer(2); + + List throwAwayCards = Arrays.asList(nexus, oasis, fjord, dome, labyrinthe); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.addPlaceCard(portail); + traque.playPlaceCard(portail); + PowerApplicator.resolvePlace(game, traque.getInGameId(), portail); + + //Verify that traque has only Nexus + assertEquals(Collections.singletonList(nexus), traque.getPlaceCards()); + } + + @Test + void testApplyPlayerCard_acharnement() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + Creature creature= game.getCreature(); + + List throwAwayCards = Arrays.asList(antre, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_TWO); + planet.placeJeton(placedJeton); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), ACHARNEMENT); + + traque.playPlaceCard(jungle); + PowerApplicator.resolvePlace(game, traque.getInGameId(), jungle); + + assertTrue(traque.getPlaceCards().isEmpty()); + assertEquals(1, traque.getNumberWillingness()); + Score score = new Score(2); + score.moveForwardCreature(1); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testApplyPlayerCard_angoisse() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + Creature creature= game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), ANGOISSE); + + //Start Phase1 + game.startNextPhase(); + assertFalse(game.playerResist(traque.getInGameId(), 2).state); + + assertFalse(game.getGameRoundVariables().traqueCanResist()); + } + + @Test + void testApplyPlayerCard_anticipationCatchPlayer() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + + Action targetPlayer = new ActionTargetPlayer(2); + + + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(targetPlayer); + + Traque traque = (Traque) game.getPlayer(2); + Creature creature= game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), ANTICIPATION); + assertEquals(2, game.getGameRoundVariables().getIdPlayerTargetByTrackingCardAnticipation()); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_TWO); + planet.placeJeton(placedJeton); + + List throwAwayCards = Arrays.asList(antre, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(jungle); + PowerApplicator.resolvePlace(game, traque.getInGameId(), jungle); + + + assertTrue(traque.getPlaceCards().isEmpty()); + assertEquals(2, traque.getNumberWillingness()); + Score score = new Score(2); + score.moveForwardCreature(2); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testApplyPlayerCard_anticipationCatchAnotherPlayer() throws TException { + Game game = new Game(Arrays.asList(1,2, 3), 1, planet, board, room); + + Action targetPlayer = new ActionTargetPlayer(3); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(targetPlayer); + + Traque traque = (Traque) game.getPlayer(2); + Creature creature= game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), ANTICIPATION); + assertEquals(3, game.getGameRoundVariables().getIdPlayerTargetByTrackingCardAnticipation()); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_TWO); + planet.placeJeton(placedJeton); + + List throwAwayCards = Arrays.asList(antre, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(jungle); + PowerApplicator.resolvePlace(game, traque.getInGameId(), jungle); + + + assertTrue(traque.getPlaceCards().isEmpty()); + assertEquals(2, traque.getNumberWillingness()); + Score score = new Score(3); + score.moveForwardCreature(1); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testApplyPlayerCard_cataclysme() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action choosePlace = new ActionChoosePlace(Collections.singletonList(Place.PLACE_ONE)); + + + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlace); + + Traque traque = (Traque) game.getPlayer(2); + Creature creature= game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), CATACLYSME); + + assertTrue(planet.isBlockedPlace(antre)); + + List throwAwayCards = Arrays.asList(jungle, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(antre); + PowerApplicator.resolvePlace(game, traque.getInGameId(), antre); + + assertTrue(traque.getPlaceCards().isEmpty()); + } + + @Test + void testApplyPlayerCard_champDeForce() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Creature creature= game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), CHAMP_DE_FORCE); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Arrays.asList(Place.PLACE_ONE, Place.PLACE_TWO)); + + TrackingCard champDeForce = database.findTrackingCard(CHAMP_DE_FORCE.toString()); + creature.getHand().getTrackingCardHand().clear(); + creature.addTrackingCard(champDeForce); + creature.playTrackingCard(champDeForce); + + assertTrue(game.playerPlaceJeton(creature.getInGameId(), placedJeton).state); + + assertTrue(game.getGameRoundVariables().isJetonCibleBlockPlace()); + assertTrue(game.getGameRoundVariables().jetonCibleCanBeOnTwoAdjacentPlaces()); + + //Start Phase 1 + game.startNextPhase(); + + assertFalse(game.playerPlayCard(2, antre).state); + assertFalse(game.playerPlayCard(2, jungle).state); + } + + @Test + void testApplyPlayerCard_cloneCatchPlayer() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + Creature creature= game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), CLONE); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_TWO); + planet.placeJeton(placedJeton); + + List throwAwayCards = Arrays.asList(antre, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(jungle); + PowerApplicator.resolvePlace(game, traque.getInGameId(), jungle); + + + assertTrue(traque.getPlaceCards().isEmpty()); + assertEquals(2, traque.getNumberWillingness()); + Score score = new Score(2); + score.moveForwardCreature(1); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testApplyPlayerCard_deploiementCatchPlayer() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action choosePlace = new ActionChoosePlace(Collections.singletonList(Place.PLACE_TWO)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlace); + + Traque traque = (Traque) game.getPlayer(2); + Creature creature= game.getCreature(); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_ONE); + planet.placeJeton(placedJeton); + + assertTrue(planet.isJetonSymbolOnPlaceCard(JetonSymbol.CREATURE, antre)); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), DEPLOIEMENT); + Score score = new Score(2); + score.moveBackCreature(1); + + assertFalse(planet.isJetonSymbolOnPlaceCard(JetonSymbol.CREATURE, antre)); + assertTrue(planet.isJetonSymbolOnPlaceCard(JetonSymbol.CREATURE, jungle)); + + List throwAwayCards = Arrays.asList(antre, riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + + traque.playPlaceCard(jungle); + PowerApplicator.resolvePlace(game, traque.getInGameId(), jungle); + + + assertTrue(traque.getPlaceCards().isEmpty()); + assertEquals(2, traque.getNumberWillingness()); + score.moveForwardCreature(1); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testApplyPlayerCard_desespoir() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Creature creature= game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), DESESPOIR); + + assertFalse(game.getGameRoundVariables().traqueCanPickSurvivalCards()); + } + + @Test + void testApplyPlayerCard_detourCatchPlayer() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action movePlayer = new ActionMovePlayer(2, Place.PLACE_ONE); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(movePlayer); + + Traque traque = (Traque) game.getPlayer(2); + Creature creature= game.getCreature(); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_ONE); + planet.placeJeton(placedJeton); + + List throwAwayCards = Arrays.asList(riviere, plage, rover); + traque.throwAwayPlaceCard(throwAwayCards); + traque.playPlaceCard(jungle); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), DETOUR); + + assertTrue(planet.isJetonSymbolOnPlaceCard(JetonSymbol.CREATURE, antre)); + + game.managePhase3(); + + assertEquals(Collections.singletonList(antre), traque.getPlaceCardsPlayed()); + Score score = new Score(2); + score.moveForwardCreature(1); + assertEquals(score, game.getBoard().getScore()); + assertEquals(1, traque.getNumberWillingness()); + + game.managePhase4(); + assertTrue(traque.getDefausse().containsAll(Arrays.asList(jungle, riviere, plage, rover))); + assertEquals(Collections.singletonList(antre), traque.getPlaceCards()); + } + + @Test + void testApplyPlayerCard_domination() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action choosePlayer = new ActionTargetPlayer(2); + + Action chooseFirstCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + Action chooseSecondCard = new ActionChooseCard(Collections.singletonList(JUNGLE)); + Action chooseThirdCard = new ActionChooseCard(Collections.singletonList(RIVIERE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlayer) + .thenReturn(chooseFirstCard) + .thenReturn(chooseSecondCard) + .thenReturn(chooseThirdCard); + + Traque traque = (Traque) game.getPlayer(2); + Creature creature= game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), DOMINATION); + + Score score = new Score(2); + assertEquals(score, game.getBoard().getScore()); + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(antre, jungle, riviere, plage, rover))); + + game.nextRound(); + + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(jungle, riviere, plage, rover))); + assertTrue(traque.getDefausse().contains(antre)); + + PowerApplicator.subWillingness(game, 2, 1); + game.nextRound(); + + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + assertEquals(2, traque.getNumberWillingness()); + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(riviere, plage, rover))); + assertTrue(traque.getDefausse().containsAll(Arrays.asList(antre, jungle))); + + + PowerApplicator.subWillingness(game, 2, 1); + game.nextRound(); + + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + assertEquals(1, traque.getNumberWillingness()); + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(plage, rover))); + assertTrue(traque.getDefausse().containsAll(Arrays.asList(antre, jungle, riviere))); + + PowerApplicator.subWillingness(game, 2, 1); + score.moveForwardCreature(1); + game.nextRound(); + + score.moveForwardTraque(1); + + assertEquals(score, game.getBoard().getScore()); + assertEquals(3, traque.getNumberWillingness()); + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(plage, rover))); + assertTrue(traque.getDefausse().containsAll(Arrays.asList(antre, jungle, riviere))); + } + + @Test + void testApplyPlayerCard_effroi() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action choosePlayer = new ActionTargetPlayer(2); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlayer); + + Creature creature= game.getCreature(); + + Traque traque = (Traque) game.getPlayer(2); + + //Start phase 1 + game.startNextPhase(); + + assertTrue(game.playerResist(traque.getInGameId(), 1).state); + assertEquals(2, traque.getNumberWillingness()); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), EFFROI); + + assertEquals(3, traque.getNumberWillingness()); + Score score = new Score(2); + score.moveForwardCreature(1); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testApplyPlayerCard_emprise() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action choosePlayer = new ActionTargetPlayer(2); + Action chooseCards = new ActionChooseCard(Arrays.asList(ANTRE, JUNGLE, RIVIERE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlayer) + .thenReturn(chooseCards); + + Creature creature= game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), EMPRISE); + + Traque traque = (Traque) game.getPlayer(2); + + assertTrue(traque.getDefausse().containsAll(Arrays.asList(antre, jungle, riviere))); + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(plage, rover))); + } + + @Test + void testApplyPlayerCard_emprisePlayersWith2Cards() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action choosePlayer = new ActionTargetPlayer(2); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlayer); + + Creature creature= game.getCreature(); + Traque traque = (Traque) game.getPlayer(2); + traque.throwAwayPlaceCard(Arrays.asList(antre, jungle, riviere)); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), EMPRISE); + + + assertTrue(traque.getDefausse().containsAll(Arrays.asList(antre, jungle, riviere))); + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(plage, rover))); + } + + @Test + void testApplyPlayerCard_epidemie() throws TException { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + Action choosePlayer = new ActionTargetPlayer(2); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlayer); + + Creature creature= game.getCreature(); + Traque traque1 = (Traque) game.getPlayer(2); + Traque traque2 = (Traque) game.getPlayer(3); + Traque traque3 = (Traque) game.getPlayer(4); + + traque1.playPlaceCard(antre); + traque2.playPlaceCard(antre); + traque3.playPlaceCard(antre); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), EPIDEMIE); + + PowerApplicator.resolvePlace(game, traque2.getInGameId(), antre); + PowerApplicator.resolvePlace(game, traque1.getInGameId(), antre); + PowerApplicator.resolvePlace(game, traque3.getInGameId(), antre); + + + assertEquals(2, traque2.getNumberWillingness()); + assertEquals(2, traque3.getNumberWillingness()); + assertEquals(3, traque1.getNumberWillingness()); + } + + @Test + void testApplyPlayerCard_failleTemporelle() throws TException { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + Action choosePlace = new ActionChoosePlace(Collections.singletonList(Place.PLACE_ONE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlace) + .thenReturn(chooseFirstPower) + .thenReturn(chooseFirstPower) + .thenReturn(chooseFirstPower); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_ONE); + planet.placeJeton(placedJeton); + + Board board = game.getBoard(); + board.moveForwardTraque(12); + board.moveForwardCreature(6); + assertEquals(new Score(3,3), board.getScore()); + + Creature creature= game.getCreature(); + Traque traque1 = (Traque) game.getPlayer(2); + Traque traque2 = (Traque) game.getPlayer(3); + Traque traque3 = (Traque) game.getPlayer(4); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), FAILLE_TEMPORELLE); + + PowerApplicator.resolvePlace(game, traque2.getInGameId(), antre); + PowerApplicator.resolvePlace(game, traque1.getInGameId(), antre); + PowerApplicator.resolvePlace(game, traque3.getInGameId(), antre); + + + Score score = new Score(0,1); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testApplyPlayerCard_flashback() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + TrackingCard desespoir = database.findTrackingCard(DESESPOIR.toString()); + TrackingCard flashback = database.findTrackingCard(FLASHBACK.toString()); + TrackingCard cataclysme = database.findTrackingCard(CATACLYSME.toString()); + + Action choosePlace = new ActionChoosePlace(Collections.singletonList(Place.PLACE_ONE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlace); + + //Desespoir (same phase) + game.getTrackingCardPioche().throwAway(desespoir); + + Creature creature= game.getCreature(); + creature.getTrackingCardHand().clear(); + creature.addTrackingCard(flashback); + + assertTrue(game.playerPlayCard(creature.getInGameId(), flashback).state); + assertTrue(game.playerPlayCard(creature.getInGameId(), desespoir).state); + + assertFalse(game.getGameRoundVariables().traqueCanPickSurvivalCards()); + + game.nextRound(); + + //cataclysme (other phase) + game.getTrackingCardPioche().throwAway(cataclysme); + + creature.getTrackingCardHand().clear(); + creature.addTrackingCard(flashback); + + assertTrue(game.playerPlayCard(creature.getInGameId(), flashback).state); + //need to wait the prephase 3 + assertFalse(game.playerPlayCard(creature.getInGameId(), cataclysme).state); + + //Start phase1 + game.startNextPhase(); + //Start postphase1 + game.startNextPhase(); + //Start prephase2 + game.startNextPhase(); + //Start phase2 + game.startNextPhase(); + //Start postphase2 + game.startNextPhase(); + //Start prephase3 + game.startNextPhase(); + + assertTrue(game.playerPlayCard(creature.getInGameId(), cataclysme).state); + assertTrue(planet.isBlockedPlace(antre)); + } + + @Test + void testApplyPlayerCard_flashbackTrackingTrashEmpty() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + TrackingCard flashback = database.findTrackingCard(FLASHBACK.toString()); + + Creature creature= game.getCreature(); + creature.getTrackingCardHand().clear(); + creature.addTrackingCard(flashback); + + assertTrue(game.playerPlayCard(creature.getInGameId(), flashback).state); + } + + @Test + void testApplyPlayerCard_gargantua() { + Game game = new Game(Arrays.asList(1,2, 3), 1, planet, board, room); + + Traque traque1 = (Traque) game.getPlayer(2); + Traque traque2 = (Traque) game.getPlayer(3); + Creature creature= game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), GARGANTUA); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Arrays.asList(Place.PLACE_ONE, Place.PLACE_TWO)); + planet.placeJeton(placedJeton); + + traque1.playPlaceCard(jungle); + PowerApplicator.resolvePlace(game, traque1.getInGameId(), jungle); + + traque2.playPlaceCard(antre); + PowerApplicator.resolvePlace(game, traque2.getInGameId(), antre); + + assertEquals(2, traque1.getNumberWillingness()); + assertEquals(1, traque2.getNumberWillingness()); + + Score score = new Score(3); + score.moveForwardCreature(1); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testApplyPlayerCard_harcelementPlayerPlayAntre() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseADefausseCard = new ActionChooseCard(Collections.singletonList(PLAGE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseADefausseCard); + + Creature creature= game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), HARCELEMENT); + + assertEquals(1, game.getGameRoundVariables().getNumberMaxPlaceCardsGetByPlacePower()); + + Traque traque = (Traque) game.getPlayer(2); + traque.throwAwayPlaceCard(Arrays.asList(jungle, riviere, plage, rover)); + traque.playPlaceCard(antre); + PowerApplicator.resolvePlace(game, traque.getInGameId(), antre); + assertTrue(traque.getPlaceCards().contains(plage)); + } + + @Test + void testApplyPlayerCard_harcelementPlayerPlayJungle() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Creature creature= game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), HARCELEMENT); + + assertEquals(1, game.getGameRoundVariables().getNumberMaxPlaceCardsGetByPlacePower()); + + Traque traque = (Traque) game.getPlayer(2); + traque.throwAwayPlaceCard(Arrays.asList(antre, riviere, plage, rover)); + traque.playPlaceCard(jungle); + PowerApplicator.resolvePlace(game, traque.getInGameId(), jungle); + assertTrue(traque.getPlaceCards().contains(jungle)); + } + + @Test + void testApplyPlayerCard_harcelementPlayerPlayMarais() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Creature creature= game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), HARCELEMENT); + + assertEquals(1, game.getGameRoundVariables().getNumberMaxPlaceCardsGetByPlacePower()); + + Traque traque = (Traque) game.getPlayer(2); + traque.addPlaceCard(marais); + traque.playPlaceCard(marais); + PowerApplicator.resolvePlace(game, traque.getInGameId(), marais); + assertTrue(traque.getPlaceCards().contains(marais)); + } + + @Test + void testApplyPlayerCard_harcelementPlayerPlayArtefactYellow() throws TException { + Board board = new Board(BoardDistribution.BACK, BoardColor.YELLOW); + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseTwoDefausseCard = new ActionChooseCard(Arrays.asList(ANTRE, JUNGLE)); + Action chooseOneDefausseCard = new ActionChooseCard(Collections.singletonList(PLAGE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseTwoDefausseCard) + .thenReturn(chooseOneDefausseCard); + + Creature creature= game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), HARCELEMENT); + + assertEquals(1, game.getGameRoundVariables().getNumberMaxPlaceCardsGetByPlacePower()); + + Traque traque = (Traque) game.getPlayer(2); + traque.throwAwayPlaceCard(Arrays.asList(antre, jungle, riviere, plage, rover)); + traque.addPlaceCard(artefact); + traque.playPlaceCard(artefact); + PowerApplicator.resolvePlace(game, traque.getInGameId(), artefact); + assertTrue(traque.getPlaceCards().contains(plage)); + } + + @Test + void testApplyPlayerCard_hurlementPlayerChoosePower1() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseTwoDefausseCard = new ActionChooseCard(Arrays.asList(ANTRE, JUNGLE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseTwoDefausseCard) + .thenReturn(chooseFirstPower); + + planet.forceMovePlanetPawn(); + Creature creature= game.getCreature(); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), HURLEMENTS); + + Traque traque = (Traque) game.getPlayer(2); + traque.playPlaceCard(plage); + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + assertTrue(traque.getDefausse().containsAll(Arrays.asList(antre, jungle))); + assertTrue(planet.planetPawnIsActive()); + } + + @Test + void testApplyPlayerCard_hurlementPlayerChoosePower2() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseFirstPower); + + planet.forceMovePlanetPawn(); + Creature creature= game.getCreature(); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), HURLEMENTS); + + Traque traque = (Traque) game.getPlayer(2); + traque.playPlaceCard(plage); + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + assertEquals(2, traque.getNumberWillingness()); + assertTrue(planet.planetPawnIsActive()); + } + + @Test + void testApplyPlayerCard_inertiePlayerOnJeton() throws TException { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower); + + planet.forceMovePlanetPawn(); + Creature creature= game.getCreature(); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_TWO); + planet.placeJeton(placedJeton); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), INERTIE); + + Traque traque2 = (Traque) game.getPlayer(3); + traque2.playPlaceCard(jungle); + PowerApplicator.resolvePlace(game, traque2.getInGameId(), jungle); + + Traque traque3 = (Traque) game.getPlayer(4); + traque3.playPlaceCard(antre); + PowerApplicator.resolvePlace(game, traque3.getInGameId(), antre); + + Traque traque1 = (Traque) game.getPlayer(2); + traque1.playPlaceCard(plage); + PowerApplicator.resolvePlace(game, traque1.getInGameId(), plage); + + + assertEquals(2, traque2.getNumberWillingness()); + } + + @Test + void testApplyPlayerCard_inertieNoPlayerOnJeton() throws TException { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + planet.forceMovePlanetPawn(); + Creature creature= game.getCreature(); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_THREE); + planet.placeJeton(placedJeton); + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), INERTIE); + + Traque traque = (Traque) game.getPlayer(2); + traque.playPlaceCard(plage); + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + + assertTrue(planet.planetPawnIsActive()); + } + + @Test + void testApplyPlayerCard_interferencesPower1() { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + Creature creature= game.getCreature(); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_TWO); + planet.placeJeton(placedJeton); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), INTERFERENCES); + assertTrue(planet.isBlockedPlace(plage)); + assertTrue(planet.isBlockedPlace(epave)); + Traque traque1 = (Traque) game.getPlayer(2); + PowerApplicator.resolvePlace(game, traque1.getInGameId(), plage); + + Traque traque2 = (Traque) game.getPlayer(3); + PowerApplicator.resolvePlace(game, traque2.getInGameId(), epave); + } + + @Test + void testApplyPlayerCard_interferencesPower2() { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planetExtension, board, room); + Creature creature= game.getCreature(); + + planetExtension.forceMovePlanetPawn(); + + ShieldPawn pawn = (ShieldPawn) planetExtension.getPlanetPawn(); + assertEquals(2, pawn.getLocation()); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), INTERFERENCES); + + assertEquals(1, pawn.getLocation()); + } + + @Test + void testApplyPlayerCard_intuition() throws TException { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planetExtension, board, room); + Creature creature= game.getCreature(); + + List trackingCards = new ArrayList<>(game.getTrackingCardPioche().getCards().subList(0,3)); + + Action chooseCard = new ActionChooseCard(Collections.singletonList(trackingCards.get(0).getCardName())); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCard); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), INTUITION); + + assertTrue(creature.getTrackingCardToApplied().contains(trackingCards.get(0))); + assertTrue(game.getTrackingCardPioche().getTrash().containsAll(Arrays.asList(trackingCards.get(1), trackingCards.get(2)))); + + } + + @Test + void testApplyPlayerCard_magnetisme() throws TException { + Game game = new Game(Arrays.asList(1,2, 3, 4, 5, 6), 1, planet, board, room); + Creature creature= game.getCreature(); + + planet.forceMovePlanetPawn(); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_TWO); + planet.placeJeton(placedJeton); + placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_TWO); + planet.placeJeton(placedJeton); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Traque traque1 = (Traque) game.getPlayer(2); + Traque traque2 = (Traque) game.getPlayer(3); + Traque traque3 = (Traque) game.getPlayer(4); + Traque traque4 = (Traque) game.getPlayer(5); + Traque traque5 = (Traque) game.getPlayer(6); + + //Start phase 1 + game.startNextPhase(); + traque1.playPlaceCard(antre); + traque2.playPlaceCard(jungle); + traque3.playPlaceCard(riviere); + traque4.addPlaceCard(abri); + traque4.playPlaceCard(abri); + traque5.playPlaceCard(plage); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), MAGNETISME); + + //Start postphase 1 + game.startNextPhase(); + //Start prephase 2 + game.startNextPhase(); + //Start phase 2 + game.startNextPhase(); + //Start postphase 2 + game.startNextPhase(); + //Start prephase 3 + game.startNextPhase(); + //Start phase 3 + game.startNextPhase(); + + assertTrue(planet.planetPawnIsActive()); + assertEquals(2, traque1.getNumberWillingness()); + assertEquals(2, traque2.getNumberWillingness()); + assertEquals(2, traque3.getNumberWillingness()); + assertEquals(2, traque4.getNumberWillingness()); + + assertEquals(3, traque5.getNumberWillingness()); + } + + @Test + void testApplyPlayerCard_mirage() { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + Creature creature= game.getCreature(); + + creature.getTrackingCardHand().clear(); + TrackingCard mirage = database.findTrackingCard(MIRAGE.toString()); + creature.addTrackingCard(mirage); + creature.playTrackingCard(mirage); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), MIRAGE); + + //Start phase 1 + game.startNextPhase(); + //Start postphase 1 + game.startNextPhase(); + //Start prephase 2 + game.startNextPhase(); + //Start phase 2 + game.startNextPhase(); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, new ArrayList<>(Arrays.asList(Place.PLACE_FOUR, Place.PLACE_FIVE))); + + game.playerPlaceJeton(creature.getInGameId(), placedJeton); + assertTrue(game.playerPlaceJeton(creature.getInGameId(), placedJeton).state); + + Traque traque1 = (Traque) game.getPlayer(2); + PowerApplicator.resolvePlace(game, traque1.getInGameId(), plage); + + Traque traque2 = (Traque) game.getPlayer(3); + PowerApplicator.resolvePlace(game, traque2.getInGameId(), rover); + } + + @Test + void testApplyPlayerCard_mutation() throws TException { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + Creature creature= game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), MUTATION); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.ARTEMIA, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + + Action chooseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCard); + + Traque traque = (Traque) game.getPlayer(2); + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + + assertTrue(traque.getDefausse().contains(antre)); + assertEquals(2, traque.getNumberWillingness()); + } + + @Test + void testApplyPlayerCard_psychose() throws TException { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + Creature creature= game.getCreature(); + + Action targetPlayer = new ActionTargetPlayer(2); + Action chooseCards = new ActionChooseCard(Arrays.asList(ANTRE, JUNGLE, RIVIERE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(targetPlayer) + .thenReturn(chooseCards); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), PSYCHOSE); + + Traque traque = (Traque) game.getPlayer(2); + + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(antre, jungle, riviere, plage, rover))); + } + + @Test + void testApplyPlayerCard_reminiscence() throws TException { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + Creature creature= game.getCreature(); + creature.playTrackingCard(creature.getTrackingCardHand().get(0)); + + Pioche pioche = game.getTrackingCardPioche(); + List trackingCard = pioche.draw(5); + pioche.throwAway(new ArrayList<>(trackingCard)); + + Action chooseCard = new ActionChooseCard(Collections.singletonList(trackingCard.get(0).getCardName())); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCard); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), REMINISCENCE); + + assertTrue(creature.getTrackingCardHand().contains(trackingCard.get(0))); + } + + @Test + void testApplyPlayerCard_reperage() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action placeOne = new ActionChoosePlace(Collections.singletonList(Place.PLACE_ONE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(placeOne); + + Creature creature = game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), REPERAGE); + + creature.getTrackingCardHand().clear(); + TrackingCard angoisse = database.findTrackingCard(ANGOISSE.toString()); + TrackingCard cataclysme = database.findTrackingCard(CATACLYSME.toString()); + + creature.addTrackingCard(angoisse); + creature.addTrackingCard(cataclysme); + + game.nextRound(); + + assertTrue(game.playerPlayCard(creature.getInGameId(), angoisse).state); + + //Start phase 1 + game.startNextPhase(); + //Start postphase 1 + game.startNextPhase(); + //Start prephase 2 + game.startNextPhase(); + //Start phase 2 + game.startNextPhase(); + //Start postphase 2 + game.startNextPhase(); + //Start prephase 3 + game.startNextPhase(); + + assertTrue(game.playerPlayCard(creature.getInGameId(), cataclysme).state); + + assertFalse(game.getGameRoundVariables().traqueCanResist()); + assertTrue(planet.isBlockedPlace(antre)); + } + + @Test + void testApplyPlayerCard_sablesMouvants() throws TException { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + Creature creature= game.getCreature(); + creature.playTrackingCard(creature.getTrackingCardHand().get(0)); + + Action chooseCard1 = new ActionChooseCard(Arrays.asList(ANTRE, JUNGLE, RIVIERE)); + Action chooseCard2 = new ActionChooseCard(Arrays.asList(ANTRE, JUNGLE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCard1) + .thenReturn(chooseCard2); + + planet.forceMovePlanetPawn(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), SABLES_MOUVANTS); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + + placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + + Traque traque1 = (Traque) game.getPlayer(2); + Traque traque2 = (Traque) game.getPlayer(3); + Traque traque3 = (Traque) game.getPlayer(4); + + traque2.throwAwayPlaceCard(Collections.singletonList(rover)); + traque3.throwAwayPlaceCard(Arrays.asList(riviere, plage, rover)); + + PowerApplicator.resolvePlace(game, traque1.getInGameId(), plage); + PowerApplicator.resolvePlace(game, traque2.getInGameId(), plage); + PowerApplicator.resolvePlace(game, traque3.getInGameId(), plage); + + assertTrue(traque1.getDefausse().containsAll(Arrays.asList(antre, jungle, riviere))); + assertTrue(traque2.getDefausse().containsAll(Arrays.asList(antre, jungle, rover))); + assertTrue(traque3.getDefausse().containsAll(Arrays.asList(riviere, plage, rover))); + } + + @Test + void testApplyPlayerCard_soifDeSang() throws TException { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + Creature creature= game.getCreature(); + creature.playTrackingCard(creature.getTrackingCardHand().get(0)); + + Action chooseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower) + .thenReturn(chooseCard) + .thenReturn(chooseSecondPower) + .thenReturn(chooseCard) + .thenReturn(chooseSecondPower) + .thenReturn(chooseCard); + + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), SOIF_DE_SANG); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + + Traque traque1 = (Traque) game.getPlayer(2); + Traque traque2 = (Traque) game.getPlayer(3); + Traque traque3 = (Traque) game.getPlayer(4); + + traque1.throwAwayPlaceCard(Collections.singletonList(antre)); + traque1.subWillingness(1); + traque2.throwAwayPlaceCard(Collections.singletonList(antre)); + traque3.throwAwayPlaceCard(Collections.singletonList(antre)); + + PowerApplicator.resolvePlace(game, traque1.getInGameId(), plage); + PowerApplicator.resolvePlace(game, traque2.getInGameId(), riviere); + PowerApplicator.resolvePlace(game, traque3.getInGameId(), rover); + + assertEquals(3, traque1.getNumberWillingness()); + assertEquals(2, traque2.getNumberWillingness()); + assertEquals(2, traque3.getNumberWillingness()); + } + + @Test + void testApplyPlayerCard_stase() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Creature creature = game.getCreature(); + Score score = new Score(2); + + assertEquals(score, game.getBoard().getScore()); + + game.nextRound(); + + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), STASE); + + game.nextRound(); + + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testApplyPlayerCard_telepathieCreatureFindTheCard() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + Action targetPlayer = new ActionTargetPlayer(2); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCard) + .thenReturn(targetPlayer); + + Traque traque = (Traque) game.getPlayer(2); + traque.getPlaceCards().clear(); + traque.addPlaceCard(Arrays.asList(antre, antre, antre, antre, antre)); + + Creature creature = game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), TELEPATHIE); + + Score score = new Score(2); + score.moveForwardCreature(1); + assertEquals(score, game.getBoard().getScore()); + assertEquals(Collections.singletonList(antre), traque.getDefausse()); + } + + @Test + void testApplyPlayerCard_telepathieCreatureDoesNotFindTheCard() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseCard = new ActionChooseCard(Collections.singletonList(JUNGLE)); + Action targetPlayer = new ActionTargetPlayer(2); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCard) + .thenReturn(targetPlayer); + + Traque traque = (Traque) game.getPlayer(2); + traque.getPlaceCards().clear(); + traque.addPlaceCard(Arrays.asList(antre, antre, antre, antre, antre)); + + Creature creature = game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), TELEPATHIE); + + Score score = new Score(2); + assertEquals(score, game.getBoard().getScore()); + assertEquals(Collections.singletonList(antre), traque.getDefausse()); + } + + @Test + void testApplyPlayerCard_tornade() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action choosePlace = new ActionChoosePlace(Collections.singletonList(Place.PLACE_TWO)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlace); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.ARTEMIA, Place.PLACE_ONE); + planet.placeJeton(placedJeton); + Creature creature = game.getCreature(); + creature.playJeton(JetonSymbol.ARTEMIA); + + assertTrue(planet.findJetonsSymbolsOnCard(antre).contains(JetonSymbol.ARTEMIA)); + assertFalse(planet.findJetonsSymbolsOnCard(jungle).contains(JetonSymbol.ARTEMIA)); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), TORNADE); + + assertFalse(planet.findJetonsSymbolsOnCard(antre).contains(JetonSymbol.ARTEMIA)); + assertTrue(planet.findJetonsSymbolsOnCard(jungle).contains(JetonSymbol.ARTEMIA)); + } + + @Test + void testApplyPlayerCard_toxine() throws TException { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + Pioche survivalCardPioche = game.getSurvivalCardPioche(); + + SurvivalCard survivalCard = survivalCardPioche.draw(); + + Traque traque1 = (Traque) game.getPlayer(2); + traque1.getSurvivalCardsHand().clear(); + traque1.addSurvivalCard(survivalCard); + Traque traque2 = (Traque) game.getPlayer(3); + traque2.getSurvivalCardsHand().clear(); + traque2.addSurvivalCard(survivalCard); + Traque traque3 = (Traque) game.getPlayer(4); + + Action chooseCard = new ActionChooseCard(Collections.singletonList(survivalCard.getCardName())); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower) + .thenReturn(chooseCard) + .thenReturn(chooseCard) + .thenReturn(chooseSecondPower); + + Creature creature = game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), TOXINE); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + + PowerApplicator.resolvePlace(game, traque1.getInGameId(), plage); + PowerApplicator.resolvePlace(game, traque2.getInGameId(), plage); + PowerApplicator.resolvePlace(game, traque3.getInGameId(), rover); + + assertTrue(traque1.getSurvivalCardsHand().isEmpty()); + assertTrue(traque2.getSurvivalCardsHand().isEmpty()); + assertFalse(traque3.getSurvivalCardsHand().isEmpty()); + } + + @Test + void testApplyPlayerCard_ubiquite() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action swapJeton = new ActionSwapJeton(JetonSymbol.CIBLE, JetonSymbol.ARTEMIA); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(swapJeton); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.ARTEMIA, Place.PLACE_ONE); + planet.placeJeton(placedJeton); + placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Arrays.asList(Place.PLACE_THREE, Place.PLACE_TWO)); + planet.placeJeton(placedJeton); + + Creature creature = game.getCreature(); + + assertTrue(planet.findJetonsSymbolsOnCard(antre).contains(JetonSymbol.ARTEMIA)); + + assertTrue(planet.findJetonsSymbolsOnCard(jungle).contains(JetonSymbol.CIBLE)); + assertTrue(planet.findJetonsSymbolsOnCard(riviere).contains(JetonSymbol.CIBLE)); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), UBIQUITE); + + assertTrue(planet.findJetonsSymbolsOnCard(antre).contains(JetonSymbol.CIBLE)); + + assertTrue(planet.findJetonsSymbolsOnCard(jungle).contains(JetonSymbol.ARTEMIA)); + assertTrue(planet.findJetonsSymbolsOnCard(riviere).contains(JetonSymbol.ARTEMIA)); + + planet.reset(); + + placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_ONE); + planet.placeJeton(placedJeton); + placedJeton = new PlacedJeton(JetonSymbol.ARTEMIA, Arrays.asList(Place.PLACE_THREE, Place.PLACE_TWO)); + planet.placeJeton(placedJeton); + + assertTrue(planet.findJetonsSymbolsOnCard(antre).contains(JetonSymbol.CIBLE)); + + assertTrue(planet.findJetonsSymbolsOnCard(jungle).contains(JetonSymbol.ARTEMIA)); + assertTrue(planet.findJetonsSymbolsOnCard(riviere).contains(JetonSymbol.ARTEMIA)); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), UBIQUITE); + + assertTrue(planet.findJetonsSymbolsOnCard(antre).contains(JetonSymbol.ARTEMIA)); + + assertTrue(planet.findJetonsSymbolsOnCard(jungle).contains(JetonSymbol.CIBLE)); + assertTrue(planet.findJetonsSymbolsOnCard(riviere).contains(JetonSymbol.CIBLE)); + } + + @Test + void testApplyPlayerCard_virus() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Creature creature = game.getCreature(); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), VIRUS); + + assertTrue(game.getGameRoundVariables().jetonArtemiaCanBeOnTwoAdjacentPlaces()); + } + + @Test + void testApplyPlayerCard_zoneInterdite() throws TException { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + Creature creature = game.getCreature(); + + Action chooseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCard); + + Traque traque1 = (Traque) game.getPlayer(2); + Traque traque2 = (Traque) game.getPlayer(3); + Traque traque3 = (Traque) game.getPlayer(4); + + PowerApplicator.applyTrackingCardPower(game, creature.getInGameId(), ZONE_INTERDITE); + + assertTrue(traque1.getDefausse().contains(antre)); + assertTrue(traque2.getDefausse().contains(antre)); + assertTrue(traque3.getDefausse().contains(antre)); + } + + @Test + void testApplyPlayerCard_adrenaline() { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + traque.subWillingness(1); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), ADRENALINE); + + assertEquals(3, traque.getNumberWillingness()); + } + + @Test + void testApplyPlayerCard_alerte() throws TException { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + + Action choosePlace = new ActionChoosePlace(Collections.singletonList(Place.PLACE_ONE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlace); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_ONE); + planet.placeJeton(placedJeton); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), ALERTE); + PowerApplicator.resolvePlace(game, traque.getInGameId(), antre); + + assertEquals(3, traque.getNumberWillingness()); + } + + @Test + void testApplyPlayerCard_amplificateur() { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + + planet.forceMovePlanetPawn(); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), AMPLIFICATEUR); + + assertTrue(planet.planetPawnIsActive()); + } + + @Test + void testApplyPlayerCard_amplificateurWithExtension() { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + Traque traque = (Traque) game.getPlayer(2); + + planetExtension.forceMovePlanetPawn(); + planetExtension.forceMovePlanetPawn(); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), AMPLIFICATEUR); + + Score score = new Score(2); + score.moveBackCreature(1); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testApplyPlayerCard_brouillage() { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), BROUILLAGE); + + assertTrue(game.getGameRoundVariables().defaussePlaceCardsAreHidden()); + } + + + @Test + void testApplyPlayerCard_cavale() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseCard = new ActionChooseCard(Collections.singletonList(PLAGE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCard) + .thenReturn(chooseFirstPower); + + planet.forceMovePlanetPawn(); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), CAVALE); + + //Start phase 1 + game.startNextPhase(); + assertTrue(game.playerPlayCard(traque.getInGameId(), Arrays.asList(plage, jungle, riviere)).state); + + game.managePhase3(); + game.managePhase4(); + + assertTrue(traque.getDefausse().containsAll(Arrays.asList(jungle, riviere))); + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(plage, antre, rover))); + assertTrue(planet.planetPawnIsActive()); + } + + @Test + void testApplyPlayerCard_detecteur() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + planet.forceMovePlanetPawn(); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.ARTEMIA, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), DETECTEUR); + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + + assertTrue(traque.getDefausse().isEmpty()); + assertTrue(planet.planetPawnIsActive()); + } + + @Test + void testApplyPlayerCard_drone() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseCard1 = new ActionChooseCard(Collections.singletonList(ARTEFACT)); + Action chooseCard2 = new ActionChooseCard(Collections.singletonList(MARAIS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCard1) + .thenReturn(chooseCard2); + + planet.forceMovePlanetPawn(); + + Traque traque = (Traque) game.getPlayer(2); + traque.addPlaceCard(artefact); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), DRONE); + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + + assertTrue(traque.getDefausse().isEmpty()); + assertFalse(planet.planetPawnIsActive()); + assertTrue(traque.getPlaceCards().contains(marais)); + } + + @Test + void testApplyPlayerCard_dronePlaceNotRevealed() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + List placeCards = planetExtension.getPlaceCardsInInterval(6,10); + PlaceCard revealed = placeCards.get(0); + + Action chooseCard1 = new ActionChooseCard(Collections.singletonList(placeCards.get(0).getCardName())); + Action chooseCard2 = new ActionChooseCard(Collections.singletonList(revealed.getCardName())); + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCard1) + .thenReturn(chooseCard2); + + planetExtension.revealPlace(revealed); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), DRONE); + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + + assertTrue(traque.getDefausse().isEmpty()); + assertFalse(planet.planetPawnIsActive()); + assertTrue(traque.getPlaceCards().contains(revealed)); + } + + @Test + void testApplyPlayerCard_entrave() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + Creature creature = game.getCreature(); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), ENTRAVE); + assertFalse(game.getGameRoundVariables().canPlaceJetonCreatureOnPlaces6To10()); + + TrackingCard fake = new TrackingCard(ANGOISSE, "","",Phase.PREPHASE_1,new ArrayList<>(Arrays.asList(JetonSymbol.CIBLE, JetonSymbol.ARTEMIA))); + creature.getTrackingCardHand().clear(); + creature.addTrackingCard(fake); + creature.playTrackingCard(fake); + + //Start phase1 + game.startNextPhase(); + //Start postphase1 + game.startNextPhase(); + //Start prephase2 + game.startNextPhase(); + //Start phase2 + game.startNextPhase(); + + assertFalse(game.playerPlaceJeton(creature.getInGameId(), new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_SIX)).state); + assertFalse(game.playerPlaceJeton(creature.getInGameId(), new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_SEVEN)).state); + assertFalse(game.playerPlaceJeton(creature.getInGameId(), new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_EIGHT)).state); + assertFalse(game.playerPlaceJeton(creature.getInGameId(), new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_NINE)).state); + assertFalse(game.playerPlaceJeton(creature.getInGameId(), new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_TEN)).state); + assertTrue(game.playerPlaceJeton(creature.getInGameId(), new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_ONE)).state); + assertTrue(game.playerPlaceJeton(creature.getInGameId(), new PlacedJeton(JetonSymbol.ARTEMIA, Place.PLACE_SIX)).state); + assertTrue(game.playerPlaceJeton(creature.getInGameId(), new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_TEN)).state); + } + + @Test + void testApplyPlayerCard_equipementNoCardIntrash() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + SurvivalCard survivalCard = game.getSurvivalCardPioche().getCards().get(0); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), EQUIPEMENT); + + assertTrue(traque.getSurvivalCardsHand().contains(survivalCard)); + } + + @Test + void testApplyPlayerCard_equipementCantPickSurvivalCard() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + game.getGameRoundVariables().setTraqueCanPickSurvivalCards(false); + + SurvivalCard survivalCard = game.getSurvivalCardPioche().getCards().get(0); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), EQUIPEMENT); + + assertFalse(traque.getSurvivalCardsHand().contains(survivalCard)); + } + + @Test + void testApplyPlayerCard_equipementFirstPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Pioche pioche = game.getSurvivalCardPioche(); + SurvivalCard trash = pioche.draw(); + pioche.throwAway(trash); + + SurvivalCard survivalCard = game.getSurvivalCardPioche().getCards().get(0); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), EQUIPEMENT); + + assertTrue(traque.getSurvivalCardsHand().contains(survivalCard)); + } + + @Test + void testApplyPlayerCard_equipementSecondPower() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseSecondPower); + + Pioche pioche = game.getSurvivalCardPioche(); + SurvivalCard trash = pioche.draw(); + pioche.throwAway(trash); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), EQUIPEMENT); + + assertTrue(traque.getSurvivalCardsHand().contains(trash)); + } + + @Test + void testApplyPlayerCard_esquive() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + planet.forceMovePlanetPawn(); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), ESQUIVE); + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + + Score score = new Score(2); + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + assertEquals(3, traque.getNumberWillingness()); + assertTrue(planet.planetPawnIsActive()); + } + + @Test + void testApplyPlayerCard_faussePiste() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action choosePlace = new ActionChoosePlace(Collections.singletonList(Place.PLACE_FIVE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlace) + .thenReturn(chooseFirstPower); + + planet.forceMovePlanetPawn(); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), FAUSSE_PISTE); + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + + Score score = new Score(2); + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + assertEquals(3, traque.getNumberWillingness()); + assertTrue(planet.planetPawnIsActive()); + assertEquals(Collections.singletonList(JetonSymbol.CREATURE), planet.findJetonsSymbolsOnCard(rover)); + assertTrue(planet.findJetonsSymbolsOnCard(plage).isEmpty()); + } + + @Test + void testApplyPlayerCard_hologramme() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action choosePlace = new ActionChoosePlace(Collections.singletonList(Place.PLACE_FIVE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlace) + .thenReturn(chooseFirstPower); + + planet.forceMovePlanetPawn(); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.ARTEMIA, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), HOLOGRAMME); + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + + Score score = new Score(2); + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + assertEquals(3, traque.getNumberWillingness()); + assertTrue(planet.planetPawnIsActive()); + assertEquals(Collections.singletonList(JetonSymbol.ARTEMIA), planet.findJetonsSymbolsOnCard(rover)); + assertTrue(planet.findJetonsSymbolsOnCard(plage).isEmpty()); + } + + @Test + void testApplyPlayerCard_leurre() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + + Action swapJeton = new ActionSwapJeton(JetonSymbol.CIBLE, JetonSymbol.ARTEMIA); + + Action chooseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(swapJeton) + .thenReturn(chooseCard) + .thenReturn(swapJeton) + .thenReturn(chooseCard); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.ARTEMIA, Place.PLACE_ONE); + planet.placeJeton(placedJeton); + placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Arrays.asList(Place.PLACE_THREE, Place.PLACE_TWO)); + planet.placeJeton(placedJeton); + + Traque traque =(Traque) game.getPlayer(2); + traque.throwAwayPlaceCard(antre); + + assertTrue(planet.findJetonsSymbolsOnCard(antre).contains(JetonSymbol.ARTEMIA)); + assertTrue(planet.findJetonsSymbolsOnCard(jungle).contains(JetonSymbol.CIBLE)); + assertTrue(planet.findJetonsSymbolsOnCard(riviere).contains(JetonSymbol.CIBLE)); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), LEURRE); + + assertTrue(planet.findJetonsSymbolsOnCard(antre).contains(JetonSymbol.CIBLE)); + assertTrue(planet.findJetonsSymbolsOnCard(jungle).contains(JetonSymbol.ARTEMIA)); + assertTrue(planet.findJetonsSymbolsOnCard(riviere).contains(JetonSymbol.ARTEMIA)); + assertTrue(traque.getPlaceCards().contains(antre)); + + planet.reset(); + traque.throwAwayPlaceCard(antre); + + placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_ONE); + planet.placeJeton(placedJeton); + placedJeton = new PlacedJeton(JetonSymbol.ARTEMIA, Arrays.asList(Place.PLACE_THREE, Place.PLACE_TWO)); + planet.placeJeton(placedJeton); + + assertTrue(planet.findJetonsSymbolsOnCard(antre).contains(JetonSymbol.CIBLE)); + assertTrue(planet.findJetonsSymbolsOnCard(jungle).contains(JetonSymbol.ARTEMIA)); + assertTrue(planet.findJetonsSymbolsOnCard(riviere).contains(JetonSymbol.ARTEMIA)); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), LEURRE); + + assertTrue(planet.findJetonsSymbolsOnCard(antre).contains(JetonSymbol.ARTEMIA)); + assertTrue(planet.findJetonsSymbolsOnCard(jungle).contains(JetonSymbol.CIBLE)); + assertTrue(planet.findJetonsSymbolsOnCard(riviere).contains(JetonSymbol.CIBLE)); + assertTrue(traque.getPlaceCards().contains(antre)); + } + + @Test + void testApplyPlayerCard_mimetisme() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + planet.forceMovePlanetPawn(); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), MIMETISME); + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + + Score score = new Score(2); + score.moveForwardTraque(2); + assertEquals(score, game.getBoard().getScore()); + assertEquals(3, traque.getNumberWillingness()); + assertTrue(planet.planetPawnIsActive()); + } + + @Test + void testApplyPlayerCard_navette() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + + game.getBoard().moveForwardTraque(12); + assertEquals(new Score(7, 1), game.getBoard().getScore()); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), NAVETTE); + + + assertEquals(new Score(7, 0), game.getBoard().getScore()); + assertTrue(game.isFinish()); + assertEquals(PlayerTeam.TRAQUE, game.getBoard().winner()); + } + + @Test + void testApplyPlayerCard_planques() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action choosePlace = new ActionChoosePlace(Arrays.asList(Place.PLACE_ONE, Place.PLACE_TWO)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlace) + .thenReturn(chooseThirdPower) + .thenReturn(chooseSecondPower); + + Traque traque = (Traque) game.getPlayer(2); + + List survivalCards = new ArrayList<>(game.getSurvivalCardPioche().getCards()); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), PLANQUES); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), antre); + + assertTrue(traque.getSurvivalCardsHand().contains(survivalCards.get(0))); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), jungle); + + assertTrue(traque.getSurvivalCardsHand().contains(survivalCards.get(1))); + } + + @Test + void testApplyPlayerCard_planquesTwiceTheSamePlace() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + + Action choosePlace = new ActionChoosePlace(Arrays.asList(Place.PLACE_ONE, Place.PLACE_ONE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlace) + .thenReturn(chooseThirdPower) + .thenReturn(chooseSecondPower); + + Traque traque = (Traque) game.getPlayer(2); + + List survivalCards = new ArrayList<>(game.getSurvivalCardPioche().getCards()); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), PLANQUES); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), antre); + + assertTrue(traque.getSurvivalCardsHand().contains(survivalCards.get(0))); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), antre); + + assertTrue(traque.getSurvivalCardsHand().contains(survivalCards.get(1))); + } + + @Test + void testApplyPlayerCard_portail() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseCard = new ActionChooseCard(Collections.singletonList(PLAGE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCard) + .thenReturn(chooseFirstPower); + + planet.forceMovePlanetPawn(); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), PORTAIL_SURVIVAL); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), rover); + + Score score = new Score(2); + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testApplyPlayerCard_ralliement() { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + + Traque traque1 = (Traque) game.getPlayer(2); + Traque traque2 = (Traque) game.getPlayer(3); + Traque traque3 = (Traque) game.getPlayer(4); + + traque1.playPlaceCard(plage); + traque2.playPlaceCard(plage); + traque3.playPlaceCard(plage); + + PowerApplicator.applySurvivalCardPower(game, traque1.getInGameId(), RALLIEMENT); + + PowerApplicator.resolvePlace(game, traque1.getInGameId(), plage); + PowerApplicator.resolvePlace(game, traque2.getInGameId(), plage); + PowerApplicator.resolvePlace(game, traque3.getInGameId(), plage); + + game.managePhase4(); + + Score score = new Score(4); + score.moveForwardCreature(1); + assertEquals(score, game.getBoard().getScore()); + assertTrue(traque1.getPlaceCards().contains(plage)); + assertTrue(traque1.getPlaceCards().contains(plage)); + assertTrue(traque1.getPlaceCards().contains(plage)); + assertEquals(2, traque1.getNumberWillingness()); + assertEquals(2, traque2.getNumberWillingness()); + assertEquals(2, traque3.getNumberWillingness()); + } + + @Test + void testApplyPlayerCard_refuge() throws TException { + Game game = new Game(Arrays.asList(1,2, 3, 4), 1, planet, board, room); + + + Action choosePlace = new ActionChoosePlace(Arrays.asList(Place.PLACE_FOUR, Place.PLACE_FIVE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(choosePlace); + + Traque traque1 = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque1.getInGameId(), REFUGE); + + //Phase 1 + game.startNextPhase(); + //Postphase 1 + game.startNextPhase(); + //Prephase 2 + game.startNextPhase(); + //Phase 2 + game.startNextPhase(); + + Creature creature = game.getCreature(); + game.playerPlaceJeton(creature.getInGameId(), new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_FOUR)); + assertFalse(game.playerPlaceJeton(creature.getInGameId(), new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_FOUR)).state); + assertFalse(game.playerPlaceJeton(creature.getInGameId(), new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_FIVE)).state); + assertTrue(game.playerPlaceJeton(creature.getInGameId(), new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_THREE)).state); + } + + @Test + void testApplyPlayerCard_regeneration() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseCard = new ActionChooseCard(Collections.singletonList(PLAGE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCard) + .thenReturn(chooseFirstPower); + + planet.forceMovePlanetPawn(); + + Traque traque = (Traque) game.getPlayer(2); + + //Do nothing when there is not cards in defausse + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), REGENERATION); + + traque.throwAwayPlaceCard(plage); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), REGENERATION); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), rover); + + Score score = new Score(2); + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + assertTrue(traque.getDefausse().contains(plage)); + } + + @Test + void testApplyPlayerCard_resistance() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + planet.forceMovePlanetPawn(); + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), RESISTANCE); + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + + Score score = new Score(2); + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + assertEquals(3, traque.getNumberWillingness()); + assertTrue(planet.planetPawnIsActive()); + } + + @Test + void testApplyPlayerCard_retraite() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action movePlayer = new ActionMovePlayer(2, Place.PLACE_FOUR); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(movePlayer); + + planet.forceMovePlanetPawn(); + + + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_FIVE); + planet.placeJeton(placedJeton); + placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + + + Traque traque = (Traque) game.getPlayer(2); + traque.playPlaceCard(rover); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), RETRAITE); + + game.managePhase3(); + + Score score = new Score(2); + assertEquals(score, game.getBoard().getScore()); + assertEquals(3, traque.getNumberWillingness()); + assertFalse(planet.planetPawnIsActive()); + } + + @Test + void testApplyPlayerCard_riposte() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + + Creature creature = game.getCreature(); + + List trackingCards = new ArrayList<>(creature.getTrackingCardHand()); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), RIPOSTE); + + assertEquals(1, creature.getTrackingCardHand().size()); + assertTrue(trackingCards.containsAll(game.getTrackingCardPioche().getTrash())); + } + + @Test + void testApplyPlayerCard_sacrifice() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCard); + + Traque traque = (Traque) game.getPlayer(2); + + Creature creature = game.getCreature(); + TrackingCard acharnement = database.findTrackingCard(ACHARNEMENT.toString()); + creature.getTrackingCardHand().clear(); + creature.addTrackingCard(acharnement); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), SACRIFICE); + + //Start Phase1 + game.startNextPhase(); + //Start PostPhase1 + game.startNextPhase(); + //Start PrePhase2 + game.startNextPhase(); + + assertFalse(game.playerPlayCard(creature.getInGameId(), creature.getTrackingCardHand().get(0)).state); + } + + @Test + void testApplyPlayerCard_sacrificeAndPlayerHaveNotCard() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + + Creature creature = game.getCreature(); + TrackingCard acharnement = database.findTrackingCard(ACHARNEMENT.toString()); + creature.getTrackingCardHand().clear(); + creature.addTrackingCard(acharnement); + + traque.throwAwayPlaceCard(Arrays.asList(antre, jungle, riviere, plage, rover)); + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), SACRIFICE); + + //Start Phase1 + game.startNextPhase(); + //Start PostPhase1 + game.startNextPhase(); + //Start PrePhase2 + game.startNextPhase(); + + assertTrue(game.playerPlayCard(creature.getInGameId(), creature.getTrackingCardHand().get(0)).state); + } + + @Test + void testApplyPlayerCard_secondSouffle() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + + traque.throwAwayPlaceCard(Arrays.asList(antre, jungle, riviere, plage)); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), SECOND_SOUFFLE); + + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(antre, jungle, riviere, plage, rover))); + assertTrue(traque.getDefausse().isEmpty()); + } + + @Test + void testApplyPlayerCard_secondSoufflePlayerHasMoreThanOneCard() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + + traque.throwAwayPlaceCard(Arrays.asList(antre, jungle, riviere)); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), SECOND_SOUFFLE); + + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(plage, rover))); + assertTrue(traque.getDefausse().containsAll(Arrays.asList(antre, jungle, riviere))); + } + + @Test + void testApplyPlayerCard_sixiemeSens() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseCard = new ActionChooseCard(Arrays.asList(ANTRE, JUNGLE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCard); + + Traque traque = (Traque) game.getPlayer(2); + + traque.throwAwayPlaceCard(Arrays.asList(antre, jungle, riviere)); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), SIXIEME_SENS); + + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(plage, rover, antre, jungle))); + assertTrue(traque.getDefausse().contains(riviere)); + } + + @Test + void testApplyPlayerCard_sixiemeSensPlayerHasOnlyTwoCardsInDefausse() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + + traque.throwAwayPlaceCard(Arrays.asList(antre, jungle)); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), SIXIEME_SENS); + + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(plage, rover, antre, jungle, riviere))); + assertTrue(traque.getDefausse().isEmpty()); + } + + @Test + void testApplyPlayerCard_sixiemeSensPlayerHasOnlyOneCardsInDefausse() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + + traque.throwAwayPlaceCard(Collections.singletonList(antre)); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), SIXIEME_SENS); + + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(plage, rover, antre, jungle, riviere))); + assertTrue(traque.getDefausse().isEmpty()); + } + + @Test + void testApplyPlayerCard_systemeD() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), SYSTEME_D); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), plage); + + Score score = new Score(2); + score.moveForwardTraque(1); + assertEquals(score, game.getBoard().getScore()); + assertTrue(planet.planetPawnIsActive()); + } + + @Test + void testApplyPlayerCard_systemeDWithExtension() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planetExtension, board, room); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseFirstPower); + + planetExtension.forceMovePlanetPawn(); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), SYSTEME_D); + + PowerApplicator.resolvePlace(game, traque.getInGameId(), dome); + + Score score = new Score(2); + score.moveBackCreature(1); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testApplyPlayerCard_tenaciteWithOnePawnWillingness() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseCards = new ActionChooseCard(Arrays.asList(ANTRE, JUNGLE, RIVIERE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCards); + + Traque traque = (Traque) game.getPlayer(2); + traque.throwAwayPlaceCard(Arrays.asList(antre, jungle, riviere, plage, rover)); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), TENACITE); + + //Start Phase 1 + game.startNextPhase(); + + assertTrue(game.playerResist(traque.getInGameId(), 1).state); + assertEquals(2, traque.getNumberWillingness()); + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(antre, jungle, riviere))); + assertTrue(traque.getDefausse().containsAll(Arrays.asList(plage, rover))); + } + + @Test + void testApplyPlayerCard_tenaciteWithTwoPawnsWillingness() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + + Action chooseCards = new ActionChooseCard(Arrays.asList(ANTRE, JUNGLE, RIVIERE, PLAGE, ROVER, MARAIS)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCards); + + Traque traque = (Traque) game.getPlayer(2); + traque.addPlaceCard(marais); + traque.throwAwayPlaceCard(Arrays.asList(antre, jungle, riviere, plage, rover, marais)); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), TENACITE); + + //Start Phase 1 + game.startNextPhase(); + + assertTrue(game.playerResist(traque.getInGameId(), 2).state); + assertEquals(1, traque.getNumberWillingness()); + assertTrue(traque.getPlaceCards().containsAll(Arrays.asList(antre, jungle, riviere, plage, rover, marais))); + assertTrue(traque.getDefausse().isEmpty()); + } + + @Test + void testApplyPlayerCard_vaccin() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), VACCIN); + + Score score = new Score(2); + score.moveBackCreature(1); + assertEquals(score, game.getBoard().getScore()); + } + + @Test + void testApplyPlayerCard_volteFace() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Traque traque = (Traque) game.getPlayer(2); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), VOLTE_FACE); + + traque.playPlaceCard(antre); + + assertFalse(traque.getPlaceCards().contains(antre)); + + game.managePhase4(); + + assertTrue(traque.getPlaceCards().contains(antre)); + } + + @Test + void testApplyPlayerCard_vortex() throws TException { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + + Action chooseCard = new ActionChooseCard(Collections.singletonList(ANTRE)); + + when(room.askAction(any(Integer.class), any(TAskAction.class))) + .thenReturn(chooseCard); + + Traque traque = (Traque) game.getPlayer(2); + + traque.throwAwayPlaceCard(antre); + traque.playPlaceCard(jungle); + + assertFalse(traque.getPlaceCards().contains(jungle)); + assertTrue(traque.getPlaceCardsPlayed().contains(jungle)); + assertTrue(traque.getDefausse().contains(antre)); + + PowerApplicator.applySurvivalCardPower(game, traque.getInGameId(), VORTEX); + + assertTrue(traque.getPlaceCards().contains(jungle)); + assertFalse(traque.getDefausse().contains(antre)); + assertTrue(traque.getPlaceCardsPlayed().contains(antre)); + assertFalse(traque.getPlaceCardsPlayed().contains(jungle)); + } + + @Test + void testPickSurvivalCards_numberToKeepGreaterThanNumberToPick() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + assertThrows(IllegalArgumentException.class, () -> PowerApplicator.pickSurvivalCards(game, 2, 2, 3)); + } + + @Test + void testCheckPlayerIsNotCreature_playerIsCreature() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + assertThrows(IllegalArgumentException.class, () -> PowerApplicator.checkPlayerIsNotCreature(game, 1)); + } + + @Test + void testCheckInertieCondition_playerOn() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + PowerApplicator.applyTrackingCardPower(game, 1, INERTIE); + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + Traque traque = (Traque)game.getPlayer(2); + traque.playPlaceCard(plage); + assertTrue(PowerApplicator.checkInertieCondition(game)); + } + + @Test + void testCheckInertieCondition_noPlayerOn() { + Game game = new Game(Arrays.asList(1,2), 1, planet, board, room); + PowerApplicator.applyTrackingCardPower(game, 1, INERTIE); + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CIBLE, Place.PLACE_FOUR); + planet.placeJeton(placedJeton); + Traque traque = (Traque)game.getPlayer(2); + traque.playPlaceCard(rover); + assertFalse(PowerApplicator.checkInertieCondition(game)); + } +} \ No newline at end of file diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/RoomServiceControllerTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/RoomServiceControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..027a275bae0e2e62d1dbd4e609f74daad8571a4f --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/RoomServiceControllerTest.java @@ -0,0 +1,171 @@ +package fr.univnantes.alma.server.game; + +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.utilitary.request.*; +import fr.univnantes.alma.server.user.User; +import fr.univnantes.alma.thrift.GameNotFound; +import fr.univnantes.alma.thrift.InvalidOperationException; +import fr.univnantes.alma.thrift.Response; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class RoomServiceControllerTest { + + Room room; + RoomServiceController roomServiceController; + + User user1; + User user2; + User user3; + + @BeforeEach + void setup() { + user1 = mock(User.class); + when(user1.getId()).thenReturn("1"); + user2 = mock(User.class); + when(user2.getId()).thenReturn("2"); + user3 = mock(User.class); + + room = mock(Room.class); + when(room.getRoomId()).thenReturn("900"); + when(room.join(user1)).thenReturn(new Response(true, "")); + roomServiceController = new RoomServiceController(); + roomServiceController.addRoom(room); + } + + @Test + void testAddRoom_alreadyExist() { + Room room = mock(Room.class); + when(room.getRoomId()).thenReturn("900"); + assertFalse(roomServiceController.addRoom(room)); + } + + @Test + void testCreateRoom() throws InvalidOperationException { + String roomId = roomServiceController.createRoom(user1); + Map stringRoomMap = roomServiceController.getRooms(); + Map userStringMap = roomServiceController.getPlayers(); + assertTrue(stringRoomMap.containsKey(roomId)); + assertTrue(userStringMap.containsKey(user1)); + Room room = stringRoomMap.get(roomId); + assertTrue(room.isCreator(user1)); + } + + @Test + void testCreateRoom_userAlreadyInAGame() throws InvalidOperationException { + roomServiceController.createRoom(user1); + assertThrows(InvalidOperationException.class, () -> roomServiceController.createRoom(user1)); + } + + @Test + void testJoinRoom() throws GameNotFound { + roomServiceController.joinRoom(user1, "900"); + Map userStringMap = roomServiceController.getPlayers(); + verify(room).join(user1); + assertTrue(userStringMap.containsKey(user1)); + } + + @Test + void testJoinRoom_playerAlreadyInARoom() throws InvalidOperationException, GameNotFound { + roomServiceController.createRoom(user1); + Response response = new Response(false, "Player already in a room"); + assertEquals(response, roomServiceController.joinRoom(user1, "900")); + } + + @Test + void testJoinRoom_inexistantGame() { + assertThrows(GameNotFound.class, () -> roomServiceController.joinRoom(user1, "800")); + } + + @Test + void testStartGame() throws GameNotFound { + roomServiceController.joinRoom(user1, "900"); + roomServiceController.startGame(user1, 1, null, null); + verify(room).start(user1, 1, null, null); + } + + @Test + void testStartGame_playerNotInARoom() { + Response response = roomServiceController.startGame(user1, 1, null, null); + assertEquals(new Response(false, "Player is not in a room"), response); + } + + @Test + void testGetGameDescription() throws GameNotFound, InvalidOperationException { + roomServiceController.joinRoom(user1, "900"); + roomServiceController.getGameDescription(user1); + verify(room).getGameDescription(user1); + } + + @Test + void testGetGameDescription_playerNotInARoom() { + assertThrows(InvalidOperationException.class, () -> roomServiceController.getGameDescription(user1)); + } + + + @Test + void testSendFinishPhase() throws GameNotFound, InvalidOperationException { + roomServiceController.joinRoom(user1, "900"); + roomServiceController.sendFinishPhase(user1, Phase.PREPHASE_1); + verify(room).addRequest(new GameFinishPhaseRequest(user1, Phase.PREPHASE_1)); + } + + @Test + void testSendFinishPhase_playerNotInARoom() { + assertThrows(InvalidOperationException.class, () -> roomServiceController.sendFinishPhase(user1, Phase.PREPHASE_1)); + } + + @Test + void testSendPlayCards() throws GameNotFound, InvalidOperationException { + roomServiceController.joinRoom(user1, "900"); + roomServiceController.sendPlayCards(user1, new ArrayList<>()); + verify(room).addRequest(new GamePlayCardsRequest(user1, new ArrayList<>())); + } + + @Test + void testSendPlayCards_playerNotInARoom() { + assertThrows(InvalidOperationException.class, () -> roomServiceController.sendPlayCards(user1, new ArrayList<>())); + } + + @Test + void testSendPlaceJetons() throws GameNotFound, InvalidOperationException { + roomServiceController.joinRoom(user1, "900"); + roomServiceController.sendPlaceJetons(user1, new ArrayList<>()); + verify(room).addRequest(new GamePlaceJetonsRequest(user1, new ArrayList<>())); + } + + @Test + void testSendPlaceJetons_playerNotInARoom() { + assertThrows(InvalidOperationException.class, () -> roomServiceController.sendPlaceJetons(user1, new ArrayList<>())); + } + + @Test + void testSendResist() throws GameNotFound, InvalidOperationException { + roomServiceController.joinRoom(user1, "900"); + roomServiceController.sendResist(user1, 1); + verify(room).addRequest(new GameResistRequest(user1, 1)); + } + + @Test + void testSendResist_playerNotInARoom() { + assertThrows(InvalidOperationException.class, () -> roomServiceController.sendResist(user1, 1)); + } + + @Test + void testSendGiveUp() throws GameNotFound, InvalidOperationException { + roomServiceController.joinRoom(user1, "900"); + roomServiceController.sendGiveUp(user1); + verify(room).addRequest(new GameGiveUpRequest(user1)); + } + + @Test + void testSendGiveUp_playerNotInARoom() { + assertThrows(InvalidOperationException.class, () -> roomServiceController.sendGiveUp(user1)); + } +} \ No newline at end of file diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/RoomTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/RoomTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5039054049efdc1a8dca38f704063a5082c56ef2 --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/RoomTest.java @@ -0,0 +1,421 @@ +package fr.univnantes.alma.server.game; + +import fr.univnantes.alma.common.NotAloneDatabase; +import fr.univnantes.alma.data.DatabaseFactory; +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.action.Action; +import fr.univnantes.alma.server.game.item.action.ActionTargetPlayer; +import fr.univnantes.alma.server.game.item.board.Board; +import fr.univnantes.alma.server.game.item.board.BoardColor; +import fr.univnantes.alma.server.game.item.board.BoardDistribution; +import fr.univnantes.alma.server.game.item.card.PlaceCard; +import fr.univnantes.alma.server.game.item.jeton.JetonSymbol; +import fr.univnantes.alma.server.game.item.jeton.PlacedJeton; +import fr.univnantes.alma.server.game.item.planet.Place; +import fr.univnantes.alma.server.game.item.planet.Planet; +import fr.univnantes.alma.server.game.item.player.Creature; +import fr.univnantes.alma.server.game.item.player.Traque; +import fr.univnantes.alma.server.game.utilitary.Conversion; +import fr.univnantes.alma.server.game.utilitary.request.*; +import fr.univnantes.alma.server.user.User; +import fr.univnantes.alma.thrift.*; +import org.apache.thrift.TException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import static fr.univnantes.alma.server.game.item.card.CardName.*; +import static fr.univnantes.alma.server.game.item.player.PlayerTeam.CREATURE; +import static fr.univnantes.alma.server.game.item.player.PlayerTeam.TRAQUE; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; + +class RoomTest { + + NotAloneDatabase database = DatabaseFactory.getDatabase(); + + final PlaceCard antre = database.findPlaceCard(ANTRE.toString()); + final PlaceCard jungle = database.findPlaceCard(JUNGLE.toString()); + final PlaceCard riviere = database.findPlaceCard(RIVIERE.toString()); + final PlaceCard plage = database.findPlaceCard(PLAGE.toString()); + final PlaceCard rover = database.findPlaceCard(ROVER.toString()); + final PlaceCard marais = database.findPlaceCard(MARAIS.toString()); + final PlaceCard abri = database.findPlaceCard(ABRI.toString()); + final PlaceCard epave = database.findPlaceCard(EPAVE.toString()); + final PlaceCard source = database.findPlaceCard(SOURCE.toString()); + final PlaceCard artefact = database.findPlaceCard(ARTEFACT.toString()); + + User user1; + User user2; + User user3; + User user4; + User user5; + User user6; + User user7; + User user8; + + Planet planet; + Board board; + List placeCards; + Room genericRoom; + + Game genericGame; + + @BeforeEach + void setup() throws InterruptedException { + user1 = mock(User.class); + when(user1.getId()).thenReturn("1"); + user2 = mock(User.class); + when(user2.getId()).thenReturn("2"); + user3 = mock(User.class); + when(user3.getId()).thenReturn("3"); + user4 = mock(User.class); + when(user4.getId()).thenReturn("4"); + user5 = mock(User.class); + when(user5.getId()).thenReturn("5"); + user6 = mock(User.class); + when(user6.getId()).thenReturn("6"); + user7 = mock(User.class); + when(user7.getId()).thenReturn("7"); + user8 = mock(User.class); + when(user8.getId()).thenReturn("8"); + + placeCards = new ArrayList(); + placeCards.add(antre); + placeCards.add(jungle); + placeCards.add(riviere); + placeCards.add(plage); + placeCards.add(rover); + placeCards.add(marais); + placeCards.add(abri); + placeCards.add(epave); + placeCards.add(source); + placeCards.add(artefact); + + planet = new Planet(placeCards); + board = new Board(BoardDistribution.FRONT, BoardColor.BLUE); + + String roomId = "1001"; + genericRoom = new Room(roomId, user1); + genericRoom.join(user2); + Thread.sleep(20); + genericRoom.start(user1, 1, board, planet); + genericGame = new Game(Arrays.asList(1,2), 1, planet, board, genericRoom); + genericRoom.setGame(genericGame); + } + + @Test + void testCreateGame() { + String roomId = "1001"; + Room room = new Room(roomId, user1); + assertSame(1, room.getNumberPlayers()); + assertEquals(roomId, room.getRoomId()); + assertTrue(room.isCreator(user1)); + } + + @Test + void testJoinGame_sevenPlayersJoin() throws InterruptedException { + String roomId = "1001"; + Room room = new Room(roomId, user1); + assertTrue(room.join(user2).state); + assertTrue(room.join(user3).state); + assertTrue(room.join(user4).state); + assertTrue(room.join(user5).state); + assertTrue(room.join(user6).state); + assertTrue(room.join(user7).state); + assertTrue(room.isCreator(user1)); + assertFalse(room.isCreator(user2)); + Thread.sleep(50); + assertSame(7, room.getNumberPlayers()); + } + + @Test + void testJoinGame_eightPlayersJoin() throws InterruptedException { + String roomId = "1001"; + Room room = new Room(roomId, user1); + assertTrue(room.join(user2).state); + assertTrue(room.join(user3).state); + assertTrue(room.join(user4).state); + assertTrue(room.join(user5).state); + assertTrue(room.join(user6).state); + assertTrue(room.join(user7).state); + Response response = room.join(user8); + assertFalse(response.state); + assertEquals("Room is full", response.getMessage()); + Thread.sleep(50); + assertSame(7, room.getNumberPlayers()); + } + + @Test + void testJoin_gameIsStarted() throws InterruptedException { + String roomId = "1001"; + Room room = new Room(roomId, user1); + assertTrue(room.join(user2).state); + Thread.sleep(10); + assertTrue(room.start(user1, 1, board, planet).state); + Response response = room.join(user3); + assertFalse(response.state); + assertEquals("Game has started", response.getMessage()); + assertSame(2, room.getNumberPlayers()); + } + + @Test + void testStart_enoughPlayer() throws InterruptedException { + String roomId = "1001"; + Room room = new Room(roomId, user1); + assertTrue(room.join(user2).state); + Thread.sleep(10); + Response response = room.start(user1, 1, board, planet); + assertTrue(response.state); + assertEquals("Game start", response.getMessage()); + } + + @Test + void testStart_noEnoughPlayer() { + String roomId = "1001"; + Room room = new Room(roomId, user1); + Response response = room.start(user1, 1, board, planet); + assertFalse(response.state); + assertEquals("Need 2 players", response.getMessage()); + } + + @Test + void testStart_isNotCreatorWhoStart() throws InterruptedException { + String roomId = "1001"; + Room room = new Room(roomId, user1); + assertTrue(room.join(user2).state); + Thread.sleep(10); + Response response = room.start(user2, 1, board, planet); + assertFalse(response.state); + assertEquals("Only the room creator can start the game", response.getMessage()); + } + + @Test + void testStart_invalidCreatureId() throws InterruptedException { + String roomId = "1001"; + Room room = new Room(roomId, user1); + assertTrue(room.join(user2).state); + Thread.sleep(10); + Response response = room.start(user1, 5, board, planet); + assertFalse(response.state); + assertEquals("5 is not a valid id", response.getMessage()); + } + + @Test + void testGetGameDescription_creature() { + TDescription tDescription = genericRoom.getGameDescription(user1); + TPlayerTeam tPlayerTeam = tDescription.getTeam(); + assertEquals(CREATURE.toString(), tPlayerTeam.getType()); + Creature creature = genericGame.getCreature(); + //THand + THand tHand = tDescription.getHand(); + THand tHandExpected = Conversion.toTHand(creature); + assertEquals(tHandExpected, tHand); + + //TScore + TScore tScore = tDescription.getScore(); + TScore tScoreExpect = Conversion.toTScore(genericGame.getBoard()); + assertEquals(tScoreExpect, tScore); + + //TPlanet + TPlanet tPlanet = tDescription.getPlanet(); + TPlanet tPlanetExpect = Conversion.toTPlanet(genericGame.getPlanet()); + assertEquals(tPlanetExpect, tPlanet); + + //Reserve + List reserves = tDescription.getReserve(); + List reservesExpect = Conversion.toTCardReserveList(genericGame.getReserve()); + assertEquals(reservesExpect, reserves); + + //Variables + List variables = tDescription.getVariables(); + List variablesExpect = Conversion.toTGameVariable(genericGame.getGameRoundVariables()); + assertEquals(variablesExpect, variables); + + //Traques information + List traques = tDescription.getTraquesInformation(); + List traquesExpect = genericGame.getTraques().stream().map(Conversion::toTTraque).collect(Collectors.toList()); + assertEquals(traquesExpect, traques); + + //Creature information + TCreature tCreature = tDescription.getCreatureInformation(); + TCreature tCreatureExpect = Conversion.toTCreature(genericGame.getCreature()); + assertEquals(tCreatureExpect, tCreature); + } + + @Test + void testGetGameDescription_traque() { + TDescription tDescription = genericRoom.getGameDescription(user2); + TPlayerTeam tPlayerTeam = tDescription.getTeam(); + assertEquals(TRAQUE.toString(), tPlayerTeam.getType()); + Traque traque = genericGame.getTraques().get(0); + //THand + THand tHand = tDescription.getHand(); + THand tHandExpected = Conversion.toTHand(traque); + assertEquals(tHandExpected, tHand); + + //TScore + TScore tScore = tDescription.getScore(); + TScore tScoreExpect = Conversion.toTScore(genericGame.getBoard()); + assertEquals(tScoreExpect, tScore); + + //TPlanet + TPlanet tPlanet = tDescription.getPlanet(); + TPlanet tPlanetExpect = Conversion.toTPlanet(genericGame.getPlanet()); + assertEquals(tPlanetExpect, tPlanet); + + //Reserve + List reserves = tDescription.getReserve(); + List reservesExpect = Conversion.toTCardReserveList(genericGame.getReserve()); + assertEquals(reservesExpect, reserves); + + //Variables + List variables = tDescription.getVariables(); + List variablesExpect = Conversion.toTGameVariable(genericGame.getGameRoundVariables()); + assertEquals(variablesExpect, variables); + + //Traques information + List traques = tDescription.getTraquesInformation(); + List traquesExpect = genericGame.getTraques().stream().map(Conversion::toTTraque).collect(Collectors.toList()); + assertEquals(traquesExpect, traques); + + //Creature information + TCreature tCreature = tDescription.getCreatureInformation(); + TCreature tCreatureExpect = Conversion.toTCreature(genericGame.getCreature()); + assertEquals(tCreatureExpect, tCreature); + } + + @Test + void testAddRequest_userNotInTheRoom() { + Response response = genericRoom.addRequest(new GameFinishPhaseRequest(user3, Phase.PREPHASE_1)); + assertFalse(response.state); + assertEquals("You must be in the room", response.getMessage()); + } + + @Test + void testSendFinishPhase_requestAccepted() throws TException, InterruptedException { + Response response = genericRoom.addRequest(new GameFinishPhaseRequest(user1, Phase.PREPHASE_1)); + assertTrue(response.state); + assertEquals("Request sent", response.getMessage()); + Thread.sleep(10); + Response expected = new Response(true, ""); + verify(user1).sendResponse(expected); + } + + @Test + void testSendFinishPhase_badRequest() throws TException, InterruptedException { + Response response = genericRoom.addRequest(new GameFinishPhaseRequest(user1, Phase.PHASE_2)); + assertTrue(response.state); + assertEquals("Request sent", response.getMessage()); + Thread.sleep(10); + Response expected = new Response(false, "The current phase is PREPHASE_1"); + verify(user1).sendResponse(expected); + } + + @Test + void testSendPlayCards_traque() throws TException, InterruptedException { + //Start phase 1 + genericGame.startNextPhase(); + Response response = genericRoom.addRequest(new GamePlayCardsRequest(user2, Collections.singletonList(antre))); + assertTrue(response.state); + assertEquals("Request sent", response.getMessage()); + Thread.sleep(10); + Response expected = new Response(true, ""); + verify(user2).sendResponse(expected); + } + + @Test + void testSendPlaceJeton_creature() throws TException, InterruptedException { + //Start phase 1 + genericGame.startNextPhase(); + //Start postphase 1 + genericGame.startNextPhase(); + //Start prephase 2 + genericGame.startNextPhase(); + //Start phase 2 + genericGame.startNextPhase(); + Response response = genericRoom.addRequest(new GamePlaceJetonsRequest(user1, Collections.singletonList(new PlacedJeton(JetonSymbol.CREATURE, Place.PLACE_ONE)))); + assertTrue(response.state); + assertEquals("Request sent", response.getMessage()); + Thread.sleep(10); + Response expected = new Response(true, ""); + verify(user1).sendResponse(expected); + } + + @Test + void testSendResist_traque() throws TException, InterruptedException { + //Start phase 1 + genericGame.startNextPhase(); + Response response = genericRoom.addRequest(new GameResistRequest(user2, 1)); + assertTrue(response.state); + assertEquals("Request sent", response.getMessage()); + Thread.sleep(10); + Response expected = new Response(true, ""); + verify(user2).sendResponse(expected); + } + + @Test + void testSendGiveUp_traque() throws TException, InterruptedException { + //Start phase 1 + genericGame.startNextPhase(); + Response response = genericRoom.addRequest(new GameGiveUpRequest(user2)); + assertTrue(response.state); + assertEquals("Request sent", response.getMessage()); + Thread.sleep(10); + Response expected = new Response(true, ""); + verify(user2).sendResponse(expected); + } + + @Test + void testAskAction() throws TException { + Action action = new ActionTargetPlayer(2); + TAskAction tAskAction = new TAskAction("TARGET_PLAYER", "", new ArrayList<>()); + TAction tAction = new TAction("TARGET_PLAYER", Collections.singletonList(new TPair("PLAYER", "2"))); + when(user1.askAction(any(TAskAction.class))).thenReturn(tAction); + assertEquals(action, genericRoom.askAction(1, tAskAction)); + verify(user1).askAction(tAskAction); + } + + @Test + void testSendAction() throws TException { + TAskAction tAskAction = new TAskAction("SHOW_CARD", "", new ArrayList<>()); + genericRoom.sendAction(1, tAskAction); + verify(user1).sendAction(tAskAction); + } + + @Test + void testSendFirstRoundStart() throws TException { + verify(user1, atLeastOnce()).sendFirstRoundStart(); + verify(user2, atLeastOnce()).sendFirstRoundStart(); + } + + @Test + void testSendStartPhase() throws TException { + genericGame.startNextPhase(); + verify(user1, atLeastOnce()).sendStartPhase(eq(new TPhase(Phase.PHASE_1.toString())), any(TDescription.class)); + verify(user2, atLeastOnce()).sendStartPhase(eq(new TPhase(Phase.PHASE_1.toString())), any(TDescription.class)); + } + + @Test + void testSendDescription() throws TException { + TDescription tDescription = new TDescription(new TPlayerTeam("TEST"), null, null, null, null, null, null, null); + genericRoom.sendDescription(1, tDescription); + verify(user1).sendGameDescription(tDescription); + } + + @Test + void testSendGameIsFinished() throws TException { + TPlayerTeam tPlayerTeam = new TPlayerTeam("CREATURE"); + genericRoom.sendGameIsFinished(tPlayerTeam); + verify(user1, atLeastOnce()).sendGameIsFinished(tPlayerTeam); + verify(user2, atLeastOnce()).sendGameIsFinished(tPlayerTeam); + } + +} + diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/ReserveTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/ReserveTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a9c9d5e4faf33644e572aac9d8c0c25f0dafe60c --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/ReserveTest.java @@ -0,0 +1,83 @@ +package fr.univnantes.alma.server.game.item; + +import fr.univnantes.alma.server.game.item.card.CardName; +import fr.univnantes.alma.server.game.item.card.PlaceCard; +import fr.univnantes.alma.server.game.item.card.SurvivalCard; +import fr.univnantes.alma.server.game.utilitary.Pair; +import javassist.NotFoundException; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.awt.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ReserveTest { + + List testCards= new ArrayList<>(); + Reserve reserve; + + @BeforeEach + void test(){ + PlaceCard c1 = new PlaceCard(CardName.ANTRE,"antre","antre",6,"url1", "bleu"); + PlaceCard c2 = new PlaceCard(CardName.PLAGE,"plage","plage",7,"url2", "bleu"); + PlaceCard c3 = new PlaceCard(CardName.JUNGLE,"jungle","jungle",8,"url3", "bleu"); + PlaceCard c4 = new PlaceCard(CardName.ABRI,"abri","abri",9,"url4", "bleu"); + PlaceCard c5 = new PlaceCard(CardName.RIVIERE,"riviere","riviere",10,"url5", "bleu"); + testCards.add(c1); + testCards.add(c2); + testCards.add(c3); + testCards.add(c4); + testCards.add(c5); + reserve = new Reserve(testCards,4); + } + + @Test + void testGetPlaceCards(){ + Map> placeCards = new HashMap<>(); + for(PlaceCard c : testCards) { + placeCards.put(c.getNumber(), new Pair<>(c, 2)); + } + assertEquals(placeCards,reserve.getPlaceCards()); + } + + @Test + void testIsNotEmpty(){ + assertTrue(reserve.isNotEmpty()); + } + + @Test + void testNotEmpty(){ + assertTrue(reserve.notEmpty(6)); + } + + @Test + void testPick() throws NotFoundException { + PlaceCard c = new PlaceCard(CardName.ANTRE,"antre","antre",6,"url1", "bleu"); + assertEquals(c,reserve.pick(6)); + } + + @Test + void testAdd() throws NotFoundException { + PlaceCard c = new PlaceCard(CardName.MARAIS,"marais","marais",6,"url", "bleu"); + reserve.add(c); + assertEquals(c,reserve.pick(6)); + } + + @Test + void testEquals(){ + Reserve rev = new Reserve(testCards,4); + assertEquals(reserve,rev); + } + + @Test + void testToString(){ + assertEquals("Reserve(ANTRE(2), PLAGE(2), JUNGLE(2), ABRI(2), RIVIERE(2))",reserve.toString()); + } +} \ No newline at end of file diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/board/BoardTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/board/BoardTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cbd398aa101b5d1f59013bf54263e739eccec861 --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/board/BoardTest.java @@ -0,0 +1,28 @@ +package fr.univnantes.alma.server.game.item.board; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class BoardTest { + + BoardColor boardColor = BoardColor.BLUE; + BoardDistribution boardDistribution = BoardDistribution.FRONT; + Board board = new Board(boardDistribution,boardColor); + + @Test + public void testInitializeScore() { + Score score = new Score(4); + int playerNumber = 4; + board.initializeScore(4); + assertEquals(score.getScoreCreature(),board.getScore().getScoreCreature()); + assertEquals(score.getScoreTraque(),board.getScore().getScoreTraque()); + } + + @Test + public void testIsArtemiaSquare(){ + Score score = new Score(4); + boolean result = score.scoreTraqueGreaterThanBase() && score.getScoreTraque()%2 == 1; + assertEquals(board.isArtemiaSquare(),result); + } +} \ No newline at end of file diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/board/ScoreTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/board/ScoreTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0e39719d5c58b3dc10d70e8cea720156b02c8455 --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/board/ScoreTest.java @@ -0,0 +1,95 @@ +package fr.univnantes.alma.server.game.item.board; + +import fr.univnantes.alma.server.game.item.player.PlayerTeam; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class ScoreTest { + + @Test + void testGetScoreTraque() { + Score s = new Score(2,3); + assertEquals(3, s.getScoreTraque()); + } + + @Test + void testGetScoreCreature() { + Score s = new Score(2,3); + assertEquals(2, s.getScoreCreature()); + } + + @Test + void testIsFinish_isFinish() { + Score s = new Score(2,3); + s.moveForwardCreature(2); + assertTrue(s.isFinish()); + + s = new Score(2,3); + s.moveForwardTraque(3); + assertTrue(s.isFinish()); + } + + @Test + void testIsFinish_isNotFinish() { + Score s = new Score(5,4); + s.moveForwardCreature(2); + assertFalse(s.isFinish()); + + s = new Score(4,5); + s.moveForwardTraque(3); + assertFalse(s.isFinish()); + } + + @Test + void testActualBestTeam() { + Score s = new Score(5,6); + assertEquals(PlayerTeam.CREATURE, s.actualBestTeam()); + + s = new Score(5,4); + assertEquals(PlayerTeam.TRAQUE, s.actualBestTeam()); + } + + @Test + void testScoreCreatureGreaterThanBase() { + Score s = new Score(2); + assertFalse(s.scoreCreatureGreaterThanBase()); + s.moveForwardCreature(1); + assertTrue(s.scoreCreatureGreaterThanBase()); + } + + @Test + void testScoreTraqueGreaterThanBase() { + Score s = new Score(2); + assertFalse(s.scoreTraqueGreaterThanBase()); + s.moveForwardTraque(1); + assertTrue(s.scoreTraqueGreaterThanBase()); + } + + @Test + void testMoveForwardTraque() { + Score s = new Score(5,6); + s.moveForwardTraque(1); + assertEquals(5, s.getScoreTraque()); + } + + @Test + void testMoveBackTraque() { + Score s = new Score(5,6); + s.moveBackTraque(1); + assertEquals(7, s.getScoreTraque()); + } + + @Test + void testMoveForwardCreature() { + Score s = new Score(5,6); + s.moveForwardCreature(1); + assertEquals(4, s.getScoreCreature()); + } + + @Test + void testMoveBackCreature() {Score s = new Score(5,6); + s.moveBackCreature(1); + assertEquals(6, s.getScoreCreature()); + } +} \ No newline at end of file diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/card/PlaceCardTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/card/PlaceCardTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4cc4fe69f13a7275ecf0365f47c053314bea7b0b --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/card/PlaceCardTest.java @@ -0,0 +1,7 @@ +package fr.univnantes.alma.server.game.item.card; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class PlaceCardTest { + +} \ No newline at end of file diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/card/SurvivalCardTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/card/SurvivalCardTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2d02bdda155e2ca7c73d333d8123b23314ed812a --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/card/SurvivalCardTest.java @@ -0,0 +1,7 @@ +package fr.univnantes.alma.server.game.item.card; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class SurvivalCardTest { + +} \ No newline at end of file diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/card/TrackingCardTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/card/TrackingCardTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3cb3dc9cd338a1d837b2e4185cdaa055609532cd --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/card/TrackingCardTest.java @@ -0,0 +1,7 @@ +package fr.univnantes.alma.server.game.item.card; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class TrackingCardTest { + +} \ No newline at end of file diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/pioche/PiocheTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/pioche/PiocheTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e86dbcacacf4dbe2148b07beaee828dbacfd2338 --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/pioche/PiocheTest.java @@ -0,0 +1,85 @@ +package fr.univnantes.alma.server.game.item.pioche; + +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.card.CardName; +import fr.univnantes.alma.server.game.item.card.SurvivalCard; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class PiocheTest { + + List cards; + Random identityRandom; + + @BeforeEach + void setup() { + cards = new ArrayList<>(Arrays.asList( + new SurvivalCard(CardName.ADRENALINE, "Adrénaline", "", Phase.PREPHASE_1), + new SurvivalCard(CardName.CAVALE, "Cavale", "", Phase.PREPHASE_1), + new SurvivalCard(CardName.RESISTANCE, "Résistance", "", Phase.PREPHASE_1) + )); + identityRandom = mock(Random.class); + when(identityRandom.nextInt(any(Integer.class))) + .thenReturn(2) + .thenReturn(1) + .thenReturn(0); + } + + @Test + void testMix_equals() { + Pioche pioche = new Pioche<>(cards, identityRandom); + assertIterableEquals(cards, pioche.getCards()); + } + + @Test + void testDraw_equals() { + Pioche pioche = new Pioche<>(cards, identityRandom); + assertEquals(cards.get(0), pioche.draw()); + pioche = new Pioche<>(cards, identityRandom); + List expect = new ArrayList<>(cards.subList(0,2)); + assertIterableEquals(expect, pioche.draw(2)); + } + + @Test + void testDraw_noEnoughCardInPioche() { + Pioche pioche = new Pioche<>(cards, identityRandom); + assertThrows(IllegalArgumentException.class, () -> pioche.draw(4)); + } + + @Test + void testThrowAway_equals() { + SurvivalCard survivalCard = new SurvivalCard(CardName.NAVETTE, "Navette", "", Phase.PREPHASE_1); + SurvivalCard survivalCard2 = new SurvivalCard(CardName.SECOND_SOUFFLE, "Second souffle", "", Phase.PREPHASE_1); + Pioche pioche = new Pioche<>(cards, identityRandom); + pioche.throwAway(survivalCard); + assertEquals(Collections.singletonList(survivalCard), pioche.getTrash()); + + List survivalCards = new ArrayList<>(Arrays.asList(survivalCard, survivalCard2)); + pioche = new Pioche<>(cards, identityRandom); + pioche.throwAway(survivalCards); + assertIterableEquals(survivalCards, pioche.getTrash()); + } + + @Test + void testDrawLastTrashCards_equals() { + SurvivalCard survivalCard = new SurvivalCard(CardName.NAVETTE, "Navette", "", Phase.PREPHASE_1); + SurvivalCard survivalCard2 = new SurvivalCard(CardName.SECOND_SOUFFLE, "Second souffle", "", Phase.PREPHASE_1); + List survivalCards = new ArrayList<>(Arrays.asList(survivalCard, survivalCard2)); + Pioche pioche = new Pioche<>(cards, identityRandom); + pioche.throwAway(survivalCards); + assertIterableEquals(Collections.singletonList(survivalCard2), pioche.drawLastTrashCards(1)); + assertFalse(pioche.getTrash().contains(survivalCard2)); + + pioche = new Pioche<>(cards, identityRandom); + pioche.throwAway(survivalCards); + assertIterableEquals(Arrays.asList(survivalCard2, survivalCard), pioche.drawLastTrashCards(2)); + assertFalse(pioche.getTrash().containsAll(survivalCards)); + } +} \ No newline at end of file diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/player/CreatureTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/player/CreatureTest.java new file mode 100644 index 0000000000000000000000000000000000000000..bb066dceb1cea30e61d5c1dd71f5533101720c1b --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/player/CreatureTest.java @@ -0,0 +1,5 @@ +package fr.univnantes.alma.server.game.item.player; + +class CreatureTest { + //TODO tests +} \ No newline at end of file diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/player/TraqueTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/player/TraqueTest.java new file mode 100644 index 0000000000000000000000000000000000000000..eab7fb3a7dd77bcdac76cc6bc997c5c4f4c131e5 --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/player/TraqueTest.java @@ -0,0 +1,5 @@ +package fr.univnantes.alma.server.game.item.player; + +class TraqueTest { + //TODO tests +} \ No newline at end of file diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/player/hand/DeckTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/player/hand/DeckTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2b506ec7d8ea418b7f7cec8bf273ca805498e616 --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/player/hand/DeckTest.java @@ -0,0 +1,108 @@ +package fr.univnantes.alma.server.game.item.player.hand; + +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.card.Card; +import fr.univnantes.alma.server.game.item.card.CardName; +import fr.univnantes.alma.server.game.item.card.PlayerCard; +import fr.univnantes.alma.server.game.item.card.SurvivalCard; +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.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class DeckTest { + Deck deck; + PlayerCard card; + List cardList; + @BeforeEach + public void setUp(){ + deck = new Deck(6); + card = new SurvivalCard(CardName.ADRENALINE,"nom","description", Phase.PHASE_1); + cardList = new ArrayList<>(); + } + + @Test + public void testGetMaxCards(){ + assertEquals(6,deck.getMaxCards()); + } + + @Test + public void testGetCards(){ + assertEquals(deck.getCards(),new ArrayList<>()); + } + + @Test + public void testGetPlayedCards(){ + assertEquals(deck.getPlayedCards(),new ArrayList<>()); + } + + @Test + public void testClear(){ + deck.clear(); + assertEquals(deck.getPlayedCards(),new ArrayList<>()); + } + + @Test + void testAddCard() { + assertTrue(deck.add(card)); + } + + @Test + void testAddList() { + cardList.add(card); + assertTrue(deck.add(cardList)); + } + + @Test + void testRemoveCard() { + deck.add(card); + deck.remove(card); + assertFalse(deck.getCards().contains(card)); + } + + @Test + void testRemoveList() { + cardList.add(card); + deck.add(cardList); + deck.remove(cardList); + assertFalse(deck.getCards().containsAll(cardList)); + } + + @Test + void playCard() { + deck.add(card); + assertTrue(deck.play(card)); + } + + @Test + void playCards() { + cardList.add(card); + deck.add(cardList); + assertTrue(deck.play(cardList)); + } + + @Test + public void testHandSize(){ + assertEquals(0,deck.handSize()); + } + + @Test + public void testHandEmpty(){ + assertTrue(deck.handIsEmpty()); + } + + @Test + public void testPlayedCardSize(){ + assertEquals(0,deck.playedCardSize()); + } + + @Test + public void testPlayedCardIsEmpty(){ + assertTrue(deck.playedCardIsEmpty()); + } +} \ No newline at end of file diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/player/hand/HandCreatureTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/player/hand/HandCreatureTest.java new file mode 100644 index 0000000000000000000000000000000000000000..551854cf91ef2d0fbf19ebd3a425c0a9d62f4f20 --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/player/hand/HandCreatureTest.java @@ -0,0 +1,182 @@ +package fr.univnantes.alma.server.game.item.player.hand; + +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.card.CardName; +import fr.univnantes.alma.server.game.item.card.TrackingCard; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertEquals; +import fr.univnantes.alma.server.game.item.jeton.JetonSymbol; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + + +class HandCreatureTest { + + HandCreature hand = new HandCreature(); + + @Test + public void testInitializationJeton(){ + assertTrue(hand.getJetonSymbols().contains(JetonSymbol.ARTEMIA)); + assertTrue(hand.getJetonSymbols().contains(JetonSymbol.CREATURE)); + assertTrue(hand.getJetonSymbols().contains(JetonSymbol.CIBLE)); + assertTrue(hand.getJetonSymbolsPlayed().isEmpty()); + } + @Test + public void testAddTrackingCardToApplied(){ + TrackingCard card = new TrackingCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + hand.addTrackingCardToApplied(card); + assertTrue(hand.getTrackingCardToApplied().contains(card)); + } + @Test + public void testAddTrackingCardToAppliedList(){ + TrackingCard card = new TrackingCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + List testCards= new ArrayList<>(); + testCards.add(card); + hand.addTrackingCardToApplied(testCards); + assertTrue(hand.getTrackingCardToApplied().containsAll(testCards)); + } + @Test + public void testRemoveTrackingCardToApplied(){ + TrackingCard card = new TrackingCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + hand.addTrackingCardToApplied(card); + hand.removeTrackingCardToApplied(card); + assertFalse(hand.getTrackingCardToApplied().contains(card)); + } + @Test + public void testRemoveTrackingCardToAppliedList(){ + TrackingCard card = new TrackingCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + List testCards= new ArrayList<>(); + testCards.add(card); + hand.addTrackingCardToApplied(testCards); + hand.removeTrackingCardToApplied(testCards); + assertFalse(hand.getTrackingCardToApplied().containsAll(testCards)); + } + @Test + public void testGetTrackingCardToApplied(){ + assertEquals(hand.getTrackingCardToApplied(),new ArrayList<>()); + } + @Test + public void testGetJetonSymbolsPlayed(){ + assertEquals(hand.getJetonSymbolsPlayed(),new ArrayList<>()); + } + @Test + public void testGetJetonSymbols(){ + assertEquals(hand.getJetonSymbols(),new ArrayList<>(Arrays.asList(JetonSymbol.CIBLE, JetonSymbol.CREATURE, JetonSymbol.ARTEMIA))); + } + @Test + public void testPlayJeton(){ + JetonSymbol j1 = JetonSymbol.ARTEMIA; + boolean result = hand.playJeton(j1); + assertTrue(result); + assertFalse(hand.getJetonSymbols().contains(j1)); + assertTrue(hand.getJetonSymbolsPlayed().contains(j1)); + } + @Test + public void testPlayJetonList(){ + JetonSymbol j1 = JetonSymbol.ARTEMIA; + List testjetons = new ArrayList<>(); + testjetons.add(j1); + hand.getJetonSymbols().add(j1); + boolean result = hand.playJeton(testjetons); + assertTrue(result); + assertFalse(hand.getJetonSymbols().containsAll(testjetons)); + assertTrue(hand.getJetonSymbolsPlayed().containsAll(testjetons)); + } + @Test + public void testJetonSize(){ + assertEquals(3,hand.jetonsSize()); + } + @Test + public void testJetonsPlayedSize(){ + assertEquals(0,hand.jetonsPlayedSize()); + } + @Test + public void testJetonsIsEmpty(){ + assertFalse(hand.jetonsIsEmpty()); + } + @Test + public void testJetonsPlayedIsEmpty(){ + assertTrue(hand.jetonsPlayedIsEmpty()); + } + @Test + public void testGetMaxTrackingCards(){ + assertEquals(3,hand.getMaxTrackingCards()); + } + @Test + public void testTrackingCardHandSize(){ + assertEquals(0,hand.trackingCardHandSize()); + } + @Test + public void testTrackingCardPlayedSize(){ + assertEquals(0,hand.trackingCardPlayedSize()); + } + @Test + public void testTrackingCardHandIsEmpty(){ + assertTrue(hand.trackingCardIsEmpty()); + } + @Test + public void testTrackingCardHandPlayedIsEmpty(){ + assertTrue(hand.trackingCardPlayedIsEmpty()); + } + @Test + public void testClearTrackingCardPlayed(){ + TrackingCard card = new TrackingCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + hand.addTrackingCard(card); + hand.playTrackingCard(card); + hand.clearTrackingCardPlayed(); + assertTrue(hand.trackingCardPlayedIsEmpty()); + } + @Test + public void testAddTrackingCard(){ + TrackingCard card = new TrackingCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + hand.addTrackingCard(card); + assertTrue(hand.getTrackingCardHand().contains(card)); + } + @Test + public void testAddTrackingCardList(){ + TrackingCard card = new TrackingCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.addTrackingCard(testCards); + assertTrue(hand.getTrackingCardHand().containsAll(testCards)); + } + @Test + public void testRemoveTrackingCard(){ + TrackingCard card = new TrackingCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + hand.addTrackingCard(card); + hand.removeTrackingCard(card); + assertFalse(hand.getTrackingCardHand().contains(card)); + } + @Test + public void testRemoveTrackingCardList(){ + TrackingCard card = new TrackingCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.addTrackingCard(testCards); + hand.removeTrackingCard(testCards); + assertFalse(hand.getTrackingCardHand().containsAll(testCards)); + } + @Test + public void testPlayTrackingCard(){ + TrackingCard card = new TrackingCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + hand.addTrackingCard(card); + assertTrue(hand.playTrackingCard(card)); + assertFalse(hand.getTrackingCardHand().contains(card)); + assertTrue(hand.getTrackingCardsPlayed().contains(card)); + } + @Test + public void testPlayTrackingCardList(){ + TrackingCard card = new TrackingCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.addTrackingCard(testCards); + assertTrue(hand.playTrackingCard(testCards)); + assertFalse(hand.getTrackingCardHand().containsAll(testCards)); + assertTrue(hand.getTrackingCardsPlayed().containsAll(testCards)); + } + +} \ No newline at end of file diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/player/hand/HandTraqueTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/player/hand/HandTraqueTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d1f70f8f4127ca02d0cae00d2ee96f55feb7d9a8 --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/item/player/hand/HandTraqueTest.java @@ -0,0 +1,292 @@ +package fr.univnantes.alma.server.game.item.player.hand; + +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.card.*; +import fr.univnantes.alma.server.game.item.card.SurvivalCard; +import fr.univnantes.alma.server.game.item.card.SurvivalCard; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class HandTraqueTest { + + HandTraque hand = new HandTraque(); + + @Test + public void testAddSurvivalCardToApplied(){ + SurvivalCard card = new SurvivalCard(CardName.ADRENALINE,"ADRENALINECard","yes adrenaline", Phase.PHASE_2); + hand.addSurvivalCardToApplied(card); + assertTrue(hand.getSurvivalCardsToApplied().contains(card)); + } + + @Test + public void testAddSurvivalCardToAppliedList(){ + SurvivalCard card = new SurvivalCard(CardName.ADRENALINE,"ADRENALINECard","yes adrenaline", Phase.PHASE_2); + List testCards= new ArrayList<>(); + testCards.add(card); + hand.addSurvivalCardToApplied(testCards); + assertTrue(hand.getSurvivalCardsToApplied().containsAll(testCards)); + } + + @Test + public void testRemoveSurvivalCardToApplied(){ + SurvivalCard card = new SurvivalCard(CardName.ADRENALINE,"ADRENALINECard","yes adrenaline", Phase.PHASE_2); + hand.addSurvivalCardToApplied(card); + hand.removeSurvivalCardToApplied(card); + assertFalse(hand.getSurvivalCardsToApplied().contains(card)); + } + @Test + public void testRemoveSurvivalCardToAppliedList(){ + SurvivalCard card = new SurvivalCard(CardName.ADRENALINE,"ADRENALINECard","yes adrenaline", Phase.PHASE_2); + List testCards= new ArrayList<>(); + testCards.add(card); + hand.addSurvivalCardToApplied(testCards); + hand.removeSurvivalCardToApplied(testCards); + assertFalse(hand.getSurvivalCardsToApplied().containsAll(testCards)); + } + @Test + public void testGetSurvivalCardToApplied(){ + assertEquals(hand.getSurvivalCardsToApplied(),new ArrayList<>()); + } + /* PlaceCardDeck methods */ + + @Test + public void testSetPlaceCards() { + PlaceCard card = new PlaceCard(CardName.ANTRE,"antre","antre",1,"url","bleu"); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.setPlaceCards(testCards); + assertTrue(hand.getPlaceCards().containsAll(testCards)); + } + @Test + public void testSetDefausse() { + PlaceCard card = new PlaceCard(CardName.ANTRE,"antre","antre",1,"url","bleu"); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.setDefausse(testCards); + assertTrue(hand.getDefausse().containsAll(testCards)); + } + @Test + public void testPlaceCardHandSize(){ + assertEquals(hand.placeCardHandSize(),0); + } + @Test + public void testPlaceCardIsEmpty(){ + assertTrue(hand.placeCardIsEmpty()); + } + @Test + public void testDefausseSize(){ + assertEquals(hand.defausseSize(),0); + } + @Test + public void testDefausseIsEmpty(){ + assertTrue(hand.defausseIsEmpty()); + } + @Test + public void testPlaceCardPlayedSize(){ + assertEquals(hand.placeCardPlayedSize(),0); + } + @Test + public void testPlaceCardPlayedIsEmpty(){ + assertTrue(hand.placeCardPlayedIsEmpty()); + } + @Test + public void testThrowAwayPlaceCard(){ + PlaceCard card = new PlaceCard(CardName.ANTRE,"antre","antre",1,"url","bleu"); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.setPlaceCards(testCards); + hand.playPlaceCard(testCards); + assertTrue(hand.throwAwayPlaceCard()); + assertTrue(hand.getDefausse().containsAll(testCards)); + assertTrue(hand.getPlaceCardsPlayed().isEmpty()); + } + @Test + public void testThrowAwayPlaceCardGiven(){ + PlaceCard card = new PlaceCard(CardName.ANTRE,"antre","antre",1,"url","bleu"); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.setPlaceCards(testCards); + assertTrue(hand.throwAwayPlaceCard(card)); + assertFalse(hand.getPlaceCards().contains(card)); + assertTrue(hand.getDefausse().contains(card)); + } + @Test + public void testThrowAwayPlaceCardList(){ + PlaceCard card = new PlaceCard(CardName.ANTRE,"antre","antre",1,"url","bleu"); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.setPlaceCards(testCards); + assertTrue(hand.throwAwayPlaceCard(testCards)); + assertTrue(hand.getDefausse().containsAll(testCards)); + } + @Test + public void testTakeBackPlaceCardGiven(){ + PlaceCard card = new PlaceCard(CardName.ANTRE,"antre","antre",1,"url","bleu"); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.setPlaceCards(testCards); + hand.throwAwayPlaceCard(card); + assertTrue(hand.takeBackPlaceCard(card)); + assertTrue(hand.getPlaceCards().contains(card)); + assertFalse(hand.getDefausse().contains(card)); + } + @Test + public void testTakeBackPlaceCardList(){ + PlaceCard card = new PlaceCard(CardName.ANTRE,"antre","antre",1,"url","bleu"); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.setPlaceCards(testCards); + hand.throwAwayPlaceCard(testCards); + assertTrue(hand.takeBackPlaceCard(testCards)); + assertTrue(hand.getPlaceCards().containsAll(testCards)); + } + @Test + public void testTakeBackPlayedPlaceCards(){ + PlaceCard card = new PlaceCard(CardName.ANTRE,"antre","antre",1,"url","bleu"); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.setPlaceCards(testCards); + hand.playPlaceCard(testCards); + hand.takeBackPlayedPlaceCards(); + assertTrue(hand.getPlaceCards().containsAll(testCards)); + assertTrue(hand.getPlaceCardsPlayed().isEmpty()); + } + @Test + public void testTakeBackAllPlaceCardFromDefausse(){ + PlaceCard card = new PlaceCard(CardName.ANTRE,"antre","antre",1,"url","bleu"); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.setPlaceCards(testCards); + hand.playPlaceCard(testCards); + hand.takeBackAllPlaceCardFromDefausse(); + assertTrue(hand.getPlaceCards().containsAll(testCards)); + assertTrue(hand.getDefausse().isEmpty()); + } + @Test + public void testAddPlaceCard(){ + PlaceCard card = new PlaceCard(CardName.ANTRE,"antre","antre",1,"url","bleu"); + assertTrue(hand.addPlaceCard(card)); + assertTrue(hand.getPlaceCards().contains(card)); + } + @Test + public void testAddPlaceCardList(){ + PlaceCard card = new PlaceCard(CardName.ANTRE,"antre","antre",1,"url","bleu"); + List testCards = new ArrayList<>(); + testCards.add(card); + assertTrue(hand.addPlaceCard(testCards)); + assertTrue(hand.getPlaceCards().containsAll(testCards)); + } + @Test + public void testAddPlaceCardInDefausse(){ + PlaceCard card = new PlaceCard(CardName.ANTRE,"antre","antre",1,"url","bleu"); + assertTrue(hand.addPlaceCardInDefausse(card)); + assertTrue(hand.getDefausse().contains(card)); + } + @Test + public void testAddPlaceCardListInDefausse(){ + PlaceCard card = new PlaceCard(CardName.ANTRE,"antre","antre",1,"url","bleu"); + List testCards = new ArrayList<>(); + testCards.add(card); + assertTrue(hand.addPlaceCardInDefausse(testCards)); + assertTrue(hand.getDefausse().containsAll(testCards)); + } + @Test + public void testPlayPlaceCard(){ + PlaceCard card = new PlaceCard(CardName.ANTRE,"antre","antre",1,"url","bleu"); + hand.addPlaceCard(card); + assertTrue(hand.playPlaceCard(card)); + assertTrue(hand.getPlaceCardsPlayed().contains(card)); + assertFalse(hand.getPlaceCards().contains(card)); + } + @Test + public void testPlayPlaceCardList(){ + PlaceCard card = new PlaceCard(CardName.ANTRE,"antre","antre",1,"url","bleu"); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.addPlaceCard(testCards); + assertTrue(hand.playPlaceCard(testCards)); + assertTrue(hand.getPlaceCardsPlayed().containsAll(testCards)); + assertFalse(hand.getPlaceCards().containsAll(testCards)); + } + + /* SurvivalCards Methods */ + + @Test + public void testSurvivalCardHandSize(){ + assertEquals(0,hand.survivalCardHandSize()); + } + @Test + public void testSurvivalCardPlayedSize(){ + assertEquals(0,hand.survivalCardPlayedSize()); + } + @Test + public void testSurvivalCardHandIsEmpty(){ + assertTrue(hand.survivalCardIsEmpty()); + } + @Test + public void testSurvivalCardHandPlayedIsEmpty(){ + assertTrue(hand.survivalCardPlayedIsEmpty()); + } + @Test + public void testClearSurvivalCardPlayed(){ + SurvivalCard card = new SurvivalCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + hand.addSurvivalCard(card); + hand.playSurvivalCard(card); + hand.clearSurvivalCardPlayed(); + assertTrue(hand.survivalCardPlayedIsEmpty()); + } + @Test + public void testAddSurvivalCard(){ + SurvivalCard card = new SurvivalCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + hand.addSurvivalCard(card); + assertTrue(hand.getSurvivalCardsHand().contains(card)); + } + @Test + public void testAddSurvivalCardList(){ + SurvivalCard card = new SurvivalCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.addSurvivalCard(testCards); + assertTrue(hand.getSurvivalCardsHand().containsAll(testCards)); + } + @Test + public void testRemoveSurvivalCard(){ + SurvivalCard card = new SurvivalCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + hand.addSurvivalCard(card); + hand.removeSurvivalCard(card); + assertFalse(hand.getSurvivalCardsHand().contains(card)); + } + @Test + public void testRemoveSurvivalCardList(){ + SurvivalCard card = new SurvivalCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.addSurvivalCard(testCards); + hand.removeSurvivalCard(testCards); + assertFalse(hand.getSurvivalCardsHand().containsAll(testCards)); + } + @Test + public void testPlaySurvivalCard(){ + SurvivalCard card = new SurvivalCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + hand.addSurvivalCard(card); + assertTrue(hand.playSurvivalCard(card)); + assertFalse(hand.getSurvivalCardsHand().contains(card)); + assertTrue(hand.getSurvivalCardsPlayed().contains(card)); + } + @Test + public void testPlaySurvivalCardList(){ + SurvivalCard card = new SurvivalCard(CardName.INTERFERENCES,"InterferenceCard","The powers of the Beach and the Wreck are ineffective", Phase.PHASE_2); + List testCards = new ArrayList<>(); + testCards.add(card); + hand.addSurvivalCard(testCards); + assertTrue(hand.playSurvivalCard(testCards)); + assertFalse(hand.getSurvivalCardsHand().containsAll(testCards)); + assertTrue(hand.getSurvivalCardsPlayed().containsAll(testCards)); + } +} \ No newline at end of file diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/utilitary/ConversionTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/utilitary/ConversionTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a031cb4ce7dd84f384551870f81ba79546c4f6a9 --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/utilitary/ConversionTest.java @@ -0,0 +1,336 @@ +package fr.univnantes.alma.server.game.utilitary; + +import fr.univnantes.alma.server.game.item.Phase; +import fr.univnantes.alma.server.game.item.action.*; +import fr.univnantes.alma.server.game.item.board.BoardColor; +import fr.univnantes.alma.server.game.item.board.BoardDistribution; +import fr.univnantes.alma.server.game.item.card.*; +import fr.univnantes.alma.server.game.item.jeton.JetonSymbol; +import fr.univnantes.alma.server.game.item.jeton.PlacedJeton; +import fr.univnantes.alma.server.game.item.planet.Place; +import fr.univnantes.alma.thrift.*; +import org.junit.jupiter.api.Test; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; + +class ConversionTest { + + @Test + void testToPhase_validPhase() { + assertEquals(Phase.PREPHASE_1, Conversion.toPhase("PREPHASE_1")); + assertEquals(Phase.PHASE_1, Conversion.toPhase("PHASE_1")); + assertEquals(Phase.POSTPHASE_1, Conversion.toPhase("POSTPHASE_1")); + assertEquals(Phase.PREPHASE_2, Conversion.toPhase("PREPHASE_2")); + assertEquals(Phase.PHASE_2, Conversion.toPhase("PHASE_2")); + assertEquals(Phase.POSTPHASE_2, Conversion.toPhase("POSTPHASE_2")); + assertEquals(Phase.PREPHASE_3, Conversion.toPhase("PREPHASE_3")); + assertEquals(Phase.PHASE_3, Conversion.toPhase("PHASE_3")); + assertEquals(Phase.POSTPHASE_3, Conversion.toPhase("POSTPHASE_3")); + assertEquals(Phase.PREPHASE_4, Conversion.toPhase("PREPHASE_4")); + assertEquals(Phase.PHASE_4, Conversion.toPhase("PHASE_4")); + assertEquals(Phase.POSTPHASE_4, Conversion.toPhase("POSTPHASE_4")); + assertEquals(Phase.PREPHASE_1, Conversion.toPhase(new TPhase("PREPHASE_1"))); + assertEquals(Phase.PHASE_1, Conversion.toPhase(new TPhase("PHASE_1"))); + assertEquals(Phase.POSTPHASE_1, Conversion.toPhase(new TPhase("POSTPHASE_1"))); + assertEquals(Phase.PREPHASE_2, Conversion.toPhase(new TPhase("PREPHASE_2"))); + assertEquals(Phase.PHASE_2, Conversion.toPhase(new TPhase("PHASE_2"))); + assertEquals(Phase.POSTPHASE_2, Conversion.toPhase(new TPhase("POSTPHASE_2"))); + assertEquals(Phase.PREPHASE_3, Conversion.toPhase(new TPhase("PREPHASE_3"))); + assertEquals(Phase.PHASE_3, Conversion.toPhase(new TPhase("PHASE_3"))); + assertEquals(Phase.POSTPHASE_3, Conversion.toPhase(new TPhase("POSTPHASE_3"))); + assertEquals(Phase.PREPHASE_4, Conversion.toPhase(new TPhase("PREPHASE_4"))); + assertEquals(Phase.PHASE_4, Conversion.toPhase(new TPhase("PHASE_4"))); + assertEquals(Phase.POSTPHASE_4, Conversion.toPhase(new TPhase("POSTPHASE_4"))); + } + + @Test + void testToPhase_invalidPhase(){ + assertThrows(IllegalArgumentException.class, () -> Conversion.toPhase("PHASE_5")); + } + + @Test + void testToBoardColor_validColor() { + assertEquals(BoardColor.BLUE, Conversion.toBoardColor("BLUE")); + assertEquals(BoardColor.GREEN, Conversion.toBoardColor("GREEN")); + assertEquals(BoardColor.RED, Conversion.toBoardColor("RED")); + assertEquals(BoardColor.YELLOW, Conversion.toBoardColor("YELLOW")); + assertEquals(BoardColor.BLUE, Conversion.toBoardColor(new TColor("BLUE"))); + assertEquals(BoardColor.GREEN, Conversion.toBoardColor(new TColor("GREEN"))); + assertEquals(BoardColor.RED, Conversion.toBoardColor(new TColor("RED"))); + assertEquals(BoardColor.YELLOW, Conversion.toBoardColor(new TColor("YELLOW"))); + } + + @Test + void testToBoardColor_invalidColor() { + assertThrows(IllegalArgumentException.class, () -> Conversion.toBoardColor("MAGENTA")); + } + + @Test + void testToBoardDistribution_validDistribution() { + assertEquals(BoardDistribution.BACK, Conversion.toBoardDistribution("BACK")); + assertEquals(BoardDistribution.FRONT, Conversion.toBoardDistribution("FRONT")); + assertEquals(BoardDistribution.BACK, Conversion.toBoardDistribution(new TBoard("BACK"))); + assertEquals(BoardDistribution.FRONT, Conversion.toBoardDistribution(new TBoard("FRONT"))); + } + + @Test + void testToBoardDistribution_invalidDistribution() { + assertThrows(IllegalArgumentException.class, () -> Conversion.toBoardDistribution("SIDE")); + } + + @Test + void testToCardType_validType() { + assertEquals(Card.CardType.PLACE, Conversion.toCardType("PLACE")); + assertEquals(Card.CardType.TRACKING, Conversion.toCardType("TRACKING")); + assertEquals(Card.CardType.SURVIVAL, Conversion.toCardType("SURVIVAL")); + } + + @Test + void testToCardType_invalidType() { + assertThrows(IllegalArgumentException.class, () -> Conversion.toCardType("BONUS")); + } + + @Test + void testToCard_validCard() { + PlaceCard placeCard = new PlaceCard(CardName.ANTRE, "Antre", "", 1, "url", "color"); + assertEquals(placeCard, Conversion.toCard(new TCard("PLACE", "ANTRE", new ArrayList<>()))); + } + + + @Test + void testToCard_invalidCard() { + TCard tCard = new TCard("PLACE", "NANTES", new ArrayList<>()); + assertThrows(IllegalArgumentException.class, () -> Conversion.toCard(tCard)); + } + + @Test + void testToCardList_validCards() { + PlaceCard placeCard = new PlaceCard(CardName.ANTRE, "Antre", "", 1, "url", "color"); + SurvivalCard survivalCard = new SurvivalCard(CardName.RESISTANCE, "Résistance", "", Phase.PREPHASE_1); + TrackingCard trackingCard = new TrackingCard(CardName.ACHARNEMENT, "Acharnement", "", Phase.PREPHASE_1); + List cards = new ArrayList<>(Arrays.asList(placeCard, survivalCard, trackingCard)); + + List tCards = new ArrayList<>(Arrays.asList( + new TCard("PLACE", "ANTRE", new ArrayList<>()), + new TCard("SURVIVAL", "RESISTANCE", new ArrayList<>()), + new TCard("TRACKING", "ACHARNEMENT", new ArrayList<>()) + )); + + assertEquals(cards, Conversion.toCardList(tCards)); + } + + @Test + void testToPlaceCardList_validCards() { + PlaceCard placeCard1 = new PlaceCard(CardName.ANTRE, "Antre", "", 1, "url", "color"); + PlaceCard placeCard2 = new PlaceCard(CardName.JUNGLE, "Jungle", "", 1, "url", "color"); + PlaceCard placeCard3 = new PlaceCard(CardName.ROVER, "Rover", "", 1, "url", "color"); + List cards = new ArrayList<>(Arrays.asList(placeCard1, placeCard2, placeCard3)); + + List tCards = new ArrayList<>(Arrays.asList( + new TCard("PLACE", "ANTRE", new ArrayList<>()), + new TCard("PLACE", "JUNGLE", new ArrayList<>()), + new TCard("PLACE", "ROVER", new ArrayList<>()) + )); + + assertEquals(cards, Conversion.toPlaceCardList(tCards)); + } + + @Test + void testToPlaceCardList_invalidCards() { + List tCards = new ArrayList<>(Arrays.asList( + new TCard("PLACE", "ANTRE", new ArrayList<>()), + new TCard("SURVIVAL", "RESISTANCE", new ArrayList<>()), + new TCard("PLACE", "ROVER", new ArrayList<>()) + )); + assertThrows(IllegalArgumentException.class, () -> Conversion.toPlaceCardList(tCards)); + } + + @Test + void testToCardName_validCardName() { + assertEquals(CardName.ANTRE, Conversion.toCardName("ANTRE")); + assertEquals(CardName.ACHARNEMENT, Conversion.toCardName("ACHARNEMENT")); + assertEquals(CardName.PORTAIL_SURVIVAL, Conversion.toCardName("PORTAIL_SURVIVAL")); + } + + @Test + void testToCardName_invalidCardName() { + assertThrows(IllegalArgumentException.class, () -> Conversion.toCardName("NANTES")); + } + + + @Test + void testToJetonSymbol_validSymbol() { + assertEquals(JetonSymbol.CIBLE, Conversion.toJetonSymbol("CIBLE")); + assertEquals(JetonSymbol.CREATURE, Conversion.toJetonSymbol("CREATURE")); + assertEquals(JetonSymbol.ARTEMIA, Conversion.toJetonSymbol("ARTEMIA")); + } + + @Test + void testToJetonSymbol_invalidSymbol() { + + assertThrows(IllegalArgumentException.class, () -> Conversion.toJetonSymbol("PIQUE")); + } + + @Test + void testToPlacedJeton() { + PlacedJeton placedJeton = new PlacedJeton(JetonSymbol.CREATURE, Arrays.asList(Place.PLACE_ONE, Place.PLACE_TWO)); + TPlacedJeton tPlacedJeton = new TPlacedJeton(new TJeton("CREATURE"), new TPositionJeton( + Arrays.asList("PLACE_ONE", "PLACE_TWO") + )); + assertEquals(placedJeton, Conversion.toPlacedJeton(tPlacedJeton)); + } + + @Test + void testToPlacedJetonList() { + List placedJetons = new ArrayList<>(Arrays.asList( + new PlacedJeton(JetonSymbol.CREATURE, Arrays.asList(Place.PLACE_ONE, Place.PLACE_TWO)), + new PlacedJeton(JetonSymbol.CIBLE, Arrays.asList(Place.PLACE_NINE, Place.PLACE_TEN)), + new PlacedJeton(JetonSymbol.ARTEMIA, Arrays.asList(Place.PLACE_FIVE, Place.PLACE_SIX)) + )); + List tPlacedJetons = new ArrayList<>(Arrays.asList( + new TPlacedJeton(new TJeton("CREATURE"), new TPositionJeton( + Arrays.asList("PLACE_ONE", "PLACE_TWO") + )), + new TPlacedJeton(new TJeton("CIBLE"), new TPositionJeton( + Arrays.asList("PLACE_NINE", "PLACE_TEN") + )), + new TPlacedJeton(new TJeton("ARTEMIA"), new TPositionJeton( + Arrays.asList("PLACE_FIVE", "PLACE_SIX") + )) + )); + assertEquals(placedJetons, Conversion.toPlacedJetonList(tPlacedJetons)); + } + + @Test + void testToPlace_validPlace() { + assertEquals(Place.PLACE_ONE, Conversion.toPlace("PLACE_ONE")); + assertEquals(Place.PLACE_TWO, Conversion.toPlace("PLACE_TWO")); + assertEquals(Place.PLACE_THREE, Conversion.toPlace("PLACE_THREE")); + assertEquals(Place.PLACE_FOUR, Conversion.toPlace("PLACE_FOUR")); + assertEquals(Place.PLACE_FIVE, Conversion.toPlace("PLACE_FIVE")); + assertEquals(Place.PLACE_SIX, Conversion.toPlace("PLACE_SIX")); + assertEquals(Place.PLACE_SEVEN, Conversion.toPlace("PLACE_SEVEN")); + assertEquals(Place.PLACE_EIGHT, Conversion.toPlace("PLACE_EIGHT")); + assertEquals(Place.PLACE_NINE, Conversion.toPlace("PLACE_NINE")); + assertEquals(Place.PLACE_TEN, Conversion.toPlace("PLACE_TEN")); + } + + @Test + void testToPlace_invalidPlace() { + assertThrows(IllegalArgumentException.class, () -> Conversion.toPlace("ROOM")); + } + + @Test + void testToPlaceList_validPlaceList() { + List places = new ArrayList<>(Arrays.asList(Place.PLACE_ONE, Place.PLACE_TWO, Place.PLACE_THREE, Place.PLACE_FOUR)); + List strings = new ArrayList<>(Arrays.asList("PLACE_ONE", "PLACE_TWO", "PLACE_THREE", "PLACE_FOUR")); + assertEquals(places, Conversion.toPlaceList(strings)); + } + + @Test + void testToTPairType_validPairType() { + assertEquals(TPairType.CARD, Conversion.toTPairType("CARD")); + assertEquals(TPairType.JETON, Conversion.toTPairType("JETON")); + assertEquals(TPairType.NUMBER, Conversion.toTPairType("NUMBER")); + assertEquals(TPairType.PLACE, Conversion.toTPairType("PLACE")); + assertEquals(TPairType.PLAYER, Conversion.toTPairType("PLAYER")); + } + + @Test + void testToTPairType_invalidPairType() { + assertThrows(IllegalArgumentException.class, () -> Conversion.toTPairType("CREATURE")); + } + + @Test + void testToAction_actionAssociateCardnamesToPlaces() { + Map cardNamePlaceMap = new HashMap<>(); + cardNamePlaceMap.put(CardName.ACHARNEMENT, Place.PLACE_ONE); + cardNamePlaceMap.put(CardName.ANGOISSE, Place.PLACE_TWO); + cardNamePlaceMap.put(CardName.RESISTANCE, Place.PLACE_THREE); + Action action = new ActionAssociateCardNamesToPlaces(cardNamePlaceMap); + TAction tAction = new TAction("ASSOCIATE_CARDNAMES_TO_PLACES", + Arrays.asList( + new TPair("CARD", "ACHARNEMENT"), + new TPair("PLACE", "PLACE_ONE"), + new TPair("CARD", "ANGOISSE"), + new TPair("PLACE", "PLACE_TWO"), + new TPair("CARD", "RESISTANCE"), + new TPair("PLACE", "PLACE_THREE") + )); + assertEquals(action, Conversion.toAction(tAction)); + } + + + @Test + void testToAction_inexistantAction() { + TAction tAction = new TAction("fakeType", Collections.singletonList(new TPair("PLAYER", "2"))); + assertThrows(IllegalArgumentException.class, () -> Conversion.toAction(tAction)); + } + + @Test + void testToAction_actionChooseCard() { + List cardNames = new ArrayList<>(Arrays.asList(CardName.ANTRE, CardName.ACHARNEMENT, CardName.RESISTANCE)); + Action action = new ActionChooseCard(cardNames); + TAction tAction = new TAction("CHOOSE_CARD", Arrays.asList( + new TPair("CARD", "ANTRE"), + new TPair("CARD", "ACHARNEMENT"), + new TPair("CARD", "RESISTANCE") + )); + assertEquals(action, Conversion.toAction(tAction)); + } + + @Test + void testToAction_actionChoosePlace() { + List places = new ArrayList<>(Arrays.asList(Place.PLACE_ONE, Place.PLACE_FIVE, Place.PLACE_TEN)); + Action action = new ActionChoosePlace(places); + TAction tAction = new TAction("CHOOSE_PLACE", Arrays.asList( + new TPair("PLACE", "PLACE_ONE"), + new TPair("PLACE", "PLACE_FIVE"), + new TPair("PLACE", "PLACE_TEN") + )); + assertEquals(action, Conversion.toAction(tAction)); + } + + @Test + void testToAction_actionChoosePower() { + Action action = new ActionChoosePower(1); + TAction tAction = new TAction("CHOOSE_POWER", Collections.singletonList( + new TPair("NUMBER", "1") + )); + assertEquals(action, Conversion.toAction(tAction)); + } + + @Test + void testToAction_actionMovePlayer() { + Action action = new ActionMovePlayer(1, Place.PLACE_FIVE); + TAction tAction = new TAction("MOVE_PLAYER", Arrays.asList( + new TPair("PLAYER", "1"), + new TPair("PLACE", "PLACE_FIVE") + )); + assertEquals(action, Conversion.toAction(tAction)); + } + + @Test + void testToAction_actionSwapJeton() { + Action action = new ActionSwapJeton(JetonSymbol.ARTEMIA, JetonSymbol.CREATURE); + TAction tAction = new TAction("SWAP_JETONS", Arrays.asList( + new TPair("JETON", "CREATURE"), + new TPair("JETON", "ARTEMIA") + )); + assertEquals(action, Conversion.toAction(tAction)); + } + + @Test + void testToAction_actionTargetPlayer() { + Action action = new ActionTargetPlayer(1); + TAction tAction = new TAction("TARGET_PLAYER", Collections.singletonList( + new TPair("PLAYER", "1") + )); + assertEquals(action, Conversion.toAction(tAction)); + } + + + +} \ No newline at end of file diff --git a/not-alone-server/src/test/java/fr/univnantes/alma/server/game/utilitary/PairTest.java b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/utilitary/PairTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a6a02d68897fd1ee8cf0fe0fa8bb3c8a1ff37754 --- /dev/null +++ b/not-alone-server/src/test/java/fr/univnantes/alma/server/game/utilitary/PairTest.java @@ -0,0 +1,92 @@ +package fr.univnantes.alma.server.game.utilitary; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class PairTest { + + @Test + void getKey_equalsToExpect() { + Integer i1 = 5; + String s1 = "test"; + Pair pair = new Pair<>(i1, s1); + assertEquals(i1, pair.getKey()); + } + + @Test + void getValue_equalsToExpect() { + Integer i1 = 5; + String s1 = "test"; + Pair pair = new Pair<>(i1, s1); + assertEquals(s1, pair.getValue()); + } + + @Test + void equals_equalsToExpect() { + Integer i1 = 5; + String s1 = "test"; + Pair pair1 = new Pair<>(i1, s1); + Pair pair2 = new Pair<>(i1, s1); + assertEquals(pair1, pair2); + } + + @Test + void equals_sameObject() { + Integer i1 = 5; + String s1 = "test"; + Pair pair1 = new Pair<>(i1, s1); + assertEquals(pair1, pair1); + } + + @Test + void equals_otherObject() { + Integer i1 = 5; + String s1 = "test"; + Pair pair1 = new Pair<>(i1, s1); + Object o1 = new Pair<>(i1, s1); + assertEquals(pair1, o1); + } + + @Test + void equals_notEquals() { + Integer i1 = 5; + String s1 = "test"; + Pair pair1 = new Pair<>(i1, s1); + Integer i2 = 2; + String s2 = "another test"; + Pair pair2 = new Pair<>(i2, s1); + //different pairs + assertNotEquals(pair1, pair2); + pair2 = new Pair<>(i1, s2); + assertNotEquals(pair1, pair2); + pair2 = new Pair<>(i2, s2); + assertNotEquals(pair1, pair2); + } + + @Test + void equals_withNullObject() { + Integer i1 = 5; + String s1 = "test"; + Pair pair1 = new Pair<>(i1, s1); + assertNotEquals(pair1, null); + } + + @Test + void equals_withOtherObject() { + Integer i1 = 5; + String s1 = "test"; + Pair pair1 = new Pair<>(i1, s1); + Object o1 = new Object(); + assertNotEquals(pair1, o1); + } + + @Test + void toString_equalsToExpect() { + Integer i1 = 5; + String s1 = "test"; + Pair pair1 = new Pair<>(i1, s1); + String expect = "Pair(5, test)"; + assertEquals(expect, ""+pair1); + } +} \ No newline at end of file diff --git a/not-alone-web/package-lock.json b/not-alone-web/package-lock.json index ae200d2e88dfc737bbd38e665674811ff09399e1..b12e8f4d380d4ec3d6d8ed1c797b0a62ce212858 100644 --- a/not-alone-web/package-lock.json +++ b/not-alone-web/package-lock.json @@ -1,25 +1,67 @@ { "name": "not-alone-web", "version": "0.0.0", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, - "dependencies": { - "@angular-devkit/architect": { + "packages": { + "": { + "version": "0.0.0", + "dependencies": { + "@angular/animations": "^6.1.0", + "@angular/common": "^6.1.0", + "@angular/compiler": "^6.1.0", + "@angular/core": "^6.1.0", + "@angular/forms": "^6.1.0", + "@angular/http": "^6.1.0", + "@angular/platform-browser": "^6.1.0", + "@angular/platform-browser-dynamic": "^6.1.0", + "@angular/router": "^6.1.0", + "core-js": "^3.8.0", + "rxjs": "~6.2.0", + "zone.js": "~0.8.26" + }, + "devDependencies": { + "@angular-devkit/build-angular": "~0.8.0", + "@angular/cli": "~6.2.5", + "@angular/compiler-cli": "^6.1.0", + "@angular/language-service": "^6.1.0", + "@types/jasmine": "~2.8.8", + "@types/jasminewd2": "~2.0.3", + "@types/node": "~8.9.4", + "codelyzer": "~4.3.0", + "jasmine-core": "~2.99.1", + "jasmine-spec-reporter": "~4.2.1", + "karma": "~3.0.0", + "karma-chrome-launcher": "~2.2.0", + "karma-coverage-istanbul-reporter": "~2.0.1", + "karma-jasmine": "~1.1.2", + "karma-jasmine-html-reporter": "^0.2.2", + "protractor": "~5.4.0", + "ts-node": "~7.0.0", + "tslint": "~5.11.0", + "typescript": "~2.9.2" + } + }, + "node_modules/@angular-devkit/architect": { "version": "0.8.9", "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.8.9.tgz", "integrity": "sha512-2tiGPkvJyFY/G3a27uC8r6Jj3H5m8SxjMqhjNUQ5AtNumweTBPt3YIYMNAvHUmxG0nA9upDolVXFmoQGK9AhKQ==", "dev": true, - "requires": { + "dependencies": { "@angular-devkit/core": "0.8.9", "rxjs": "6.2.2" + }, + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" } }, - "@angular-devkit/build-angular": { + "node_modules/@angular-devkit/build-angular": { "version": "0.8.9", "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.8.9.tgz", "integrity": "sha512-J6o0MwIG1cJT29p87c7uUn7NY3QLEoQOVw4VXWM9cqG9bv99VK7f7eOSDhHJbXn7Snm4XYrye0zRa3RFXhMG+A==", "dev": true, - "requires": { + "dependencies": { "@angular-devkit/architect": "0.8.9", "@angular-devkit/build-optimizer": "0.8.9", "@angular-devkit/build-webpack": "0.8.9", @@ -70,420 +112,100 @@ "webpack-sources": "1.3.0", "webpack-subresource-integrity": "1.1.0-rc.4" }, - "dependencies": { - "ajv": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.4.0.tgz", - "integrity": "sha1-06/3jpJ3VJdx2vAWTP9ISCt1T8Y=", - "dev": true, - "requires": { - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0", - "uri-js": "^3.0.2" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "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" - } - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "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 - }, - "source-map-support": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", - "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "uri-js": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-3.0.2.tgz", - "integrity": "sha1-+QuFhQf4HepNz7s8TD2/orVX+qo=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - } + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" + }, + "optionalDependencies": { + "node-sass": "^4.9.3" } }, - "@angular-devkit/build-optimizer": { + "node_modules/@angular-devkit/build-optimizer": { "version": "0.8.9", "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.8.9.tgz", "integrity": "sha512-h8u5iAhSmt0TsLDZXZCmOkXZDMgP2itLkgZvOIsGInyMAESJuWK4P1qegMSv2R5ELOsinJiuhe218M4K2enEdA==", "dev": true, - "requires": { + "dependencies": { "loader-utils": "1.1.0", "source-map": "0.5.7", "typescript": "2.9.2", "webpack-sources": "1.3.0" + }, + "bin": { + "build-optimizer": "src/build-optimizer/cli.js", + "purify": "src/purify/cli.js" + }, + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" } }, - "@angular-devkit/build-webpack": { + "node_modules/@angular-devkit/build-webpack": { "version": "0.8.9", "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.8.9.tgz", "integrity": "sha512-2csJ6utodPSLABTXfBLymYLrndJURF3xVqVjEDzUFl9zLqK1YOkKH4XPr12vfH8SfAtvzIutNLRxBtAuWJmDlw==", "dev": true, - "requires": { + "dependencies": { "@angular-devkit/architect": "0.8.9", "@angular-devkit/core": "0.8.9", "rxjs": "6.2.2" + }, + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" + }, + "peerDependencies": { + "webpack": "^4.6.0", + "webpack-dev-server": "^3.1.4" } }, - "@angular-devkit/core": { + "node_modules/@angular-devkit/core": { "version": "0.8.9", "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.8.9.tgz", "integrity": "sha512-Umax3YKBPTQy360TeoSNaIIOJOKoXvN/S2WNTV8wDjSWWNiWLTIlckWMb9DVsafAifjUi0mtOLRFuM4YatKgTw==", "dev": true, - "requires": { + "dependencies": { "ajv": "6.4.0", "chokidar": "2.0.4", "rxjs": "6.2.2", "source-map": "0.5.7" }, - "dependencies": { - "ajv": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.4.0.tgz", - "integrity": "sha1-06/3jpJ3VJdx2vAWTP9ISCt1T8Y=", - "dev": true, - "requires": { - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0", - "uri-js": "^3.0.2" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "uri-js": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-3.0.2.tgz", - "integrity": "sha1-+QuFhQf4HepNz7s8TD2/orVX+qo=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - } + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" } }, - "@angular-devkit/schematics": { + "node_modules/@angular-devkit/schematics": { "version": "0.8.9", "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.8.9.tgz", "integrity": "sha512-JZiK1aHJUFV6xDtUMBLoH3cLgi7EtR1bXjNqqa11MAjnHMqzm2GBazPvzGkMwVbCxC1sdYgswwGX9GS2tpHawA==", "dev": true, - "requires": { + "dependencies": { "@angular-devkit/core": "0.8.9", "rxjs": "6.2.2" }, - "dependencies": { - "@angular-devkit/core": { - "version": "0.8.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.8.9.tgz", - "integrity": "sha512-Umax3YKBPTQy360TeoSNaIIOJOKoXvN/S2WNTV8wDjSWWNiWLTIlckWMb9DVsafAifjUi0mtOLRFuM4YatKgTw==", - "dev": true, - "requires": { - "ajv": "6.4.0", - "chokidar": "2.0.4", - "rxjs": "6.2.2", - "source-map": "0.5.7" - } - }, - "ajv": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.4.0.tgz", - "integrity": "sha1-06/3jpJ3VJdx2vAWTP9ISCt1T8Y=", - "dev": true, - "requires": { - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0", - "uri-js": "^3.0.2" - } - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "chokidar": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", - "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.2.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "lodash.debounce": "^4.0.8", - "normalize-path": "^2.1.1", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.5" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "uri-js": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-3.0.2.tgz", - "integrity": "sha1-+QuFhQf4HepNz7s8TD2/orVX+qo=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - } + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" } }, - "@angular/animations": { + "node_modules/@angular/animations": { "version": "6.1.10", "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-6.1.10.tgz", "integrity": "sha512-dd/lq7kw3uwfHPICan8psu2nthuUpp7PvMLuNIm0XxObZ4oNs0ls6uxKEDPnEkRKoGdiJpvmsyzZZN9ACMPEAA==", - "requires": { + "dependencies": { "tslib": "^1.9.0" + }, + "peerDependencies": { + "@angular/core": "6.1.10" } }, - "@angular/cli": { + "node_modules/@angular/cli": { "version": "6.2.9", "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-6.2.9.tgz", "integrity": "sha512-4xuTbmMKGx1bMi0KA3Xmtx/emy10wlSwTXoUijlhd2tcWmlI2wRjAYjR7efSbFo8dVskiq0CyAVFWr1IanYQZw==", "dev": true, - "requires": { + "dependencies": { "@angular-devkit/architect": "0.8.9", "@angular-devkit/core": "0.8.9", "@angular-devkit/schematics": "0.8.9", @@ -500,1561 +222,14135 @@ "symbol-observable": "1.2.0", "yargs-parser": "10.1.0" }, + "bin": { + "ng": "bin/ng" + }, + "engines": { + "node": ">= 8.9.0", + "npm": ">= 5.5.1" + } + }, + "node_modules/@angular/common": { + "version": "6.1.10", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-6.1.10.tgz", + "integrity": "sha512-73xxTSYJNKfiJ7C1Ajg+sz5l8y+blb/vNgHYg7O3yem5zLBnfPpidJ1UGg4W4d2Y+jwUVJbZKh8SKJarqAJVUQ==", "dependencies": { - "@angular-devkit/architect": { - "version": "0.8.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.8.9.tgz", - "integrity": "sha512-2tiGPkvJyFY/G3a27uC8r6Jj3H5m8SxjMqhjNUQ5AtNumweTBPt3YIYMNAvHUmxG0nA9upDolVXFmoQGK9AhKQ==", - "dev": true, - "requires": { - "@angular-devkit/core": "0.8.9", - "rxjs": "6.2.2" - } - }, - "@angular-devkit/core": { - "version": "0.8.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.8.9.tgz", - "integrity": "sha512-Umax3YKBPTQy360TeoSNaIIOJOKoXvN/S2WNTV8wDjSWWNiWLTIlckWMb9DVsafAifjUi0mtOLRFuM4YatKgTw==", - "dev": true, - "requires": { - "ajv": "6.4.0", - "chokidar": "2.0.4", - "rxjs": "6.2.2", - "source-map": "0.5.7" - } - }, - "ajv": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.4.0.tgz", - "integrity": "sha1-06/3jpJ3VJdx2vAWTP9ISCt1T8Y=", - "dev": true, - "requires": { - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0", - "uri-js": "^3.0.2" - }, - "dependencies": { - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", - "dev": true - } - } - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "chokidar": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", - "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.2.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "lodash.debounce": "^4.0.8", - "normalize-path": "^2.1.1", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.5" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", - "dev": true - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "opn": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz", - "integrity": "sha512-YF9MNdVy/0qvJvDtunAOzFw9iasOQHpVthTCvGzxt61Il64AYSGdK+rYwld7NAfk9qJ7dt+hymBNSc9LNYS+Sw==", - "dev": true, - "requires": { - "is-wsl": "^1.1.0" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - } - }, - "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "uri-js": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-3.0.2.tgz", - "integrity": "sha1-+QuFhQf4HepNz7s8TD2/orVX+qo=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", - "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } - } - } - }, - "@angular/common": { - "version": "6.1.10", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-6.1.10.tgz", - "integrity": "sha512-73xxTSYJNKfiJ7C1Ajg+sz5l8y+blb/vNgHYg7O3yem5zLBnfPpidJ1UGg4W4d2Y+jwUVJbZKh8SKJarqAJVUQ==", - "requires": { "tslib": "^1.9.0" + }, + "peerDependencies": { + "@angular/core": "6.1.10", + "rxjs": "^6.0.0" } }, - "@angular/compiler": { + "node_modules/@angular/compiler": { "version": "6.1.10", "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-6.1.10.tgz", "integrity": "sha512-FPIb2j3zfoBwb6vo/u0gQeu70h8InGlSisBr3xMACs/35/pwB6kbQR+JQiUr0D7k6QApg7AuMkvq8aFNelg0aw==", - "requires": { + "dependencies": { "tslib": "^1.9.0" } }, - "@angular/compiler-cli": { + "node_modules/@angular/compiler-cli": { "version": "6.1.10", "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-6.1.10.tgz", "integrity": "sha512-GCWdyeNQSnF4RfzO4A0+WHsNEgxKpl5arg4ldLSWMNkj/DrhMD4TnmxhR+IVY+7ieMkUBwpcuWRnjdOdnbmV+w==", "dev": true, - "requires": { + "dependencies": { "chokidar": "^1.4.2", "minimist": "^1.2.0", "reflect-metadata": "^0.1.2", "tsickle": "^0.32.1" }, + "bin": { + "ng-xi18n": "src/extract_i18n.js", + "ngc": "src/main.js" + }, + "engines": { + "node": ">=8.0" + }, + "peerDependencies": { + "@angular/compiler": "6.1.10", + "typescript": ">=2.7.2 <2.10" + } + }, + "node_modules/@angular/compiler-cli/node_modules/anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, "dependencies": { - "anymatch": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", - "dev": true, - "requires": { - "micromatch": "^2.1.5", - "normalize-path": "^2.0.0" - } - }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "chokidar": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", - "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", - "dev": true, - "requires": { - "anymatch": "^1.3.0", - "async-each": "^1.0.0", - "fsevents": "^1.0.0", - "glob-parent": "^2.0.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^2.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true, - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "dev": true, - "requires": { - "is-glob": "^2.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } - } - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", - "dev": true - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "node_modules/@angular/compiler-cli/node_modules/arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "dependencies": { + "arr-flatten": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/compiler-cli/node_modules/array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/compiler-cli/node_modules/braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "dependencies": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/compiler-cli/node_modules/chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", + "dev": true, + "dependencies": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + }, + "optionalDependencies": { + "fsevents": "^1.0.0" + } + }, + "node_modules/@angular/compiler-cli/node_modules/expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "dependencies": { + "is-posix-bracket": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/compiler-cli/node_modules/extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "dependencies": { + "is-extglob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/compiler-cli/node_modules/glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "dependencies": { + "is-glob": "^2.0.0" + } + }, + "node_modules/@angular/compiler-cli/node_modules/is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/compiler-cli/node_modules/is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "dependencies": { + "is-extglob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/compiler-cli/node_modules/micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "dependencies": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@angular/core": { + "version": "6.1.10", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-6.1.10.tgz", + "integrity": "sha512-61l3rIQTVdT45eOf6/fBJIeVmV10mcrxqS4N/1OWkuDT29YSJTZSxGcv8QjAyyutuhcqWWpO6gVRkN07rWmkPg==", + "dependencies": { + "tslib": "^1.9.0" + }, + "peerDependencies": { + "rxjs": "^6.0.0", + "zone.js": "~0.8.26" + } + }, + "node_modules/@angular/forms": { + "version": "6.1.10", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-6.1.10.tgz", + "integrity": "sha512-zAPx2kMV1/FbP5DrY472Sd/ze1m+GS6T5ullZCtP392r62p2RkwzDCXieR51YiRJjZj3M6c3AcRND7PWBdXT7A==", + "dependencies": { + "tslib": "^1.9.0" + }, + "peerDependencies": { + "@angular/common": "6.1.10", + "@angular/core": "6.1.10", + "@angular/platform-browser": "6.1.10", + "rxjs": "^6.0.0" + } + }, + "node_modules/@angular/http": { + "version": "6.1.10", + "resolved": "https://registry.npmjs.org/@angular/http/-/http-6.1.10.tgz", + "integrity": "sha512-LDsSqyexh8fj23y+G2oSGLWSZVhbxBBo2ehYHnRgH/jlp0pmZVLRaGgUMNSCVtZc1rxLzpEjZjtw+P+qlutAtw==", + "deprecated": "Package no longer supported. Use @angular/common instead, see https://angular.io/guide/deprecations#angularhttp", + "dependencies": { + "tslib": "^1.9.0" + }, + "peerDependencies": { + "@angular/core": "6.1.10", + "@angular/platform-browser": "6.1.10", + "rxjs": "^6.0.0" + } + }, + "node_modules/@angular/language-service": { + "version": "6.1.10", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-6.1.10.tgz", + "integrity": "sha512-nN29Ovomg21eL8acwOSUFAYwWFI1TuFwUgUu37ZssfVQrYdaV+BFx3yv3P0nKU90h3Hp+oIkWHd8U34UYrvBCg==", + "dev": true + }, + "node_modules/@angular/platform-browser": { + "version": "6.1.10", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-6.1.10.tgz", + "integrity": "sha512-CB7pqMwtgb7KjdHDAJlsXcs0rrU+2xQVaoOaqEfJtUrKhtGMLaZh8Qoic5l92SoGattkOw7SYarAOsWlAsVfvw==", + "dependencies": { + "tslib": "^1.9.0" + }, + "peerDependencies": { + "@angular/common": "6.1.10", + "@angular/core": "6.1.10" + } + }, + "node_modules/@angular/platform-browser-dynamic": { + "version": "6.1.10", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-6.1.10.tgz", + "integrity": "sha512-DmBSUyFPoyKqkmBXyJ2CrP1oXDioeoBlPA8lmWUDUv2yBuoHIzIkdY/OkTZbdyu/QYa1hK2Jl9OlfoeoenKddg==", + "dependencies": { + "tslib": "^1.9.0" + }, + "peerDependencies": { + "@angular/common": "6.1.10", + "@angular/compiler": "6.1.10", + "@angular/core": "6.1.10", + "@angular/platform-browser": "6.1.10" + } + }, + "node_modules/@angular/router": { + "version": "6.1.10", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-6.1.10.tgz", + "integrity": "sha512-tekI3dkdvd65oMoxjjgRA+16uDgPUBWHhYxids6pgO8vobZNtCo8VaVlcDyLUhdmtS5kONELx0iL5E2M0Y2Bag==", + "dependencies": { + "tslib": "^1.9.0" + }, + "peerDependencies": { + "@angular/common": "6.1.10", + "@angular/core": "6.1.10", + "@angular/platform-browser": "6.1.10", + "rxjs": "^6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/generator": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", + "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/generator/node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.11.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "node_modules/@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/highlight/node_modules/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, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/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, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/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 + }, + "node_modules/@babel/highlight/node_modules/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, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz", + "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", + "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.12.7", + "@babel/types": "^7.12.7" + } + }, + "node_modules/@babel/traverse": { + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz", + "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.12.7", +