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> </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 ' '; 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> </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