БлогNot. Автоплеер для файла PGN

Автоплеер для файла PGN

Файл PGN может содержать любое количество партий (экспорт с Личесса тоже подойдёт) и располагается на сервере в папке скрипта. После загрузки клиентской страницы index.html, средствами AJAX вызывается серверный скрипт loader.php, который парсит и читает файл PGN в скрытый раздел документа. В дальнейшем клиентский Javascript-плеер, основанный на chess.js и chessboard.js, прокручивает партии, запоминая в хранилище, на какой игре Вы остановились.

Я использовал кусочки прежнего кода из XMLHttpRequest и "обезьяньих шахмат".

Кроме того, хотелось обновить chess.js, так как моя версия ещё не умеет загружать из партии комментарии, но у автора теперь только .ts-файл, конвертировал онлайн вот здесь в .js и убрал директиву export (заменил на пустое место).

Обновил также неупакованные chessboard.js и jquery.js от производителей, все они во вложенной папке js архива. В первом пришлось изменить одну строку

config.pieceTheme = './img/{piece}.png'

чтобы был относительный путь к картинкам с фигурами.

Предполагается, что мы будем вставлять новые партии в PGN в конец файла base.pgn, тогда нумерация не собьётся.

Плеер не смутят лишние пустые строки или "незнакомые" (отсутствующие) теги PGN в заголовке, например, такой base.pgn вполне корректен:

[Event "Мои великие победы: Мои великие победы (4)"]
[Site "https://lichess.org/study/vWmLfY8d/uXt8SC5h"]
[White "PerS"]
[Black "NePers"]
[Result "1-0"]
[UTCDate "2021.02.13"]
[UTCTime "09:11:17"]
[Variant "Standard"]
[ECO "C40"]
[Opening "Elephant Gambit"]
[Annotator "https://lichess.org/@/Old_Drunkard"]

1. e4 { [%eval 0.25] } 1... e5 { [%eval 0.31] } 2. Nf3 { [%eval 0.28] } 
2... d5?! { [%eval 0.98] } { Inaccuracy. Nc6 was best. } (2... Nc6 3. Bb5 Nf6 4. d3 Bc5 5. Bxc6 dxc6 
6. O-O Bd6 7. a4) 3. c3?? { [%eval -0.88] } { Blunder. exd5 was best. } 
{ Типа я решил проверить, а что будет на c3 :) } (3. exd5 Qxd5 4. Nc3 Qc5 5. Bb5+ c6 6. Ba4 Be7 7. Bb3 Nf6) 
3... dxe4 { [%eval -0.82] } 4. Nxe5 { [%eval -0.52] } 4... f6?? { [%eval 2.92] } { Blunder. Qe7 was best. } 
(4... Qe7 5. Nc4 Nc6 6. Be2 Be6 7. d4 exd3 8. Qxd3 Rd8 9. Qe3) 5. Qh5+ { [%eval 2.76] } 
5... g6 { [%eval 2.86] } 6. Nxg6 { [%eval 2.75] } 6... Kf7?? { [%eval 9.48] } { Blunder. hxg6 was best. } 
(6... hxg6 7. Qxh8 Be6 8. Qh4 Qd5 9. Qg3 Nd7 10. d4 O-O-O 11. Nd2 g5 12. Qe3 f5 13. Bc4) 7. Ne5+ { [%eval 7.41] } 
7... Kg7? { [%eval #3] } { Checkmate is now unavoidable. Ke7 was best. } (7... Ke7 8. Qf7+ Kd6
9. Nc4+ Kc6 10. Na5+ Kd6 11. Na3 Qe7 12. Nb5+ Kd7 13. Qd5+ Ke8 14. Nxb7) 8. Qf7+ { [%eval #2] }
8... Kh6 { [%eval #2] } 9. d3+ { [%eval #1] } 9... e3 { [%eval #1] } 10. Bxe3# { 1-0 White wins by checkmate. } 1-0


[Event "Детский мат"]
1. e4   e5    2. Bc4 Bc5 3. Qh5 Nf6 4. Qxf7#

1. e3 (1. f3 e5 2. 
g4 Qh4#)

"Вытягивать" основное содержимое партии в одну строку, как того требует формат, необязательно, главное не допускать пустых строк внутри списка ходов и комментариев.

Также предполагается, что все партии начинаются со стартовой позиции.

Серверный скрипт loader.php довольно прост и не гарантирует безошибочного разбора всех на свете PGN-файлов:

<?php
 $name = './base.pgn';
 $games = [];
 $headers = [];
 $lines = file($name,FILE_IGNORE_NEW_LINES);
 if ($lines === false) {
  echo '<div id="gamesCount">1</div>'.
   '<div id="headers0">[Event "Не могу прочитать файл"]</div>'.
   '<div id="game0">1. h4 </div>';
  return;
 }
 $i = $k = 0;
 $cnt = count($lines);
 while ($i < $cnt) {
  while (empty(trim($lines[$i]))) {
   $i++;
   if ($i >= $cnt) break 2;
  }
  $headers[$k] = '';
  while (preg_match("/^\[.+\]$/",trim($lines[$i])) === 1) {
   $headers[$k] .= htmlspecialchars(trim($lines[$i]),ENT_QUOTES,'UTF-8').'<br>';
   $i++;
   if ($i >= $cnt) break 2;
  }
  while (empty(trim($lines[$i]))) {
   $i++;
   if ($i >= $cnt) break 2;
  }
  $games[$k] = '';
  while (preg_match("/^\[.+\]$/",trim($lines[$i])) === 0) {
   if (empty(trim($lines[$i]))) break;
   $games[$k] .= htmlspecialchars(trim($lines[$i]),ENT_QUOTES,'UTF-8').' ';
   $i++;
   if ($i >= $cnt) break 2;
  }
  if ($i < $cnt) $k++;
 }
 if ($k < 1) {
  echo  '<div id="gamesCount">1</div>'.
   '<div id="headers0">[Event "Неверный файл"]</div>'.
   '<div id="game0">1. g4 </div>';
  return;
 }
 $cnt = count($games);
 $gamesContent = '<div id="gamesContent">'."\n";
 for ($i = 0; $i < count($games); $i++) {
  if (!isset($games[$i]) or empty($games[$i]) or $games[$i] === "") {
   $cnt--; continue;
  }
  else if (!isset($headers[$i]) or empty($headers[$i])) $headers[$i] = "";
  $gamesContent .=
   '<div id="headers'.$i.'">'."\n".
   $headers[$i].
   '</div>'."\n".
   '<div id="game'.$i.'">'."\n".
   $games[$i].
   '</div>'."\n";
 }
 $gamesContent .= '</div>';
 $gamesCount = '<div id="gamesCount">'.$cnt.'</div>'."\n";
 echo "$gamesCount";
 echo "$gamesContent";
?>

Увидеть все клиентские файлы .html, .js и .css легко из исходника страницы по прямым ссылкам, картинки находятся во вложенной папке img под стандартными именами. Возможно, исходник будет ещё немного улучшаться, написал всё сегодня и довольно-таки левой ногой.

Для наполнения базы я использовал немного своих "великих побед" над безразрядниками :)

 Открыть скрипт MyChessPGNPlayer в новом окне/вкладке

08.03.2023, 17:58 [340 просмотров]


теги: javascript шахматы textprocessing php форматы

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