Commit Diff


commit - d2d0d371dc3e7838f681d30182572bb1d0878d3f
commit + 8866f3d056b249109622f7e95931d856f885e08d
blob - /dev/null
blob + 8612d279c6437c5ff71c52f316282f2fde1cbe20 (mode 644)
--- /dev/null
+++ cookbook/chess.php
@@ -0,0 +1,255 @@
+<?php if (!defined('PmWiki')) exit();
+/*  Copyright 2005-2022 Patrick R. Michaud (pmichaud@pobox.com)
+    This file is chess.php; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published
+    by the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.  
+
+    This recipe enables PGN (Portable Game Notation) chess markup
+    in PmWiki.  Strings in the markup text matching the PGN move format 
+    (e.g., things like "5. O-O Nf6" and "4...exd4") are internally 
+    recorded as moves in a "game", and then the {FEN} markup can be
+    used to obtain the current board position in Forsyth-Edwards
+    Notation.  The markup also allows lines of play to be explored,
+    as (re-)specifying an earlier move automatically undoes any
+    previously recorded later moves for the current game.
+
+    The recipe also defines a "Chessboard:" InterMap shortcut,
+    which can be used in combination with {FEN} to draw a graphical
+    representation of the current board position.  Normally this is
+    done with either the "(:chessboard:") markup, which generates
+    a table, or the "Chessboard:{FEN}&t=.gif" markup, which calls
+    the chessboard.php application.  An administrator can override
+    the Chessboard: InterMap shortcut to change the default board display
+    settings or use a different script entirely:
+
+    # (in local/localmap.txt)
+    # redefine "Chessboard:" to use a green+tan board
+    Chessboard	$PubDirUrl/chess/chessboard.php?light=ffffcc&dark=00bb00&fen=$1
+  
+    # define "CB:" as a small 160x160 board
+    CB          $PubDirUrl/chess/chessboard.php?w=160&h=160&fen=$1
+    
+    Script maintained by Petko Yotov https://www.pmwiki.org/petko
+*/
+
+SDV($RecipeInfo['ChessMarkup']['Version'], '20220103');
+SDVA($CustomSyntax, array('ChessMarkup'=>'InterMap  Chessboard:\{FEN\}'));
+
+## First, we define the Chessboard: InterMap shortcut
+SDV($LinkFunctions['Chessboard:'], 'LinkIMap');
+SDV($IMap['Chessboard:'], "$PubDirUrl/chess/chessboard.php?fen=\$1");
+
+## Define the pgn and {FEN} markups:
+$PGNMovePattern = "[KQRBNP]?[a-h]?[1-8]?x?[a-h][1-8](?:=[KQRBNP])?|O-O-O|O-O";
+Markup('pgn', 'directives',
+  "/(\\d+)\\.\\s*($PGNMovePattern|\\.+)(?:[\\s+#?!]*($PGNMovePattern))?/",
+  "PGNMove");
+Markup('{FEN}', '>pgn', '/\\{FEN\\}/', 'FENBoard');
+
+## The (:chessboard:) markup by default generates a table, since
+## some PHP installations don't have GD support compiled in.
+Markup('chessboard', '>{FEN}', 
+  '/\\(:chessboard(\\s.*?)?:\\)/i',
+  "ChessTable");
+
+
+## $PGNMoves is an array of all moves (in PGN notation).  The
+## PGNMove($num, $white, $black) function adds moves for white and
+## black into the array, removing any later moves that might be
+## already present.
+$PGNMoves = array();
+function PGNMove($m) {
+  $out = array_shift($m);
+  @list($num, $white, $black) = $m;
+  global $PGNMoves;
+  if ($white[0] != '.') { 
+    $PGNMoves[$num*2-2] = $white;
+    array_splice($PGNMoves, $num*2-1);
+  }
+  if ($black) {
+    $PGNMoves[$num*2-1] = $black;
+    array_splice($PGNMoves, $num*2);
+  }
+  return Keep($out);
+}
+
+
+## FENBoard() plays out the moves given in $PGNMoves and returns
+## the resulting position as a FEN record.  Internally $board
+## is maintained as a 10x10 character string, with $board{11}
+## corresponding to a8 and $board{88} corresponding to h1.
+## Since PGN generally gives us only the name of the piece being
+## moved and the square it moved to, we have to figure out where
+## that piece came from.  Castling is handled by directly manipulating
+## the $board to the result of the castle.  The from position
+## for pawn moves is computed directly by inspection, while all 
+## other pieces use the $legalmoves array to determine the relative
+## square offsets where pieces could've come from.  Once we
+## figure out where the piece came from, we put the piece in its
+## new position ($to) and change the old position ($from) to an
+## empty square.
+
+function FENBoard() {
+  global $PGNMoves;
+  $num = count($PGNMoves) * 2;
+  # initialize the board and our allowed moves
+  $board = "-----------rnbqkbnr--pppppppp--........--........-"
+           . "-........--........--PPPPPPPP--RNBQKBNR-----------";
+  $legalmoves = array(
+    'K' => array(-11, -10, -9, -1, 1, 9, 10, 11),
+    'Q' => array(-11, -10, -9, -1, 1, 9, 10, 11),
+    'B' => array(-11, -9, 9, 11),
+    'R' => array(-10, -1, 1, 10),
+    'N' => array(-21, -19, -12, -8, 8, 12, 19, 21));
+
+  # now, walk through each move and update the board accordingly
+  for($i=0; $i<$num; $i++) {
+    $move = @$PGNMoves[$i];                                # odd numbered
+    $isblack = $i % 2;                                     # moves are black
+    if ($move == 'O-O') {                                  # kingside castling
+      $board = ($isblack)
+               ? substr_replace($board, '.rk.', 15, 4)
+               : substr_replace($board, '.RK.', 85, 4);
+      continue;
+    }
+    if ($move == 'O-O-O') {                                # queenside castling
+      $board = ($isblack)
+               ? substr_replace($board, '..kr.', 11, 5)
+               : substr_replace($board, '..KR.', 81, 5);
+      continue;
+    }
+    if (preg_match(                                        # all other moves
+            "/^([KQRBNP]?)([a-h]?)([1-8]?)(x?)([a-h])([1-8])(=[KQRBNP])?/",
+            $move, $match)) {
+      @list($m, $piece, $ff, $fr, $cap, $tf, $tr, $promotion) = $match;
+      $tf = strpos("abcdefgh", $tf)+1; 
+      $ff = ($ff) ? strpos("abcdefgh", $ff)+1 : 0; 
+      $to = (9-$tr)*10 + $tf;
+      if (!$piece) $piece = "P";
+      $pp = ($isblack) ? strtolower($piece) : $piece;
+      if ($pp == 'P') {                                    # white's pawn move
+        if ($cap) {                                        # capture
+          $from = (9-$tr)*10+10+$ff; 
+          if ($board[$to]=='.') $board[$to+10]='.';        # en passant
+        }
+        elseif ($board[$to+10]==$pp) $from=$to+10;         # move
+        elseif ($tr==4 && $board[$to+20]==$pp) $from=$to+20;   # first move
+      } elseif ($pp == 'p') {                              # black's pawn
+        if ($cap) {                                        # capture
+          $from = (9-$tr)*10-10+$ff; 
+          if ($board[$to]=='.') $board[$to-10]='.';        # en passant
+        }
+        elseif ($board[$to-10]==$pp) $from=$to-10;         # move
+        elseif ($tr==5 && $board[$to-20]==$pp) $from=$to-20;   # first move
+      } else {
+        # Here we look at squares along the lines for the piece
+        # being moved.  $n contains an offset for each square along
+        # a valid line for the current piece.
+        foreach($legalmoves[$piece] as $n) {               
+          for($from=$to+$n; $from>10 && $from<89; $from+=$n) {
+            # if we find the piece we're looking for, we're done
+            if ($board[$from] == $pp                       
+                && (!$ff || ($from%10==$ff))               
+                && (!$fr || ((int)($from/10)==(9-$fr)))) break 2;                                     
+            # if we find anything but an empty square, try another line
+            if ($board[$from] != '.') continue 2;
+
+            # kings and knights don't repeat offsets
+            if ($piece == 'K' || $piece == 'N') continue 2;
+          }
+        }
+      }
+
+      # pawn promotions
+      if ($promotion)
+        $pp = ($isblack) ? strtolower($promotion[1]) : $promotion[1];
+
+      # move the piece
+      $board[$to] = $pp; $board[$from] = '.';
+    }
+  }
+
+  # now, convert the board to a FEN record
+  $board = PPRA(array('/-+/'  =>'/', 
+                      '/\\.+/'=> 'chess_cb_length'
+                      ),
+                      substr($board, 11, 78));
+
+  # and return it
+  return $board;
+}
+
+function chess_cb_length($m) { return strlen($m[0]); }
+
+## The ChessTable function takes a FEN string (or the current
+## game position as returned by FENBoard() above) and creates an 
+## HTML table representing the current game position.
+$ChessPieces = array(
+   'k' => 'kd-60.png', 'q' => 'qd-60.png', 'r' => 'rd-60.png',
+   'b' => 'bd-60.png', 'n' => 'nd-60.png', 'p' => 'pd-60.png',
+   'K' => 'kl-60.png', 'Q' => 'ql-60.png', 'R' => 'rl-60.png',
+   'B' => 'bl-60.png', 'N' => 'nl-60.png', 'P' => 'pl-60.png',
+   '.' => 'blank-60.png');
+$ChessChars = array(
+   'k' => '&#x265A;', 'q' => '&#x265B;', 'r' => '&#x265C;',
+   'b' => '&#x265D;', 'n' => '&#x265E;', 'p' => '&#x265F;',
+   'K' => '&#x2654;', 'Q' => '&#x2655;', 'R' => '&#x2656;',
+   'B' => '&#x2657;', 'N' => '&#x2658;', 'P' => '&#x2659;',
+   '.' => '&nbsp;');
+SDV($HTMLStylesFmt['chess'],  " 
+  table.chesstable td.square1 { background-color: #cccccc; } 
+  table.chesstable { border:1px solid #666666; line-height: 0; } ");
+  
+
+function ChessTable($m) {
+  global $ChessPieces, $ChessChars, $ChessPubDirUrlFmt, $FmtV;
+  
+  extract($GLOBALS['MarkupToHTML']);
+  $args = ParseArgs($m[1]);
+  
+  
+# Some day: SDV($ChessSquareFmt, "<td>\$PieceChar</td>");
+  SDV($ChessSquareFmt, 
+    "<td class='square\$SquareColor'><img 
+       src='\$FarmPubDirUrl/chess/\$PieceImg' alt='\$PieceName' title='\$PieceName'
+       width='\$SquareWidth' height='\$SquareHeight' /></td>");
+  SDV($ChessDefaults, array(
+    'width' => 240, 'class' => 'chesstable',
+    'cellspacing' => 0, 'cellpadding' => 0));
+  $args = array_merge($ChessDefaults, $args);
+  $fen = (@$args['']) ? $args[''][0] : FENBoard();
+  $width = $args['width'];
+  $height = (@$args['height'] > 0) ? $args['height'] : $width;
+
+  $tableargs = "";
+  foreach(array('class', 'cellspacing', 'cellpadding', 'align', 'style') as $a)
+    if (isset($args[$a])) 
+      $tableargs .= " $a='".str_replace("'", "&#039;", $args[$a])."'";
+  
+  ## build the 8x8 board from the FEN record
+  $board = str_repeat('.', 64);
+  $file = 0; $rank = 0;
+  $len = strlen($fen);
+  for($i=0; ($i<$len) && ($rank+$file<64); $i++) {
+    $k = $fen[$i];
+    if (is_numeric($k) && $k > 0) { $file += $k; continue; }
+    if ($k == '/') { $rank += 8; $file = 0; continue; }
+    if ($ChessPieces[$k]) { $board[$rank+$file] = $k; $file++; }
+  }
+
+  ## Now generate the table from the 8x8 board
+  $FmtV['$SquareWidth'] = $width / 8;
+  $FmtV['$SquareHeight'] = $height / 8;
+  for($i=0; $i<64; $i++) {
+    if ($i%8 == 0) $out[] = "<tr>";
+    $FmtV['$PieceImg'] = $ChessPieces[$board[$i]];
+    $FmtV['$PieceChar'] = $ChessChars[$board[$i]];
+    $FmtV['$PieceName'] = $board[$i];
+    $FmtV['$SquareColor'] = ($i + (int)($i/8)) % 2;
+    $out[] = FmtPageName($ChessSquareFmt, $pagename);
+    if ($i%8 == 7) $out[] = "</tr>";
+  }
+  return "<table $tableargs>".Keep(implode('', $out))."</table>";
+}
+  
blob - /dev/null
blob + 5dfac74a1e91fa3ecc9cfc43f526410a6f7b1256 (mode 644)
Binary files /dev/null and cookbook/chess.zip differ
blob - /dev/null
blob + 5b6e7c66c276e7610d4a73c70ec1a1f7c1003259 (mode 644)
--- /dev/null
+++ pub/chess/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
blob - /dev/null
blob + f476a7a96a9bbb7bdca46fd259876b100379f711 (mode 644)
Binary files /dev/null and pub/chess/bd-60.png differ
blob - /dev/null
blob + 7c0c463ce684dcee6c6860a66a2477252d4bd7f3 (mode 644)
Binary files /dev/null and pub/chess/bl-60.png differ
blob - /dev/null
blob + 04a28a9d332f523a1a672c93b3def53c593bc1cb (mode 644)
Binary files /dev/null and pub/chess/blank-60.png differ
blob - /dev/null
blob + d71762bdbb755a46144375ca042bc1ef270d04f1 (mode 644)
--- /dev/null
+++ pub/chess/chessboard.php
@@ -0,0 +1,116 @@
+<?php
+/*  Copyright 2005-2021 Patrick R. Michaud (pmichaud@pobox.com)
+    This file is chessboard.php; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published
+    by the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.  
+
+    This script generates a GIF image of a chessboard from a board
+    position given in Forsyth-Edwards Notation (FEN) [1].  The parameters
+    understood by this script include:
+
+        fen=[position]         A game position in FEN notation
+        w=[width]              Width of GIF image (default 240 pixels)
+        h=[height]             Height of GIF image (default same as width)
+        light=[rrggbb]         Color of light squares (default "ffffff")
+        dark=[rrggbb]          Color of dark squares (default "cccccc")
+        border=[rrggbb]        Border color (default "999999")
+
+    The chess piece images are held in an image file specified by 
+    $default['pieces'].  This file is a single image containing
+    all of the images to be used for pieces laid out end-to-end
+    horizontally, starting with White's king, queen, rook, bishop, 
+    knight, and pawn, and then the same sequence for Black's pieces.  
+
+    The pieces-60.gif file distributed with chessboard.php was created
+    from chess tile images provided by David Benbennick and available
+    through the Wikimedia Commons [2] under either a public domain
+    or GPL-compatible license.
+
+    1. http://en.wikipedia.org/wiki/FEN
+    2. http://commons.wikimedia.org/wiki/Image:Chess_tile_pd.png
+    
+    Script maintained by Petko Yotov https://www.pmwiki.org/petko
+*/
+
+  $defaults = array(
+    'w' => 240,                                              # chessboard width
+    'fen' => 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR',  # default position
+    'dark' => 'cccccc',                                      # dark squares
+    'light' => 'ffffff',                                     # light squares
+    'border' => '666666',                                    # border color
+    'pieces' => 'pieces-60.gif',                             # image file
+  );
+
+  # merge the request parameters with the defaults
+  $opt = array_merge($defaults, (array)$_REQUEST);
+
+  # set the values we'll use
+  $w = $opt['w'];
+  $h = (@$opt['h']) ? $opt['h'] : $w;
+  $fen = $opt['fen'];
+  $dark = hexdec($opt['dark']);
+  $light = hexdec($opt['light']);
+
+  # if no FEN position specified, use the default
+  if (!$fen) { $fen = $defaults['fen']; }
+  
+
+  # load the piece images
+  $piece = imagecreatefromgif($defaults['pieces']);
+
+  # determine the width and height of a single piece
+  $pw = imagesx($piece)/12;
+  $ph = imagesy($piece);
+
+  # build an 8x8 board to draw pieces on
+  $bw = $pw * 8; $bh = $ph * 8;
+  $board = imagecreatetruecolor($bw, $bh);
+
+  # draw the squares
+  imagefilledrectangle($board, 0, 0, $bw, $bh, $dark);
+  for($i = 0; $i < 8; $i += 2) {
+    for($j = 0; $j < 8; $j += 2) {
+      $x = $i * $pw; $y = $j * $ph;
+      imagefilledrectangle($board, $x, $y, $x+$pw, $y+$ph, $light);
+      $x += $pw; $y += $ph;
+      imagefilledrectangle($board, $x, $y, $x+$pw, $y+$ph, $light);
+    }
+  }
+
+  # locate the starting horizontal offset of each piece by name
+  $str = "KQRBNPkqrbnp";
+  for($i=0; $i < 12; $i++) { $k = $str[$i]; $pk[$k] = $i * $pw; }
+
+  # Now, walk through the FEN record and draw the pieces in the
+  # appropriate position.
+  $file = 0; $rank = 0;
+  $len = strlen($fen);
+  for($i=0; $i<$len; $i++) {
+    $k = $fen[$i];
+    if (is_numeric($k) && $k > 0) { $file+=$k; continue; }
+    if ($k == '/') { $rank++; $file=0; continue; }
+    if (isset($pk[$k])) {
+      imagecopy($board, $piece, $file*$pw, $rank*$ph, $pk[$k], 0, $pw, $ph);
+      $file++;
+    }
+  }
+  imagedestroy($piece);
+
+  # resize the board if needed
+  if ($w != $bw || $h != $bh) {
+    $old = $board;
+    $board = imagecreatetruecolor($w, $h);
+    imagecopyresampled($board, $old, 0, 0, 0, 0, $w, $h, $bw, $bh);
+    imagedestroy($old);
+  }
+
+  # draw a border if requested
+  if ($opt['border']) 
+    imagerectangle($board, 0, 0, $w-1, $h-1, hexdec($opt['border']));
+
+  # return the completed chessboard image
+  header("Content-type: image/gif");
+  imagegif($board);
+  imagedestroy($board);
+
blob - /dev/null
blob + cd527739b11ce5174a546b2c4f2329a36e8b3b25 (mode 644)
Binary files /dev/null and pub/chess/kd-60.png differ
blob - /dev/null
blob + ddb730a2636765c68263e88a4de46e1ab496963a (mode 644)
Binary files /dev/null and pub/chess/kl-60.png differ
blob - /dev/null
blob + 253e98ebf5403eaf6eb11eeb8cb2f51d8b921239 (mode 644)
Binary files /dev/null and pub/chess/nd-60.png differ
blob - /dev/null
blob + 3761c020af036f4fe5aaca4058445e814a27d27b (mode 644)
Binary files /dev/null and pub/chess/nl-60.png differ
blob - /dev/null
blob + cc392f97a88f85810ffc932708055ffb15b8b1df (mode 644)
Binary files /dev/null and pub/chess/pd-60.png differ
blob - /dev/null
blob + 0821f78a1d8e70fb92d92c3f85a926e5aa4206d5 (mode 644)
Binary files /dev/null and pub/chess/pieces-60.gif differ
blob - /dev/null
blob + d183f30aed40217777b449d1b1b29e6a0ea3df38 (mode 644)
Binary files /dev/null and pub/chess/pl-60.png differ
blob - /dev/null
blob + b2e1067c8dbdcdcfd3e6784e580a01581ec2d171 (mode 644)
Binary files /dev/null and pub/chess/qd-60.png differ
blob - /dev/null
blob + e97d6c401ce79ae33c68c4d7c60dfa2a5c760004 (mode 644)
Binary files /dev/null and pub/chess/ql-60.png differ
blob - /dev/null
blob + 73a29d87553d4337455f8a8d117ea5bb4b63afa6 (mode 644)
Binary files /dev/null and pub/chess/rd-60.png differ
blob - /dev/null
blob + f3d0ad6e84a891109944fa6fc431d7f5ec99307a (mode 644)
Binary files /dev/null and pub/chess/rl-60.png differ