{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": 1,
      "id": "a1b2c3d4-1111-4222-8333-944455556666",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Хоккей      \u03bb = 3.2 : 2.8   P(\u0444\u0430\u0432\u043e\u0440\u0438\u0442) = 56.4%   P(\u0430\u0443\u0442\u0441\u0430\u0439\u0434\u0435\u0440) = 43.6%   CV = 59.8%\n",
            "\u0411\u0430\u0441\u043a\u0435\u0442\u0431\u043e\u043b   \u03bb = 125.7 : 110.0   P(\u0444\u0430\u0432\u043e\u0440\u0438\u0442) = 84.7%   P(\u0430\u0443\u0442\u0441\u0430\u0439\u0434\u0435\u0440) = 15.3%   CV = 9.5%\n"
          ]
        }
      ],
      "source": [
        "import numpy as np\n",
        "from scipy.stats import poisson\n",
        "\n",
        "def match_probs(lam_fav, lam_dog, max_goals=250):\n",
        "    k = np.arange(max_goals)\n",
        "    p_fav = poisson.pmf(k, lam_fav)\n",
        "    p_dog = poisson.pmf(k, lam_dog)\n",
        "    joint = np.outer(p_fav, p_dog)       # joint[i, j] = P(\u0444\u0430\u0432\u043e\u0440\u0438\u0442=i, \u0430\u0443\u0442\u0441\u0430\u0439\u0434\u0435\u0440=j)\n",
        "    win = np.tril(joint, k=-1).sum()     # \u0444\u0430\u0432\u043e\u0440\u0438\u0442 \u0437\u0430\u0431\u0440\u043e\u0441\u0438\u043b \u0431\u043e\u043b\u044c\u0448\u0435\n",
        "    tie = np.trace(joint)\n",
        "    lose = np.triu(joint, k=1).sum()     # \u0430\u0443\u0442\u0441\u0430\u0439\u0434\u0435\u0440 \u0437\u0430\u0431\u0440\u043e\u0441\u0438\u043b \u0431\u043e\u043b\u044c\u0448\u0435\n",
        "    return win, tie, lose\n",
        "\n",
        "# \u0422\u043e\u0442 \u0436\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0440\u0430\u0437\u0440\u044b\u0432 \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 (8:7), \u0440\u0430\u0437\u043d\u044b\u0439 \u043c\u0430\u0441\u0448\u0442\u0430\u0431 \u0441\u0447\u0451\u0442\u0430\n",
        "lam_fav_h, lam_dog_h = 3.2, 2.8                      # \u0445\u043e\u043a\u043a\u0435\u0439: \u0448\u0430\u0439\u0431\u044b \u0437\u0430 \u043c\u0430\u0442\u0447\n",
        "lam_dog_b = 110.0\n",
        "lam_fav_b = lam_dog_b * (lam_fav_h / lam_dog_h)      # \u0431\u0430\u0441\u043a\u0435\u0442\u0431\u043e\u043b: \u043e\u0447\u043a\u0438 \u0437\u0430 \u043c\u0430\u0442\u0447\n",
        "\n",
        "for sport, lf, ld in [('\u0425\u043e\u043a\u043a\u0435\u0439', lam_fav_h, lam_dog_h),\n",
        "                       ('\u0411\u0430\u0441\u043a\u0435\u0442\u0431\u043e\u043b', lam_fav_b, lam_dog_b)]:\n",
        "    win, tie, lose = match_probs(lf, ld)\n",
        "    p_fav = win + tie / 2   # \u043d\u0438\u0447\u044c\u044f \u0441\u043d\u0438\u043c\u0430\u0435\u0442\u0441\u044f \u043e\u0432\u0435\u0440\u0442\u0430\u0439\u043c\u043e\u043c/\u0431\u0443\u043b\u043b\u0438\u0442\u0430\u043c\u0438 - \u043c\u043e\u043d\u0435\u0442\u043a\u043e\u0439\n",
        "    cv = ld ** 0.5 / ld     # \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0432\u0430\u0440\u0438\u0430\u0446\u0438\u0438 \u0441\u0447\u0451\u0442\u0430 \u0430\u0443\u0442\u0441\u0430\u0439\u0434\u0435\u0440\u0430\n",
        "    print(f'{sport:10s}  \u03bb = {lf:.1f} : {ld:.1f}   '\n",
        "          f'P(\u0444\u0430\u0432\u043e\u0440\u0438\u0442) = {p_fav:.1%}   P(\u0430\u0443\u0442\u0441\u0430\u0439\u0434\u0435\u0440) = {1 - p_fav:.1%}   '\n",
        "          f'CV = {cv:.1%}')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "id": "b2c3d4e5-2222-4333-8444-955566667777",
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Хоккей      MC P(\u0444\u0430\u0432\u043e\u0440\u0438\u0442, 1 \u043c\u0430\u0442\u0447) = 56.4%   P(\u0444\u0430\u0432\u043e\u0440\u0438\u0442, \u0441\u0435\u0440\u0438\u044f \u0434\u043e 4 \u043f\u043e\u0431\u0435\u0434) = 63.7%   P(\u0430\u0443\u0442\u0441\u0430\u0439\u0434\u0435\u0440, \u0441\u0435\u0440\u0438\u044f) = 36.3%\n",
            "\u0411\u0430\u0441\u043a\u0435\u0442\u0431\u043e\u043b   MC P(\u0444\u0430\u0432\u043e\u0440\u0438\u0442, 1 \u043c\u0430\u0442\u0447) = 84.8%   P(\u0444\u0430\u0432\u043e\u0440\u0438\u0442, \u0441\u0435\u0440\u0438\u044f \u0434\u043e 4 \u043f\u043e\u0431\u0435\u0434) = 98.7%   P(\u0430\u0443\u0442\u0441\u0430\u0439\u0434\u0435\u0440, \u0441\u0435\u0440\u0438\u044f) = 1.3%\n"
          ]
        }
      ],
      "source": [
        "import random, math\n",
        "from math import comb\n",
        "\n",
        "random.seed(42)\n",
        "\n",
        "def poisson_sample(lam):\n",
        "    L, k, p = math.exp(-lam), 0, 1.0\n",
        "    while True:\n",
        "        k += 1\n",
        "        p *= random.random()\n",
        "        if p <= L:\n",
        "            return k - 1\n",
        "\n",
        "def simulate(lam_fav, lam_dog, n=500_000):\n",
        "    fav_wins = ties = 0\n",
        "    for _ in range(n):\n",
        "        f, d = poisson_sample(lam_fav), poisson_sample(lam_dog)\n",
        "        if f > d:\n",
        "            fav_wins += 1\n",
        "        elif f == d:\n",
        "            ties += 1\n",
        "    return fav_wins / n, ties / n\n",
        "\n",
        "def series_win_prob(p, best_of=7):\n",
        "    need = best_of // 2 + 1\n",
        "    return sum(comb(need - 1 + l, l) * p**need * (1 - p)**l for l in range(need))\n",
        "\n",
        "for sport, lf, ld in [('\u0425\u043e\u043a\u043a\u0435\u0439', lam_fav_h, lam_dog_h),\n",
        "                       ('\u0411\u0430\u0441\u043a\u0435\u0442\u0431\u043e\u043b', lam_fav_b, lam_dog_b)]:\n",
        "    win, tie = simulate(lf, ld)\n",
        "    p_game = win + tie / 2\n",
        "    p_series = series_win_prob(p_game)\n",
        "    print(f'{sport:10s}  MC P(\u0444\u0430\u0432\u043e\u0440\u0438\u0442, 1 \u043c\u0430\u0442\u0447) = {p_game:.1%}   '\n",
        "          f'P(\u0444\u0430\u0432\u043e\u0440\u0438\u0442, \u0441\u0435\u0440\u0438\u044f \u0434\u043e 4 \u043f\u043e\u0431\u0435\u0434) = {p_series:.1%}   '\n",
        "          f'P(\u0430\u0443\u0442\u0441\u0430\u0439\u0434\u0435\u0440, \u0441\u0435\u0440\u0438\u044f) = {1 - p_series:.1%}')"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.2"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
