I’m down to my past project (Probability calculator). I couldn’t get pass the 2nd test, could you please help. I attached screenshot of Chrome console and it indicated some Assertion Errors. Could you please explain to me what those errors are ?

import copy
import random

class Hat:
def __init__(self, **kwargs):
self.contents = []
for color, num in kwargs.items():
for i in range (0,num):
self.contents.append(color)

def draw(self, num):
if num >= len(self.contents):
return self.contents
else:
for i in range(0,num):
self.contents.pop(random.randrange(len(self.contents)))
return self.contents

def experiment(hat, expected_balls, num_balls_drawn, num_experiments):

pass

I explained it to you in the other thread, about the assertion error.

Did you have a more specific question about it?

https://www.freecodecamp.org/learn/scientific-computing-with-python/build-a-probability-calculator-project/build-a-probability-calculator-project

You might not yet be at the point that you need to troubleshoot using the console. Sections of code are not implemented yet.

The draw method in hat class should reduce number of items in contents.

Use some print() statements in your code to print out your variables and see what the contents are to troubleshoot this.

newhat = Hat(yellow=3, blue=2, green=6)
print(newhat.contents)
newhat.draw(1)
print(newhat.contents)
['yellow', 'yellow', 'yellow', 'blue', 'blue', 'green', 'green', 'green', 'green', 'green', 'green']
['yellow', 'yellow', 'yellow', 'blue', 'green', 'green', 'green', 'green', 'green', 'green']

This does seem to work. I wouldn’t worry about it for now, and implement the next function first. Maybe the tests use the experiment function.

If the number of balls to draw exceeds the available quantity, return all the balls.

I’m questioning this instruction. Does it require the contents to be emptied? It doesn’t say so, but that seems like it would be the case. If you draw all the balls, they should all be removed from contents, right?

From the browser console:

FAIL: test_hat_draw_2 (test_module.UnitTests.test_hat_draw_2)
self.assertEqual(actual, expected, 'Expected hat draw to leave no items in contents.')
AssertionError: 19 != 0 : Expected hat draw to leave no items in contents.

Thanks for spending so much effort troubleshooting.
The instruction “draw should reduce number of balls in contents” — this is subject to interpretation. I think i did that. It’s just looping of this line :

self.contents.pop(random.randrange(len(self.contents)))

Believe me I did use print wherever I could on my laptop, but codes run on fcc shows no error messages.

I’m just 3 test away from getting certified. Would passing the 3rd test help with passing the 2nd one?

Confirmed, that does seem to work.

Maybe the test calls experiment() to run it’s test though, in which case draw() would never be called

thanks . How do I get through the 2nd test ?

@pkdvalis earlier gave you this

newhat = Hat(yellow=3, blue=2, green=6)
print(newhat.contents)
newhat.draw(1)
print(newhat.contents)

I would even try this to be more complete:

number_of_balls = 3+2+6
for i in range(1, number_of_balls +3):
newhat = Hat(yellow=3, blue=2, green=6)
print(newhat.contents)
newhat.draw(i)
print(newhat.contents)
print(f"Length of content after draw is {max(0, number_of_balls - i)}:", len(newhat.contents) == max(0, number_of_balls - i))

once this is always true, test 2 and 3 should be fine

did you mean getting through test 3 would make test 2 work too ?

no, but both test 2 and 3 are about the draw method working correctly

here is better

number_of_balls = 3+2+6
for i in range(1, number_of_balls +3):
newhat = Hat(yellow=3, blue=2, green=6)
print("hat before drawing", newhat.contents)
drawn = newhat.draw(i)
print("hat after drawing", newhat.contents)
print("drawn", drawn)
print(f"Length of content after draw is {max(0, number_of_balls - i)}:", len(newhat.contents) == max(0, number_of_balls - i))
print(f"Length of drawn array is {min(i, number_of_balls)}:", len(drawn) == min(i, number_of_balls))
print("\n\n\n")

Hi ilenia,

I spent quite a number of hours trying to refine and debug my code.
I printed and reprinted pretty much anything I could to verify my results.
I made use of copy.deepcopy to do the experiment instead of expected an “=” would copy the passed on “hat” obj.
I used random.randrange to randomly pop items
I used “count” (function of list class) to count the number of matches of “expected_balls” on “hat” the passed on obj.
I rounded off resulted probability to 2 decimal places

import copy
import random

class Hat:
def __init__(self, **kwargs):
self.contents = []
for color, num in kwargs.items():
for i in range (0,num):
self.contents.append(color)

def __str__(self):
return(str(self.contents))

def draw(self, num):
if num >= len(self.contents):
return self.contents
else:
for i in range(0,num):
self.contents.pop(random.randrange(len(self.contents)))
return self.contents

def experiment(hat, expected_balls, num_balls_drawn, num_experiments):
M = 0
expected_balls_list = [(key, value) for key, value in expected_balls.items()]
print("original balls :", hat)
print("drawn balls:", num_balls_drawn, "  expected_balls_list :", expected_balls_list)
for rep in range(0, num_experiments):
checked_expected_list = 0
experiment_hat = copy.deepcopy(hat)
drawn_balls_list = experiment_hat.draw(num_balls_drawn).copy()
for i in range(0,len(expected_balls_list)):
if expected_balls_list[i][1] <= drawn_balls_list.count(expected_balls_list[i][0]):
checked_expected_list += 1
print("Drawn balls :", experiment_hat , " lengh of expected_balls :", len(expected_balls_list))
print("checked_expected_list :", checked_expected_list)
if checked_expected_list == len(expected_balls_list):
M += 1
return round(M/num_experiments,2)

how is this returning the drawn balls?

it randomly removes “num” number of elements on the list “contents”

Tests:

hat2 = Hat(red=10, blue=10)
print(hat2)
print(hat2.draw(100))
print(hat2.draw(10))
print(hat2.draw(9))

results:

d:\py>py ran.py
['red', 'red', 'red', 'red', 'red', 'red', 'red', 'red', 'red', 'red', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue']
['red', 'red', 'red', 'red', 'red', 'red', 'red', 'red', 'red', 'red', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue']
['red', 'red', 'red', 'red', 'red', 'red', 'red', 'blue', 'blue', 'blue']
['red']

all variables are class objects, once modified they are changed forever. hat2.contents above originally has 20 elements, you can pop a few elements by running the class function of a list “pop” by using hat2.contents.pop(x)

this should return the nine drawn balls, it doesn’t.

and this should empty contents but it doesn’t

Thanks!
I changed the code and used random.sample(self.contents, num) instead to pick the specified number of balls to draw, and it returned “num” number of balls.

I also passed the 4th test “experiment” , but failed 2nd and 3rd

def draw(self, num):
if num >= len(self.contents):
return self.contents
else:
return random.sample(self.contents, num)

Inputs:

hat2 = Hat(red=10, blue=10, pink=2)
print("original: ", hat2)
print("draw more than orig: ",hat2.draw(100))
print("draw less than orig: ", hat2.draw(10))
print("draw less than orig: ", hat2.draw(9))
print("draw less than orig: ", hat2.draw(5))
print("draw less than orig: ", hat2.draw(6))

Results:

original:  ['red', 'red', 'red', 'red', 'red', 'red', 'red', 'red', 'red', 'red', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'pink', 'pink']
draw more than orig:  ['red', 'red', 'red', 'red', 'red', 'red', 'red', 'red', 'red', 'red', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'pink', 'pink']
draw less than orig:  ['red', 'red', 'pink', 'red', 'blue', 'red', 'blue', 'blue', 'blue', 'pink']
draw less than orig:  ['blue', 'red', 'blue', 'red', 'red', 'blue', 'red', 'blue', 'red']
draw less than orig:  ['blue', 'red', 'blue', 'blue', 'pink']
draw less than orig:  ['blue', 'red', 'red', 'red', 'red', 'blue']