Posts: 3,441
Threads: 126
Joined: Jun 2003
Reputation:
1
- Implémenter Garde Impériale
- Implémenter Chaos en général
- Implémenter Nécron
- Implémenter Orks
Posts: 3,441
Threads: 126
Joined: Jun 2003
Reputation:
1
La V10 sortant, on va changer la todo list.
1. Refactoring préparation V10.
Posts: 3,441
Threads: 126
Joined: Jun 2003
Reputation:
1
J'ai commencé à refactoriser pour la V10.
On a donc les profils (+ un Record et un builder=:
Code: package com.calculateur.warhammer.data.identifiable;
import java.util.Set;
import com.calculateur.warhammer.data.enumeration.EProfil;
import com.calculateur.warhammer.data.enumeration.EProfilMotCle;
/**
* Un profil à warhammer 40K
* @author phili
*
*/
public interface IProfil{
/**
*
* @return Le mouvelment
*/
Integer getMouvement();
/**
*
* @return L'endurance
*/
Integer getEndurance();
/**
*
* @return La sauvegarde
*/
Integer getSauvegarde();
/**
*
* @return La sauvegarde Invulnérable
*/
Integer getSauvegardeInvulnerable();
/**
*
* @return Le nombre de point de vie
*/
Integer getNombrePointDeVie();
/**
*
* @return Le commandement
*/
Integer getCommandement();
/**
*
* @return Le contrôle d'objectif
*/
Integer getControlObjectif();
/**
*
* @return Les types du profil
*/
Set<EProfil> getTypesProfils();
/**
*
* @return Les mots clés décrivant le profil
*/
Set<EProfilMotCle> getMotsCles();
/**
*
* @return Vrai si c'est un volant
*/
default Boolean isVolant() {
return getTypesProfils().contains(EProfil.VOL) || getTypesProfils().contains(EProfil.AERODYNE);
}
}
Et l'arme:
Code: package com.calculateur.warhammer.data.identifiable;
import java.util.Set;
import com.calculateur.warhammer.data.enumeration.EArmeMotCle;
import com.calculateur.warhammer.data.enumeration.EArmeRegle;
/**
* L'arme utilisé
* @author phili
*
*/
public interface IArme{
/**
*
* @return La portée de l'arme
*/
Integer getPortee();
/**
*
* @return Le nombre d'attaque de base
*/
Integer getNombreAttaqueBase();
/**
*
* @return Le nombre d'attaque par D3
*/
Integer getNombreAttaqueD3();
/**
*
* @return Le nombre d'attaque par D6
*/
Integer getNombreAttaqueD6();
/**
*
* @return Le jet de touche, c'est à dire la CT (tir) ou la CC (pour le corps à corps)
*/
Integer getJetTouche();
/**
*
* @return La Force de l'arme
*/
Integer getForce();
/**
*
* @return La PA de l'arme
*/
Integer getPA();
/**
*
* @return Les dégats de base
*/
Integer getDegats();
/**
*
* @return Le nombre de D3 qu'il faut avoir pour avoir les dégâts
*/
Integer getDegatsParD3();
/**
*
* @return Nombre d'attaque par D6
*/
Integer getDegatsParD6();
/**
*
* @return Les mots clés propres à une règles
*/
Set<EArmeRegle> getRegles();
/**
*
* @return Les mots clés définissant l'arme.
*/
Set<EArmeMotCle> getMotsCles();
/**
*
* @return Vrai si il s'agit d'une arme de mêlée
*/
boolean isArmeMelee();
}
Pour les règles, on introduit quelques mots clés:
Code: package com.calculateur.warhammer.data.enumeration;
/**
* Enumération des différents mots clés utilisés pour les règles d'armes.
* @author phili
*
*/
public enum EArmeRegle {
ASSAUT,
LOURDE,
TIR_RAPIDE,
GRENADE,
PISTOLET,
JUMELEE,
SOUFLE,
BLAST,
TIR_INDIRECT;
}
Fini la Dakka comme les sauvegarde démonique (pour l'instant).
Par ailleurs, on voit que ça simplifie côté règles, on arrête enfin de se trainer de la programmation générique avec des arme (arme de tir ou de corps à corps) qui complexifiait le code (et en particulier les factory...). On va bien vers une simplification du jeu.
Posts: 3,441
Threads: 126
Joined: Jun 2003
Reputation:
1
Fini le premier gros refactoring lié aux armes.
Do List: - Refonte des bâtiments
- Implémentation des jets de dés (Touche, blessure).
Posts: 3,441
Threads: 126
Joined: Jun 2003
Reputation:
1
Et voilà, les bâtiments sont refondu en vue de la V10.
Rappel Avant:
Code: package com.calculateur.warhammer.data.identifiable;
/**
* Cette interface représente un batiment à 40K
* @author phili
*
*/
public interface IBatiment{
/**
*
* @return Vrai si le terrain est dificile
*/
boolean isTerrainDifficile();
/**
*
* @return Vrai si le batiment est défendable
*/
boolean isDefendable();
/**
*
* @return Vrai si le batiment est un couvert dense
*/
boolean isCouvertDense();
/**
*
* @return Vrai si le batiment est un couvert léger
*/
boolean isCouvertLeger();
/**
*
* @return Vrai si le batiment est un couvert lourd
*/
boolean isCouvertLourd();
/**
*
* @return Vrai si bâtiment est exaltant
*/
boolean isExaltant();
}
Mais maintenant, fini tout ça:
Code: package com.calculateur.warhammer.data.identifiable;
/**
* Cette interface représente un batiment à 40K
* @author phili
*
*/
public interface IBatiment{
/**
*
* @return Vrai si le batiment permet d'avoir au tir une sauvegarde de couvert.
*/
boolean isSauvegardeCouvert();
/**
*
* @return Vrai si au tir, le tireur améliore sa PA.
*/
boolean isAmeliorationPA();
}
Ce qui simplifie les TU:
Code: package com.calculateur.warhammer.data.regles;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import com.calculateur.warhammer.data.enumeration.ESimule;
import com.calculateur.warhammer.data.identifiable.IBatiment;
@Execution(ExecutionMode.SAME_THREAD)
@ExtendWith(MockitoExtension.class)
public class RegleAttaqueBatimentTest {
@Mock
private IBatiment batiment;
@Test
public void testAmeliorationPARuineNiveauSol() {
testAmeliorationPA(false);
}
@Test
public void testAmeliorationPARuineEtage() {
testAmeliorationPA(true);
}
private void testAmeliorationPA(boolean isAmelioration) {
Mockito.when(batiment.isAmeliorationPA()).thenReturn(isAmelioration);
IRegleAttaque regle;
boolean isVraimentAmelioration;
Integer bonusPA;
for(ESimule simule:ESimule.values()) {
regle = new RegleAttaqueBatiment(batiment, simule);
isVraimentAmelioration = isAmelioration && simule.isActionTir();
bonusPA = isVraimentAmelioration?-1:0;
Assertions.assertThat(regle.getBonusPA()).isEqualTo(bonusPA);
}
}
}
Code: package com.calculateur.warhammer.data.regles;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import com.calculateur.warhammer.data.enumeration.ESimule;
import com.calculateur.warhammer.data.identifiable.IBatiment;
@Execution(ExecutionMode.SAME_THREAD)
@ExtendWith(MockitoExtension.class)
public class RegleDefenseBatimentTest {
@Mock
private IBatiment batiment;
@Test
public void testSauvegardeDecouvert() {
testSauvegardeCouvert(false);
}
@Test
public void testSauvegardeRuine() {
testSauvegardeCouvert(true);
}
private void testSauvegardeCouvert(boolean isSauvegardeCouvert) {
Mockito.when(batiment.isSauvegardeCouvert()).thenReturn(isSauvegardeCouvert);
IRegleDefense regle;
for(ESimule simule:ESimule.values()) {
regle = new RegleDefenseBatiment(batiment, simule);
Assertions.assertThat(regle.isSauvegardeCouvert()).isEqualTo(isSauvegardeCouvert && simule.isActionTir());
}
}
}
Et l'implémentation:
Code: package com.calculateur.warhammer.data.regles;
import com.calculateur.warhammer.data.enumeration.ESimule;
import com.calculateur.warhammer.data.identifiable.IBatiment;
/**
* Règle pour l'attaquant étant dans un bâtiment
* @author phili
*
*/
public class RegleAttaqueBatiment implements IRegleAttaque {
private final IBatiment batiment;
private final ESimule simule;
public RegleAttaqueBatiment(IBatiment batiment, ESimule simule) {
this.batiment = batiment;
this.simule = simule;
}
@Override
public Integer getBonusPA() {
return (batiment.isAmeliorationPA() && simule.isActionTir())?-1:IRegleAttaque.super.getBonusPA();
}
}
Code: package com.calculateur.warhammer.data.regles;
import com.calculateur.warhammer.data.enumeration.ESimule;
import com.calculateur.warhammer.data.identifiable.IBatiment;
public class RegleDefenseBatiment implements IRegleDefense{
private final IBatiment batiment;
private final ESimule simule;
public RegleDefenseBatiment(IBatiment batiment, ESimule simule) {
this.batiment = batiment;
this.simule = simule;
}
@Override
public boolean isSauvegardeCouvert() {
return batiment.isSauvegardeCouvert() && simule.isActionTir();
}
}
J'en ai aussi profité pour simplifier ce qui est autour du bâtiment.
Déjà, suppression du bâtiment de la BDD.
Ensuite, simplification de la couche DTO (Data Transfert Object) qui est ce qui est donné (sous forme de JSON) au client.
J'ai déja enuméré par DTO les 2 règles existantes:
Code: package com.calculateur.warhammer.dto;
import java.util.Arrays;
import java.util.Optional;
import com.calculateur.warhammer.base.builder.IBuilder;
import com.calculateur.warhammer.dto.contrat.IEnumDTO;
/**
* Enumération qui décrit une règle de batiment.
* @author phili
*
*/
public enum EDescriptionRegleBatimentDTO implements IEnumDTO,IBuilder<DescriptionRegleBatimentDTO>{
SAUVEGARDE_COUVERT(1,"batiment.sauvegarde.couvert"),
AMELIORATION_PA(2,"batiment.amelioration.pa");
private final Integer id;
private final String cleTraduction;
private EDescriptionRegleBatimentDTO(Integer id, String cleTraduction) {
this.id = id;
this.cleTraduction = cleTraduction;
}
@Override
public Integer getId() {
return id;
}
@Override
public String getCleTraduction() {
return cleTraduction;
}
@Override
public DescriptionRegleBatimentDTO build() {
DescriptionRegleBatimentDTO dto = new DescriptionRegleBatimentDTO();
dto.setEnumeration(this);
return dto;
}
public static EDescriptionRegleBatimentDTO getByCleTraduction(String cle) {
Optional<EDescriptionRegleBatimentDTO> o = Arrays.asList(EDescriptionRegleBatimentDTO.values()).stream().filter(e -> e.getCleTraduction().equals(cle)).findFirst();
return o.isPresent()?o.get():null;
}
}
Ce qui permet de le sortir à l'extérieur pour un futur JSON:
Code: package com.calculateur.warhammer.dto;
/**
* DTO pour décrire la règle d'un bâtiment.
* @author phili
*
*/
public class DescriptionRegleBatimentDTO extends AbstractLibelleEtDescriptionParEnumerationDTO<EDescriptionRegleBatimentDTO>{
/**
*
*/
private static final long serialVersionUID = 1L;
private static final String RESOURCES_TRADUCTION = "com.calculateur.warhammer.dto.description_regle_batiment.description_regle_batiment";
@Override
public String getResourceBudleAsString() {
return RESOURCES_TRADUCTION;
}
}
C'est donc une énumération pour DTO qui implémentera l'interface de règle:
Code: package com.calculateur.warhammer.dto;
import java.util.Arrays;
import java.util.Optional;
import com.calculateur.warhammer.base.builder.IBuilder;
import com.calculateur.warhammer.data.identifiable.IBatiment;
import com.calculateur.warhammer.dto.contrat.IEnumDTO;
public enum EBatimentDTO implements IBatiment,IEnumDTO,IBuilder<BatimentDTO>{
AUCUN(1,"batiment.aucun",false,false),
CRATERE(2,"batiment.cratere",true,false),
DECOMBRES(3,"batiment.decombres",true,false),
BARRICADES(4,"batiment.barricades",true,false),
PIPELINE(5,"batiment.pipeline",true,false),
DEBRIS_CHAMPS_BATAILLE(6,"batiment.debris.champs.bataille",true,false),
COLLINES(7,"batiment.colline",true,false),
FORET(8,"batiment.foret",true,false),
RUINE(9,"batiment.ruine",true,false),
RUINE_HAUTEUR(10,"batiment.ruine.hauteur",true,true);
private Integer id;
private String cleTraduction;
private boolean isCouvert;
private boolean isAmeliorationPA;
private EBatimentDTO(Integer id, String cleTraduction, boolean isCouvert, boolean isAmeliorationPA) {
this.id = id;
this.cleTraduction = cleTraduction;
this.isCouvert = isCouvert;
this.isAmeliorationPA = isAmeliorationPA;
}
@Override
public Integer getId() {
return id;
}
@Override
public String getCleTraduction() {
return cleTraduction;
}
@Override
public boolean isSauvegardeCouvert() {
return isCouvert;
}
@Override
public boolean isAmeliorationPA() {
return isAmeliorationPA;
}
@Override
public BatimentDTO build() {
BatimentDTO dto = new BatimentDTO();
dto.setEnumeration(this);
return dto;
}
public static EBatimentDTO getByCleTraduction(String cle) {
Optional<EBatimentDTO> o = Arrays.asList(EBatimentDTO.values()).stream().filter(e -> e.getCleTraduction().equals(cle)).findFirst();
return o.isPresent()?o.get():null;
}
}
Que l'on s'empresse également de sortir:
Code: package com.calculateur.warhammer.dto;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class BatimentDTO extends AbstractLibelleParEnumerationDTO<EBatimentDTO>{
/**
*
*/
private static final long serialVersionUID = 1L;
private static final String RESOURCES_TRADUCTION = "com.calculateur.warhammer.dto.batiment.batiment";
private List<DescriptionRegleBatimentDTO> descriptions;
@Override
public String getResourceBudleAsString() {
return RESOURCES_TRADUCTION;
}
@Override
public void traduireLibelles(Locale locale) {
super.traduireLibelles(locale);
for(DescriptionRegleBatimentDTO description:descriptions) {
description.traduireLibelles(locale);
}
}
@Override
public void setEnumeration(EBatimentDTO enumeration) {
super.setEnumeration(enumeration);
descriptions = new ArrayList<>();
if(enumeration != null) {
if(enumeration.isSauvegardeCouvert()) {
descriptions.add(EDescriptionRegleBatimentDTO.SAUVEGARDE_COUVERT.build());
}
if(enumeration.isAmeliorationPA()) {
descriptions.add(EDescriptionRegleBatimentDTO.AMELIORATION_PA.build());
}
}
}
public List<DescriptionRegleBatimentDTO> getDescriptions() {
return descriptions;
}
public void setDescriptions(List<DescriptionRegleBatimentDTO> descriptions) {
this.descriptions = descriptions;
}
}
Ce qui donne après une légère refonte du client:
batimant-v10-1.jpg (Size: 158.35 KB / Downloads: 1)
batimant-v10-2.jpg (Size: 155.75 KB / Downloads: 1)
Do List:
Les jets de dés.
Posts: 3,441
Threads: 126
Joined: Jun 2003
Reputation:
1
Fini les jet (j'ai repris les jet de blessures). J'ai la touche, la blessure, la sauvegarde, on va commencer l'arbre de probabilité.
Posts: 3,441
Threads: 126
Joined: Jun 2003
Reputation:
1
J'ai enfin commencé l'arbre de probabilité qui va jusqu'à la sauvegarde.
Pour commencer, afin de faciliter la lecture du code, j'ai fait un gros refactoring pour introduire les données du calcul:
Code: package com.calculateur.warhammer.calcul.mort.arbre.data;
import com.calculateur.warhammer.data.action.IContexteAction;
import com.calculateur.warhammer.data.enumeration.EGestionDe;
import com.calculateur.warhammer.data.unite.IConstituantAttaquant;
import com.calculateur.warhammer.data.unite.IConstituantDefenseur;
/**
* Encapsulation des données nécessaires pour générer l'arbre de probabilité.
* @author phili
*
*/
public interface IDataCalculProbabilite {
/**
*
* @return Le contexte de l'action
*/
IContexteAction getContexteAction();
/**
*
* @return L'attaquant
*/
IConstituantAttaquant getAttaquant();
/**
*
* @return Le défenseur
*/
IConstituantDefenseur getDefenseur();
/**
*
* @return La Gestion du nombre d'attaque (partie aléatoire)
*/
EGestionDe getGestionNombreAttaque();
/**
*
* @return La Gestion des jets de dés pour la touche et la blessure.
*/
EGestionDe getGestionJetToucheBlessure();
/**
*
* @return La gestion des sauvegarde du défenseur.
*/
EGestionDe getGestionSauvegardeDefenseur();
}
L'arbre est représenté par un noeud, qui permet d'avoir la probabilité (de l'évnement et au sein de l'arbre), le pool de dé restant, ainsi que les renfant, le parent, et sa description et libellé. Le noeud est donc traduisible:
Code: package com.calculateur.warhammer.calcul.mort.arbre;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.apache.commons.math3.fraction.Fraction;
import com.calculateur.warhammer.base.traduction.ITraduction;
import com.calculateur.warhammer.calcul.de.EDe;
import com.calculateur.warhammer.data.enumeration.EBlessure;
/**
* Représente un noeud de l'arbre de probabilité
* @author phili
*
*/
public interface INoeudArbre extends ITraduction{
/**
*
* @return La nature du noed.
*/
ENatureNoeud getNatureNoeud();
/**
*
* @return La probabilité que l'évènement ait lieu.
*/
Fraction getProbabiliteNoeud();
/**
*
* @return La probabilité conditionnelle en prenant en compte l'évènement précédent. Soit la probabilité au sein de l'arbre.
*/
default Fraction getProbabiliteConditionnelle() {
Optional<INoeudArbre> oPrecedent = precedent();
Fraction proba = getProbabiliteNoeud();
if(oPrecedent.isPresent()) {
proba = proba.multiply(oPrecedent.get().getProbabiliteConditionnelle());
}
return proba;
}
/**
*
* @return L'évènement précédent.
*/
Optional<INoeudArbre> precedent();
/**
*
* @return Les enfants
*/
List<INoeudArbre> enfants();
/**
*
* @return Les noeuds de l'arbre.
*/
Set<INoeudArbre> arbre();
/**
*
* @return Le nombre de dé dans le pool à cette étape.
*/
Integer getNombreDansPoolDe();
/**
*
* @return Libellé du noeud
*/
String libelle();
/**
* Description du noeud.
* @return
*/
String description();
/**
*
* @return Le nombre de blessures sur ce noud accumuulé depuis me début.
*/
Map<EBlessure, Integer> mapBlessure();
/**
*
* @return Le nombre de blessures dont les dégâts sont déterminés aux dés
*/
Map<EDe, Map<EBlessure, Integer>> mapBlessuresAleatoires();
}
On stocke aussi les blessures infligées.
On peut donc construire le contrat qui donne l'arbre (ici, de fait, la racine):
Code: package com.calculateur.warhammer.calcul.mort.arbre.calcul;
import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.calcul.mort.arbre.INoeudArbre;
import com.calculateur.warhammer.calcul.mort.arbre.data.IDataCalculProbabilite;
/**
* Interface pour calculer l'arbre de probabilité
* @author phili
*
*/
public interface ICalculArbre {
/**
* Calcul l'ensemble de l'arbre de probabilité et retourne la racine
* @param data Les données pour le calcul
* @return Le noeud racine
* @throws FunctionnalExeption
*/
INoeudArbre getRacine(IDataCalculProbabilite data)throws FunctionnalExeption;
}
Qui a l'implémentation suivante:
Code: package com.calculateur.warhammer.calcul.mort.arbre.calcul;
import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.calcul.mort.arbre.INoeudArbre;
import com.calculateur.warhammer.calcul.mort.arbre.NoeudJetTouche;
import com.calculateur.warhammer.calcul.mort.arbre.data.IDataCalculProbabilite;
import com.calculateur.warhammer.calcul.mort.parametres.IParametres;
import com.calculateur.warhammer.calcul.mort.validation.IValidationCalcul;
import com.calculateur.warhammer.calcul.mort.validation.ValidationContextAction;
public class CalculArbre implements ICalculArbre{
private final IParametres parametres;
private final IValidationCalcul validationContext;
public CalculArbre(IParametres parametres) {
this.parametres = parametres;
validationContext = new ValidationContextAction();
}
@Override
public INoeudArbre getRacine(IDataCalculProbabilite data) throws FunctionnalExeption {
//Validation
validationContext.valideCalcul(data);
for(IValidationCalcul validationCalcul:parametres.getFactoryValidation().getValidations(data.getContexteAction().getSimule())) {
validationCalcul.valideCalcul(data);
}
//Initialisation diverse
parametres.getFactoryInitialisation().getInterfaceInitialisationAttaquant().initialiseAttaquant(data.getAttaquant());
Integer nombreAttaque = parametres.getFactoryAttaque().getInterfaceCalculNombreAttaque(data.getGestionNombreAttaque()).getNombreAttaque(data)
* data.getAttaquant().getNombre();
INoeudArbre racine;
if(data.getAttaquant().getRegles().isIgnoreJetTouche()) {
racine = null;//TODO
}else {
racine = NoeudJetTouche.getJetToucheAsRacine(nombreAttaque, data, parametres);
}
return racine;
}
}
La prochaine étape sera de faire la cas des lances-flammes.
On fait donc un TU générique:
Code: package com.calculateur.warhammer.calcul.mort.arbre.calcul;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Locale;
import java.util.logging.Logger;
import org.apache.commons.math3.fraction.Fraction;
import org.assertj.core.api.Assertions;
import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.base.traduction.AbstractTraductionTest;
import com.calculateur.warhammer.calcul.mort.arbre.ENatureNoeud;
import com.calculateur.warhammer.calcul.mort.arbre.INoeudArbre;
import com.calculateur.warhammer.calcul.mort.arbre.data.IDataCalculProbabilite;
import com.calculateur.warhammer.calcul.mort.parametres.ParametresBuilder;
public abstract class AbstractCalculArbreTest {
private static final Logger LOGGER = Logger.getLogger(AbstractCalculArbreTest.class.getName());
private static final Fraction ENSEMBLE = new Fraction(1);
private static final Locale[] LOCALES = AbstractTraductionTest.LOCALES_APPLICATION ;
private final ICalculArbre calculArbre;
public AbstractCalculArbreTest() {
calculArbre = new CalculArbre(ParametresBuilder.getInstance().build());
}
protected INoeudArbre doTestStandard(IDataCalculProbabilite data,Fraction probaAttendu,Integer poolReussite) throws FunctionnalExeption{
INoeudArbre racine = calculArbre.getRacine(data);
Integer nombreReussite = 0;
Fraction probaReussite = new Fraction(0);
boolean racineFound = false;
for(INoeudArbre noeud:racine.arbre()) {
if(noeud == racine) {
racineFound = true;
}
if(noeud.getNatureNoeud() == ENatureNoeud.REUSSITE) {
nombreReussite += noeud.getNombreDansPoolDe();
probaReussite = probaReussite.add(noeud.getProbabiliteConditionnelle());
}
validateNoeud(noeud);
}
assertThat(racineFound).isTrue();
assertThat(probaReussite).isEqualTo(probaAttendu);
assertThat(nombreReussite).isEqualTo(poolReussite);
return racine;
}
private void validateNoeud(INoeudArbre noeud) {
//Racince
if(noeud.precedent().isEmpty()) {
assertThat(noeud.getProbabiliteNoeud()).isEqualTo(ENSEMBLE);
assertThat(noeud.getProbabiliteConditionnelle()).isEqualTo(noeud.getProbabiliteNoeud());
valideEtapeIntermediaire(noeud);
}else {
Assertions.assertThat(noeud.getProbabiliteConditionnelle()).isEqualTo(noeud.getProbabiliteNoeud().multiply(noeud.precedent().get().getProbabiliteConditionnelle()));
if(noeud.getNatureNoeud().isEnfant()) {
valideEtapeIntermediaire(noeud);
}else {
assertThat(noeud.enfants()).isEmpty();
}
}
valideTraduction(noeud);
}
private void valideTraduction(INoeudArbre noeud) {
for(Locale locale:LOCALES) {
Assertions.assertThat(noeud.getResourceBundle(locale)).isNotNull();
noeud.traduireLibelles(locale);
Assertions.assertThat(noeud.libelle()).isNotNull();
Assertions.assertThat(noeud.description()).isNotNull();
LOGGER.info("Libelle noeud : "+noeud.libelle());
LOGGER.info("Description noeud : "+noeud.description());
}
}
private void valideEtapeIntermediaire(INoeudArbre noeud) {
Fraction probaSomme = new Fraction(0);
for(INoeudArbre enfant :noeud.enfants()) {
probaSomme = probaSomme.add(enfant.getProbabiliteNoeud());
Assertions.assertThat(enfant.getProbabiliteConditionnelle()).isEqualTo(noeud.getProbabiliteConditionnelle().multiply(enfant.getProbabiliteNoeud()));
}
assertThat(probaSomme).isEqualTo(ENSEMBLE);
}
}
On vérifie la cohérence de l'arbre et que l'on a la probabilité attendue, ainsi qu'au final le bon pool de dé.
On retourne l'arbre pour vérifier d'autres trucs (comme les blessures à la fin).
Et ainsi, les marines peuvent tirer sur les nouveaux termagants:
Code: package com.calculateur.warhammer.calcul.mort.arbre.calcul;
import org.apache.commons.math3.fraction.Fraction;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.calcul.mort.arbre.ENatureNoeud;
import com.calculateur.warhammer.calcul.mort.arbre.INoeudArbre;
import com.calculateur.warhammer.calcul.mort.arbre.calcul.builder.space.marine.SpaceMarineBuilderAttaque;
import com.calculateur.warhammer.calcul.mort.arbre.calcul.builder.tyranide.TermagantBuilderDefense;
import com.calculateur.warhammer.calcul.mort.arbre.data.IDataCalculProbabilite;
import com.calculateur.warhammer.calcul.mort.arbre.data.RecordDataCalculProbabilite;
import com.calculateur.warhammer.calcul.test.utils.FractionCheminBuilder;
import com.calculateur.warhammer.data.action.IContexteAction;
import com.calculateur.warhammer.data.enumeration.EBlessure;
import com.calculateur.warhammer.data.enumeration.EGestionDe;
import com.calculateur.warhammer.data.enumeration.EMouvement;
import com.calculateur.warhammer.data.enumeration.ESimule;
import com.calculateur.warhammer.data.identifiable.IBatiment;
import com.calculateur.warhammer.data.identifiable.batiment.RecordBatiment;
import com.calculateur.warhammer.data.regles.detachement.space.marine.ESermentInstantChoix;
public class SpaceMarineVsTermagantTirTest extends AbstractCalculArbreTest{
@Test
public void testMarineImmobileTermagantImmobileDecouvertLesDeux12ps() throws FunctionnalExeption{
IContexteAction contexteAction = getContexteDecouvert(EMouvement.IMMOBILE);
IDataCalculProbabilite data = getData(contexteAction);
Fraction probaTouche = new Fraction(5, 6);
Fraction probaBlesse = new Fraction(2, 3);
Fraction probaRateSauvegarde = new Fraction(5,6);
Fraction probaAttendu = FractionCheminBuilder.getInstance().addFraction(probaTouche).addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
Integer reussite = 10;
INoeudArbre racine = doTestStandard(data, probaAttendu, reussite);
valideBlessuresSansRelances(racine);
}
@Test
public void testMarineMouvementNormalTermagantImmobileDecouvertLesDeux12ps() throws FunctionnalExeption{
IContexteAction contexteAction = getContexteDecouvert(EMouvement.NORMAL);
IDataCalculProbabilite data = getData(contexteAction);
Fraction probaTouche = new Fraction(2, 3);
Fraction probaBlesse = new Fraction(2, 3);
Fraction probaRateSauvegarde = new Fraction(5,6);
Fraction probaAttendu = FractionCheminBuilder.getInstance().addFraction(probaTouche).addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
Integer reussite = 8;
INoeudArbre racine = doTestStandard(data, probaAttendu, reussite);
valideBlessuresSansRelances(racine);
}
@Test
public void testMarineImmobileTermagantImmobileMarineCouvertEtageTermagantDecouvertLesDeux12ps() throws FunctionnalExeption{
IContexteAction contexteAction = getContexteBatiment(new RecordBatiment(true, true), new RecordBatiment(false, false));
IDataCalculProbabilite data = getData(contexteAction);
Fraction probaTouche = new Fraction(5, 6);
Fraction probaBlesse = new Fraction(2, 3);
Fraction probaAttendu = FractionCheminBuilder.getInstance().addFraction(probaTouche).addFraction(probaBlesse).build();
Integer reussite = 12;
INoeudArbre racine = doTestStandard(data, probaAttendu, reussite);
valideBlessuresSansRelances(racine);
}
@Test
public void testMarineImmobileTermagantImmobileMarineDecouvertTermagantCouvert12ps() throws FunctionnalExeption{
IContexteAction contexteAction = getContexteBatiment(new RecordBatiment(false, false), new RecordBatiment(true, false));
IDataCalculProbabilite data = getData(contexteAction);
Fraction probaTouche = new Fraction(5, 6);
Fraction probaBlesse = new Fraction(2, 3);
Fraction probaRateSauvegarde = new Fraction(2,3);
Fraction probaAttendu = FractionCheminBuilder.getInstance().addFraction(probaTouche).addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
Integer reussite = 8;
INoeudArbre racine = doTestStandard(data, probaAttendu, reussite);
valideBlessuresSansRelances(racine);
}
@Test
public void testMarineImmobileTermagantImmobileMarineRuineEtageTermagantRuine12ps() throws FunctionnalExeption{
IContexteAction contexteAction = getContexteBatiment(new RecordBatiment(true, true), new RecordBatiment(true, false));
IDataCalculProbabilite data = getData(contexteAction);
Fraction probaTouche = new Fraction(5, 6);
Fraction probaBlesse = new Fraction(2, 3);
Fraction probaRateSauvegarde = new Fraction(5,6);
Fraction probaAttendu = FractionCheminBuilder.getInstance().addFraction(probaTouche).addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
Integer reussite = 10;
INoeudArbre racine = doTestStandard(data, probaAttendu, reussite);
valideBlessuresSansRelances(racine);
}
private void valideBlessuresSansRelances(INoeudArbre racine) {
int nbNoeudReussite = 0;
for(INoeudArbre noeud:racine.arbre()) {
if(noeud.getNatureNoeud() == ENatureNoeud.REUSSITE) {
nbNoeudReussite++;
Assertions.assertThat(noeud.mapBlessuresAleatoires()).isEmpty();
Assertions.assertThat(noeud.mapBlessure()).hasSize(1);
Assertions.assertThat(noeud.mapBlessure()).containsKey(EBlessure.NORMALES);
Integer nombreBlessure = noeud.mapBlessure().get(EBlessure.NORMALES);
Assertions.assertThat(nombreBlessure).isEqualTo(1);
}else {
Assertions.assertThat(noeud.mapBlessure()).isEmpty();
}
}
Assertions.assertThat(nbNoeudReussite).isEqualTo(1);
}
@Test
public void testMarineImmobileTermagantImmobileDecouvertLesDeux12psMarineSermentInstant() throws FunctionnalExeption{
IContexteAction contexteAction = getContexteDecouvert(EMouvement.IMMOBILE);
IDataCalculProbabilite data = getData(contexteAction,ESermentInstantChoix.OUI);
Fraction probaTouche = new Fraction(5, 6);
Fraction probaEchecTouche = new Fraction(1,6);
Fraction probaBlesse = new Fraction(2, 3);
Fraction probaEchecBlesse = new Fraction(1,3);
Fraction probaRateSauvegarde = new Fraction(5,6);
//Reussit tout
Fraction chemin1 = FractionCheminBuilder.getInstance().addFraction(probaTouche).addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
//Rate seulement touche
Fraction chemin2 = FractionCheminBuilder.getInstance().addFraction(probaEchecTouche).addFraction(probaTouche).addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
//Rate seulement blessure
Fraction chemin3 = FractionCheminBuilder.getInstance().addFraction(probaTouche).addFraction(probaEchecBlesse).addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
//Rate touche et blessure
Fraction chemin4 = FractionCheminBuilder.getInstance().addFraction(probaEchecTouche).addFraction(probaTouche).addFraction(probaEchecBlesse).addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
Integer reussite = 15;
Fraction probaAttendu = chemin1.add(chemin2).add(chemin3).add(chemin4);
INoeudArbre racine = doTestStandard(data, probaAttendu, reussite);
valideBlessuresAvecRelances(racine);
}
private void valideBlessuresAvecRelances(INoeudArbre racine) {
int nbNoeudReussite = 0;
for(INoeudArbre noeud:racine.arbre()) {
if(noeud.getNatureNoeud() == ENatureNoeud.REUSSITE) {
nbNoeudReussite++;
Assertions.assertThat(noeud.mapBlessuresAleatoires()).isEmpty();
Assertions.assertThat(noeud.mapBlessure()).hasSize(1);
Assertions.assertThat(noeud.mapBlessure()).containsKey(EBlessure.NORMALES);
Integer nombreBlessure = noeud.mapBlessure().get(EBlessure.NORMALES);
Assertions.assertThat(nombreBlessure).isEqualTo(1);
}else {
Assertions.assertThat(noeud.mapBlessure()).isEmpty();
}
}
Assertions.assertThat(nbNoeudReussite).isEqualTo(4);
}
private IDataCalculProbabilite getData(IContexteAction contexteAction) {
return getData(contexteAction, ESermentInstantChoix.NON);
}
private IDataCalculProbabilite getData(IContexteAction contexteAction,ESermentInstantChoix choix) {
SpaceMarineBuilderAttaque builderAttaquant = SpaceMarineBuilderAttaque.getInstance(contexteAction, 10);
builderAttaquant.addBatiment(contexteAction.getBatimentAttaquant());
builderAttaquant.addSermentInstant(choix);
TermagantBuilderDefense builderDefenseur = TermagantBuilderDefense.getInstance(contexteAction, 10);
builderDefenseur.addBatiment(contexteAction.getBatimentDefenseur());
return new RecordDataCalculProbabilite(contexteAction, builderAttaquant.build(), builderDefenseur.build(), EGestionDe.SIMULATION_OPTIMISTE, EGestionDe.SIMULATION_OPTIMISTE,EGestionDe.SIMULATION_OPTIMISTE);
}
private IContexteAction getContexteDecouvert(EMouvement mouvementAttaquant) {
return getContexteAction(mouvementAttaquant, new RecordBatiment(false, false), new RecordBatiment(false, false));
}
private IContexteAction getContexteBatiment(IBatiment batimentAttaquant,IBatiment batimentDefenseur) {
return getContexteAction(EMouvement.IMMOBILE, batimentAttaquant, batimentDefenseur);
}
private IContexteAction getContexteAction(EMouvement mouvementAttaquant,IBatiment batimentAttaquant,IBatiment batimentDefenseur) {
return ContextActionForTestProbaBuilder.getInstance()
.addSimule(ESimule.TIR_PHASE_TIR)
.addNumeroTour(2)
.addEffectifInitialAttaquant(10)
.addNombreAttaquant(10)
.addMouvementAttaquant(mouvementAttaquant)
.addBatimentAttaquant(batimentAttaquant)
.addNombreDefenseur(10)
.addMouvementDefenseur(EMouvement.IMMOBILE)
.addBatimentDefenseur(batimentDefenseur)
.addDistanceEntreBelligerant(12.0)
.build();
}
}
Posts: 3,441
Threads: 126
Joined: Jun 2003
Reputation:
1
Et assez rapidement, on teste les marines dans la boite Leviathan: l'escouade Infernus.
Un nouveau TU est écrit:
Code: package com.calculateur.warhammer.calcul.mort.arbre.calcul;
import org.apache.commons.math3.fraction.Fraction;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.calcul.mort.arbre.ENatureNoeud;
import com.calculateur.warhammer.calcul.mort.arbre.INoeudArbre;
import com.calculateur.warhammer.calcul.mort.arbre.calcul.builder.space.marine.SpaceMarineBuilderAttaque;
import com.calculateur.warhammer.calcul.mort.arbre.calcul.builder.tyranide.TermagantBuilderDefense;
import com.calculateur.warhammer.calcul.mort.arbre.data.DataCalculProbabiliteBuilder;
import com.calculateur.warhammer.calcul.mort.arbre.data.IDataCalculProbabilite;
import com.calculateur.warhammer.calcul.test.utils.FractionCheminBuilder;
import com.calculateur.warhammer.data.action.IContexteAction;
import com.calculateur.warhammer.data.enumeration.EBlessure;
import com.calculateur.warhammer.data.enumeration.EGestionDe;
import com.calculateur.warhammer.data.enumeration.EMouvement;
import com.calculateur.warhammer.data.enumeration.ESimule;
import com.calculateur.warhammer.data.identifiable.batiment.RecordBatiment;
import com.calculateur.warhammer.data.regles.detachement.space.marine.ESermentInstantChoix;
public class SpaceMarineInfernusVsTermagantTirTest extends AbstractCalculArbreTest{
@Test
public void testMarineContreTermagantDecouvert() throws FunctionnalExeption {
IContexteAction contexte = getContexteAction(false);
IDataCalculProbabilite data = getData(contexte, ESermentInstantChoix.NON);
testMarineContreTermagantSansRelance(data);
}
@Test
public void testMarineContreTermagantCouvert() throws FunctionnalExeption {
IContexteAction contexte = getContexteAction(true);
IDataCalculProbabilite data = getData(contexte, ESermentInstantChoix.NON);
testMarineContreTermagantSansRelance(data);
}
private void testMarineContreTermagantSansRelance(IDataCalculProbabilite dada) throws FunctionnalExeption {
Fraction probaBlesse = new Fraction(2, 3);
Fraction probaRateSauvegarde = new Fraction(2,3);
Fraction probaAttendu = FractionCheminBuilder.getInstance().addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
Integer pool = 26;
INoeudArbre noeud = doTestStandard(dada, probaAttendu, pool);
int nombreChemin = 0;
Integer blessure;
for(INoeudArbre aNoeud:noeud.arbre()) {
if(aNoeud.getNatureNoeud() == ENatureNoeud.REUSSITE) {
nombreChemin++;
Assertions.assertThat(aNoeud.mapBlessure()).hasSize(1);
blessure = aNoeud.mapBlessure().get(EBlessure.NORMALES);
Assertions.assertThat(blessure).isEqualTo(1);
Assertions.assertThat(aNoeud.mapBlessuresAleatoires()).isEmpty();
}
}
Assertions.assertThat(nombreChemin).isEqualTo(1);
}
@Test
public void testMarineContreTermagantDecouvertSermentInstant() throws FunctionnalExeption {
IContexteAction contexte = getContexteAction(false);
IDataCalculProbabilite data = getData(contexte, ESermentInstantChoix.OUI);
testMarineContreTermagantAvecRelance(data);
}
@Test
public void testMarineContreTermagantCouvertSermentInstant() throws FunctionnalExeption {
IContexteAction contexte = getContexteAction(true);
IDataCalculProbabilite data = getData(contexte, ESermentInstantChoix.OUI);
testMarineContreTermagantAvecRelance(data);
}
private void testMarineContreTermagantAvecRelance(IDataCalculProbabilite dada) throws FunctionnalExeption {
Fraction probaBlesse = new Fraction(2, 3);
Fraction probaRateBlesse = new Fraction(1,3);
Fraction probaRateSauvegarde = new Fraction(2,3);
Fraction chemin1 = FractionCheminBuilder.getInstance().addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
Fraction chemin2 = FractionCheminBuilder.getInstance().addFraction(probaRateBlesse).addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
Fraction probaAttendu = chemin1.add(chemin2);
Integer pool = 34;
INoeudArbre noeud = doTestStandard(dada, probaAttendu, pool);
int nombreChemin = 0;
Integer blessure;
for(INoeudArbre aNoeud:noeud.arbre()) {
if(aNoeud.getNatureNoeud() == ENatureNoeud.REUSSITE) {
nombreChemin++;
Assertions.assertThat(aNoeud.mapBlessure()).hasSize(1);
blessure = aNoeud.mapBlessure().get(EBlessure.NORMALES);
Assertions.assertThat(blessure).isEqualTo(1);
Assertions.assertThat(aNoeud.mapBlessuresAleatoires()).isEmpty();
}
}
Assertions.assertThat(nombreChemin).isEqualTo(2);
}
private IDataCalculProbabilite getData(IContexteAction contexteAction,ESermentInstantChoix choix) {
SpaceMarineBuilderAttaque builderAttaquant = SpaceMarineBuilderAttaque.getInstance(contexteAction, 10).equipeAvecPyroBlaster();
builderAttaquant.addBatiment(contexteAction.getBatimentAttaquant());
builderAttaquant.addSermentInstant(choix);
TermagantBuilderDefense builderDefenseur = TermagantBuilderDefense.getInstance(contexteAction, 10);
builderDefenseur.addBatiment(contexteAction.getBatimentDefenseur());
return DataCalculProbabiliteBuilder.getInstance()
.addContextAction(contexteAction).addAttaquant(builderAttaquant.build()).addDefenseur(builderDefenseur.build())
.addGestionNombreAttaque(EGestionDe.SIMULATION_OPTIMISTE).addGestionJetToucheBlessure(EGestionDe.SIMULATION_OPTIMISTE)
.addGestionSauvegardeDefenseur(EGestionDe.SIMULATION_OPTIMISTE).build();
}
private IContexteAction getContexteAction(boolean defenseurCouvert) {
return ContextActionForTestProbaBuilder.getInstance()
.addSimule(ESimule.TIR_PHASE_TIR)
.addNumeroTour(2)
.addEffectifInitialAttaquant(10)
.addNombreAttaquant(10)
.addMouvementAttaquant(EMouvement.IMMOBILE)
.addBatimentAttaquant(new RecordBatiment(false, false))
.addNombreDefenseur(10)
.addMouvementDefenseur(EMouvement.IMMOBILE)
.addBatimentDefenseur(new RecordBatiment(defenseurCouvert, false))
.addDistanceEntreBelligerant(6.0)
.build();
}
}
Ce qui permet de finir le code de calcul:
Code: package com.calculateur.warhammer.calcul.mort.arbre.calcul;
import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.calcul.mort.arbre.INoeudArbre;
import com.calculateur.warhammer.calcul.mort.arbre.NoeudJetBlessure;
import com.calculateur.warhammer.calcul.mort.arbre.NoeudJetTouche;
import com.calculateur.warhammer.calcul.mort.arbre.data.IDataCalculProbabilite;
import com.calculateur.warhammer.calcul.mort.parametres.IParametres;
import com.calculateur.warhammer.calcul.mort.validation.IValidationCalcul;
import com.calculateur.warhammer.calcul.mort.validation.ValidationContextAction;
public class CalculArbre implements ICalculArbre{
private final IParametres parametres;
private final IValidationCalcul validationContext;
public CalculArbre(IParametres parametres) {
this.parametres = parametres;
validationContext = new ValidationContextAction();
}
@Override
public INoeudArbre getRacine(IDataCalculProbabilite data) throws FunctionnalExeption {
//Validation
validationContext.valideCalcul(data);
for(IValidationCalcul validationCalcul:parametres.getFactoryValidation().getValidations(data.getContexteAction().getSimule())) {
validationCalcul.valideCalcul(data);
}
//Initialisation diverse
parametres.getFactoryInitialisation().getInterfaceInitialisationAttaquant().initialiseAttaquant(data.getAttaquant());
Integer nombreAttaque = parametres.getFactoryAttaque().getInterfaceCalculNombreAttaque(data.getGestionNombreAttaque()).getNombreAttaque(data)
* data.getAttaquant().getNombre();
INoeudArbre racine;
if(data.getAttaquant().getRegles().isIgnoreJetTouche()) {
racine = NoeudJetBlessure.getJetBlessureAsRacine(data, parametres, nombreAttaque);
}else {
racine = NoeudJetTouche.getJetToucheAsRacine(nombreAttaque, data, parametres);
}
return racine;
}
}
Posts: 3,441
Threads: 126
Joined: Jun 2003
Reputation:
1
On continue avec les spaces marines du chaos, qui permettent de tester les touches supplémentaire (sur 6+) ou les blessures automatiques (sur 6+).
Soit le TU suivant:
Code: package com.calculateur.warhammer.calcul.mort.arbre.calcul;
import static org.assertj.core.api.Assertions.assertThat;
import org.apache.commons.math3.fraction.Fraction;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import com.calculateur.warhammer.base.exception.FunctionnalExeption;
import com.calculateur.warhammer.calcul.mort.arbre.ENatureNoeud;
import com.calculateur.warhammer.calcul.mort.arbre.INoeudArbre;
import com.calculateur.warhammer.calcul.mort.arbre.calcul.builder.chaos.space.marine.SpaceMarineDuChaosBuilderAttaque;
import com.calculateur.warhammer.calcul.mort.arbre.calcul.builder.space.marine.SpaceMarineBuilderDefense;
import com.calculateur.warhammer.calcul.mort.arbre.data.DataCalculProbabiliteBuilder;
import com.calculateur.warhammer.calcul.mort.arbre.data.IDataCalculProbabilite;
import com.calculateur.warhammer.calcul.test.utils.FractionCheminBuilder;
import com.calculateur.warhammer.data.action.IContexteAction;
import com.calculateur.warhammer.data.enumeration.EBlessure;
import com.calculateur.warhammer.data.enumeration.EGestionDe;
import com.calculateur.warhammer.data.enumeration.EMouvement;
import com.calculateur.warhammer.data.enumeration.ESimule;
import com.calculateur.warhammer.data.identifiable.batiment.RecordBatiment;
import com.calculateur.warhammer.data.regles.detachement.chaos.space.marine.EPactesSombres;
import com.calculateur.warhammer.data.unite.IConstituantAttaquant;
import com.calculateur.warhammer.data.unite.IConstituantDefenseur;
public class SpaceMarineDuChaosVsSpaceMarineAdeptusAstartesTest extends AbstractCalculArbreTest{
@Test
public void testAttaqueMarineDuChaosPasDePacteContreSpaceMarine() throws FunctionnalExeption {
IDataCalculProbabilite data = getData(EPactesSombres.AUCUN, false);
Fraction probaTouche = new Fraction(2,3);
Fraction probaBlesse = new Fraction(1,2);
Fraction probaRateSauvegarde = new Fraction(1,2);
Fraction probaAttendu = FractionCheminBuilder.getInstance().addFraction(probaTouche).addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
Integer poolAttendu = 6;
INoeudArbre racine = doTestStandard(data, probaAttendu, poolAttendu);
validateBlessures(racine, 1);
}
@Test
public void testAttaqueMarineDuChaosPasDePacteContreSpaceArmureMepris() throws FunctionnalExeption {
IDataCalculProbabilite data = getData(EPactesSombres.AUCUN, true);
Fraction probaTouche = new Fraction(2,3);
Fraction probaBlesse = new Fraction(1,2);
Fraction probaRateSauvegarde = new Fraction(1,3);
Fraction probaAttendu = FractionCheminBuilder.getInstance().addFraction(probaTouche).addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
Integer poolAttendu = 4;
INoeudArbre racine = doTestStandard(data, probaAttendu, poolAttendu);
validateBlessures(racine, 1);
}
@Test
public void testAttaqueMarineDuChaosPacteTouchesSoutenuesContreSpaceMarine() throws FunctionnalExeption {
IDataCalculProbabilite data = getData(EPactesSombres.TOUCHES_SOUTENUES, false);
Fraction probaTouche = new Fraction(2,3);
Fraction probaBlesse = new Fraction(1,2);
Fraction probaRateSauvegarde = new Fraction(1,2);
Fraction probaAttendu = FractionCheminBuilder.getInstance().addFraction(probaTouche).addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
Integer poolAttendu = 9;
INoeudArbre racine = doTestStandard(data, probaAttendu, poolAttendu);
validateBlessures(racine, 1);
}
@Test
public void testAttaqueMarineDuChaosPacteTouchesSoutenuesSpaceArmureMepris() throws FunctionnalExeption {
IDataCalculProbabilite data = getData(EPactesSombres.TOUCHES_SOUTENUES, true);
Fraction probaTouche = new Fraction(2,3);
Fraction probaBlesse = new Fraction(1,2);
Fraction probaRateSauvegarde = new Fraction(1,3);
Fraction probaAttendu = FractionCheminBuilder.getInstance().addFraction(probaTouche).addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
Integer poolAttendu = 6;
INoeudArbre racine = doTestStandard(data, probaAttendu, poolAttendu);
validateBlessures(racine, 1);
}
@Test
public void testAttaqueMarineDuChaosPacteCoupsMortelsContreSpaceMarine() throws FunctionnalExeption {
IDataCalculProbabilite data = getData(EPactesSombres.COUPS_MORTELS, false);
Fraction probaToucheAvecJetBlessure = new Fraction(1,2);
Fraction probaToucheSansJetBlessure = new Fraction(1,6);
Fraction probaBlesse = new Fraction(1,2);
Fraction probaRateSauvegarde = new Fraction(1,2);
Fraction chemin1 = FractionCheminBuilder.getInstance().addFraction(probaToucheAvecJetBlessure).addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
Fraction chemin2 = FractionCheminBuilder.getInstance().addFraction(probaToucheSansJetBlessure).addFraction(probaRateSauvegarde).build();
Fraction probaAttendu = chemin1.add(chemin2);
Integer poolAttendu = 9;
INoeudArbre racine = doTestStandard(data, probaAttendu, poolAttendu);
validateBlessures(racine, 2);
}
@Test
public void testAttaqueMarineDuChaosPacteCoupsMortelsSpaceArmureMepris() throws FunctionnalExeption {
IDataCalculProbabilite data = getData(EPactesSombres.COUPS_MORTELS, true);
Fraction probaToucheAvecJetBlessure = new Fraction(1,2);
Fraction probaToucheSansJetBlessure = new Fraction(1,6);
Fraction probaBlesse = new Fraction(1,2);
Fraction probaRateSauvegarde = new Fraction(1,3);
Fraction chemin1 = FractionCheminBuilder.getInstance().addFraction(probaToucheAvecJetBlessure).addFraction(probaBlesse).addFraction(probaRateSauvegarde).build();
Fraction chemin2 = FractionCheminBuilder.getInstance().addFraction(probaToucheSansJetBlessure).addFraction(probaRateSauvegarde).build();
Fraction probaAttendu = chemin1.add(chemin2);
Integer poolAttendu = 6;
INoeudArbre racine = doTestStandard(data, probaAttendu, poolAttendu);
validateBlessures(racine, 2);
}
private void validateBlessures(INoeudArbre racine,int attendu) {
int found = 0;
for(INoeudArbre noeud:racine.arbre()) {
if(noeud.getNatureNoeud() == ENatureNoeud.REUSSITE) {
found++;
Assertions.assertThat(noeud.mapBlessure()).hasSize(1);
Integer nombreBlessure = noeud.mapBlessure().get(EBlessure.NORMALES);
assertThat(nombreBlessure).isEqualTo(1);
Assertions.assertThat(noeud.mapBlessuresAleatoires()).isEmpty();
}
}
Assertions.assertThat(found).isEqualTo(attendu);
}
private IDataCalculProbabilite getData(EPactesSombres pacte, boolean isArmureMepris) {
IContexteAction context = ContextActionForTestProbaBuilder.getInstance()
.addSimule(ESimule.CORPS_A_CORPS_APRES_CHARGE)
.addNumeroTour(2)
.addEffectifInitialAttaquant(10)
.addNombreAttaquant(10)
.addMouvementAttaquant(EMouvement.NORMAL)
.addMouvementDefenseur(EMouvement.NORMAL)
.addBatimentAttaquant(new RecordBatiment(false, false))
.addNombreDefenseur(10)
.addBatimentDefenseur(new RecordBatiment(false, false))
.addDistanceEntreBelligerant(0.0)
.build();
IConstituantAttaquant spaceMarineChaos = SpaceMarineDuChaosBuilderAttaque.getInstance(context, 10, pacte).build();
IConstituantDefenseur spaceMarine = SpaceMarineBuilderDefense.getInstance(context, 10, isArmureMepris).build();
return DataCalculProbabiliteBuilder.getInstance()
.addAttaquant(spaceMarineChaos).addDefenseur(spaceMarine).addContextAction(context)
.addGestionNombreAttaque(EGestionDe.SIMULATION_OPTIMISTE).addGestionJetToucheBlessure(EGestionDe.SIMULATION_OPTIMISTE)
.addGestionSauvegardeDefenseur(EGestionDe.SIMULATION_OPTIMISTE).build();
}
}
Problème: Il y a le cas où la sauvegarde n'est pas permise...
Il va falloir construire un cas de test!
Posts: 3,441
Threads: 126
Joined: Jun 2003
Reputation:
1
Pour le projet Data, qui implémente l'ensemble des règles, je suis à une couverture de code de 88,4% (75,3% dans le code utilisable, 96.6% dans le code de test).
Dans le projet Calcul qui fait le calcul de proba, je suis à une couverture de code de 98,1% (94,2% dans le code utilisable, 97,9% dans le code de test).
|