1<?php
2require_once 'Games/Chess/Standard.php';
3require_once 'Games/Chess/Losers.php';
4require_once 'Games/Chess/Crazyhouse.php';
5
6if (!version_compare(phpversion(), '4.2.0', '>=')) {
7    die('Requires PHP version 4.2.0 or greater');
8}
9
10// hack control
11if (!isset($_GET['start']) || !is_string($_GET['start'])) {
12    $_GET['start'] = '';
13}
14if (strlen($_GET['start']) != 2) {
15    $_GET['start'] = '';
16} elseif ($_GET['start'] != '' && !preg_match('/[a-h][1-8]/', $_GET['start'])) {
17    $_GET['start'] = '';
18}
19
20if (!isset($_GET['goto']) || !is_string($_GET['goto'])) {
21    $_GET['goto'] = '';
22} elseif (strlen($_GET['goto']) != 2) {
23    $_GET['goto'] = '';
24} elseif (!preg_match('/[a-h][1-8]/', $_GET['goto'])) {
25    $_GET['goto'] = '';
26}
27
28if (!empty($_GET['promote']) && !in_array($_GET['promote'], array('Q', 'R',
29      'N', 'B'))) {
30    $_GET['promote'] = 'Q';
31}
32/**
33* Creates the game and maintains persistence through sessions
34* Call this at the top of the webpage
35* @param string name of the session containing the current game
36* @param string name of the game variable (a {@link visualboard} class)
37*/
38function setup_game($session_id, $gamename)
39{
40    session_name($session_id);
41    session_start();
42    if (isset($_GET['newgame'])) {
43        session_destroy();
44    }
45    session_name($session_id);
46    session_register($gamename);
47}
48
49/**
50 * The primary class - declare one of these at the top of the file
51 *
52 * Do it like this:
53 *
54 * <code>
55 * setup_game('mygame','x');
56 * $x = $_SESSION['x'];
57 * if (!isset($x)) $x = new visualboard;
58 * </code>
59 * @author Greg Beaver <cellog@users.sourceforge.net>
60 * @copyright Copyright 2002, Greg Beaver
61 * @version 1.0
62 */
63class visualboard
64{
65    /**
66     * The logical board
67     * @var Games_Chess
68     */
69    var $_board;
70    /**
71     * Promotion contents
72     * @var false|array
73     */
74    var $promote = false;
75    /**
76     * Game type (Standard, Losers, Crazyhouse)
77     * @var string
78     */
79    var $_type;
80
81    /**
82     * Initializes {@link $moves, $board}
83     */
84    function visualboard($fen = false, $type = 'Standard')
85    {
86        $board = 'Games_Chess_' . $type;
87        $this->_board = new $board;
88        $this->_type = $type;
89        $err = $this->_board->resetGame($fen);
90        if ($this->_board->isError($err)) {
91            echo '<b>' .$err->getMessage() . '</b><br />';
92            $this->_board->resetGame();
93        }
94    }
95
96    /**
97     * Prints javascript for the function addmove:
98     * {@source}
99     */
100    function javascript()
101    {?>
102<script language="JavaScript" type="text/javascript">
103<!--
104function addMove(move, piece)
105{
106    if (document.forms[0].start.value == '')
107    {
108        document.forms[0].start.value = move;
109        switch (piece)
110        {
111            case "P" :
112            case "Q" :
113            case "R" :
114            case "B" :
115            case "N" :
116            case "K" :
117            break;
118            default :
119                piece = null;
120            break;
121        }
122        document.forms[0].startpiece.value = piece;
123    } else
124    {
125        if (document.forms[0]["goto"].value == '')
126        {
127            document.forms[0]["goto"].value = move;
128            first = document.forms[0].startpiece.value;
129            if (first) {
130                if (first == "P") {
131                    first = "";
132                    if (piece) {
133                        first = document.forms[0].start.value.charAt(0) + "x";
134                    }
135                } else {
136                    if (piece) {
137                        first += "x";
138                    }
139                }
140            }
141            if (confirm("Do this move? (" + first + move + ")"))
142            {
143                document.forms[0].submit();
144            } else {
145                document.forms[0].start.value = '';
146                document.forms[0].startpiece.values = '';
147                document.forms[0]["goto"].value = '';
148                document.forms[0].SAN.value = '';
149            }
150        }
151    }
152}
153
154function doPlacement(piece)
155{
156    switch (piece) {
157        case "P" :
158            name = "Pawn";
159        break;
160        case "Q" :
161            name = "Queen";
162        break;
163        case "R" :
164            name = "Rook";
165        break;
166        case "B" :
167            name = "Bishop";
168        break;
169        case "N" :
170            name = "Knight";
171        break;
172    }
173    square = prompt("Where should the " + name + " be placed (a1-h8, a1 is lower left)?", "e4");
174    if (square) {
175        document.forms[0].SAN.value = piece + "@" + square;
176        document.forms[0].start.value = "";
177        document.forms[0]["goto"].value = "";
178        if (square.charAt(1) == "1" || square.charAt(1) == "8") {
179            document.forms[0].SAN.value = '';
180            document.forms[0].start.value = "";
181            document.forms[0]["goto"].value = "";
182            alert("Cannot place a pawn on the first or last rank");
183        } else {
184            document.forms[0].submit();
185        }
186    }
187}
188//-->
189</script>
190<?php
191    }
192
193    function doCaptured($captured)
194    {
195        $imagepath = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'images';
196        echo '<table border="1">';
197//        echo '<tr><td>&nbsp;</td><td colspan="2">White</td><td colspan="2">Black</td></tr>';
198        foreach ($captured['W'] as $piece => $number) {
199            echo '<tr><td>';
200            if (file_exists($imagepath . '/' . $piece . '.gif')) {
201                $image = $piece . '.gif';
202                $imgsize = GetImageSize($imagepath . DIRECTORY_SEPARATOR . $image);
203                $click = ($this->_board->toMove() == 'W' && $number) ?
204                    '<a href="#" onclick="doPlacement(\'' . $piece . '\')">' :
205                    '';
206                echo $click . '<img src="images/' . $image . '" border="0" width="' . $imgsize[0] .
207                     '" height="' . $imgsize[1] . '" alt="'. $piece . '">';
208                echo ($click ? '</a>' : '');
209            } else {
210                echo $piece;
211            }
212            echo '</td><td>' . $number . '</td>';
213            $number = $captured['B'][$piece];
214            echo '<td>';
215            if (file_exists($imagepath . '/' . $piece . '.gif')) {
216                $image = 'dark/' . $piece . '.gif';
217                $imgsize = GetImageSize($imagepath . DIRECTORY_SEPARATOR . $image);
218                $click = ($this->_board->toMove() == 'B' && $number) ?
219                    '<a href="#" onclick="doPlacement(\'' . $piece . '\')">' :
220                    '';
221                echo $click . '<img src="images/' . $image . '" border="0" width="' . $imgsize[0] .
222                     '" height="' . $imgsize[1] . '" alt="'. $piece . '">';
223                echo ($click ? '</a>' : '');
224            } else {
225                echo $piece;
226            }
227            echo '</td><td>' . $number . '</td></tr>';
228        }
229        echo '</table>';
230    }
231
232    /**
233     * Grabs the next move from form variables start, goto, kingcastle and queencastle
234     *
235     * If $_GET['start'] is not used, it checks for $_GET['kingcastle'] and tries
236     * to castle kingside if found.  Otherwise, it looks for $_GET['queencastle']
237     * and tries to castle queenside
238     */
239    function domove()
240    {
241        if (!empty($_GET['from']) && !empty($_GET['to']) && !empty($_GET['promote'])) {
242            $err = $this->_board->moveSquare($_GET['from'], $_GET['to'],
243                                             $_GET['promote']);
244            if ($this->_board->isError($err)) {
245                echo '<b>' .$err->getMessage() . '</b><br />';
246            }
247            $this->promote = false;
248            return;
249        }
250        if (!empty($_GET['SAN'])) {
251            $err = $this->_board->moveSAN($_GET['SAN']);
252            if ($this->_board->isError($err)) {
253                echo '<b>' .$err->getMessage() . '</b><br />';
254            }
255            return;
256        }
257        if (!empty($_GET['start']) && !empty($_GET['goto'])) {
258            if ($this->_board->isPromoteMove($_GET['start'], $_GET['goto'])) {
259                $this->promote = array($_GET['start'], $_GET['goto']);
260                return;
261            } else {
262                $this->promote = false;
263            }
264            $err = $this->_board->moveSquare($_GET['start'], $_GET['goto']);
265            if ($this->_board->isError($err)) {
266                echo '<b>' .$err->getMessage() . '</b><br />';
267            }
268        } elseif (isset($_GET['kingcastle'])) {
269            $err = $this->_board->moveSAN('O-O');
270            if ($this->_board->isError($err)) {
271                echo '<b>' .$err->getMessage() . '</b><br />';
272            }
273        } elseif (isset($_GET['queencastle'])) {
274            $err = $this->_board->moveSAN('O-O-O');
275            if ($this->_board->isError($err)) {
276                echo '<b>' .$err->getMessage() . '</b><br />';
277            }
278        }
279    }
280
281    /**
282     * This function prints the javascript that will ask the user what to promote the pawn to
283     *
284     * Using the alert() function, this method asks the user if they want a queen.
285     * If they click Cancel, it asks if they want a rook, then knight, then
286     * bishop.  If they cancel on bishop, it promotes to queen
287     * to avoid any illogical possibilities
288     */
289    function dopromote()
290    {
291    ?>
292<form action="<?php echo $_SERVER['PHP_SELF'].'?'.session_name().'='.session_id() ?>" name="chess" id="chess">
293<input type="hidden" name="promote" value=""><input type="hidden" name="from" value="">
294<input type="hidden" name="to" value="">
295<input type="submit" name="newmove" value="New move"></form>
296<script language="JavaScript" type="text/javascript">
297<!--
298
299function promote(from, to)
300{
301    document.forms[0].from.value = from;
302    document.forms[0].to.value = to;
303    if (confirm("promote to Queen?"))
304    {
305        document.forms[0].promote.value = 'Q';
306        document.forms[0].submit();
307    } else
308    {
309        if (confirm("promote to Rook?"))
310        {
311            document.forms[0].promote.value = 'R';
312            document.forms[0].submit();
313        } else
314        {
315            if (confirm("promote to Knight?"))
316            {
317                document.forms[0].promote.value = 'N';
318                document.forms[0].submit();
319            } else
320            {
321                if (confirm("promote to Bishop?"))
322                {
323                    document.forms[0].promote.value = 'B';
324                    document.forms[0].submit();
325                } else
326                {
327                    document.forms[0].promote.value = 'Q';
328                    document.forms[0].submit();
329                }
330            }
331        }
332    }
333}
334promote('<?php print $this->promote[0] . "', '" . $this->promote[1]; ?>');
335//-->
336</script>
337<?php
338    }
339
340    /**
341    * Print out the chess game in its entirety: the board, move list and control buttons
342    *
343    * first, it checks for a pawn promotion and adds the promote move to {@link $moves} using
344    * {@link game::addpromote()}.  Then it moves the next piece by calling {@link domove()}.
345    * Then it checks for stalemate and checkmate, and stops the gameplay if either condition is met.
346    * It creates a visual representation of the board using {@link abstractboard::createrows()}, and
347    * displays the chessboard by linking together the display of each row on the chessboard using
348    * {@link row::draw()}, and finally the movelist using {@link game::draw()}
349    */
350    function draw()
351    {
352        $this->domove();
353        if ($this->promote)
354        {
355            return $this->dopromote();
356        }
357        $board = $this->_board->toArray();
358        if ($this->_type == 'Crazyhouse') {
359            $captured = $board['captured'];
360            $board = $board['board'];
361        }
362        $checkmate = $this->_board->inCheckmate();
363        $fen = $this->_board->renderFen();
364        $colors = array('#999933', '#FFFFFF');
365        $textcolors = array('#FFFFFF', '#000000');
366        $cycle = 0;
367        if (!$checkmate) $this->javascript();
368        echo '<table border="1">';
369        $imagepath = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'images';
370        foreach($board as $square => $piece) {
371            if ($square{0} == 'a') {
372                echo '<tr>';
373                $cycle = ($cycle + 1) % 2;
374            }
375            echo '<td width="30" bgcolor="' .$colors[$cycle]. '"><font color="' .$textcolors[$cycle]. '">';
376            $upperpiece = $piece ? strtoupper($piece) : false;
377            echo "<a href=\"#\" onClick=\"addMove('$square', '$upperpiece');return false;" .
378                "\" id=\"$square\">";
379
380
381            if ($piece) {
382                if (file_exists($imagepath . '/' . strtoupper($piece) . '.gif')) {
383                    if ($piece != strtoupper($piece)) {
384                        $image = 'dark/' . $piece . '.gif';
385                    } else {
386                        $image = $piece . '.gif';
387                    }
388                    $imgsize = GetImageSize($imagepath . DIRECTORY_SEPARATOR . $image);
389                    echo '<img src="images/' . $image . '" border="0" width="' . $imgsize[0] .
390                         '" height="' . $imgsize[1] . '" alt="'. $piece . '">';
391                } else {
392                    echo $piece;
393                }
394            } else {
395                if (file_exists($imagepath . '/blank.gif')) {
396                    if ($this->_board->getDiagonalColor($square) == 'W') {
397                        $image = 'blank.gif';
398                    } else {
399                        $image = 'dark/blank.gif';
400                    }
401                    $imgsize = GetImageSize($imagepath . DIRECTORY_SEPARATOR . $image);
402                    echo '<img src="images/' . $image . '" border="0" width="' . $imgsize[0] .
403                         '" height="' . $imgsize[1] . '" alt="'. $piece . '">';
404                } else {
405                    echo '&nbsp;';
406                }
407            }
408            echo '</a>';
409            echo '</font></td>';
410            if ($square{0} == 'h') {
411                echo '</tr>';
412            }
413            $cycle = ($cycle + 1) % 2;
414        }
415        echo '</table>';
416
417        $side = $this->_board->toMove() == 'W' ? 'White' : 'Black';
418        $gameOver = $this->_board->gameOver();
419        if ($gameOver) {
420            $winner = $gameOver == 'W' ? 'White' : 'Black';
421            if ($stalemate = $this->_board->inStalemate())
422            {
423                print "<h1>STALEMATE</h1>";
424            } elseif ($draw = $this->_board->inDraw())
425            {
426                print "<h1>DRAW</h1>";
427            } elseif ($this->_board->inCheckmate()) {
428                if (!is_a($this->_board, 'games_chess_standard')) {
429                    $winner = $side;
430                } else {
431                    $winner = ($side == 'White') ? 'Black' : 'White';
432                }
433                print "<h1>CHECKMATE! $winner WINS!</h1>";
434            } else {
435                print "<h1>$winner WINS!</h1>";
436            }
437        }
438
439?><form action="<?php echo $_SERVER['PHP_SELF'].'?'.session_name().'='.session_id() ?>" name="chess" id="chess">
440<?php         if (!$gameOver) { echo "<b>{$side} to move</b><br>";
441if (isset($captured)) {
442    echo "<b>Crazyhouse captured pieces available for placement:</b><br>";
443    $this->doCaptured($captured);
444}
445 ?><input type="hidden" value="" name="startpiece">
446from <input type="text" name="start" size="2" maxlength="2"> to <input type="text" name="goto" size="2" maxlength="2">
447<input type="submit" name="newmove" value="New move"><br>
448(alternate) SAN move: <input type="text" name="SAN" size="5"><br>
449Reset with new FEN: <input type="text" name="FEN" size="70"><br>
450<br><input type="reset"><br>
451<?php $this->castlebutton(); } ?><br><br>
452
453<input type="submit" name="newgame" value="New Game"><input type="submit" name="newlosergame" value="New Losers Game"><input type="submit" name="newcrazyhousegame" value="New Crazyhouse Game"></form><?php if (!$gameOver) { ?>
454for a friend to join, click here <a href="mailto:example@example.com?Subject=Join my chess game!&Body=<?php
455echo htmlentities("go to <a href=\"http://" . $_SERVER['SERVER_NAME'] . $_SERVER['PHP_SELF'] .
456"?mygame=".session_id()."\">Here</a> to play me in chess! http://$_SERVER[SERVER_NAME]$_SERVER[PHP_SELF]?mygame=" .
457session_id()); ?>">Email my friend</a>
458
459<form action="<?php echo $_SERVER['PHP_SELF'].'?'.session_name().'='.session_id() ?>">
460<input type="submit" value="Check to see if opponent has moved"></form>
461<?php }
462
463        echo "<blockquote>Current position FEN: <strong>$fen</strong></blockquote>";
464        $moves = $this->_board->getMoveList(true);
465        echo '<table border="1"><th colspan="3" align="center">Moves</th><tr>' .
466             '<td>#</td><td>White</td><td>Black</td></tr>';
467        foreach($moves as $num => $moveset) {
468            echo '<tr>';
469            echo "<td>$num</td>";
470            if (isset($moveset[0])) {
471                echo "<td>$moveset[0]</td>";
472            } else {
473                echo "<td>&nbsp;</td>";
474            }
475
476            if (isset($moveset[1])) {
477                echo "<td>$moveset[1]</td>";
478            }
479            echo '</tr>';
480        }
481        echo '</table>';
482    }
483
484    /**
485    * Prints the castling buttons after checking castling rights
486    *
487    * If castling rights have been taken away by a king or rook move, the button is not displayed.  This function
488    * uses {@link Games_Chess::canCastleKingside(), Games_Chess::canCastleQueenside()} to find out.
489    */
490    function castlebutton()
491    {
492        if ($this->_board->canCastleKingside())
493        echo '<input type="submit" name="kingcastle" value="Castle Your King Kingside">';
494        if ($this->_board->canCastleQueenside())
495        echo '<input type="submit" name="queencastle" value="Castle Your King Queenside">';
496    }
497}
498
499setup_game('mygame','x');
500$x = $_SESSION['x'];
501$fen = isset($_GET['FEN']) ? $_GET['FEN'] : false;
502if (!isset($x) || isset($_GET['newgame']) || $fen
503      || isset($_GET['newlosergame']) || isset($_GET['newcrazyhousegame'])) {
504    if (isset($_GET['newcrazyhousegame'])) {
505        $x = new visualboard($fen, 'Crazyhouse');
506    } elseif (isset($_GET['newlosergame'])) {
507        $x = new visualboard($fen, 'Losers');
508    } else {
509        $x = new visualboard($fen, 'Standard');
510    }
511}
512?>
513<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
514
515<html>
516<head>
517    <title>PHP Chess!</title>
518</head>
519
520<body>
521<h1>Welcome to <a href="http://www.chiaraquartet.net">The Chiara Quartet's</a> PHP Chess</h1>
522<?php
523$x->draw();
524$_SESSION['x'] = $x;
525?>
526
527
528</body>
529</html>
530
531
532