I just had a course about this and as a rehearsal, I wanted to model the interacting populations of character classes in cRPG, through a variation of evolutionary game theory (please ignore my pompous wording).
So, the idea is to say : we got a number of classes and each class can do more or less good against another class. Those relations exist in cRPG. One of the most obvious examples are polearms. With a vast choice of powerful axes, they are very effective against shielders. More importantly, the more shielders there are, the better polearms will do.
Another obvious observation of cRPG is that the more powerful a class is or seems, the more people will play it. But this change is not linear. It is always more difficult to convince the last, hardcore players of a certain class to change (this is reflected in the model), as witnessed with the last horse throwers (hi Zlisch).
The model aims to take into account that kind of relationship for all classes in relation with all classes (even a class with itself), and the population changes that occur with time. With the right choice of parameters, this model can show what could happen if say, cav became super strong against 2h or if shielders suddenly were able to dispatch mounted ranged with ease. It's also fun because of the chaotic nature of the system. Just like in real cRPG, classes vary in popularity but sometimes we don't really know why (or at least, an explanation would be overly complicated).
At the moment I have 6 classes : "Ranged", "Shield", "2h", "Pole", "Cav" and "HR" (which means horse ranged), the program can easily be extended to include more detailed classes. I have set the payoff matrix in the code based on my ingame experience and also testing the results I got with various settings.
As it is really short, here's a copy pasta of the code (Python 2.7)
classes = ("Ranged","Shield","2h","Pole","Cav","HR")
#payoff of the line class against the column class
payoff = {"Ranged" : { "Ranged" : 2, "Shield" : 1, "2h" : 4, "Pole" : 4, "Cav" : 4, "HR" : 3},
"Shield" : { "Ranged" : 5, "Shield" : 3, "2h" : 2, "Pole" : 2, "Cav" : 1, "HR" : 1},
"2h" : { "Ranged" : 1, "Shield" : 4, "2h" : 3, "Pole" : 4, "Cav" : 3, "HR" : 1},
"Pole" : { "Ranged" : 1, "Shield" : 5, "2h" : 3, "Pole" : 3, "Cav" : 5, "HR" : 1},
"Cav" : { "Ranged" : 4, "Shield" : 5, "2h" : 2, "Pole" : 1, "Cav" : 1, "HR" : 2},
"HR" : { "Ranged" : 2, "Shield" : 1, "2h" : 4, "Pole" : 3, "Cav" : 4, "HR" : 2}}
simulationSpeed = 0.1
def main():
#class populations are initialized equally, could be something else
pop = {}
for c in classes:
pop[c] = 1.0/len(classes)
time=0
while True:
print "Time : ",time
for c in classes:
print c,"\t",pop[c]
fitness = {}
totalFitness = 0
# evaluate the fitness of each class
for myClass in classes:
fitness[myClass] = 0
for opposingClass in classes:
fitness[myClass] += pop[opposingClass] * payoff[myClass][opposingClass]
#this simulates a tendency for the last members of a class to stick to it
fitness[myClass] = fitness[myClass] * (1-pow(pop[myClass],2))
totalFitness += fitness[myClass] * pop[myClass]
#change the populations
for myClass in classes:
fitness[myClass] -= totalFitness
pop[myClass] = pop[myClass] * (1+(fitness[myClass] * simulationSpeed))
time += simulationSpeed
raw_input()
main()
After 5 units of time 2h were at 8% then 15 units later they are at 20% of the playerbase, mainly because there are lots of poles. It's a bit like an aquarium. I realize I should do this with matlab and post graphs but heh I did this for fun and I tought it would be nice to post it, if you are into that kind of things, enjoy