-1

I am attempting to create a randomly generated "perks assignment" from MMO games or games of the like.

The rules are as follows:

  • Has to have 5 in one container and can only have 1 container with 5
  • All 20 points have to be distributed
  • Points have to be distributed by RNG (using random)

So far, all we have is this:

import random

# Variables
cont = [0, 0, 0, 0, 0]
items = 20
maxNum = 5

# Start our first loop
i = 0
while items != 0:
    i = 0
    while i < len(cont) - 1:
        num1 = random.randint(3, maxNum)
        if items < 5:
            if cont[i] = 00:
                cont[i] += items
                items = 0
                break
        cont[i] = num1
        if cont[i] == 5:
            maxNum = 4
        i += 1
        items = items - num1

    print(items)

print(cont)

This ends up working sometimes, but other times it will get stuck in the loop and will not work.

The way this code can be correct is that every time it outputs, it will print:

  • [5,4,4,4,3]
  • [4,4,4,4,4]
  • [5,4,3,4,4]
  • etc.

Please help me solve why it gets stuck in the loop sometimes! Thank you!

  • 2
    You say it works "sometimes". That points to the fact that the random statement is sometimes generating a number that is causing the error. Try printing 'num1' each time it generates and see if the loop always fails from the same number(s). Edit the results into your answer if you didn't solve it yourself. – Tom Burrows Feb 15 '17 at 16:07
  • And what do you mean by the loop "gets stuck"? Does it crash? If so, post the full error trace back. – Tom Burrows Feb 15 '17 at 16:09
  • @Gloin we have done that and it ends up that it is creating a number larger that items and subtracting bigger numbers and causing it to go into the negatives and repeat infinitely. – Blake Bowling Feb 15 '17 at 16:10
  • Why do you assign cont[i] = items, then cont[i] = num1? The first statement is always overwritten by the second – Tom Burrows Feb 15 '17 at 16:13
  • I don't see how this code would 'sometimes' work. The current snippet just prints 20 on each line without end. – Bas Jansen Feb 15 '17 at 16:14
  • You should move the i+=1 down a line to fix the thing Bas Jansen said – Tom Burrows Feb 15 '17 at 16:16
  • I also suggest you look at http://stackoverflow.com/questions/3589214/generate-multiple-random-numbers-to-equal-a-value-in-python – Bas Jansen Feb 15 '17 at 16:17
  • @BasJansen, sorry updated code to most recently working – Blake Bowling Feb 15 '17 at 16:21

2 Answers2

1

It's sometimes getting stuck in the loop since your code can generate a case where all 5 stats have been assigned but items is still not 0.

e.g., if it keeps assigning 3 to every item in the list, then we'll end up with const = [3,3,3,3,3] and yet items = 5. Even in the case const = [5,4,4,4,0] and we roll a 4 on the random number, even though you catch the case that items < 5 and so to dump the remaining value into the last stat, the changes get overwritten on the next line where yo uset cont[i] = num1 anyway.

So, first of all, the assignment of cont[i] = num1 needs to be in an else statement. Also, the way I'm reading this the only possibilities are either all values are 4, or one value is 5, one value is 3 and the rest are all 4. You're catching the case that there can only be one 5, but inversely there can also only be one 3, as otherwise it can't all add up to 20. So add a catch for minNum like you did for maxNum. Also, you don't really need the outer loop, as our logic now ensures that the final value is 20. The items < 5 check also needs to be items <= 5 so to allow for the dumping of 5 into the final value. I've tried it myself and it seems to be working.

Final result:

import random

# Variables
cont = [0, 0, 0, 0, 0]
items = 20
maxNum = 5
minNum = 3

# Start our first loop
i = 0
while i < len(cont):
    num1 = random.randint(minNum, maxNum)
    if items <= 5:
        cont[i] = items
    else:
        cont[i] = num1
    if cont[i] == 5:
        maxNum = 4
    if cont[i] == 3:
        minNum = 4
    items -= cont[i]
    i += 1

print(cont)

I didn't try and create a more efficient answer for you and instead focused on correcting your existing attempt at a solution :)

Louise Davies
  • 14,781
  • 6
  • 38
  • 41
0

It will be easier to just randomly allocate the maximum number of points into one container at the beginning, and then fill the rest afterwards.

from random import randint 

def assign(num_containers, container_max, max_points):
    containers = [0]*num_containers
    full_container = randint(0, num_containers-1)
    containers[full_container] = container_max
    assigned = container_max

    while assigned < max_points:
       cont = randint(0, num_containers-1)
           if cont is not full_container and containers[cont] < container_max - 1:
               containers[cont] += 1
               assigned += 1

   return containers
degraafc
  • 56
  • 4