Je réécris cette réponse après avoir trouvé une bien meilleure façon de montrer ce que j'ai trouvé. Voici donc ce qu'il en est.
TLDR : la méthode de la Question donne des chiffres systématiquement plus élevés mais les statistiques ont à peu près la même forme. Faire le Knave-1 de Blckknght donne une équivalence approximative sans les bonus négatifs. Faire une méthode Knave où les stats sont produites au lieu du bonus donne plus de 0 et de 1, avec de rares 2.
J'ai donc créé un script python (le code se trouve à la fin pour ceux qui sont intéressés) pour générer des tableaux et essayer de voir si la méthode proposée encouragerait différents types de stratégies et si la méthode générerait une répartition différente des attributs. Le programme a généré des tableaux, les a triés par ordre croissant, puis a comparé la statistique la plus élevée à d'autres plus élevées, puis la deuxième plus élevée à d'autres deuxièmes plus élevées. Et ainsi de suite jusqu'à la plus basse.
Je ne me sens pas mal à l'aise en triant les chiffres car je suppose que les joueurs choisiront une classe en fonction des statistiques qui peuvent obtenir les bonus les plus élevés.
J'ai testé cinq stratégies pour choisir une course. Mon hypothèse est que certaines méthodes pourraient encourager des utilisations différentes des bonus raciaux.
- Utiliser l'humain standard pour +1 partout
- Optimiseur : Essayez d'obtenir un bonus de +1 à deux statistiques. Il s'agit d'obtenir le bonus le plus important dans les statistiques principales.
- Généraliste : Essayez d'obtenir +1 dans la plus haute et la troisième plus haute. L'objectif est d'obtenir un bon bonus dans toutes les statistiques utiles d'une classe MAD comme le moine.
J'ai testé trois méthodes.
- Tableau standard (il a d'ailleurs donné lieu à un cas de contrôle intéressant)
- 4d6 chute la plus faible.
- la méthode de génération de Knave mentionnée dans la question (KnaveBonus).
- Knave-1, extrait de Blckknght
- KnaveScore. Lancer 2d6, en utilisant le plus bas comme score de l'attribut. Ainsi, un 5 et un 2 donnent un 12 pour le score et un bonus de +1.
Résultats
Comme l'a montré @Blckknght, le tableau des Cavaliers a des bonus moyens supérieurs de 1 à 4d6 (donc +2 par rapport au tableau standard). Le maximum et le minimum sont également 1 plus élevés que 4d6 en moyenne. Je suppose donc, comme @Blcknght l'a mentionné dans sa réponse, qu'en utilisant la méthode Knave mais en réduisant tous les bonus de 1, on obtiendrait des résultats similaires dans la plupart des cas.
Effets des races
Ce qui est plus intéressant, du moins à mes yeux, c'est que les différentes stratégies n'affectent pas tellement le nombre de statistiques les plus élevées et les plus élevées. Comme on peut s'y attendre, l'augmentation des deux stats principales donne des stats supérieures plus élevées que l'augmentation des stats principales et troisièmes principales. Et l'utilisation de l'humain standard donne les meilleures statistiques inférieures au détriment des statistiques supérieures.
Le tableau suivant montre la fourchette attendue du bonus pour les trois principales stratégies en utilisant la méthode Knave proposée. Par exemple, la paire (0,87 / 1,59) signifie une moyenne de +1,23 avec 66% des rouleaux entre 0,87 et 1,59. Comme il s'agit de dés et de nombres entiers, la plupart des résultats sont des uns, avec plus de deux que de zéros.
Test
Prime la plus basse
deuxième plus haut niveau
le plus élevé
standard Humain
(0.87 / 1.59)
(1.18 / 2.20)
(1.70 / 2.55)
(1.99 / 3.24)
(2.57 / 3.98)
(3.37 / 5.11)
Optimiseur
(0.96 / 1.11)
(0.87 / 1.56)
(1.00 / 2.15)
(1.55 / 2.60)
(3.00 / 4.43)
(3.82 / 5.50)
Généraliste
(0.96 / 1.10)
(0.87 / 1.53)
(1.00 / 2.13)
(1.92 / 3.24)
(2.59 / 3.77)
(3.80 / 5.50)
Méthodes de génération de statistiques
Le tableau ci-dessous décrit les tableaux de la stratégie Optimizer.
Test
Prime la plus basse
deuxième plus haut niveau
le plus élevé
4d6
(-1.7 / -0.2)
(-0.6 / 0.56)
(-0.0 / 1.29)
(0.58 / 1.84)
(2.22 / 3.42)
(2.93 / 4.23)
Cavalier
(0.96 / 1.11)
(0.87 / 1.56)
(0.99 / 2.13)
(1.55 / 2.63)
(3.00 / 4.44)
(3.83 / 5.52)
Cavalier-1
(-0.0 / 0.11)
(-0.1 / 0.56)
(0.01 / 1.16)
(0.55 / 1.63)
(2.01 / 3.43)
(2.82 / 4.51)
Score Knave
(-0.0 / 0.32)
(-0.0 / 0.90)
(0.35 / 1.18)
(0.78 / 1.41)
(1.94 / 2.99)
(2.64 / 3.33)
- Si l'on compare le tableau 4d6 et le tableau Knave, on constate que le tableau 4d6 est en moyenne inférieur d'un bon -1 à la méthode Knave pour chaque jet. C'est encore plus vrai pour la stat la plus basse, pour laquelle le Knave ne peut pas être négatif. Puisqu'il ne peut pas descendre en dessous de +1, on peut supposer que le 0,96 est dû au fait que la moyenne est très proche de 1, c'est-à-dire que la plupart des jets sont des 1, mais quelques uns sont des 2.
- Comparaison entre 4d6 et le Knave-1. Les chiffres sont beaucoup plus proches. Acceptez que le Knave-1 n'aille pas dans les négatifs.
- Comparaison entre 4d6 et le KnaveScore. Le KnaveScore a des hauts plus bas et des bas plus élevés. Le score le plus élevé est en fait un chiffre complet derrière 4d6.
Le code
Voici ce que j'ai utilisé, cela devrait être du code Python3 standard.
# -*- coding: utf-8 -*-
from random import randint
"""
Score generation
"""
def ConvertScoreToBonus(_score):
if( _score < 10):
_score -= 1 #Need to adjust so that 9=>-1
return int( (_score-10) / 2 )
def GetStandardArray():
official = [15, 14, 13, 12, 10, 8]
official.sort()
return official
def Get4d6Array():
def oneRoll():
oneroll = [randint(1,6) for i in range(4)]
oneroll.remove(min(oneroll))
return sum(oneroll)
ret = [ oneRoll() for stat in range(6) ]
ret.sort()
return ret
def Get3d6Array():
def oneRoll():
oneroll = [randint(1,6) for i in range(3)]
return sum(oneroll)
ret = [ oneRoll() for stat in range(6) ]
ret.sort()
return ret
def GetKnaveBonusArray():
def bonus():
rolls = [randint(1,6) for i in range(3)]
return min(rolls)
ret = [ 10+2*bonus() + (1 if randint(1,2)==1 else 0)\
for stat in range(6) ]
ret.sort()
return ret
def GetKnaveMinusOneArray():
def bonus():
rolls = [randint(1,6) for i in range(3)]
return min(rolls) - 1
ret = [ 10+2*bonus() + (1 if randint(1,2)==1 else 0)\
for stat in range(6) ]
ret.sort()
return ret
def GetKnaveScoreArray():
def score():
rolls = [randint(1,6) for i in range(2)]
return 10+min(rolls)
ret = [ score() for stat in range(6) ]
ret.sort()
return ret
"""
Player race selection and strategy
"""
def player_NoRace( _stats ):
return [ConvertScoreToBonus(s) for s in _stats]
def player_UseHuman( _stats ):
return [ConvertScoreToBonus(s+1) for s in _stats]
def player_OptimizerHuman( _stats ):
_stats[-1] += 2
_stats[-2] += 2
return [ConvertScoreToBonus(s) for s in _stats]
def player_GeneralistHuman( _stats ):
_stats[-1] += 2
_stats[-3] += 2
_stats.sort()
return [ConvertScoreToBonus(s) for s in _stats]
def player_OptimizerSingleBonus( _stats ):
_stats[-1] += 2
_stats[-2] += 1
_stats.sort()
return [ConvertScoreToBonus(s) for s in _stats]
def player_GeneralistSingleBonus( _stats ):
_stats[-1] += 1
_stats[-2] += 2
_stats.sort()
return [ConvertScoreToBonus(s) for s in _stats]
"""
Statistic stuff
"""
class StatsForRoll:
def __init__( self, _array ):
self.m_array = list(_array)
self.m_max = max(self.m_array)
self.m_countOfMax = self.m_array.count( self.m_max )
self.m_countOfSecond = self.m_array.count( StatsForRoll.getSecond(self.m_array) )
self.m_min = min(self.m_array)
self.m_average = sum(self.m_array) / len(self.m_array)
def getSecond( _array ):
localcopy = list(_array)
maximum = max(localcopy)
while( maximum in localcopy and len(localcopy)>1 ):
localcopy.remove( maximum )
return max(localcopy)
def GetAverageArrays( _arrayOfRolls ):
#_arrayOfRolls = list(_arrayOfRolls)
divider = 0
stats = [ 0 for i in range(6)]
for roll in _arrayOfRolls:
divider += 1
for i in range(len(roll.m_array)):
stats[i] += roll.m_array[i]
for i in range(6):
stats[i] /= divider
return stats
def GetErrorBarOnArray( _arrayOfRolls, _averageArray ):
"""
Returns the array as tuples of average +- Average Absolute Deviation
"""
#_arrayOfRolls = list(_arrayOfRolls)
divider = 0
absoluteDeviations = [0 for i in range(6)]
for roll in _arrayOfRolls:
divider += 1
for i in range(len(roll.m_array)):
absoluteDeviations [i] += abs(roll.m_array[i] - _averageArray[i])
for i in range(6):
absoluteDeviations[i] /= divider
return [ (_averageArray[i]-absoluteDeviations[i],\
_averageArray[i]+absoluteDeviations[i] )\
for i in range(6)]
if __name__ == "__main__":
class TestToDo:
def __init__(self, _statCreator, _player, _testLength = 5000):
self.m_statCreator = _statCreator
self.m_player = _player
self.m_testLength = _testLength
testsToDo = []
#testsToDo.append( TestToDo(GetStandardArray, player_UseHuman, 1) )
#testsToDo.append( TestToDo(GetStandardArray, player_OptimizerHuman, 1) )
#testsToDo.append( TestToDo(GetStandardArray, player_GeneralistHuman, 1) )
#testsToDo.append( TestToDo(Get3d6Array, player_UseHuman) )
testsToDo.append( TestToDo(Get4d6Array, player_OptimizerHuman) )
testsToDo.append( TestToDo(GetKnaveBonusArray, player_OptimizerHuman) )
testsToDo.append( TestToDo(GetKnaveMinusOneArray, player_OptimizerHuman) )
testsToDo.append( TestToDo(GetKnaveScoreArray, player_OptimizerHuman) )
#testsToDo.append( TestToDo(Get4d6Array, player_GeneralistHuman) )
#testsToDo.append( TestToDo(Get4d6Array, player_OptimizerSingleBonus) )
#testsToDo.append( TestToDo(Get4d6Array, player_GeneralistSingleBonus) )
for test in testsToDo:
rolls = list(StatsForRoll(test.m_player(test.m_statCreator()))\
for i in range(test.m_testLength))
averageArray = GetAverageArrays( rolls )
errorBars = GetErrorBarOnArray( rolls, averageArray)
testName = test.m_statCreator.__name__ #+ test.m_player.__name__
def fmtNumber(x):
return str(x)[:4]
numbers = ("("+fmtNumber(t[0]) + " / "+ fmtNumber(t[1])+")" \
for t in errorBars)
line = "{0} | {1} |".format(testName, " | ".join(numbers))
print( line )
print()