mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-04-12 10:00:39 -04:00
260 lines
11 KiB
Markdown
260 lines
11 KiB
Markdown
---
|
||
id: 5e44414f903586ffb414c950
|
||
title: Калькулятор вірогідностей
|
||
challengeType: 23
|
||
forumTopicId: 462364
|
||
dashedName: probability-calculator
|
||
---
|
||
|
||
# --description--
|
||
|
||
Уявімо, що у капелюсі лежить 5 синіх, 4 червоні та 2 зелені кульки. Яка вірогідність того, що з 4 кульок, які ви витягнете, принаймні 1 буде червоною та 2 зеленими? І хоча можливо прорахувати вірогідність за допомогою вищої математики, легше буде написати програму для виконання великої кількості експериментів, щоб оцінити приблизну вірогідність.
|
||
|
||
У цьому проєкті напишіть програму, яка визначатиме вірогідність випадкового діставання певних кульок із капелюха.
|
||
|
||
Спочатку створіть клас `Hat` в `main.py`. Клас має приймати змінну кількість аргументів, які вказують кількість кульок всіх кольорів із капелюха. Наприклад, об’єкт класу можна створити такими способами:
|
||
|
||
```py
|
||
hat1 = Hat(yellow=3, blue=2, green=6)
|
||
hat2 = Hat(red=5, orange=4)
|
||
hat3 = Hat(red=5, orange=4, black=1, blue=0, pink=2, striped=9)
|
||
```
|
||
|
||
Капелюх завжди створюється з принаймні однією кулькою. Аргументи, які передаються в об’єкт-капелюх, під час створення мають конвертуватися в поле класу `contents`. `contents` має бути списком рядків, де один елемент дорівнює кожній кульці у капелюсі. Кожний елемент списку має бути назвою кольору, яка позначає кульку певного кольору. Наприклад, якщо капелюх `{"red": 2, "blue": 1}`, то `contents` має бути `["red", "red", "blue"]`.
|
||
|
||
Клас `Hat` повинен мати метод `draw`, який приймає аргумент з позначенням кількості кульок, які можна витягти з капелюха. Цей метод має випадково витягати кульки з `contents` та повертати ці кульки у вигляді списку рядків. Кульки не повинні повертатися до капелюха після того, як їх витягли (як в експерименті з урною без заміни). Якщо кількість кульок, які треба витягти, перевищує доступну кількість, поверніть усі кульки.
|
||
|
||
Потім створіть функцію `experiment` в `main.py` (не в класі `Hat`). Ця функція повинна приймати наступні аргументи:
|
||
|
||
- `hat`: об’єкт-капелюх з кульками, що потрібно скопіювати у функцію.
|
||
- `expected_balls`: об’єкт, який вказує на точну кількість кульок, які треба вийняти з капелюха для експерименту. Наприклад, щоб визначити вірогідність того, що ви витягнете 2 сині та 1 червону кульки з капелюха, встановіть `expected_balls` на `{"blue":2, "red":1}`.
|
||
- `num_balls_drawn`: кількість кульок, які треба витягти з капелюха в кожному експерименті.
|
||
- `num_experiments`: кількість експериментів, які треба провести. (Чим більше експериментів було проведено, тим точнішою буде вірогідність.)
|
||
|
||
Функція `experiment` повинна повертати вірогідність.
|
||
|
||
Допустимо, ви хочете визначити вірогідність витягти щонайменше дві червоні кульки та одну зелену, коли витягаєте п’ять кульок з капелюха, який містить шість чорних, чотири червоні та три зелені кульки. Для цього вам треба виконати `N` експериментів, порахувати скільки `M` разів ви можете витягти принаймні дві червоні кульки і одну зелену кульку та вирахувати вірогідність як `M/N`. Кожен експеримент складається з капелюха (з певними кульками), витягування декількох кульок та перевірки, чи ви витягли необхідні кульки.
|
||
|
||
Ось так ви можете викликати функцію `experiment`, базуючись на прикладі зверху з 2000 експериментами:
|
||
|
||
```py
|
||
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)
|
||
```
|
||
|
||
Результат буде приблизно таким:
|
||
|
||
```bash
|
||
>>> 0.356
|
||
```
|
||
|
||
Оскільки все базується на випадкових витяганнях, то вірогідність буде злегка відрізнятися з кожним новим запуском коду.
|
||
|
||
_Підказка: спробуйте використати вже імпортовані модулі зверху. Не ініціалізуйте випадкове початкове значення у файлі._
|
||
|
||
|
||
# --hints--
|
||
|
||
Створення об’єкта `hat` має додати правильний вміст.
|
||
|
||
```js
|
||
({
|
||
test: () => {
|
||
pyodide.FS.writeFile("/home/pyodide/probability_calculator.py", code);
|
||
pyodide.FS.writeFile(
|
||
"/home/pyodide/test_module.py",
|
||
`
|
||
import unittest
|
||
import probability_calculator
|
||
from importlib import reload
|
||
|
||
reload(probability_calculator)
|
||
|
||
probability_calculator.random.seed(95)
|
||
class UnitTests(unittest.TestCase):
|
||
maxDiff = None
|
||
def test_hat_class_contents(self):
|
||
hat = probability_calculator.Hat(red=3,blue=2)
|
||
actual = hat.contents
|
||
expected = ["red","red","red","blue","blue"]
|
||
self.assertEqual(actual, expected, 'Expected creation of hat object to add correct contents.')
|
||
`
|
||
);
|
||
const testCode = `
|
||
from unittest import main
|
||
import test_module
|
||
from importlib import reload
|
||
|
||
reload(test_module)
|
||
t = main(module='test_module', exit=False)
|
||
t.result.wasSuccessful()
|
||
`;
|
||
const out = __pyodide.runPython(testCode);
|
||
assert(out);
|
||
},
|
||
});
|
||
```
|
||
|
||
Метод `draw` у класі `hat` має зменшити кількість елементів у вмісті.
|
||
|
||
|
||
```js
|
||
({
|
||
test: () => {
|
||
pyodide.FS.writeFile("/home/pyodide/probability_calculator.py", code);
|
||
pyodide.FS.writeFile(
|
||
"/home/pyodide/test_module.py",
|
||
`
|
||
import unittest
|
||
import probability_calculator
|
||
from importlib import reload
|
||
|
||
reload(probability_calculator)
|
||
|
||
probability_calculator.random.seed(95)
|
||
def test_hat_draw(self):
|
||
hat = probability_calculator.Hat(red=5,blue=2)
|
||
actual = hat.draw(2)
|
||
expected = ['blue', 'red']
|
||
self.assertEqual(actual, expected, 'Expected hat draw to return two random items from hat contents.')
|
||
actual = len(hat.contents)
|
||
expected = 5
|
||
self.assertEqual(actual, expected, 'Expected hat draw to reduce number of items in contents.')
|
||
`
|
||
);
|
||
const testCode = `
|
||
from unittest import main
|
||
import test_module
|
||
from importlib import reload
|
||
|
||
reload(test_module)
|
||
t = main(module='test_module', exit=False)
|
||
t.result.wasSuccessful()
|
||
`;
|
||
const out = __pyodide.runPython(testCode);
|
||
assert(out);
|
||
},
|
||
});
|
||
```
|
||
|
||
Метод `experiment` має повернути іншу вірогідність.
|
||
|
||
|
||
```js
|
||
({
|
||
test: () => {
|
||
pyodide.FS.writeFile("/home/pyodide/probability_calculator.py", code);
|
||
pyodide.FS.writeFile(
|
||
"/home/pyodide/test_module.py",
|
||
`
|
||
import unittest
|
||
import probability_calculator
|
||
from importlib import reload
|
||
|
||
reload(probability_calculator)
|
||
|
||
probability_calculator.random.seed(95)
|
||
class UnitTests(unittest.TestCase):
|
||
maxDiff = None
|
||
def test_prob_experiment(self):
|
||
hat = probability_calculator.Hat(blue=3,red=2,green=6)
|
||
probability = probability_calculator.experiment(hat=hat, expected_balls={"blue":2,"green":1}, num_balls_drawn=4, num_experiments=1000)
|
||
actual = probability
|
||
expected = 0.272
|
||
self.assertAlmostEqual(actual, expected, delta = 0.01, msg = 'Expected experiment method to return a different probability.')
|
||
hat = probability_calculator.Hat(yellow=5,red=1,green=3,blue=9,test=1)
|
||
probability = probability_calculator.experiment(hat=hat, expected_balls={"yellow":2,"blue":3,"test":1}, num_balls_drawn=20, num_experiments=100)
|
||
actual = probability
|
||
expected = 1.0
|
||
self.assertAlmostEqual(actual, expected, delta = 0.01, msg = 'Expected experiment method to return a different probability.')
|
||
`
|
||
);
|
||
const testCode = `
|
||
from unittest import main
|
||
import test_module
|
||
from importlib import reload
|
||
|
||
reload(test_module)
|
||
t = main(module='test_module', exit=False)
|
||
t.result.wasSuccessful()
|
||
`;
|
||
const out = __pyodide.runPython(testCode);
|
||
assert(out);
|
||
},
|
||
});
|
||
```
|
||
|
||
# --seed--
|
||
|
||
## --seed-contents--
|
||
|
||
```py
|
||
import copy
|
||
import random
|
||
|
||
class Hat:
|
||
pass
|
||
|
||
def experiment(hat, expected_balls, num_balls_drawn, num_experiments):
|
||
pass
|
||
```
|
||
|
||
# --solutions--
|
||
|
||
```py
|
||
import copy
|
||
import random
|
||
|
||
class Hat:
|
||
def __init__(self, **hat):
|
||
self.hat = hat
|
||
contents = []
|
||
for i in hat:
|
||
for j in range(hat[i]):
|
||
contents.append(i)
|
||
self.contents = contents
|
||
|
||
|
||
def draw(self, number):
|
||
drawn = []
|
||
if number >= len(self.contents):
|
||
return self.contents
|
||
else:
|
||
for i in range(number):
|
||
drawn.append(
|
||
self.contents.pop(random.randrange(len(self.contents)))
|
||
)
|
||
return drawn
|
||
|
||
def experiment(hat, expected_balls, num_balls_drawn, num_experiments):
|
||
|
||
expected_balls_list = []
|
||
drawn_list = []
|
||
success = 0
|
||
for i in expected_balls:
|
||
for j in range(expected_balls[i]):
|
||
expected_balls_list.append(i)
|
||
for j in range(num_experiments):
|
||
hat_copy = copy.deepcopy(hat)
|
||
drawn_list.append(hat_copy.draw(num_balls_drawn))
|
||
exp_ball_list_copy = expected_balls_list[:]
|
||
for k in range(len(drawn_list[j])):
|
||
try:
|
||
ind = exp_ball_list_copy.index(drawn_list[j][k])
|
||
exp_ball_list_copy.pop(ind)
|
||
except:
|
||
continue
|
||
if len(exp_ball_list_copy) == 0:
|
||
success += 1
|
||
|
||
|
||
|
||
|
||
probability = success/num_experiments
|
||
|
||
return probability
|
||
```
|