I don't really know python at all.
If your monster list changes often classical weighted chance probably won't work for you, at least if you are pedantic about performance. The problem lies in calculating the maximum chance; you need to iterate over the list at least twice to get the value.
Option 1: Custom List
By creating a custom list class you can skip one loop over the values.
Let's say for instance we have some MonsterList
class that you can use as follows:
monsterlist = MonsterList()
monsterlist.add('snake', 60);
monsterlist.add('troll', 80); # problem?
monsterlist.add('antlion', 30);
The internal representation would actually be:
[
{ 'snake', 0 } # 0
{ 'troll', 60 } # 0 + 60
{ 'antlion', 140 } # 0 + 60 + 80
# 0 + 60 + 80 + 30 = 170
]
In other words the list would be keeping track of an internal total as you create it. To get a value you have a further two sub-options, in both cases you will need to choose a value between 0 and 170 (the current internal total).
Linear Search (O(n)
)
Simply loop over the list until the current item has a value less than the random value.
Binary Search (O(log2N)
)
Extend the internal representation to the following:
[
{ 'snake', 0, 60 } # 0
{ 'troll', 60, 140 } # 0 + 60
{ 'antlion', 140, 270 } # 0 + 60 + 80
# 0 + 60 + 80 + 30 = 170
]
Now perform your basic binary search over the list, stopping when the random value is within the range in the internal representation.
This works because of the way we add values to the list; the running total is guaranteed to be sorted.
Option 2: Multiple Additions
Another option is to add each monster to the list multiple times, however, depending on how granular the weights could be you could land up with a rather large list - so this would be a memory-performance trade-off.
monsterlist = []
snake = 'snake'
troll = 'troll'
antlion = 'antlion'
# snake is twice as likely to appear in comparison to antlion.
# troll is three times as likely to appear in comparison to antlion.
# troll is 1.5 times as likely to appear in comparison to snake.
monsterlist.append(snake, snake, troll, troll, troll, antlion)
Getting a value from that list would merely involve choose a random index (given the count) and indexing the list directly (O(1)
).
targetlist[1][1]
in the last line? \$\endgroup\$ – sam hocevar Dec 11 '11 at 12:28monsterlist
change often? \$\endgroup\$ – sam hocevar Dec 11 '11 at 12:29