Нашли ошибку?
Скачать чистый
мини-проект≈ 20 минупражнения: 0 из 4

Мини-проект: кости и игра

Проверить, честный ли кубик, найти самую частую сумму трёх кубиков, посчитать точную вероятность перебором всех исходов и выяснить, выгодна ли игра «15 и больше».

Python запустится при первом выполнении

В парке аттракционов предлагают игру: билет стоит 10 ₽, вы бросаете три кубика, и если сумма 15 или больше — получаете 100 ₽. Стоит ли играть? Ответим двумя способами — моделированием и точным перебором — и сравним.

Шаг 1. Честный ли кубик

Если кубик честный, каждая грань выпадает в среднем в 1/6 бросков. При 60 000 бросков — около 10 000 раз, но не ровно: случайность даёт небольшой разброс.

[ ]Упражнение 160 000 бросков решено

Создайте генератор с seed 7, сделайте 60 000 бросков кубика и сохраните в faces число выпадений каждой грани 1–6, а в worst_gap — наибольшее отклонение от ожидаемых 10 000 в большую сторону.

import numpy as np

faces = ...
worst_gap = ...

Отклонение около 150 из 10 000 — полтора процента. Много это или мало? Теория вероятностей говорит, что у честного кубика при 60 000 бросков число выпадений грани обычно отличается от 10 000 примерно на 90 в ту или другую сторону. 153 — в пределах обычного разброса; насторожиться стоило бы, если бы отклонение было в 3–4 раза больше типичного. Строгая проверка честности — критерий хи-квадрат, он за рамками курса.

Пояснение с ответом появится, когда решите упражнение «60 000 бросков».

Шаг 2. Три кубика

[ ]Упражнение 2Самая частая сумма решено

Создайте генератор с seed 9, смоделируйте 20 000 бросков трёх кубиков (таблица 20 000 × 3) и сохраните в sums3 сумму каждого броска, а в common_sum — сумму, которая выпадала чаще всего.

sums3 = ...
common_sum = ...

Шаг 3. Точный перебор

У трёх кубиков всего 6 × 6 × 6 = 216 равновероятных исходов — их можно перебрать без случайности. В модуле о транслировании таблица всех пар получалась из столбца и строки. Для троек нужна третья ось — трёхмерный массив формы (6, 6, 6). Его удобно представлять стопкой из шести таблиц 6 × 6: all_sums[i] — таблица для случая, когда на первом кубике i + 1, а all_sums[i, j, k] — сумма (i + 1) + (j + 1) + (k + 1).

Грани первого кубика кладём по оси 0, второго — по оси 1, третьего — по оси 2. np.newaxis можно ставить на любое место: он добавляет ось длины 1 именно там. А (6,) по первому правилу транслирования дополняется единицами слева до (1, 1, 6). Сумма трёх массивов растягивается до (6, 6, 6) — все 216 сумм:

[ ]Все 216 исходов
face = np.arange(1, 7)
first = face[:, np.newaxis, np.newaxis]     # (6, 1, 1): грани первого кубика — по оси 0
second = face[np.newaxis, :, np.newaxis]    # (1, 6, 1): второго — по оси 1
third = face                                # (6,) — это как (1, 1, 6): третьего — по оси 2
print(first.shape, second.shape, third.shape)
all_sums = first + second + third
print(all_sums.shape, all_sums.size)
print(all_sums[0])          # таблица 6 × 6: на первом кубике 1, строки — второй кубик, столбцы — третий
print(all_sums[2, 3, 4])    # 3 + 4 + 5
print(np.bincount(all_sums.ravel())[3:])    # сколько исходов дают сумму 3, 4, …, 18
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
(6, 1, 1) (1, 6, 1) (6,)
(6, 6, 6) 216
[[ 3  4  5  6  7  8]
 [ 4  5  6  7  8  9]
 [ 5  6  7  8  9 10]
 [ 6  7  8  9 10 11]
 [ 7  8  9 10 11 12]
 [ 8  9 10 11 12 13]]
12
[ 1  3  6 10 15 21 25 27 27 25 21 15 10  6  3  1]

Последняя строка — сколько исходов даёт каждую сумму от 3 до 18. У сумм 10 и 11 — поровну, по 27: они равновероятны. В моделировании из шага 2 десятка обогнала одиннадцать случайно (2550 против 2511); с другим seed победить могла и 11.

[ ]Упражнение 3Точная вероятность суммы 10 решено

Сохраните в p10 точную вероятность выбросить на трёх кубиках ровно 10 — долю исходов в all_sums, где сумма равна 10. А в sim_p10 — ту же вероятность по моделированию из шага 2.

p10 = ...
sim_p10 = ...

Шаг 4. Выгодна ли игра

Средний выигрыш за игру — вероятность выигрыша × 100 ₽ минус цена билета 10 ₽. Если он отрицательный, в среднем игра приносит убыток.

[ ]Упражнение 4Средний результат одной игры решено

Сохраните в win_p точную вероятность получить 15 или больше (по all_sums), в expected — средний результат одной игры в рублях по точной вероятности, а в sim_expected — то же по моделированию из шага 2.

win_p = ...
expected = ...
sim_expected = ...

Выводы

[ ]Итоги
print("выигрышных исходов:", (all_sums >= 15).sum(), "из", all_sums.size)
print("точно:", round(win_p, 4), "→ средний результат", round(expected, 2), "₽")
print("моделирование:", round((sums3 >= 15).mean(), 4), "→", round(sim_expected, 2), "₽")
Выводсохранённый · нажмите «Выполнить», чтобы получить свой
выигрышных исходов: 20 из 216
точно: 0.0926 → средний результат -0.74 ₽
моделирование: 0.0933 → -0.67 ₽
Итог появится, когда решите все упражнения урока, — в нём ответы. Ячейку можно и выполнить.

Выигрышных исходов 20 из 216 — чуть больше 9 %. В среднем каждая игра приносит игроку −0.74 ₽: аттракцион в выигрыше. Моделирование дало близкий ответ (−0.67 ₽) — за доли секунды и без единой формулы. Для трёх кубиков можно перебрать всё, а для задач, где исходов миллиарды, моделирование часто оказывается единственным быстрым способом.

Выводы с ответами появятся, когда решите все упражнения урока.

Подробнее в справочнике

Практика по модулю

Задачи по NumPy для самостоятельной практики появятся в разделе «Задачи → NumPy».

Нашли ошибку?