Search code examples
python-3.xnumpyprobabilitycombinatorics

Remove elements while in a for loop


I have a simpel Card Game, which I am currently working on for my thesis. The Rules are simpel. You have a deck of 52 Cards, from 1 to 10 and jack, queen, knight. You draw a card from your Deck. If its a Number it gets added to your Account. If you draw a jack, queen or knight, your account gets reset to 0. After every draw you can decide if you want to draw again or stop.

For this game, i programmed a code with the help of this site. It should give the probability, that you draw exactly "target". So for example, the probability to draw, so that you have 1 Point in your account, is 4/52, since you have four 1´s. The Programm does give me exactly this value.

But. The probabiltity, that you have exactly 2 points in your account is 4/52 + 4/52*3/51. You can either draw a 2 with prob of 4/52 or a 1 and another 1 with prob 4/52*3/51. Here the code messes up. It calculates the probability to have exactly 2 points in your account as 4/52 + 4/52*4/51 and i dont get why?

Can anyone help me?

 import collections
 import numpy as np


def probability(n, s, target):
    prev = {0: 1}  # previous roll is 0 for first time
    for q in range(n):
        cur = collections.defaultdict(int)  # current probability
        for r, times in prev.items():
            cards = [card for card in range(1, 11)] * 4
            for i in cards[:]:
                cards.remove(i)
                # if r occurred `times` times in the last iteration then
                # r+i have `times` more possibilities for the current iteration.
                cur[r + i] += times
        prev = cur  # use this for the next iteration
    return (cur[t]*np.math.factorial(s-n)) / (np.math.factorial(s))


if __name__ == '__main__':
    s = 52
    for target in range(1, 151):
        prob = 0

        for n in range(1, 52):
            prob += probability(n, s, target)
        print(prob)

EDIT: I am fairly sure, that the line

for i in [i for i in cards]:

is the problem. Since cards.remove(i) removes the drawn card, but i doesnt care and can draw it anyway.

EDIT 2: Still searching. I tried the suggestions in this two qestions

How to remove list elements in a for loop in Python?

and

How to remove items from a list while iterating?

Nothing worked so far as it should.


Solution

  • I have solved it. After like a 4 Days.

    This is the Code:

    import numpy as np
    
    
    def probability(cards, target, with_replacement = False):
        x = 0 if with_replacement else 1
    
        def _a(idx, l, r, t):
            if t == sum(l):
                r.append(l)
            elif t < sum(l):
                return
            for u in range(idx, len(cards)):
                _a(u + x, l + [cards[u]], r, t)
            return r
        return _a(0, [], [], target)
    
    
    if __name__ == '__main__':
        s = 52  # amount of cards in your deck
        cards = [c for c in range(1, 11)] * 4
        prob = 0
        for target in range(1, 151):  # run till 150 points
            prob = probability(cards, target, with_replacement = False)
            percentage = 0
            for i in range(len(prob)):
                percentage += np.math.factorial(len(prob[i])) * np.math.factorial(s-len(prob[i]))/(np.math.factorial(s))
            print(percentage)
    

    This Code is the Solution to my Question. Therefore this Thread can be closed. For those who want to know, what it does as a tl;dr version.

    You have a List (in this case Cards). The Code gives you every possible Combination of Elements in the List such as the Sum over the elements equals the target Value. Furthermore it also gives the Probability in the above mentioned Cardgame to draw a specific Value. The above mentioned game is basically the pig dice game but with cards.