# Help with prob calc

Hey guys, I have some problems with my code. I’m getting traceback with about 0.01 to 0.06 difference in test_module. Can some1 check code and maybe spot where I did mistake? Would be grateful . Here is my code:

``````import random

class Hat:

def __init__(self, **kwargs):
self.balls = dict()
for key, value in kwargs.items():
self.balls[key] = value
self.ball_list = list()
self.contents = list()
for key, value in self.balls.items():
self.ball_count = value * (key,)
self.ball_list.append(self.ball_count)
for x in self.ball_list:
for y in x:
self.contents.append(y)

def draw(self, draw_number):
self.draw_number = draw_number
self.drawn_balls = list()
count = len(self.contents)
for i in range(self.draw_number):
self.ball = random.randint(0, len(self.contents)-1)
self.drawn_balls.append(self.contents[self.ball])
del self.contents[self.ball]
count -= 1
if count == 0:
for x in self.ball_list:
for y in x:
self.contents.append(y)
count = len(self.contents)
continue
return self.drawn_balls

def experiment(hat, expected_balls, num_balls_drawn, num_experiments):
count_matching_balls = 0
balls_drawn = dict()
count = num_experiments
while count > 0:
Hat.draw(hat, num_balls_drawn)
for x in hat.drawn_balls:
if x in balls_drawn.keys():
balls_drawn[x] += 1
else:
balls_drawn[x] = 1
if check_balls(expected_balls, balls_drawn) is None:
count_matching_balls += 1
balls_drawn.clear()
count -= 1
if count_matching_balls == 0:
percentage = 0
else:
percentage = count_matching_balls/num_experiments
print(percentage)

def check_balls(a, b):
results = list()
final_result = list()
for x in a.keys():
if x in b.keys():
match = a[x] - b[x]
if match > 0:
results.append("False")
else:
results.append("True")
else:
return False
for x in results:
if x == "False":
final_result.append("False")
for x in final_result:
if x == "False":
return False
``````

also here is pic of traceback:

There are two things. First:

This kills the testing from the console. You have to return the value or the tests will fail.

Second is in `draw()`, here:

The test you attached the error for is placing 19 balls in the hat and drawing out 20, and making sure that matches a subset of the balls in the hat so that the probability must be 1. When you try to rebuild your hat at the end of a draw (pulling 20 from 19 here), `count` will get to 0 and trigger the resulting code, which leads to the single `test` item not getting pulled from the hat a small amount of the time, and hence, test failure. You can see it in action if you modify `experiment()` like this:

``````        if check_balls(expected_balls, balls_drawn) is None:
count_matching_balls += 1
else:
print(hat.drawn_balls)
print(balls_drawn)
print(expected_balls)
``````

You should see around 7 sets of lines with `test` absent from the drawn balls set.

2 Likes

Hey, I rewrote my draw method it passed my tests and I’m done now . Just want to ask you to check second part “elif”. I’m not sure that It is correct. If number of balls that will be drawn from hat is lower than number of items in hat. For example:
hat : yellow = 2, blue = 3
number of balls to be drawn = 2
number of experiments = 3
When my method pulls 2 times, number of remaining balls in hat is 1, do I have to return that ball to picked balls and then rebuild Hat, or just delete that 1 ball and rebuild. Btw thanks for your help mate!
here is my new code that passed tests and my second code for you to understand my question.

Final code that passed test:

``````    def draw(self, draw_number):
self.draw_number = draw_number
self.drawn_balls = list()
count = len(self.contents)
if count < draw_number:
self.drawn_balls.extend(self.contents)
self.contents.clear()
for x in self.ball_list:
for y in x:
self.contents.append(y)
continue
elif count > draw_number:
for i in range(self.draw_number):   # 20
self.ball = random.randint(0, len(self.contents)-1)
self.drawn_balls.append(self.contents[self.ball])
del self.contents[self.ball]
count -= 1
if count < draw_number:
self.contents.clear()
for x in self.ball_list:
for y in x:
self.contents.append(y)
count = len(self.contents)
continue
return self.drawn_balls
``````

code that I think is correct:

``````    def draw(self, draw_number):
self.draw_number = draw_number
self.drawn_balls = list()
count = len(self.contents)
if count < draw_number:
self.drawn_balls.extend(self.contents)
self.contents.clear()
for x in self.ball_list:
for y in x:
self.contents.append(y)
continue
elif count > draw_number:
for i in range(self.draw_number):   # 20
self.ball = random.randint(0, len(self.contents)-1)
self.drawn_balls.append(self.contents[self.ball])
del self.contents[self.ball]
count -= 1
if count == 0:
self.contents.clear()
for x in self.ball_list:
for y in x:
self.contents.append(y)
count = len(self.contents)
continue
return self.drawn_balls
``````

Well, the important thing is passing the test. If your customer finds a problem now, they need to write a new test to make the code fail, which should be more billable hours for you.

But in general, changing the hat during an experiment can lead to errors that are more subtle than the ones that are tested now. I believe the typical solution in this situation would return all the balls if more were requested than available, so that the user of the `draw()` method was responsible for interpretation of results for their experiment. The workaround to depleting the hat was the hint in the project to use the `copy` module and just start with a new hat on each experiment.

1 Like

Nevermind I’m stupid haha, just figured put that hat is reseted after 2 balls are pulled…

Yes haha! Thats is what I was thinking about thanks a lot mate for help!

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.