Skip to content

Instantly share code, notes, and snippets.

@naholyr
Created December 2, 2025 10:39
Show Gist options
  • Select an option

  • Save naholyr/35eab4c0f4cdbd01576a3a60209664db to your computer and use it in GitHub Desktop.

Select an option

Save naholyr/35eab4c0f4cdbd01576a3a60209664db to your computer and use it in GitHub Desktop.
const leD12blanc = [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, "*", "*"];
const leD12noir = [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, "*", "*"];
const leD6noir = [0, 0, 0, 2, "x", "*"];
const leD6bleu = [0, 0, 1, 1, 2, "*"];
const leD6rouge = [1, 1, 2, 2, "*", "*"];
const leD6jaune = [0, 1, 2, 3, 3, "*"];
const lancer = (dé, nbLancers = 1) => {
const résultats = [];
for (let i = 0; i < nbLancers; i++) {
const i = Math.floor(Math.random() * dé.length);
résultats.push(dé[i]);
}
return résultats;
};
const lancerD12 = (dé, nbLancers = 1, valeurSpéciale = 0) => {
const résultats = lancer(dé, nbLancers);
return résultats.reduce(
(total, face) =>
total + (face === "*" ? valeurSpéciale : face === 1 ? 1 : 0),
0
);
};
const lancerAttaque = ({ nbDésRouges, nbDésJaunes, nbDégatsSpéciale = 0 }) => {
const résultatsRouges = lancer(leD6rouge, nbDésRouges);
const résultatsJaune = lancer(leD6jaune, nbDésJaunes);
return résultatsRouges
.concat(résultatsJaune)
.reduce(
(total, face) => total + (face === "*" ? nbDégatsSpéciale : face),
0
);
};
const lancerDéfense = ({
nbDésBleus,
nbDésNoirs,
nbBoucliersSpéciale = 0,
esquiveSiSpéciale = false,
}) => {
const résultatsEsquive = lancer(leD6noir, nbDésNoirs);
if (
résultatsEsquive.includes("x") ||
(esquiveSiSpéciale && résultatsEsquive.includes("*"))
) {
return "esquive";
}
const boucliersDésNoirs = résultatsEsquive.reduce(
(total, face) => total + (face === "*" || face === "x" ? 0 : face),
0
);
const résultatsBleus = lancer(leD6bleu, nbDésBleus);
const boucliersDésBleus = résultatsBleus.reduce(
(total, face) => total + (face === "*" ? nbBoucliersSpéciale : face),
0
);
return boucliersDésBleus - boucliersDésNoirs;
};
const résolutionAttaque = ({
attaque: {
nbDésRouges = 0,
nbDésJaunes = 0,
nbDégatsSpéciale = 0,
bonusDégats = 0,
},
défense: {
nbDésBleus = 0,
nbDésNoirs = 0,
nbBoucliersSpéciale = 0,
esquiveSiSpéciale = false,
bonusBoucliers = 0,
},
}) => {
const dégats =
lancerAttaque({ nbDésRouges, nbDésJaunes, nbDégatsSpéciale }) + bonusDégats;
const défense = lancerDéfense({
nbDésBleus,
nbDésNoirs,
nbBoucliersSpéciale,
esquiveSiSpéciale,
});
if (défense === "esquive") {
return "annulé";
}
const défenseFinale = défense + bonusBoucliers;
if (défenseFinale > dégats) {
return "annulé";
}
return dégats - défenseFinale;
};
const stopOuEncore = ({
nbD12blanc,
nbSuccèsSpécial,
nbD12noir,
nbStopSpécial,
nbMaxStop,
}) => {
let nbSuccès = 0;
let nbStops = 0;
while (nbStops < nbMaxStop) {
nbSuccès += lancerD12(leD12blanc, nbD12blanc, nbSuccèsSpécial);
nbStops += lancerD12(leD12noir, nbD12noir, nbStopSpécial);
}
if (nbStops > nbMaxStop) {
return 0;
}
return nbSuccès;
};
const dardDeFeu = (niveau = 1, nbBoucliersAuratiques = 0) =>
stopOuEncore({
nbD12blanc: niveau,
nbSuccèsSpécial: 1,
nbD12noir: 2,
nbStopSpécial: nbBoucliersAuratiques,
nbMaxStop: 2,
});
const annulé = (résultat) => résultat === "annulé";
const simulation = (titre, itération, nbItérations = 10000) => {
const résultats = [];
for (let i = 0; i < nbItérations; i++) {
résultats.push(itération());
}
const nbAnnulés = résultats.filter(annulé).length;
const nbÉchecs = résultats.filter((r) => annulé(r) || r === 0).length;
const succès = résultats.filter((r) => !annulé(r) && r > 0);
const max = Math.max(...succès);
const min = Math.min(...succès);
const mean = succès.reduce((acc, curr) => acc + curr, 0) / succès.length;
const median = succès.sort((a, b) => a - b)[Math.floor(succès.length / 2)];
const p90 = succès.sort((a, b) => a - b)[Math.floor(succès.length * 0.9)];
console.log(`${titre}:
Total échecs: ${(nbÉchecs / nbItérations) * 100}%${
nbAnnulés > 0 ? ` (${(nbAnnulés / nbItérations) * 100}% annulés)` : ""
}
Max succès: ${max} (${
(succès.filter((r) => r === max).length / nbItérations) * 100
}% des succès)
Min succès: ${min} (${
(succès.filter((r) => r === min).length / nbItérations) * 100
}% des succès)
Moyenne des succès: ${mean}
Médiane des succès: ${median}
P90 des succès: ${p90} (90% des succès sont inférieurs à cette valeur)
`);
};
simulation("dardDeFeu niveau 1, max 6 PA, sans bouclier auratique", () =>
dardDeFeu(1, 0)
);
simulation("dardDeFeu niveau 2, max 6 PA, sans bouclier auratique", () =>
dardDeFeu(2, 0)
);
simulation("dardDeFeu niveau 3, max 6 PA, sans bouclier auratique", () =>
dardDeFeu(3, 0)
);
simulation("dardDeFeu niveau 1, max 6 PA, avec 1 bouclier auratique", () =>
dardDeFeu(1, 1)
);
simulation("dardDeFeu niveau 2, max 6 PA, avec 1 bouclier auratique", () =>
dardDeFeu(2, 1)
);
simulation("dardDeFeu niveau 3, max 6 PA, avec 1 bouclier auratique", () =>
dardDeFeu(3, 1)
);
simulation("dardDeFeu niveau 1, max 6 PA, avec 2 boucliers auratiques", () =>
dardDeFeu(1, 2)
);
simulation("dardDeFeu niveau 2, max 6 PA, avec 2 boucliers auratiques", () =>
dardDeFeu(2, 2)
);
simulation("dardDeFeu niveau 3, max 6 PA, avec 2 boucliers auratiques", () =>
dardDeFeu(3, 2)
);
simulation(
"Lance (niveau 2) contre molosse (2 dés rouges + 2 dégats par face spéciale vs 2 dés noirs + esquive si face spéciale)",
() =>
résolutionAttaque({
attaque: { nbDésRouges: 2, nbDégatsSpéciale: 2 },
défense: {
nbDésNoirs: 2,
esquiveSiSpéciale: true,
},
})
);
simulation(
"Épée (niveau 1) contre molosse (2 dés jaunes vs 2 dés noirs + esquive si face spéciale)",
() =>
résolutionAttaque({
attaque: { nbDésJaunes: 2 },
défense: {
nbDésNoirs: 2,
esquiveSiSpéciale: true,
},
})
);
simulation(
"Épée (niveau 2) contre molosse (3 dés jaunes vs 2 dés noirs + esquive si face spéciale)",
() =>
résolutionAttaque({
attaque: { nbDésJaunes: 3 },
défense: {
nbDésNoirs: 2,
esquiveSiSpéciale: true,
},
})
);
simulation(
"Molosse contre Ughnal pas très bien couvert (1 dé rouge + 1 choc vs 1 dé bleu + 1 bouclier par face spéciale + 1 bouclier de base",
() =>
résolutionAttaque({
attaque: { nbDésRouges: 1, bonusDégats: 1 },
défense: {
nbDésBleus: 1,
nbBoucliersSpéciale: 1,
bonusBoucliers: 1,
},
})
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment