БлогNot. Шахматы: считаем вероятность победы каждого игрока в турнире

Шахматы: считаем вероятность победы каждого игрока в турнире

Идея, подсмотренная на форуме, была такой:

Обережний герой: Интересно написать программу, которая бы делила все исходы на множества, в которых выигрывает тот или иной шахматист

Речь, конечно, шла о турнире претендентов-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 [2256 просмотров]


теги: шахматы статистика php

К этой статье пока нет комментариев, Ваш будет первым