Шахматы: считаем вероятность победы каждого игрока в турнире
Идея, подсмотренная на форуме, была такой:
Обережний герой: Интересно написать программу, которая бы делила все исходы на множества, в которых выигрывает тот или иной шахматист
Речь, конечно, шла о турнире претендентов-2018, который входит в решающую фазу (осталось 2 тура).
Данные о прошедших партиях взял просто со страницы турнира, только переписал их в массив
$tournament
(его можно было не делать двумерным) и избавился от длинных тире между фамилиями игроков, заменив их дефисом. Символ слэша "/" отделяет фамилии от результата партии,
ещё не состоявшиеся партии также помечены в исходных данных дефисом.
Скрипт обсчитывает результаты прошедших партий в массив $players
, заодно проверяя единообразие написания всех фамилий.
Потом на основе массива $comb
, содержащего пары игроков, которые ещё не сыграли, считается и выводится
массив $table
, содержащий фамилии и очки возможных победителей.
Если ставить скрипт на локальный хост вроде Denwer'а, то лучше разместить его файл во вложенную папку в кодировке Юникод (UTF-8) и в этой же папке создать файл .htaccess со строкой
AddDefaultCharset utf-8
Ниже приводится полный текст скрипта на момент без 2 сыгранных туров, может пригодиться для других турниров.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Chess Sets</title> <style type="text/css"> html, body { padding:0; margin:10px; background:#ffffff; color:#000000; } </style> </head> <body> <p>Количество вариантов и вероятность победы каждого из шахматистов турнира. Учитываются только результаты партий. Данные берутся из массивов в тексте скрипта, подробности на <a href="http://blog.kislenko.net/show.php?id=1954" target="_blank">его странице</a>. </p> <?php set_time_limit (0); $tournament = Array ( 1 => Array ( 'Крамник - Грищук / 1-0', 'Карякин - Мамедьяров/ 0-1', 'Аронян - Дин Лижэнь / 1/2', 'Каруана - Со / 1-0' ), 2 => Array ( 'Грищук - Со / 1-0', 'Дин Лижэнь - Каруана/ 1/2', 'Мамедьяров - Аронян / 1/2', 'Крамник - Карякин / 1/2' ), 3 => Array ( 'Карякин - Грищук / 1/2', 'Аронян - Крамник / 0-1', 'Каруана - Мамедьяров / 1/2', 'Со - Дин Лижэнь / 1/2' ), 4 => Array ( 'Грищук - Дин Лижэнь / 1/2', 'Мамедьяров - Со / 1/2', 'Крамник - Каруана / 0-1', 'Карякин - Аронян / 0-1' ), 5 => Array ( 'Аронян - Грищук / 1/2', 'Каруана - Карякин / 1/2', 'Со - Крамник / 1/2', 'Дин Лижэнь - Мамедьяров / 1/2' ), 6 => Array ( 'Каруана - Грищук/ 1/2', 'Со - Аронян / 1-0', 'Дин Лижэнь - Карякин/ 1/2', 'Мамедьяров - Крамник / 1-0' ), 7 => Array ( 'Грищук - Мамедьяров/ 1/2', 'Крамник - Дин Лижэнь/ 1/2', 'Карякин - Со /1-0', 'Аронян - Каруана / 0-1' ), 8 => Array ( 'Грищук - Крамник / 1-0', 'Мамедьяров - Карякин/ 1/2', 'Дин Лижэнь - Аронян / 1/2', 'Со - Каруана / 1/2' ), 9 => Array ( 'Со - Грищук / 1/2', 'Каруана - Дин Лижэнь/ 1/2', 'Аронян - Мамедьяров / 1/2', 'Карякин - Крамник / 1-0' ), 10 => Array ( 'Грищук - Карякин / 1/2', 'Крамник - Аронян / 1-0', 'Мамедьяров - Каруана/ 1/2', 'Дин Лижэнь - Со / 1/2' ), 11 => Array ( 'Дин Лижэнь - Грищук / 1/2', 'Со - Мамедьяров / 1/2', 'Каруана - Крамник/ 1/2', 'Аронян - Карякин / 0-1' ), 12 => Array ( 'Грищук - Аронян / 1/2', 'Карякин - Каруана/ 1-0', 'Крамник - Со / 1/2', 'Мамедьяров - Дин Лижэнь / 0-1' ), 13 => Array ( 'Мамедьяров - Грищук / -', 'Дин Лижэнь - Крамник / -', 'Со - Карякин / -', 'Каруана - Аронян / -' ), 14 => Array ( 'Грищук - Каруана / -', 'Аронян - Со / -', 'Карякин - Дин Лижэнь / -', 'Крамник - Мамедьяров / -' ) ); $players = Array ( 'Мамедьяров'=>0,'Крамник'=>0,'Со'=>0,'Аронян'=>0,'Каруана'=>0,'Дин Лижэнь'=>0,'Грищук'=>0,'Карякин'=>0 ); $comb = Array(); foreach ($tournament as $number => $result) { foreach ($result as $gameindex=>$game) { list($player1,$player2,$cnt1,$cnt2) = preg_split ("/[\-\/]+/u",trim($game)); $player1 = trim($player1); $player2 = trim($player2); $cnt1 = intval(trim($cnt1)); $cnt2 = intval(trim($cnt2)); $cnt = ''; if ($cnt1 == 1 and $cnt2 == 2) $cnt = '1/2'; else if ($cnt1 == 1 and $cnt2 == 0) $cnt = '1-0'; else if ($cnt1 == 0 and $cnt2 == 1) $cnt = '0-1'; if (!array_key_exists($player1,$players) or !array_key_exists($player2,$players)) { exit ('Неверные фамилии или ошибка формата в строке '.$game); } if (!empty($cnt)) { if ($cnt=='1/2') { $players[$player1]+=0.5; $players[$player2]+=0.5; } else if ($cnt=='1-0') $players[$player1]++; else if ($cnt=='0-1') $players[$player2]++; $all++; } else { $comb[] = Array ($player1,$player2,0); } } } $table = Array (); $vars = Array ( '1-0','1/2','0-1' ); $cn = count($comb); $n = floor(pow(count($vars),$cn)); $start = 0; for ($i=0; $i<$n; $i++) { $s=str_pad(base_convert ($i,10,3),$cn,'0',STR_PAD_LEFT); for ($j=0; $j<$cn; $j++) $comb[$j][2]=$s[$j]; $keystr = cnt1 ($players,$comb,$vars); if (array_key_exists($keystr,$table)) $table[$keystr]++; else $table[$keystr] = 1; } arsort ($table); $nres = count($table); $sum = array_sum($table); echo '<p>'; foreach ($table as $key=>$val) { echo $key.': '.$val.' вар., '.round($val/$sum*100,2).'%<br>'; } echo '</p>'; echo '<p>Всего вариантов победы по очкам: '.$nres.', всего возможных исходов: '.$sum.'</p>'; function cnt1 ($players,$comb,$vars) { $n = count($comb); for ($i=0; $i<$n; $i++) { $game = $comb[$i]; $player1 = $game[0]; $player2 = $game[1]; $cnt = $game[2]; if ($cnt == '1') { $players[$player1]++; } else if ($cnt == '0') { $players[$player1]+=0.5; $players[$player2]+=0.5;} else if ($cnt == '2') { $players[$player2]++; } } arsort($players); $max = max($players); $keymax = Array(); foreach ($players as $name=>$balls) { if ($balls==$max) { $keymax[] = $name; } } sort ($keymax); $keystr = implode (',',$keymax); return $keystr.'('.$max.')'; } ?> </body> </html>
Вот результаты вывода: победитель или победители, в скобках - их количество очков, затем количество таких исходов и их доля в общем количестве исходов, которое равно 3m, где m - количество оставшихся партий.
Обратите внимание, как в листинге с помощью троичных чисел и функции str_pad
считаются перестановки исходов.
Каруана(8.5): 720 вар., 10.97% Карякин(8.5): 702 вар., 10.7% Карякин(9): 648 вар., 9.88% Каруана(9): 648 вар., 9.88% Грищук(8.5): 405 вар., 6.17% Дин Лижэнь(8.5): 351 вар., 5.35% Каруана,Карякин(8.5): 288 вар., 4.39% Мамедьяров(8.5): 270 вар., 4.12% Каруана,Карякин(8): 180 вар., 2.74% Грищук,Карякин(8.5): 162 вар., 2.47% Дин Лижэнь,Каруана(8.5): 144 вар., 2.19% Грищук,Карякин(8): 126 вар., 1.92% Каруана(8): 120 вар., 1.83% Карякин,Мамедьяров(8.5): 108 вар., 1.65% Каруана,Мамедьяров(8.5): 90 вар., 1.37% Карякин(8): 90 вар., 1.37% Каруана,Карякин,Мамедьяров(8): 90 вар., 1.37% Грищук,Каруана,Карякин(8): 90 вар., 1.37% Дин Лижэнь,Каруана(8): 90 вар., 1.37% Грищук(8): 84 вар., 1.28% Грищук,Дин Лижэнь(8.5): 81 вар., 1.23% Каруана,Карякин(9): 81 вар., 1.23% Карякин,Мамедьяров(8): 72 вар., 1.1% Грищук,Дин Лижэнь(8): 63 вар., 0.96% Дин Лижэнь,Каруана,Карякин(8): 60 вар., 0.91% Грищук,Каруана(8): 60 вар., 0.91% Каруана,Мамедьяров(8): 60 вар., 0.91% Дин Лижэнь,Мамедьяров(8.5): 54 вар., 0.82% Мамедьяров(8): 48 вар., 0.73% Дин Лижэнь(8): 45 вар., 0.69% Грищук,Дин Лижэнь,Каруана(8): 45 вар., 0.69% Дин Лижэнь,Каруана,Мамедьяров(8): 45 вар., 0.69% Грищук,Дин Лижэнь,Карякин(8): 42 вар., 0.64% Грищук,Карякин,Мамедьяров(8): 36 вар., 0.55% Дин Лижэнь,Мамедьяров(8): 36 вар., 0.55% Каруана,Карякин,Мамедьяров(8.5): 36 вар., 0.55% Грищук,Дин Лижэнь,Каруана,Карякин(8): 30 вар., 0.46% Дин Лижэнь,Каруана,Карякин,Мамедьяров(8): 30 вар., 0.46% Дин Лижэнь,Карякин(8): 30 вар., 0.46% Грищук,Мамедьяров(8): 24 вар., 0.37% Дин Лижэнь,Карякин,Мамедьяров(8): 24 вар., 0.37% Дин Лижэнь,Каруана,Мамедьяров(8.5): 18 вар., 0.27% Грищук,Каруана,Карякин,Мамедьяров(8): 18 вар., 0.27% Грищук,Дин Лижэнь,Мамедьяров(8): 18 вар., 0.27% Грищук,Дин Лижэнь,Карякин,Мамедьяров(8): 12 вар., 0.18% Грищук,Каруана,Мамедьяров(8): 12 вар., 0.18% Грищук,Дин Лижэнь,Каруана,Мамедьяров(8): 9 вар., 0.14% Грищук,Дин Лижэнь,Каруана,Карякин,Мамедьяров(7.5): 9 вар., 0.14% Грищук,Дин Лижэнь,Каруана,Карякин,Мамедьяров(8): 6 вар., 0.09% Грищук,Каруана,Карякин,Крамник,Мамедьяров(7.5): 3 вар., 0.05% Грищук,Дин Лижэнь,Каруана,Крамник,Мамедьяров(7.5): 3 вар., 0.05% Дин Лижэнь,Каруана,Крамник,Мамедьяров(7.5): 3 вар., 0.05% Грищук,Дин Лижэнь,Крамник,Мамедьяров(7.5): 3 вар., 0.05% Грищук,Карякин,Крамник,Мамедьяров(7.5): 3 вар., 0.05% Грищук,Дин Лижэнь,Карякин,Крамник,Мамедьяров(7.5): 3 вар., 0.05% Каруана,Карякин,Крамник,Мамедьяров(7.5): 3 вар., 0.05% Дин Лижэнь,Каруана,Карякин,Мамедьяров(7.5): 3 вар., 0.05% Грищук,Каруана,Карякин,Мамедьяров(7.5): 3 вар., 0.05% Грищук,Дин Лижэнь,Каруана,Карякин,Крамник(7.5): 3 вар., 0.05% Грищук,Дин Лижэнь,Каруана,Карякин(7.5): 3 вар., 0.05% Грищук,Каруана,Карякин,Крамник(7.5): 3 вар., 0.05% Грищук,Дин Лижэнь,Каруана,Мамедьяров(7.5): 3 вар., 0.05% Грищук,Дин Лижэнь,Каруана,Карякин,Крамник,Мамедьяров(7.5): 3 вар., 0.05% Грищук,Дин Лижэнь,Карякин,Мамедьяров(7.5): 3 вар., 0.05% Грищук,Дин Лижэнь,Каруана,Крамник(7.5): 3 вар., 0.05% Дин Лижэнь,Каруана,Карякин,Крамник,Мамедьяров(7.5): 3 вар., 0.05% Всего вариантов победы по очкам: 66, всего возможных исходов: 6561
Проверял на тесте для гипотетических 4 шахматистов, играющих круговик в 3 тура (каждый с каждым по разу), получил варианты победителей
Четыре(2.5): 72 вар., 9.88% Один(2.5): 72 вар., 9.88% Два(2.5): 72 вар., 9.88% Три(2.5): 72 вар., 9.88% Три(2): 36 вар., 4.94% Два(2): 36 вар., 4.94% Четыре(2): 36 вар., 4.94% Один(2): 36 вар., 4.94% Три(3): 27 вар., 3.7% Четыре(3): 27 вар., 3.7% Один(3): 27 вар., 3.7% Два(3): 27 вар., 3.7% Два,Один(2): 24 вар., 3.29% Два,Три(2): 24 вар., 3.29% Один,Четыре(2): 24 вар., 3.29% Три,Четыре(2): 24 вар., 3.29% Два,Четыре(2): 24 вар., 3.29% Один,Три(2): 24 вар., 3.29% Два,Один,Три,Четыре(1.5): 15 вар., 2.06% Два,Три,Четыре(2): 3 вар., 0.41% Два,Четыре(2.5): 3 вар., 0.41% Один,Четыре(2.5): 3 вар., 0.41% Два,Три(2.5): 3 вар., 0.41% Три,Четыре(2.5): 3 вар., 0.41% Два,Один(2.5): 3 вар., 0.41% Два,Один,Три(2): 3 вар., 0.41% Два,Один,Четыре(2): 3 вар., 0.41% Один,Три,Четыре(2): 3 вар., 0.41% Один,Три(2.5): 3 вар., 0.41% Всего вариантов победы по очкам: 29, всего возможных исходов: 729
26.03.2018, 19:02 [2327 просмотров]