Last active
September 23, 2022 13:53
-
-
Save reireias/bb56dbb87432e1641ac4e95943c07f61 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"id": "c0d3da22-2463-4ca1-aa30-f2a4a201a5fe", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# Elo Rating\n", | |
"# 勝敗は実力に応じて確率的に\n", | |
"# レート差マッチング禁止\n", | |
"# マッチング前にRateでGROUPS個のグループに分け、そのグループ内でマッチング\n", | |
"\n", | |
"import random\n", | |
"import numpy\n", | |
"import matplotlib.pyplot as plt\n", | |
"import re\n", | |
"\n", | |
"USERS = 256\n", | |
"TEAM_MEMBER = 4\n", | |
"GAMES = 100 # 1人の試合数\n", | |
"ELO_K = 32\n", | |
"P = 0.8\n", | |
"GROUPS = 4 # USERS / GROUP は TEAM_MEMBER の 2n倍である必要がる\n", | |
"X = 16 # sim6でのマッチング範囲\n", | |
"\n", | |
"def elo(ra, rb, k=ELO_K):\n", | |
" ea = 1.0 / (1 + 10**((rb-ra)/400)) # Aが勝つ確率\n", | |
" # eb = 1.0 / (1 + 10**((ra-rb)/400))\n", | |
" nra = ra + k * (1-ea)\n", | |
" nrb = rb - k * (1-ea)\n", | |
" return [nra, nrb]\n", | |
"\n", | |
"def simulate_near(p=P):\n", | |
" users = [{ 'id': i, 'result': '', 'win': 0, 'lose': 0, 'rate': 1500, 'skill': random.random(), 'order': '' } for i in range(USERS)]\n", | |
" for _ in range(GAMES * USERS // TEAM_MEMBER // 2):\n", | |
" rate = random.choice(users)['rate']\n", | |
" near_users = []\n", | |
" x = 0\n", | |
" while len(near_users) < 2 * TEAM_MEMBER:\n", | |
" x += X\n", | |
" near_users = [user for user in users if rate-x <= user['rate'] <= rate+x]\n", | |
" target = [user['id'] for user in random.sample(near_users, 8)]\n", | |
" team_a = target[0 : TEAM_MEMBER]\n", | |
" team_b = target[TEAM_MEMBER :]\n", | |
" \n", | |
" # rateの降順にソート\n", | |
" team_a.sort(key = lambda x: users[x]['rate'], reverse=True)\n", | |
" team_b.sort(key = lambda x: users[x]['rate'], reverse=True)\n", | |
" # チーム内のrate順で何番目かを記録\n", | |
" for j in range(TEAM_MEMBER):\n", | |
" users[team_a[j]]['order'] += str(j)\n", | |
" users[team_b[j]]['order'] += str(j)\n", | |
" rate_a = numpy.average([users[id]['rate'] for id in team_a])\n", | |
" rate_b = numpy.average([users[id]['rate'] for id in team_b])\n", | |
"\n", | |
" skill_a = sum([users[id]['skill'] for id in team_a])\n", | |
" skill_b = sum([users[id]['skill'] for id in team_b])\n", | |
"\n", | |
" # Aが勝つ確率 win_a を算出\n", | |
" if isinstance(p, float) or isinstance(p, int):\n", | |
" # p が数値の場合\n", | |
" win_a = p if skill_a >= skill_b else 1 - p\n", | |
" else:\n", | |
" # p が関数の場合\n", | |
" win_a = p(skill_a - skill_b)\n", | |
"\n", | |
" # ダイスを降って勝利判定\n", | |
" dice = random.random()\n", | |
" if (dice <= win_a):\n", | |
" winner, winner_rate, loser, loser_rate = team_a, rate_a, team_b, rate_b\n", | |
" else:\n", | |
" winner, winner_rate, loser, loser_rate = team_b, rate_b, team_a, rate_a\n", | |
"\n", | |
" for id in winner:\n", | |
" users[id]['win'] += 1\n", | |
" users[id]['result'] += 'w'\n", | |
" nr = elo(users[id]['rate'], loser_rate)\n", | |
" users[id]['rate'] = nr[0]\n", | |
" for id in loser:\n", | |
" users[id]['lose'] += 1\n", | |
" users[id]['result'] += 'l'\n", | |
" nr = elo(winner_rate, users[id]['rate'])\n", | |
" users[id]['rate'] = nr[1]\n", | |
" \n", | |
" # 連勝->連敗 を懲罰マッチとみなした場合\n", | |
" count_a = [0, 0, 0] # 5連続, 6連続, 7連続\n", | |
" # 連勝->味方が低レート を懲罰マッチとみなした場合\n", | |
" count_b = [0, 0, 0] # 5連続, 6連続, 7連続\n", | |
" for user in users:\n", | |
" count_a[0] += user['result'].count('wwwwwlllll')\n", | |
" count_a[1] += user['result'].count('wwwwwwllllll')\n", | |
" count_a[2] += user['result'].count('wwwwwwwlllllll')\n", | |
" s = ''\n", | |
" for i in range(len(user['result'])):\n", | |
" s += user['result'][i] + user['order'][i]\n", | |
" \n", | |
" count_b[0] += len(re.findall('w.w.w.w.w..0.0.0.0.0', s))\n", | |
" count_b[1] += len(re.findall('w.w.w.w.w.w..0.0.0.0.0.0', s))\n", | |
" count_b[2] += len(re.findall('w.w.w.w.w.w.w..0.0.0.0.0.0.0', s))\n", | |
" return [count_a, count_b]\n", | |
"\n", | |
"def simulate(groups=GROUPS, p=P):\n", | |
" users = [{ 'id': i, 'result': '', 'win': 0, 'lose': 0, 'rate': 1500, 'skill': random.random(), 'order': '' } for i in range(USERS)]\n", | |
" \n", | |
" for _ in range(GAMES):\n", | |
" ids = list(range(USERS))\n", | |
" ids.sort(key = lambda x: users[x]['rate'])\n", | |
" group_list = []\n", | |
" users_in_group = USERS // groups\n", | |
" for g in range(groups):\n", | |
" group_list.append(ids[g * users_in_group : (g+1) * users_in_group])\n", | |
" for group in group_list:\n", | |
" ids = group\n", | |
" random.shuffle(ids)\n", | |
" for i in range(len(group) // (TEAM_MEMBER * 2)):\n", | |
" team_a = ids[TEAM_MEMBER * 2 * i : TEAM_MEMBER * (2*i + 1)]\n", | |
" team_b = ids[TEAM_MEMBER * (2*i+1) : TEAM_MEMBER * 2*(i+1)]\n", | |
" # rateの降順にソート\n", | |
" team_a.sort(key = lambda x: users[x]['rate'], reverse=True)\n", | |
" team_b.sort(key = lambda x: users[x]['rate'], reverse=True)\n", | |
" # チーム内のrate順で何番目かを記録\n", | |
" for j in range(TEAM_MEMBER):\n", | |
" users[team_a[j]]['order'] += str(j)\n", | |
" users[team_b[j]]['order'] += str(j)\n", | |
" rate_a = numpy.average([users[id]['rate'] for id in team_a])\n", | |
" rate_b = numpy.average([users[id]['rate'] for id in team_b])\n", | |
" \n", | |
" skill_a = sum([users[id]['skill'] for id in team_a])\n", | |
" skill_b = sum([users[id]['skill'] for id in team_b])\n", | |
" \n", | |
" # Aが勝つ確率 win_a を算出\n", | |
" if isinstance(p, float) or isinstance(p, int):\n", | |
" # p が数値の場合\n", | |
" win_a = p if skill_a >= skill_b else 1 - p\n", | |
" else:\n", | |
" # p が関数の場合\n", | |
" win_a = p(skill_a - skill_b)\n", | |
" \n", | |
" # ダイスを降って勝利判定\n", | |
" dice = random.random()\n", | |
" if (dice <= win_a):\n", | |
" winner, winner_rate, loser, loser_rate = team_a, rate_a, team_b, rate_b\n", | |
" else:\n", | |
" winner, winner_rate, loser, loser_rate = team_b, rate_b, team_a, rate_a\n", | |
"\n", | |
" for id in winner:\n", | |
" users[id]['win'] += 1\n", | |
" users[id]['result'] += 'w'\n", | |
" nr = elo(users[id]['rate'], loser_rate)\n", | |
" users[id]['rate'] = nr[0]\n", | |
" for id in loser:\n", | |
" users[id]['lose'] += 1\n", | |
" users[id]['result'] += 'l'\n", | |
" nr = elo(winner_rate, users[id]['rate'])\n", | |
" users[id]['rate'] = nr[1]\n", | |
"\n", | |
" # high_skill = [user['rate'] for user in users if user['skill'] < 0.5]\n", | |
" # low_skill = [user['rate'] for user in users if user['skill'] >= 0.5]\n", | |
" # plt.hist([high_skill, low_skill], stacked=True)\n", | |
"\n", | |
" # 連勝->連敗 を懲罰マッチとみなした場合\n", | |
" count_a = [0, 0, 0] # 5連続, 6連続, 7連続\n", | |
" # 連勝->味方が低レート を懲罰マッチとみなした場合\n", | |
" count_b = [0, 0, 0] # 5連続, 6連続, 7連続\n", | |
" for user in users:\n", | |
" count_a[0] += user['result'].count('wwwwwlllll')\n", | |
" count_a[1] += user['result'].count('wwwwwwllllll')\n", | |
" count_a[2] += user['result'].count('wwwwwwwlllllll')\n", | |
" s = ''\n", | |
" for i in range(GAMES):\n", | |
" s += user['result'][i] + user['order'][i]\n", | |
" \n", | |
" count_b[0] += len(re.findall('w.w.w.w.w..0.0.0.0.0', s))\n", | |
" count_b[1] += len(re.findall('w.w.w.w.w.w..0.0.0.0.0.0', s))\n", | |
" count_b[2] += len(re.findall('w.w.w.w.w.w.w..0.0.0.0.0.0.0', s))\n", | |
" return [count_a, count_b]" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"id": "dec55cda-3ccc-4f4e-9510-6ed17e195c1a", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"NAME = ['定義A', '定義B']\n", | |
"\n", | |
"def sim_average_near(times=100, p=P):\n", | |
" print('| | 5連続 | 6連続 | 7連続 |')\n", | |
" print('|--|--:|--:|--:|')\n", | |
" results = []\n", | |
" for i in range(times):\n", | |
" results.append(simulate_near(p=p))\n", | |
" for i in range(2):\n", | |
" row = []\n", | |
" for j in range(3):\n", | |
" row.append(numpy.average([result[i][j] for result in results]))\n", | |
" print(f'| {NAME[i]} |', ' | '.join(map(str, row)), '|')\n", | |
"\n", | |
"def sim_average(times=100, groups=GROUPS, p=P):\n", | |
" print('| | 5連続 | 6連続 | 7連続 |')\n", | |
" print('|--|--:|--:|--:|')\n", | |
" results = []\n", | |
" for i in range(times):\n", | |
" results.append(simulate(groups=groups, p=p))\n", | |
" for i in range(2):\n", | |
" row = []\n", | |
" for j in range(3):\n", | |
" row.append(numpy.average([result[i][j] for result in results]))\n", | |
" print(f'| {NAME[i]} |', ' | '.join(map(str, row)), '|')\n", | |
"\n", | |
"# 1\n", | |
"sim_average(groups=1, p=0.5)\n", | |
"\n", | |
"# 2\n", | |
"# sim_average(groups=1, p=1.0)\n", | |
"\n", | |
"# 3\n", | |
"# sim_average(groups=1, p=0.6)\n", | |
"# sim_average(groups=1, p=0.7)\n", | |
"# sim_average(groups=1, p=0.8)\n", | |
"\n", | |
"# 4\n", | |
"# sim_average(groups=1, p=lambda x: 0.5 + 0.1 * x)\n", | |
"\n", | |
"# 5\n", | |
"# sim_average(groups=4, p=lambda x: 0.5 + 0.1 * x)\n", | |
"# sim_average(groups=8, p=lambda x: 0.5 + 0.1 * x)\n", | |
"# sim_average(groups=16, p=lambda x: 0.5 + 0.1 * x)\n", | |
"# sim_average(groups=32, p=lambda x: 0.5 + 0.1 * x)\n", | |
"\n", | |
"# 6\n", | |
"# sim_average_near(p=lambda x: 0.5 + 0.1 * x)" | |
] | |
} | |
], | |
"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.9.5" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 5 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment