# Scientific Computing with Python Projects - Probability Calculator

Hello everybody, im working on the project “Probability Calculator” and I just can’t pass the third test. (“The experiment method should return a different probability”)
My calculations are near to what the probability of the example provided is, but not in the 0,1 range required, and i can’t figure out why.
My only guess is my 2 broad usages of pass and except, but those don’t seem to cause problems.

Here is my code on Replit: Probability Calculator - Replit

``````import copy
import random

class Hat:
contents = []

def __init__(self, **kwargs):

# convert input to contents
color_dict = {}
color_dict.update(**kwargs)

for color in color_dict.keys():
if color_dict.get(color) > 0:
count = 0
while count < color_dict.get(color):
count += 1
self.contents.append(color)

def draw(self, drawn_balls):
draw_number = 0
remove_list = []

# returning the randomly drawn balls and removing them from contents
if drawn_balls <= len(self.contents):
while draw_number < drawn_balls:
draw_number += 1
random_number = random.randrange(0, len(self.contents))
# print("random number:" + str(random_number))
# print(len(copy_contents))
remove_list.append(self.contents[random_number])
self.contents.pop(random_number)
return remove_list

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

run = 0
complete_success_counter = 0

# make copy of contents to restore original of contents (to return all the drawn balls)
copy_contents = copy.copy(from_hat.contents)

# return all the balls when the number of balls to draw exceeds the available quantity
while run <= num_experiments:
if len(from_hat.contents) < num_balls_drawn:
# print("not enough balls left, returning all the balls")
from_hat.contents.clear()
for count in copy_contents:
from_hat.contents.append(count)

# print(len(hat.contents))

run += 1

drawn_balls = from_hat.draw(num_balls_drawn)
drawn_balls_no_dupl = []

# remove duplicates (to not check colors multiple times)
for no_dupl in drawn_balls:
if no_dupl not in drawn_balls_no_dupl:
drawn_balls_no_dupl.append(no_dupl)

# count number of balls per color
draw_dict = {}

for color in drawn_balls:
try:
draw_dict[color] = draw_dict[color] + 1
except:
draw_dict[color] = 1

# print("expected balls: ")
# print(expected_balls)
# print(" ")
# print("drawn balls: ")
# print(draw_dict)
# print("---")

# count how many times expected and drawn balls match (per color)
success_counter = 0

for color in drawn_balls_no_dupl:
try:
if draw_dict[color] >= expected_balls[color]:
# print("Success: " + color)
success_counter += 1
except:
pass

# print("---")

# check if there is a match for all colors, and if so, add 1 to the complete success counter
if success_counter == len(expected_balls):
complete_success_counter += 1

# print(complete_success_counter)

# calculate probability and round it
probability = round(complete_success_counter / num_experiments, 3)

return probability
``````

User Agent is: `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36`

### Challenge Information:

Scientific Computing with Python Projects - Probability Calculator

open the browser console then run the tests, you have wrong parameter names

`TypeError: experiment() got an unexpected keyword argument 'hat'`

add the sample code and you will have the error in any environment that shows error (which is not yet the fcc editor)

``````hat = Hat(black=6, red=4, green=3)
probability = experiment(hat=hat,
expected_balls={"red":2,"green":1},
num_balls_drawn=5,
num_experiments=2000)
``````

Yes, sorry, i forgot to change the variable “from_hat” back to “hat” from when i was testing. I fixed it now.
But still, the issue stays the same.

I updated the code on Replit, but here it is (only class):

``````import copy
import random

class Hat:
contents = []

def __init__(self, **kwargs):

# convert input to contents
color_dict = {}
color_dict.update(**kwargs)

for color in color_dict.keys():
if color_dict.get(color) > 0:
count = 0
while count < color_dict.get(color):
count += 1
self.contents.append(color)

def draw(self, drawn_balls):
draw_number = 0
remove_list = []

# returning the randomly drawn balls and removing them from contents
if drawn_balls <= len(self.contents):
while draw_number < drawn_balls:
draw_number += 1
random_number = random.randrange(0, len(self.contents))
# print("random number:" + str(random_number))
# print(len(copy_contents))
remove_list.append(self.contents[random_number])
self.contents.pop(random_number)
return remove_list

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

run = 0
complete_success_counter = 0

# make copy of contents to restore original of contents (to return all the drawn balls)
copy_contents = copy.copy(hat.contents)

# return all the balls when the number of balls to draw exceeds the available quantity
while run <= num_experiments:
if len(hat.contents) < num_balls_drawn:
# print("not enough balls left, returning all the balls")
hat.contents.clear()
for count in copy_contents:
hat.contents.append(count)

# print(len(hat.contents))

run += 1

drawn_balls = hat.draw(num_balls_drawn)
drawn_balls_no_dupl = []

# remove duplicates (to not check colors multiple times)
for no_dupl in drawn_balls:
if no_dupl not in drawn_balls_no_dupl:
drawn_balls_no_dupl.append(no_dupl)

# count number of balls per color
draw_dict = {}

for color in drawn_balls:
try:
draw_dict[color] = draw_dict[color] + 1
except:
draw_dict[color] = 1

# print("expected balls: ")
# print(expected_balls)
# print(" ")
# print("drawn balls: ")
# print(draw_dict)
# print("---")

# count how many times expected and drawn balls match (per color)
success_counter = 0

for color in drawn_balls_no_dupl:
try:
if draw_dict[color] >= expected_balls[color]:
# print("Success: " + color)
success_counter += 1
except:
pass

# print("---")

# check if there is a match for all colors, and if so, add 1 to the complete success counter
if success_counter == len(expected_balls):
complete_success_counter += 1

# print(complete_success_counter)

# calculate probability and round it
probability = round(complete_success_counter / num_experiments, 3)

return probability
``````

There is an issue with the tests of this project, the resolution is not live yet but it will be soon. You are also failing this extra test:

Failed:The `draw` method should behave correctly when the number of ballsto extract is bigger than the number of balls in the hat.

Your function doesn’t work correctly when the balls to extract are more than the content of the hat

``````pyodide.asm.js:9 Traceback (most recent call last):
pyodide.asm.js:9   File "/home/pyodide/test_module.py", line 15, in test_hat_draw_2
pyodide.asm.js:9     self.assertEqual(actual, expected, 'Expected hat draw to return all items from hat contents.')
pyodide.asm.js:9 AssertionError: None != ['yellow', 'yellow', 'yellow', 'yellow', [118 chars]est'] : Expected hat draw to return all items from hat contents.
``````

Because the I already addressed the assignment “If the number of balls to draw exceeds the available quantity, return all the balls.” in line 45-51 of my previous code, I believe you’re talking about when “num_balls_drawn” in the call for the function experiment (e.g. print(experiment(hat=hat,
expected_balls={“red”: 2, “green”: 1},
num_balls_drawn=100000000,
num_experiments=2000))) is higher than the contents of the hat?

If so, i fixed this in the following code: (line 39-41)

``````import copy
import random

class Hat:
contents = []

def __init__(self, **kwargs):

# convert input to contents
color_dict = {}
color_dict.update(**kwargs)

for color in color_dict.keys():
if color_dict.get(color) > 0:
count = 0
while count < color_dict.get(color):
count += 1
self.contents.append(color)

def draw(self, drawn_balls):
draw_number = 0
remove_list = []

# returning the randomly drawn balls and removing them from contents
if drawn_balls <= len(self.contents):
while draw_number < drawn_balls:
draw_number += 1
random_number = random.randrange(0, len(self.contents))
# print("random number:" + str(random_number))
# print(len(copy_contents))
remove_list.append(self.contents[random_number])
self.contents.pop(random_number)
return remove_list

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

if num_balls_drawn > len(hat.contents):
print("Number of balls to draw is too high.")
exit()

run = 0
complete_success_counter = 0

# make copy of contents to restore original of contents (to return all the drawn balls)
copy_contents = copy.copy(hat.contents)

# return all the balls when the number of balls to draw exceeds the available quantity
while run <= num_experiments:
if len(hat.contents) < num_balls_drawn:
# print("not enough balls left, returning all the balls")
hat.contents.clear()
for count in copy_contents:
hat.contents.append(count)

# print(len(hat.contents))

run += 1

drawn_balls = hat.draw(num_balls_drawn)
drawn_balls_no_dupl = []

# remove duplicates (to not check colors multiple times)
for no_dupl in drawn_balls:
if no_dupl not in drawn_balls_no_dupl:
drawn_balls_no_dupl.append(no_dupl)

# count number of balls per color
draw_dict = {}

for color in drawn_balls:
try:
draw_dict[color] = draw_dict[color] + 1
except:
draw_dict[color] = 1

# print("expected balls: ")
# print(expected_balls)
# print(" ")
# print("drawn balls: ")
# print(draw_dict)
# print("---")

# count how many times expected and drawn balls match (per color)
success_counter = 0

for color in drawn_balls_no_dupl:
try:
if draw_dict[color] >= expected_balls[color]:
# print("Success: " + color)
success_counter += 1
except:
pass

# print("---")

# check if there is a match for all colors, and if so, add 1 to the complete success counter
if success_counter == len(expected_balls):
complete_success_counter += 1

# print(complete_success_counter)

# calculate probability and round it
probability = round(complete_success_counter / num_experiments, 3)

return probability
``````

Is this what you meant?

it’s still failing:

You are not satisfying this:

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

The test is finding `None` instead of the expected list.

(This is the development version of freeCodeCamp, it will be live soon)

I have updated the code, so that now the draw function itself reacts accordingly to too many balls being drawn. The test is still failing, and I have absolutely no idea why. If possible, could you look over the code and maybe tell me where my problem is? I’m out of ideas.

``````import copy
import random

class Hat:
contents = []
copy_contents = []

def __init__(self, **kwargs):

# convert input to contents
color_dict = {}
color_dict.update(**kwargs)

for color in color_dict.keys():
if color_dict.get(color) > 0:
count = 0
while count < color_dict.get(color):
count += 1
self.contents.append(color)

# make copy of contents to restore original of contents (to return all the drawn balls)
cc = copy.deepcopy(self.contents)
self.copy_contents = cc

def draw(self, drawn_balls):

if len(self.contents) < drawn_balls:
# print("not enough balls left, returning all the balls")
self.contents.clear()
for count in self.copy_contents:
self.contents.append(count)

if len(self.contents) < drawn_balls:
print("Too many balls drawn")
exit()

# print("COPY:")
# print(hat.copy_contents)
# print("OG:")
# print(hat.contents)

draw_number = 0
remove_list = []

# returning the randomly drawn balls and removing them from contents
if drawn_balls <= len(self.contents):
while draw_number < drawn_balls:
draw_number += 1
random_number = random.randrange(0, len(self.contents))
# print("random number:" + str(random_number))
# print(len(copy_contents))
remove_list.append(self.contents[random_number])
self.contents.pop(random_number)

return remove_list

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

run = 0
complete_success_counter = 0

# return all the balls when the number of balls to draw exceeds the available quantity
while run <= num_experiments:

run += 1

drawn_balls = hat.draw(num_balls_drawn)
drawn_balls_no_dupl = []

# remove duplicates (to not check colors multiple times)
for no_dupl in drawn_balls:
if no_dupl not in drawn_balls_no_dupl:
drawn_balls_no_dupl.append(no_dupl)

# count number of balls per color
draw_dict = {}

for color in drawn_balls:
try:
draw_dict[color] = draw_dict[color] + 1
except:
draw_dict[color] = 1

# print("expected balls: ")
# print(expected_balls)
# print(" ")
# print("drawn balls: ")
# print(draw_dict)
# print("---")

# count how many times expected and drawn balls match (per color)
success_counter = 0

for color in drawn_balls_no_dupl:
try:
if draw_dict[color] >= expected_balls[color]:
# print("Success: " + color)
success_counter += 1
except:
pass

# print("---")

# check if there is a match for all colors, and if so, add 1 to the complete success counter
if success_counter == len(expected_balls):
complete_success_counter += 1

# print(complete_success_counter)

# calculate probability and round it
probability = round(complete_success_counter / num_experiments, 3)

return probability`````````

now the fourth test I was talking about is live

what does your draw return in a situation like this?

``````hat = Hat(black=6, red=4, green=3)
hat.draw(20)
``````

because all I see is an error

This is what is being returned:

If the number of balls to draw exceeds the available balls, just like in your example, this string is being printed and the program exits.
That is exactly what i programmed it to do in line 35-37.
I don’t get an error.

How is that satisfying this?

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

Okay I misinterpreted the it. I’ve updated the code (line 47-51), and it works like intended, but I’m still failing the test, and I don’t know why.
Here’s the updated code:

``````import copy
import random

class Hat:
contents = []
copy_contents = []

def __init__(self, **kwargs):

# convert input to contents
color_dict = {}
color_dict.update(**kwargs)

for color in color_dict.keys():
if color_dict.get(color) > 0:
count = 0
while count < color_dict.get(color):
count += 1
self.contents.append(color)

# make copy of contents to restore original of contents (to return all the drawn balls)
cc = copy.deepcopy(self.contents)
self.copy_contents = cc

def draw(self, drawn_balls):

# print("COPY:")
# print(hat.copy_contents)
# print("OG:")
# print(hat.contents)

draw_number = 0
remove_list = []

# returning the randomly drawn balls and removing them from contents
while draw_number < drawn_balls:
# print(self.contents)
# print(len(remove_list))
draw_number += 1
random_number = random.randrange(0, len(self.contents))
# print("random number:" + str(random_number))
# print(len(copy_contents))
remove_list.append(self.contents[random_number])
self.contents.pop(random_number)

if len(self.contents) < 1:
# print("not enough balls left, returning all the balls")
self.contents.clear()
for count in self.copy_contents:
self.contents.append(count)

return remove_list

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

run = 0
complete_success_counter = 0

# return all the balls when the number of balls to draw exceeds the available quantity
while run <= num_experiments:

run += 1

drawn_balls = hat.draw(num_balls_drawn)
drawn_balls_no_dupl = []

# remove duplicates (to not check colors multiple times)
for no_dupl in drawn_balls:
if no_dupl not in drawn_balls_no_dupl:
drawn_balls_no_dupl.append(no_dupl)

# count number of balls per color
draw_dict = {}

for color in drawn_balls:
try:
draw_dict[color] = draw_dict[color] + 1
except:
draw_dict[color] = 1

# print("expected balls: ")
# print(expected_balls)
# print(" ")
# print("drawn balls: ")
# print(draw_dict)
# print("---")

# count how many times expected and drawn balls match (per color)
success_counter = 0

for color in drawn_balls_no_dupl:
try:
if draw_dict[color] >= expected_balls[color]:
# print("Success: " + color)
success_counter += 1
except:
pass

# print("---")

# check if there is a match for all colors, and if so, add 1 to the complete success counter
if success_counter == len(expected_balls):
complete_success_counter += 1

# print(complete_success_counter)

# calculate probability and round it
probability = round(complete_success_counter / num_experiments, 3)

return probability`````````

keep looking at the test output on your own

When there are more balls to draw than available balls you need to return the content of the hat as is, do not change the order