RE: Projet Calculateur - Philou - 25-10-2022
Malheureusement, MySQL (devenu Maria DB depuis) a été utilisé dans des applications techniques.
RE: Projet Calculateur - Philou - 25-10-2022
Un ingénieur d'Oracle qui a travaillé sur MySQL explique que MySQL est ... à chier
https://mysql.developpez.com/actu/329296/MySQL-est-une-base-de-donnees-plutot-mediocre-declare-un-ingenieur-Oracle-en-partance-PostgreSQL-est-une-meilleure-option-pour-un-SGBD-open-source-selon-lui/
RE: Projet Calculateur - Philou - 26-10-2022
(25-10-2022, 11:23 PM)Philou Wrote: Malheureusement, MySQL (devenu Maria DB depuis) a été utilisé dans des applications techniques.
 Je devrais dire critiques....
RE: Projet Calculateur - Philou - 06-11-2022
J'ai enfin un client (ou début de client) pour mon projet.
Donc une bonne vielle IHM cette fois ci en JavaFX.
ihm_cl_1.jpg (Size: 153.53 KB / Downloads: 14)
C'est dynamique selon les choix, et c'est traduisible.
ihm_cl_2.jpg (Size: 135.13 KB / Downloads: 4)
Et un tooltip rappelle la règle.
ihm_cl_3.jpg (Size: 150.59 KB / Downloads: 6)
Fonctionne avec un serveur derrière, évidement.
RE: Projet Calculateur - Philou - 19-11-2022
Déception pour la Raven Guard. Autant pour le trait de chapitre, il est super bien. Mais le bonus en doctrine tactique, il est super nul. D'autant que les scouts sont un choix d'élite en ce moment
RE: Projet Calculateur - Philou - 23-11-2022
J'ai enfin implémenté l'ensemble des règles spaces marines (seulement les traits de chapitres pour les Black Templar et la Deathwatch) et mon dieu, qu'est-ce qu'il y en a...
RE: Projet Calculateur - Philou - 24-11-2022
J'en profite pour cracher sur certaines personnes (dont je tairai le nom) pour dire que dans le projet data (c'est le métier), j'ai 556 tests unitaires avec une couverture de 88,5%.
RE: Projet Calculateur - Philou - 04-12-2022
En passant (dans data) à 745 tests, je suis passé à une couverture de 94,6%.
RE: Projet Calculateur - Philou - 11-12-2022
Dans le projet data, après j'arrive à une couverture de 95,5% après avoir codé 771 tests unitaires (ce qui m'a permis de simplifier le code, et trouver des bugs au passage).
RE: Projet Calculateur - Philou - 18-12-2022
40K, ce jeu où il y a trop de règles
Revenant enfin sur le métier, dans le calcul (projet calcul, il était temps), j'ai essayé de décomposer les étapes (d'abord déterminer le jet pour toucher, pour blesser ...).
Mais je suis arrivé à un problème: il faut vérifier que celui qui utilise l'API ne donne pas en entrée de la merde.
Par exemple, que l'on ne simule pas un phase de tir en mêlée alors que l'on est avec une arme à tir rapide (encore un problème, le Dark Angel peut en mêlée avec une arme à tir rapide ou une arme d'assaut en doctrine tactique)
Et mine de rien, il y a plein de choses à valider .
Du coup, j'ai re-décomposé et je me suis occupé que de la validation.
Pour commencé, comme Java est un bon langage, j'ai commencé par définir de annotations pour savoir quoi valider lors des différents calculs:
Code: package com.calculateur.warhammer.calcul.mort.validation.annotations;
/**
* Validation pour un corps à corps
* @author phili
*
*/
public @interface ValidationCorpsACorps {
}
Code: package com.calculateur.warhammer.calcul.mort.validation.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Si validation à la phase de tir
* @author phili
*
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidationPhaseTir {
}
Code: package com.calculateur.warhammer.calcul.mort.validation.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Valmidation pour un tir de contre charge
* @author phili
*
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidationTirContreCharge {
}
Ce qui permettra de fabriquer une factory (Design Pattern du GOFF).
Du coup, il n'y a plus qu'à valider:
Code: package com.calculateur.warhammer.calcul.mort.validation;
import com.calculateur.warhammer.calcul.mort.validation.exception.ValidationCalculException;
import com.calculateur.warhammer.data.action.IContexteAction;
import com.calculateur.warhammer.data.identifiable.IArme;
import com.calculateur.warhammer.data.unite.IConstituantAttaquant;
import com.calculateur.warhammer.data.unite.IConstituantDefenseur;
/**
* Validateur pour savoir si l'action calculé ou simulée est possible
* @author phili
*
* @param <A> Arme utilisée
*/
public interface IValidationCalcul <A extends IArme>{
/**
* Valide l'action simulée ou calculée
* @param attaquant Attaquant effectuant l'attaque
* @param defenseur Défenseur effectuant l'attaque
* @param contexteAction Contexte de l'action
* @throws ValidationCalculException Si l'action n'est pas possible
*/
void valideCalcul(IConstituantAttaquant<A> attaquant,IConstituantDefenseur defenseur,IContexteAction<A> contexteAction)throws ValidationCalculException;
}
Avec un utilisateur qui verra un truc traduit:
Code: package com.calculateur.warhammer.calcul.mort.validation.exception;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;
import com.calculateur.warhammer.base.traduction.ITraduction;
/**
* Exception lancée lorsque le calcul n'est pas possible
* @author phili
*
*/
@SuppressWarnings("all")
public class ValidationCalculException extends Exception implements ITraduction{
/**
*
*/
private static final long serialVersionUID = 1L;
private final String resources;
private final Object[] objets;
private final String key;
private String message;
public ValidationCalculException(String resources, Object[] objets, String key) {
this.resources = resources;
this.objets = objets;
this.key = key;
}
@Override
public ResourceBundle getResourceBundle(Locale locale) {
return ResourceBundle.getBundle(resources, locale);
}
@Override
public void traduireLibelles(Locale locale) {
String messageToFormat = getResourceBundle(locale).getString(key);
message = (objets != null)? MessageFormat.format(messageToFormat, objets):messageToFormat;
}
@Override
public String getMessage() {
return message != null?message:key;
}
public Object[] getObjets() {
return objets;
}
}
Et un test de base (toujours faire un TU):
Code: package com.calculateur.warhammer.calcul.mort.validation;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
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.junit.jupiter.MockitoExtension;
import com.calculateur.warhammer.calcul.mort.validation.exception.ValidationCalculException;
import com.calculateur.warhammer.data.action.IContexteAction;
import com.calculateur.warhammer.data.identifiable.IArme;
import com.calculateur.warhammer.data.identifiable.IProfil;
import com.calculateur.warhammer.data.regles.IRegleAttaque;
import com.calculateur.warhammer.data.unite.IConstituantAttaquant;
import com.calculateur.warhammer.data.unite.IConstituantDefenseur;
import com.calculateur.warhammer.data.unite.implementation.BasicConstituantUniteAttaquant;
@Execution(ExecutionMode.SAME_THREAD)
@ExtendWith(MockitoExtension.class)
public abstract class AbstractValidationTest <A extends IArme>{
private Locale[] LOCALES = {Locale.FRANCE,Locale.ENGLISH};
private IConstituantAttaquant<A> attaquant;
@Mock
protected IProfil profilAttaquant;
@Mock
protected IRegleAttaque regleAttaquant;
@Mock
protected IContexteAction<A> contextAction;
private final IValidationCalcul<A> validator;
protected AbstractValidationTest(IValidationCalcul<A> validator) {
this.validator = validator;
}
@BeforeEach
public void beforeEach() {
attaquant = new BasicConstituantUniteAttaquant<A>(profilAttaquant, null, null, getArme(), regleAttaquant);
}
protected abstract A getArme();
protected void testValidationStandard(boolean isExceptionAttendue) {
testValidationStandard(isExceptionAttendue, attaquant, contextAction);
}
protected void testValidationStandard(boolean isExceptionAttendue,IConstituantAttaquant<A> aAttaquant,IContexteAction<A> aContext) {
testValidationStandard(isExceptionAttendue, aAttaquant, null,contextAction);
}
protected void testValidationStandard(boolean isExceptionAttendue,IConstituantAttaquant<A> aAttaquant,IConstituantDefenseur defenseur,IContexteAction<A> aContext) {
try {
validator.valideCalcul(aAttaquant,defenseur, aContext);
Assertions.assertThat(isExceptionAttendue).isFalse();
}catch(ValidationCalculException ex) {
Assertions.assertThat(isExceptionAttendue).isTrue();
valideException(ex);
}
}
private void valideException(ValidationCalculException ex) {
String key = ex.getMessage();
Object[] params = ex.getObjets();
Assertions.assertThat(key).isNotNull();
ResourceBundle res;
for(Locale locale:LOCALES) {
res = ex.getResourceBundle(locale);
ex.traduireLibelles(locale);
Assertions.assertThat(ex.getMessage()).isEqualTo(MessageFormat.format(res.getString(key), params));
}
}
}
Soit pour savoir si on tir en mêlée:
Code: package com.calculateur.warhammer.calcul.mort.validation;
import java.util.Set;
import com.calculateur.warhammer.calcul.mort.validation.annotations.ValidationPhaseTir;
import com.calculateur.warhammer.calcul.mort.validation.exception.ValidationCalculException;
import com.calculateur.warhammer.data.action.IContexteAction;
import com.calculateur.warhammer.data.enumeration.EProfil;
import com.calculateur.warhammer.data.identifiable.IArmeDeTir;
import com.calculateur.warhammer.data.unite.IConstituantAttaquant;
import com.calculateur.warhammer.data.unite.IConstituantDefenseur;
/**
* Validation si on peut tirer en mêlée
* @author phili
*
*/
@ValidationPhaseTir
public class ValidationPhaseTirMelee implements IValidationCalcul<IArmeDeTir>{
@Override
public void valideCalcul(IConstituantAttaquant<IArmeDeTir> attaquant,IConstituantDefenseur defenseur, IContexteAction<IArmeDeTir> contexteAction)
throws ValidationCalculException {
if(contexteAction.isZoneEngagement() &&
!isVehiculeOuMonstre(attaquant.getProfil().getTypesProfils()) &&
!attaquant.getRegles().isPeutUtiliserArmePorteeEngagement(attaquant.getArme().getType())) {
Object[] params = {attaquant.getArme().getType()};
throw new ValidationCalculException(ValidationCalculUtil.RESOURCE_ERREUR_PHASE_TIR,params, "erreur.tir.melee");
}
}
private boolean isVehiculeOuMonstre(Set<EProfil> typesProfils) {
return typesProfils.contains(EProfil.VEHICULE) || typesProfils.contains(EProfil.MONSTRE);
}
}
Ou si on peut charger après une retraite:
Code: package com.calculateur.warhammer.calcul.mort.validation;
import com.calculateur.warhammer.calcul.mort.validation.annotations.ValidationCorpsACorps;
import com.calculateur.warhammer.calcul.mort.validation.exception.ValidationCalculException;
import com.calculateur.warhammer.data.action.IContexteAction;
import com.calculateur.warhammer.data.enumeration.ESimule;
import com.calculateur.warhammer.data.identifiable.IArme;
import com.calculateur.warhammer.data.unite.IConstituantAttaquant;
import com.calculateur.warhammer.data.unite.IConstituantDefenseur;
/**
* Valida si la charge est possible
* @author phili
*
*/
@ValidationCorpsACorps
public class ValidationChargePossible implements IValidationCalcul<IArme>{
@Override
public void valideCalcul(IConstituantAttaquant<IArme> attaquant,IConstituantDefenseur defenseur, IContexteAction<IArme> contexteAction)
throws ValidationCalculException {
if(contexteAction.getSimule() == ESimule.CORPS_A_CORPS_APRES_CHARGE && !attaquant.getRegles().isChargeApresTypeMouvement(contexteAction.getMouvementAttaquant())) {
Object[] param = {contexteAction.getMouvementAttaquant()};
throw new ValidationCalculException(ValidationCalculUtil.RESOURCE_ERREUR_CORPS_A_CORPS, param, "erreur.charge.impossible");
}
}
}
Evidement, tout ça est testé (avec d'autres validateurs) et les TU ont été écrit avant selon le principe du TDD.
|