[BGMC17]random.choice() dropchances

Hi! I am using a list of fish(fishlist = [1, 2, 3, 4, 5, 6, 7 etc.]) which stores IDs of aviable fish and than I use random.choice(fishlist) to select fish currently being fished. However - I want to have different dropchances for different fish. And to be more - I want it to be different in different areas(place static convex hull ghost cubes as area markers around and each of them have property with different list… How to achieve dropchances and how to store list in one property and than read it?

The first part is easy. Just add an index more than once.

fishlist = [1,1,1,2,2,3,3,3,3,3,4]

Now you will catch a lot of 2s and 3s but not many 4s.

You can put the lists in a dictionary to get the right one for the right area:

fishlists= {"deep_water":[3,4,5],
    "medium_water":[2,2,3,4,5,5,6],
    "shallow_water":[1,1,1,1,1,2],
    "the_sweet_spot":[5,5,6,7,8],
    "near_the_noisy_kids":[1]}

Then get the dictionary entry you need:

if hit:
         fish_list_type = hit.object["fish_list_type"]
         fish_list = fishlists[fish_list_type]
         fish = random.choice(fish_list)

Thanks! I will try after dinner, but this really sounds it:)

Weighted choice:


import random




def weighted_choice(items):
    value = random.random()
    for weight, item in items:
        value -= weight


        if value < 0.0:
            return item 
        
        
choices = [(0.2, 'a'), (0.1, 'b'), (0.4, 'c'), (0.3, 'd')]




import collections
iterations = 100000 
results = (weighted_choice(choices) for i in range(iterations))


for k, c in collections.Counter(results).items():
    print("p({}) = {}".format(k, round(c/iterations, 1)))
    

agoose77, your method may be much smoother, but for me it is kinda difficult to understand how it works…:smiley:

Take your items and create probabilities that sum to 1 (weights).

A typical random choice can simply take a random value create an integer lookup index from it:


import random
import math

def choice(items):
    index = math.floor(random.random())
    return items[index]

This is equivalent to iterating over the elements, and summing the probability of each item being picked, until the probability is equal or greater to the choice.
For equally weighted items (e.g random.choice) the probability is 1/len(items) (e.g with four numbers, 1/4 chance of picking any one of them).

This can be thought of as lining up all the numbers left to right, and placing your finger somewhere along that line (a non-exact position) and seeing which number you’re covering.


import random

def choice(items):
    value = random.random()
    probability = 1 / len(items)

    sum = 0.0
    for item in items:
        sum += probability

        if sum > value:
            return item

If the probability changes per item (weight), then we determine the probability per item. This can be thought of as we did before with the number line, but this time we widen the numbers if they’re more likely to be chosen. This is the same as SmokingMirror’s “add extra numbers” option.



import random

def choice(items):
    value = random.random()

    sum = 0.0
    for probability, item in items:
        sum += probability

        if sum > value:
            return item

Now, we can reduce the work of this code by using a single variable


import random

def choice(items):
    value = random.random()

    for probability, item in items:
        value -= probability

        if value < 0.0:
            return item

your method, Smoking_mirror, works. At least I think so although currently there are so much preches also in trout area:D