mambax7 /
chess
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
| 1 | <?php |
||||||
| 2 | |||||||
| 3 | use XoopsModules\Chess; |
||||||
| 4 | |||||||
| 5 | // ------------------------------------------------------------------------ // |
||||||
| 6 | // XOOPS - PHP Content Management System // |
||||||
| 7 | // Copyright (c) 2000 XOOPS.org // |
||||||
| 8 | // <https://xoops.org> // |
||||||
| 9 | // ------------------------------------------------------------------------- // |
||||||
| 10 | // This program is free software; you can redistribute it and/or modify // |
||||||
| 11 | // it under the terms of the GNU General Public License as published by // |
||||||
| 12 | // the Free Software Foundation; either version 2 of the License, or // |
||||||
| 13 | // (at your option) any later version. // |
||||||
| 14 | // // |
||||||
| 15 | // You may not change or alter any portion of this comment or credits // |
||||||
| 16 | // of supporting developers from this source code or any supporting // |
||||||
| 17 | // source code which is considered copyrighted (c) material of the // |
||||||
| 18 | // original comment or credit authors. // |
||||||
| 19 | // // |
||||||
| 20 | // This program is distributed in the hope that it will be useful, // |
||||||
| 21 | // but WITHOUT ANY WARRANTY; without even the implied warranty of // |
||||||
| 22 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // |
||||||
| 23 | // GNU General Public License for more details. // |
||||||
| 24 | // // |
||||||
| 25 | // You should have received a copy of the GNU General Public License // |
||||||
| 26 | // along with this program; if not, write to the Free Software // |
||||||
| 27 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // |
||||||
| 28 | // ------------------------------------------------------------------------ // |
||||||
| 29 | |||||||
| 30 | /** |
||||||
| 31 | * Handle an individual chess game. |
||||||
| 32 | * |
||||||
| 33 | * The array $gamedata used throughout this file contains the columns of the |
||||||
| 34 | * database row for the current game. |
||||||
| 35 | * @see ChessGame |
||||||
| 36 | * |
||||||
| 37 | * @package chess |
||||||
| 38 | * @subpackage game |
||||||
| 39 | */ |
||||||
| 40 | |||||||
| 41 | /**#@+ |
||||||
| 42 | */ |
||||||
| 43 | |||||||
| 44 | $GLOBALS['xoopsOption']['template_main'] = 'chess_game_main.tpl'; |
||||||
| 45 | require __DIR__ . '/header.php'; |
||||||
| 46 | |||||||
| 47 | require_once XOOPS_ROOT_PATH . '/class/xoopsformloader.php'; |
||||||
| 48 | $xoopsConfig['module_cache'][$xoopsModule->getVar('mid')] = 0; // disable caching |
||||||
| 49 | require_once XOOPS_ROOT_PATH . '/modules/chess/include/constants.inc.php'; |
||||||
| 50 | require_once XOOPS_ROOT_PATH . '/modules/chess/include/functions.php'; |
||||||
| 51 | |||||||
| 52 | chess_game(); |
||||||
| 53 | |||||||
| 54 | require_once XOOPS_ROOT_PATH . '/include/comment_view.php'; |
||||||
| 55 | require_once XOOPS_ROOT_PATH . '/footer.php'; |
||||||
| 56 | /**#@-*/ |
||||||
| 57 | |||||||
| 58 | /** |
||||||
| 59 | * Handle an individual chess game. |
||||||
| 60 | * |
||||||
| 61 | * processing: |
||||||
| 62 | * - fetch game data from database |
||||||
| 63 | * - handle user request |
||||||
| 64 | * - update game data in database |
||||||
| 65 | * - display board |
||||||
| 66 | */ |
||||||
| 67 | function chess_game() |
||||||
| 68 | { |
||||||
| 69 | // user input |
||||||
| 70 | |||||||
| 71 | $game_id = (int)@$_GET['game_id']; |
||||||
| 72 | |||||||
| 73 | $submit_move = isset($_POST['submit_move']); |
||||||
| 74 | |||||||
| 75 | $submit_refresh = isset($_POST['submit_refresh']); |
||||||
| 76 | |||||||
| 77 | $move = chess_sanitize(trim(@$_POST['chessmove']), 'A-Za-z0-9=-'); |
||||||
| 78 | |||||||
| 79 | $movetype = chess_sanitize(@$_POST['movetype']); |
||||||
| 80 | |||||||
| 81 | $confirm = isset($_POST['confirm']) ? 1 : 0; |
||||||
| 82 | |||||||
| 83 | $move_explain = chess_sanitize(trim(@$_POST['move_explain']), 'A-Za-z0-9 .,;:=()[]*?!-'); |
||||||
| 84 | |||||||
| 85 | $arbiter_explain = chess_sanitize(trim(@$_POST['arbiter_explain']), 'A-Za-z0-9 .,;:=()[]*?!-'); |
||||||
| 86 | |||||||
| 87 | $orientation = chess_sanitize(@$_POST['orientation']); |
||||||
| 88 | |||||||
| 89 | $show_arbiter_ctrl = isset($_POST['show_arbiter_ctrl']); |
||||||
| 90 | |||||||
| 91 | $submit_arbitrate = isset($_POST['submit_arbitrate']); |
||||||
| 92 | |||||||
| 93 | $arbiter_action = chess_sanitize(@$_POST['arbiter_action']); |
||||||
| 94 | |||||||
| 95 | // If form-submit, check security token. |
||||||
| 96 | |||||||
| 97 | if (($submit_move || $submit_refresh || $submit_arbitrate || $show_arbiter_ctrl) && is_object($GLOBALS['xoopsSecurity']) && !$GLOBALS['xoopsSecurity']->check()) { |
||||||
| 98 | redirect_header( |
||||||
| 99 | XOOPS_URL . '/modules/chess/', |
||||||
| 100 | _CHESS_REDIRECT_DELAY_FAILURE, |
||||||
| 101 | _MD_CHESS_TOKEN_ERROR . '<br>' . implode('<br>', $GLOBALS['xoopsSecurity']->getErrors()) |
||||||
| 102 | ); |
||||||
| 103 | } |
||||||
| 104 | |||||||
| 105 | // Fetch the game data from the database. |
||||||
| 106 | |||||||
| 107 | $gamedata = chess_get_game($game_id); |
||||||
| 108 | |||||||
| 109 | if (false === $gamedata) { |
||||||
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||||||
| 110 | redirect_header(XOOPS_URL . '/modules/chess/', _CHESS_REDIRECT_DELAY_FAILURE, _MD_CHESS_GAME_NOT_FOUND); |
||||||
| 111 | } |
||||||
| 112 | |||||||
| 113 | $gamedata_updated = false; |
||||||
| 114 | |||||||
| 115 | $move_performed = false; // status result from move-handler |
||||||
| 116 | $move_result_text = ''; // text result from move-handler |
||||||
| 117 | $draw_claim_error_text = ''; // text describing invalid draw-claim |
||||||
| 118 | $notify = ''; // text description of action for notification |
||||||
| 119 | $delete_game = false; |
||||||
| 120 | |||||||
| 121 | global $xoopsUser; |
||||||
| 122 | |||||||
| 123 | $uid = $xoopsUser ? $xoopsUser->getVar('uid') : 0; |
||||||
| 124 | |||||||
| 125 | $selfplay = $gamedata['white_uid'] == $gamedata['black_uid']; |
||||||
| 126 | |||||||
| 127 | if ($selfplay) { |
||||||
| 128 | if ($uid == $gamedata['white_uid']) { |
||||||
| 129 | $user_color = $gamedata['fen_active_color']; // current user is either player, so consider him active player |
||||||
| 130 | } else { |
||||||
| 131 | $user_color = ''; // current user is not a player |
||||||
| 132 | } |
||||||
| 133 | // not self-play |
||||||
| 134 | } else { |
||||||
| 135 | if ($uid == $gamedata['white_uid']) { |
||||||
| 136 | $user_color = 'w'; // current user is white |
||||||
| 137 | } elseif ($uid == $gamedata['black_uid']) { |
||||||
| 138 | $user_color = 'b'; // current user is black |
||||||
| 139 | } else { |
||||||
| 140 | $user_color = ''; // current user is not a player |
||||||
| 141 | } |
||||||
| 142 | } |
||||||
| 143 | |||||||
| 144 | // Determine whether current user is a player in the current game, and whether it's his move. |
||||||
| 145 | |||||||
| 146 | $user_is_player = 'w' == $user_color || 'b' == $user_color; |
||||||
| 147 | |||||||
| 148 | $user_is_player_to_move = $user_color == $gamedata['fen_active_color']; |
||||||
| 149 | |||||||
| 150 | $user_color_name = 'w' == $user_color ? _MD_CHESS_WHITE : _MD_CHESS_BLACK; |
||||||
| 151 | |||||||
| 152 | if ($submit_move && !$gamedata['suspended']) { |
||||||
| 153 | // If the player has changed his confirm-move preference, it needs to be updated in the database. |
||||||
| 154 | |||||||
| 155 | // For a self-play game, the white and black confirm-move preferences are kept the same, to avoid confusion. |
||||||
| 156 | |||||||
| 157 | if ($user_is_player) { |
||||||
| 158 | if ('w' == $user_color && $gamedata['white_confirm'] != $confirm) { |
||||||
| 159 | $gamedata['white_confirm'] = $confirm; |
||||||
| 160 | |||||||
| 161 | if ($selfplay) { |
||||||
| 162 | $gamedata['black_confirm'] = $confirm; |
||||||
| 163 | } |
||||||
| 164 | |||||||
| 165 | $gamedata_updated = true; |
||||||
| 166 | } elseif ('b' == $user_color && $gamedata['black_confirm'] != $confirm) { |
||||||
| 167 | $gamedata['black_confirm'] = $confirm; |
||||||
| 168 | |||||||
| 169 | if ($selfplay) { |
||||||
| 170 | $gamedata['white_confirm'] = $confirm; |
||||||
| 171 | } |
||||||
| 172 | |||||||
| 173 | $gamedata_updated = true; |
||||||
| 174 | } |
||||||
| 175 | } |
||||||
| 176 | |||||||
| 177 | switch ($movetype) { |
||||||
| 178 | default: |
||||||
| 179 | case _CHESS_MOVETYPE_NORMAL: |
||||||
| 180 | if ($user_is_player_to_move && $gamedata['offer_draw'] != $user_color) { |
||||||
| 181 | [$move_performed, $move_result_text] = chess_move($gamedata, $move); |
||||||
| 182 | |||||||
| 183 | if ($move_performed) { |
||||||
| 184 | if ($selfplay) { // If self-play, the current user's color switches. |
||||||
| 185 | $user_color = $gamedata['fen_active_color']; |
||||||
| 186 | } |
||||||
| 187 | |||||||
| 188 | $gamedata['offer_draw'] = ''; |
||||||
| 189 | |||||||
| 190 | $gamedata_updated = true; |
||||||
| 191 | |||||||
| 192 | $notify = "$user_color_name: $move"; |
||||||
| 193 | } |
||||||
| 194 | } |
||||||
| 195 | break; |
||||||
| 196 | case _CHESS_MOVETYPE_CLAIM_DRAW_3: |
||||||
| 197 | case _CHESS_MOVETYPE_CLAIM_DRAW_50: |
||||||
| 198 | if ($user_is_player_to_move && $gamedata['offer_draw'] != $user_color) { |
||||||
| 199 | if (!empty($move)) { |
||||||
| 200 | [$move_performed, $move_result_text] = chess_move($gamedata, $move); |
||||||
| 201 | |||||||
| 202 | #var_dump('chess_game', $move_performed, $move_result_text);#*#DEBUG# |
||||||
| 203 | |||||||
| 204 | if ($move_performed) { |
||||||
| 205 | if ($selfplay) { // If self-play, the current user's color switches. |
||||||
| 206 | $user_color = $gamedata['fen_active_color']; |
||||||
| 207 | } |
||||||
| 208 | |||||||
| 209 | $gamedata['offer_draw'] = ''; |
||||||
| 210 | |||||||
| 211 | $gamedata_updated = true; |
||||||
| 212 | |||||||
| 213 | $notify = "$user_color_name: $move"; |
||||||
| 214 | } else { |
||||||
| 215 | break; // move invalid, so don't bother checking draw-claim |
||||||
| 216 | } |
||||||
| 217 | } |
||||||
| 218 | |||||||
| 219 | [$draw_claim_valid, $draw_claim_text] = _CHESS_MOVETYPE_CLAIM_DRAW_3 == $movetype ? chess_is_draw_threefold_repetition($gamedata) : chess_is_draw_50_move_rule($gamedata); |
||||||
| 220 | |||||||
| 221 | #var_dump('chess_game', $draw_claim_valid, $draw_claim_text);#*#DEBUG# |
||||||
| 222 | |||||||
| 223 | if ($draw_claim_valid) { |
||||||
| 224 | $gamedata['offer_draw'] = ''; |
||||||
| 225 | |||||||
| 226 | $gamedata['pgn_result'] = '1/2-1/2'; |
||||||
| 227 | |||||||
| 228 | $comment = '{' . $draw_claim_text . '}'; |
||||||
| 229 | |||||||
| 230 | $gamedata['pgn_movetext'] = str_replace('*', "{$gamedata['pgn_result']} $comment", $gamedata['pgn_movetext']); |
||||||
| 231 | |||||||
| 232 | $gamedata_updated = true; |
||||||
| 233 | |||||||
| 234 | $notify = !empty($move) ? "$user_color_name: $move: $draw_claim_text" : "$user_color_name: $draw_claim_text"; |
||||||
| 235 | } else { |
||||||
| 236 | $draw_claim_error_text = $draw_claim_text; |
||||||
| 237 | } |
||||||
| 238 | } |
||||||
| 239 | break; |
||||||
| 240 | case _CHESS_MOVETYPE_RESIGN: |
||||||
| 241 | if ($user_is_player) { |
||||||
| 242 | $gamedata['offer_draw'] = ''; |
||||||
| 243 | |||||||
| 244 | $gamedata['pgn_result'] = 'w' == $user_color ? '0-1' : '1-0'; |
||||||
| 245 | |||||||
| 246 | $comment = '{' . $user_color_name . ' ' . _MD_CHESS_RESIGNED . '}'; |
||||||
| 247 | |||||||
| 248 | $gamedata['pgn_movetext'] = str_replace('*', "{$gamedata['pgn_result']} $comment", $gamedata['pgn_movetext']); |
||||||
| 249 | |||||||
| 250 | $gamedata_updated = true; |
||||||
| 251 | |||||||
| 252 | $notify = "$user_color_name " . _MD_CHESS_RESIGNED; |
||||||
| 253 | } |
||||||
| 254 | break; |
||||||
| 255 | case _CHESS_MOVETYPE_OFFER_DRAW: |
||||||
| 256 | if ($user_is_player && empty($gamedata['offer_draw']) && !$selfplay) { |
||||||
| 257 | $gamedata['offer_draw'] = $user_color; |
||||||
| 258 | |||||||
| 259 | $gamedata_updated = true; |
||||||
| 260 | |||||||
| 261 | $notify = "$user_color_name " . _MD_CHESS_OFFERED_DRAW; |
||||||
| 262 | } |
||||||
| 263 | break; |
||||||
| 264 | case _CHESS_MOVETYPE_ACCEPT_DRAW: |
||||||
| 265 | if ($user_is_player && !empty($gamedata['offer_draw']) && $gamedata['offer_draw'] != $user_color && !$selfplay) { |
||||||
| 266 | $gamedata['offer_draw'] = ''; |
||||||
| 267 | |||||||
| 268 | $gamedata['pgn_result'] = '1/2-1/2'; |
||||||
| 269 | |||||||
| 270 | $comment = '{' . _MD_CHESS_DRAW_BY_AGREEMENT . '}'; |
||||||
| 271 | |||||||
| 272 | $gamedata['pgn_movetext'] = str_replace('*', "{$gamedata['pgn_result']} $comment", $gamedata['pgn_movetext']); |
||||||
| 273 | |||||||
| 274 | $gamedata_updated = true; |
||||||
| 275 | |||||||
| 276 | $notify = "$user_color_name " . _MD_CHESS_ACCEPTED_DRAW; |
||||||
| 277 | } |
||||||
| 278 | |||||||
| 279 | // no break |
||||||
| 280 | case _CHESS_MOVETYPE_REJECT_DRAW: |
||||||
| 281 | if ($user_is_player && !empty($gamedata['offer_draw']) && $gamedata['offer_draw'] != $user_color && !$selfplay) { |
||||||
| 282 | $gamedata['offer_draw'] = ''; |
||||||
| 283 | |||||||
| 284 | $gamedata_updated = true; |
||||||
| 285 | |||||||
| 286 | $notify = "$user_color_name " . _MD_CHESS_REJECTED_DRAW; |
||||||
| 287 | } |
||||||
| 288 | break; |
||||||
| 289 | case _CHESS_MOVETYPE_RESTART: |
||||||
| 290 | if ($user_is_player && $selfplay) { |
||||||
| 291 | // instantiate a ChessGame to get a "fresh" gamestate |
||||||
| 292 | |||||||
| 293 | $chessgame = new Chess\ChessGame($gamedata['pgn_fen']); |
||||||
| 294 | |||||||
| 295 | $new_gamestate = $chessgame->gamestate(); |
||||||
| 296 | |||||||
| 297 | // update the game data |
||||||
| 298 | |||||||
| 299 | $gamedata['fen_piece_placement'] = $new_gamestate['fen_piece_placement']; |
||||||
| 300 | |||||||
| 301 | $gamedata['fen_active_color'] = $new_gamestate['fen_active_color']; |
||||||
| 302 | |||||||
| 303 | $gamedata['fen_castling_availability'] = $new_gamestate['fen_castling_availability']; |
||||||
| 304 | |||||||
| 305 | $gamedata['fen_en_passant_target_square'] = $new_gamestate['fen_en_passant_target_square']; |
||||||
| 306 | |||||||
| 307 | $gamedata['fen_halfmove_clock'] = $new_gamestate['fen_halfmove_clock']; |
||||||
| 308 | |||||||
| 309 | $gamedata['fen_fullmove_number'] = $new_gamestate['fen_fullmove_number']; |
||||||
| 310 | |||||||
| 311 | $gamedata['pgn_fen'] = $new_gamestate['pgn_fen']; |
||||||
| 312 | |||||||
| 313 | $gamedata['pgn_result'] = $new_gamestate['pgn_result']; |
||||||
| 314 | |||||||
| 315 | $gamedata['pgn_movetext'] = $new_gamestate['pgn_movetext']; |
||||||
| 316 | |||||||
| 317 | // update user color |
||||||
| 318 | |||||||
| 319 | $user_color = $gamedata['fen_active_color']; |
||||||
| 320 | |||||||
| 321 | $gamedata_updated = true; |
||||||
| 322 | } |
||||||
| 323 | break; |
||||||
| 324 | case _CHESS_MOVETYPE_DELETE: |
||||||
| 325 | if ($user_is_player && ($selfplay || chess_can_delete())) { |
||||||
| 326 | $delete_game = true; // must defer actual deletion until after notifications are sent |
||||||
| 327 | $notify = eval('return \'' . _MD_CHESS_DELETED_GAME . '\';'); // eval references $username |
||||||
|
0 ignored issues
–
show
|
|||||||
| 328 | } |
||||||
| 329 | break; |
||||||
| 330 | case _CHESS_MOVETYPE_WANT_ARBITRATION: |
||||||
| 331 | if ($user_is_player) { |
||||||
| 332 | // Ensure that $move_explain does not contain separator $sep. |
||||||
| 333 | |||||||
| 334 | $sep = '|'; |
||||||
| 335 | |||||||
| 336 | $move_explain = str_replace($sep, '_', $move_explain); |
||||||
| 337 | |||||||
| 338 | $gamedata['suspended'] = implode($sep, [date('Y-m-d H:i:s'), $uid, _CHESS_MOVETYPE_WANT_ARBITRATION, $move_explain]); |
||||||
| 339 | |||||||
| 340 | $gamedata_updated = true; |
||||||
| 341 | |||||||
| 342 | $notify = "$user_color_name " . _MD_CHESS_RQSTED_ARBT . ' ' . _MD_CHESS_BEEN_SUSPENDED; |
||||||
| 343 | } |
||||||
| 344 | break; |
||||||
| 345 | } |
||||||
| 346 | } |
||||||
| 347 | |||||||
| 348 | // If board orientation setting uninitialized or invalid, set it to the appropriate default. |
||||||
| 349 | |||||||
| 350 | if (!in_array($orientation, [_CHESS_ORIENTATION_ACTIVE, _CHESS_ORIENTATION_WHITE, _CHESS_ORIENTATION_BLACK])) { |
||||||
| 351 | if ($user_is_player && 'b' == $user_color) { |
||||||
| 352 | $orientation = _CHESS_ORIENTATION_BLACK; |
||||||
| 353 | } else { |
||||||
| 354 | $orientation = _CHESS_ORIENTATION_WHITE; |
||||||
| 355 | } |
||||||
| 356 | } |
||||||
| 357 | |||||||
| 358 | // Determine if user is a valid arbiter. |
||||||
| 359 | |||||||
| 360 | global $xoopsModule; |
||||||
| 361 | |||||||
| 362 | $is_arbiter = is_object($xoopsUser) && $xoopsUser->isAdmin($xoopsModule->getVar('mid')); |
||||||
| 363 | |||||||
| 364 | // If arbiter action was submitted, and user is a valid arbiter, process the action. |
||||||
| 365 | |||||||
| 366 | if ($submit_arbitrate && $is_arbiter) { |
||||||
| 367 | $username = $xoopsUser ? $xoopsUser->getVar('uname') : '*unknown*'; |
||||||
|
0 ignored issues
–
show
|
|||||||
| 368 | |||||||
| 369 | switch ($arbiter_action) { |
||||||
| 370 | case _CHESS_ARBITER_RESUME: |
||||||
| 371 | if ($gamedata['suspended'] && '*' == $gamedata['pgn_result']) { |
||||||
| 372 | $gamedata['suspended'] = ''; |
||||||
| 373 | |||||||
| 374 | $gamedata_updated = true; |
||||||
| 375 | |||||||
| 376 | $notify = eval('return \'' . _MD_CHESS_RESUMED_PLAY . '\';'); // eval references $username |
||||||
|
0 ignored issues
–
show
|
|||||||
| 377 | } |
||||||
| 378 | break; |
||||||
| 379 | case _CHESS_ARBITER_DRAW: |
||||||
| 380 | if ($gamedata['suspended'] && '*' == $gamedata['pgn_result']) { |
||||||
| 381 | $gamedata['offer_draw'] = ''; |
||||||
| 382 | |||||||
| 383 | $gamedata['pgn_result'] = '1/2-1/2'; |
||||||
| 384 | |||||||
| 385 | $arbiter_explain = str_replace('{', '(', $arbiter_explain); |
||||||
| 386 | |||||||
| 387 | $arbiter_explain = str_replace('}', ')', $arbiter_explain); |
||||||
| 388 | |||||||
| 389 | $comment = '{' . sprintf(_MD_CHESS_DRAW_DECLARED, $arbiter_explain) . '}'; |
||||||
| 390 | |||||||
| 391 | $gamedata['pgn_movetext'] = str_replace('*', "{$gamedata['pgn_result']} $comment", $gamedata['pgn_movetext']); |
||||||
| 392 | |||||||
| 393 | $gamedata['suspended'] = ''; |
||||||
| 394 | |||||||
| 395 | $gamedata_updated = true; |
||||||
| 396 | |||||||
| 397 | $notify = eval('return \'' . _MD_CHESS_DECLARED_DRAW . '\';'); // eval references $username |
||||||
|
0 ignored issues
–
show
|
|||||||
| 398 | } |
||||||
| 399 | break; |
||||||
| 400 | case _CHESS_ARBITER_DELETE: |
||||||
| 401 | if ($gamedata['suspended']) { |
||||||
| 402 | $delete_game = true; // must defer actual deletion until after notifications are sent |
||||||
| 403 | $notify = eval('return \'' . _MD_CHESS_DELETED_GAME . '\';'); // eval references $username |
||||||
|
0 ignored issues
–
show
|
|||||||
| 404 | } |
||||||
| 405 | break; |
||||||
| 406 | case _CHESS_ARBITER_SUSPEND: |
||||||
| 407 | if (!$gamedata['suspended'] && '*' == $gamedata['pgn_result']) { |
||||||
| 408 | // Ensure that $arbiter_explain does not contain separator $sep. |
||||||
| 409 | |||||||
| 410 | $sep = '|'; |
||||||
| 411 | |||||||
| 412 | $arbiter_explain = str_replace($sep, '_', $arbiter_explain); |
||||||
| 413 | |||||||
| 414 | $gamedata['suspended'] = implode('|', [date('Y-m-d H:i:s'), $uid, _CHESS_MOVETYPE_ARBITER_SUSPEND, $arbiter_explain]); |
||||||
| 415 | |||||||
| 416 | $gamedata_updated = true; |
||||||
| 417 | |||||||
| 418 | $notify = eval('return \'' . _MD_CHESS_SUSPENDED_PLAY . '\';'); // eval references $username |
||||||
|
0 ignored issues
–
show
|
|||||||
| 419 | } |
||||||
| 420 | break; |
||||||
| 421 | default: |
||||||
| 422 | break; |
||||||
| 423 | } |
||||||
| 424 | } |
||||||
| 425 | |||||||
| 426 | // Store the updated game data in the database. |
||||||
| 427 | |||||||
| 428 | if ($gamedata_updated) { |
||||||
| 429 | chess_put_game($game_id, $gamedata); |
||||||
| 430 | } |
||||||
| 431 | |||||||
| 432 | // Display the (possibly updated) board. |
||||||
| 433 | |||||||
| 434 | if (!$delete_game) { |
||||||
| 435 | chess_show_board($gamedata, $orientation, $user_color, $move_performed, $move_result_text, $draw_claim_error_text, $show_arbiter_ctrl && $is_arbiter); |
||||||
| 436 | } |
||||||
| 437 | |||||||
| 438 | // If a move (or other action) was made, notify any subscribers. |
||||||
| 439 | |||||||
| 440 | if (!empty($notify)) { |
||||||
| 441 | $notificationHandler = xoops_getHandler('notification'); |
||||||
| 442 | |||||||
| 443 | $notificationHandler->triggerEvent('game', $game_id, 'notify_game_move', ['CHESS_ACTION' => $notify]); |
||||||
|
0 ignored issues
–
show
The method
triggerEvent() does not exist on XoopsObjectHandler. It seems like you code against a sub-type of XoopsObjectHandler such as XoopsNotificationHandler or XoopsPersistableObjectHandler.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 444 | |||||||
| 445 | // admin notifications |
||||||
| 446 | |||||||
| 447 | if (_CHESS_MOVETYPE_WANT_ARBITRATION == $movetype) { |
||||||
| 448 | $event = 'notify_request_arbitration'; |
||||||
| 449 | |||||||
| 450 | $username = $xoopsUser ? $xoopsUser->getVar('uname') : '(' . _MD_CHESS_UNKNOWN . ')'; |
||||||
| 451 | |||||||
| 452 | $extra_tags = ['CHESS_REQUESTOR' => $username, 'CHESS_GAME_ID' => $game_id, 'CHESS_EXPLAIN' => $move_explain]; |
||||||
| 453 | |||||||
| 454 | $notificationHandler->triggerEvent('global', 0, $event, $extra_tags); |
||||||
| 455 | } |
||||||
| 456 | } |
||||||
| 457 | |||||||
| 458 | // Handle delete-game action. |
||||||
| 459 | |||||||
| 460 | if ($delete_game) { |
||||||
| 461 | chess_delete_game($game_id); |
||||||
| 462 | |||||||
| 463 | redirect_header(XOOPS_URL . '/modules/chess/', _CHESS_REDIRECT_DELAY_SUCCESS, _MD_CHESS_GAME_DELETED); |
||||||
| 464 | } |
||||||
| 465 | } |
||||||
| 466 | |||||||
| 467 | /** |
||||||
| 468 | * Fetch game data from database. |
||||||
| 469 | * |
||||||
| 470 | * @param int $game_id Game ID |
||||||
| 471 | * @return array Game data |
||||||
| 472 | */ |
||||||
| 473 | function chess_get_game($game_id) |
||||||
| 474 | { |
||||||
| 475 | global $xoopsDB; |
||||||
| 476 | |||||||
| 477 | $games_table = $xoopsDB->prefix('chess_games'); |
||||||
| 478 | |||||||
| 479 | $result = $xoopsDB->query("SELECT * FROM $games_table WHERE game_id = '$game_id'"); |
||||||
| 480 | |||||||
| 481 | $gamedata = $xoopsDB->fetchArray($result); |
||||||
| 482 | |||||||
| 483 | #var_dump('chess_get_game, gamedata', $gamedata);#*#DEBUG# |
||||||
| 484 | |||||||
| 485 | $xoopsDB->freeRecordSet($result); |
||||||
| 486 | |||||||
| 487 | return $gamedata; |
||||||
| 488 | } |
||||||
| 489 | |||||||
| 490 | /** |
||||||
| 491 | * Store game data in database. |
||||||
| 492 | * |
||||||
| 493 | * @param int $game_id Game ID |
||||||
| 494 | * @param array $gamedata Game data |
||||||
| 495 | */ |
||||||
| 496 | function chess_put_game($game_id, $gamedata) |
||||||
| 497 | { |
||||||
| 498 | global $xoopsDB; |
||||||
| 499 | |||||||
| 500 | $myts = MyTextSanitizer::getInstance(); |
||||||
| 501 | |||||||
| 502 | $suspended_q = $myts->addSlashes($gamedata['suspended']); |
||||||
| 503 | |||||||
| 504 | $movetext_q = $myts->addSlashes($gamedata['pgn_movetext']); |
||||||
| 505 | |||||||
| 506 | $table = $xoopsDB->prefix('chess_games'); |
||||||
| 507 | |||||||
| 508 | #echo "updating database table $table<br>\n";#*#DEBUG# |
||||||
| 509 | |||||||
| 510 | $xoopsDB->query( |
||||||
| 511 | trim( |
||||||
| 512 | " |
||||||
| 513 | UPDATE $table |
||||||
| 514 | SET |
||||||
| 515 | start_date = '{$gamedata['start_date']}', |
||||||
| 516 | last_date = '{$gamedata['last_date']}', |
||||||
| 517 | fen_piece_placement = '{$gamedata['fen_piece_placement']}', |
||||||
| 518 | fen_active_color = '{$gamedata['fen_active_color']}', |
||||||
| 519 | fen_castling_availability = '{$gamedata['fen_castling_availability']}', |
||||||
| 520 | fen_en_passant_target_square = '{$gamedata['fen_en_passant_target_square']}', |
||||||
| 521 | fen_halfmove_clock = '{$gamedata['fen_halfmove_clock']}', |
||||||
| 522 | fen_fullmove_number = '{$gamedata['fen_fullmove_number']}', |
||||||
| 523 | pgn_result = '{$gamedata['pgn_result']}', |
||||||
| 524 | pgn_movetext = '$movetext_q', |
||||||
| 525 | offer_draw = '{$gamedata['offer_draw']}', |
||||||
| 526 | suspended = '$suspended_q', |
||||||
| 527 | white_confirm = '{$gamedata['white_confirm']}', |
||||||
| 528 | black_confirm = '{$gamedata['black_confirm']}' |
||||||
| 529 | WHERE game_id = '$game_id' |
||||||
| 530 | " |
||||||
| 531 | ) |
||||||
| 532 | ); |
||||||
| 533 | |||||||
| 534 | if ($xoopsDB->errno()) { |
||||||
| 535 | trigger_error($xoopsDB->errno() . ':' . $xoopsDB->error(), E_USER_ERROR); |
||||||
| 536 | } |
||||||
| 537 | |||||||
| 538 | if ('*' != $gamedata['pgn_result'] && '1' == $gamedata['is_rated']) { |
||||||
| 539 | require_once XOOPS_ROOT_PATH . '/modules/chess/include/ratings.php'; |
||||||
| 540 | |||||||
| 541 | chess_ratings_adj($game_id); |
||||||
| 542 | } |
||||||
| 543 | } |
||||||
| 544 | |||||||
| 545 | /** |
||||||
| 546 | * Delete game from database. |
||||||
| 547 | * |
||||||
| 548 | * @param int $game_id Game ID |
||||||
| 549 | */ |
||||||
| 550 | function chess_delete_game($game_id) |
||||||
| 551 | { |
||||||
| 552 | global $xoopsModule, $xoopsDB; |
||||||
| 553 | |||||||
| 554 | // delete notifications associated with this game |
||||||
| 555 | |||||||
| 556 | xoops_notification_deletebyitem($xoopsModule->getVar('mid'), 'game', $game_id); |
||||||
| 557 | |||||||
| 558 | $table = $xoopsDB->prefix('chess_games'); |
||||||
| 559 | |||||||
| 560 | $xoopsDB->query("DELETE FROM $table WHERE game_id='$game_id'"); |
||||||
| 561 | |||||||
| 562 | if ($xoopsDB->errno()) { |
||||||
| 563 | trigger_error($xoopsDB->errno() . ':' . $xoopsDB->error(), E_USER_ERROR); |
||||||
| 564 | } |
||||||
| 565 | } |
||||||
| 566 | |||||||
| 567 | /** |
||||||
| 568 | * Handle a move. |
||||||
| 569 | * |
||||||
| 570 | * @param array $gamedata Game data (input/output) |
||||||
| 571 | * @param string $move The move |
||||||
| 572 | * @return array A two-element array: |
||||||
| 573 | * - $move_performed: true if the move was performed and the game state has been updated, false otherwise |
||||||
| 574 | * - $move_result_text: text message |
||||||
| 575 | */ |
||||||
| 576 | function chess_move(&$gamedata, $move) |
||||||
| 577 | { |
||||||
| 578 | $gamestate = [ |
||||||
| 579 | 'fen_piece_placement' => $gamedata['fen_piece_placement'], |
||||||
| 580 | 'fen_active_color' => $gamedata['fen_active_color'], |
||||||
| 581 | 'fen_castling_availability' => $gamedata['fen_castling_availability'], |
||||||
| 582 | 'fen_en_passant_target_square' => $gamedata['fen_en_passant_target_square'], |
||||||
| 583 | 'fen_halfmove_clock' => $gamedata['fen_halfmove_clock'], |
||||||
| 584 | 'fen_fullmove_number' => $gamedata['fen_fullmove_number'], |
||||||
| 585 | 'pgn_fen' => $gamedata['pgn_fen'], |
||||||
| 586 | 'pgn_result' => $gamedata['pgn_result'], |
||||||
| 587 | 'pgn_movetext' => $gamedata['pgn_movetext'], |
||||||
| 588 | ]; |
||||||
| 589 | |||||||
| 590 | $chessgame = new Chess\ChessGame($gamestate); |
||||||
| 591 | |||||||
| 592 | #echo "Performing move: '$move'<br>\n";#*#DEBUG# |
||||||
| 593 | |||||||
| 594 | [$move_performed, $move_result_text] = $chessgame->move($move); |
||||||
| 595 | |||||||
| 596 | #echo "Move result: '$move_result_text'<br>\n";#*#DEBUG# |
||||||
| 597 | |||||||
| 598 | if ($move_performed) { |
||||||
| 599 | // The move was valid - update the game data. |
||||||
| 600 | |||||||
| 601 | $new_gamestate = $chessgame->gamestate(); |
||||||
| 602 | |||||||
| 603 | #var_dump('new_gamestate', $new_gamestate);#*#DEBUG# |
||||||
| 604 | |||||||
| 605 | #*#DEBUG# - start |
||||||
| 606 | |||||||
| 607 | #if ($new_gamestate['fen_castling_availability'] != $gamedata['fen_castling_availability']) { |
||||||
| 608 | |||||||
| 609 | # echo "*** castling_availability changed from '{$gamedata['fen_castling_availability']}' to '{$new_gamestate['fen_castling_availability']}' ***<br>\n"; |
||||||
| 610 | |||||||
| 611 | #} |
||||||
| 612 | |||||||
| 613 | #*#DEBUG# - end |
||||||
| 614 | |||||||
| 615 | $gamedata['fen_piece_placement'] = $new_gamestate['fen_piece_placement']; |
||||||
| 616 | |||||||
| 617 | $gamedata['fen_active_color'] = $new_gamestate['fen_active_color']; |
||||||
| 618 | |||||||
| 619 | $gamedata['fen_castling_availability'] = $new_gamestate['fen_castling_availability']; |
||||||
| 620 | |||||||
| 621 | $gamedata['fen_en_passant_target_square'] = $new_gamestate['fen_en_passant_target_square']; |
||||||
| 622 | |||||||
| 623 | $gamedata['fen_halfmove_clock'] = $new_gamestate['fen_halfmove_clock']; |
||||||
| 624 | |||||||
| 625 | $gamedata['fen_fullmove_number'] = $new_gamestate['fen_fullmove_number']; |
||||||
| 626 | |||||||
| 627 | $gamedata['pgn_fen'] = $new_gamestate['pgn_fen']; |
||||||
| 628 | |||||||
| 629 | $gamedata['pgn_result'] = $new_gamestate['pgn_result']; |
||||||
| 630 | |||||||
| 631 | $gamedata['pgn_movetext'] = $new_gamestate['pgn_movetext']; |
||||||
| 632 | |||||||
| 633 | $gamedata['last_date'] = date('Y-m-d H:i:s'); |
||||||
| 634 | |||||||
| 635 | // if start_date undefined (first move), initialize it |
||||||
| 636 | |||||||
| 637 | if ('0000-00-00 00:00:00' == $gamedata['start_date']) { |
||||||
| 638 | $gamedata['start_date'] = $gamedata['last_date']; |
||||||
| 639 | } |
||||||
| 640 | } |
||||||
| 641 | |||||||
| 642 | return [$move_performed, $move_result_text]; |
||||||
| 643 | } |
||||||
| 644 | |||||||
| 645 | /** |
||||||
| 646 | * Verify a draw-claim under the 50-move rule. |
||||||
| 647 | * |
||||||
| 648 | * @param array $gamedata Game data |
||||||
| 649 | * @return array A two-element array: |
||||||
| 650 | * - $draw_claim_valid: True if draw-claim is valid, otherwise false |
||||||
| 651 | * - $draw_claim_text: Describes draw-claim result |
||||||
| 652 | */ |
||||||
| 653 | function chess_is_draw_50_move_rule($gamedata) |
||||||
| 654 | { |
||||||
| 655 | #var_dump('gamedata', $gamedata);#*#DEBUG# |
||||||
| 656 | |||||||
| 657 | if ($gamedata['fen_halfmove_clock'] >= 100) { |
||||||
| 658 | $draw_claim_valid = true; |
||||||
| 659 | |||||||
| 660 | $draw_claim_text = _MD_CHESS_DRAW_50; |
||||||
| 661 | } else { |
||||||
| 662 | $draw_claim_valid = false; |
||||||
| 663 | |||||||
| 664 | $draw_claim_text = _MD_CHESS_NO_DRAW_50; |
||||||
| 665 | } |
||||||
| 666 | |||||||
| 667 | return [$draw_claim_valid, $draw_claim_text]; |
||||||
| 668 | } |
||||||
| 669 | |||||||
| 670 | /** |
||||||
| 671 | * Verify a draw-claim under the threefold-repetition rule. |
||||||
| 672 | * |
||||||
| 673 | * Board positions are compared using the first four fields of the FEN data: |
||||||
| 674 | * fen_piece_placement, fen_active_color, fen_castling_availability and fen_en_passant_target_square. |
||||||
| 675 | * |
||||||
| 676 | * @param array $gamedata Game data |
||||||
| 677 | * @return array A two-element array: |
||||||
| 678 | * - $draw_claim_valid: True if draw-claim is valid, otherwise false |
||||||
| 679 | * - $draw_claim_text: Describes draw-claim result |
||||||
| 680 | */ |
||||||
| 681 | function chess_is_draw_threefold_repetition($gamedata) |
||||||
| 682 | { |
||||||
| 683 | #var_dump('gamedata', $gamedata);#*#DEBUG# |
||||||
| 684 | |||||||
| 685 | // Define this constant as true to output a log file containing a move analysis. |
||||||
| 686 | |||||||
| 687 | define('CHESS_LOG_3FOLD', false); |
||||||
| 688 | |||||||
| 689 | if (CHESS_LOG_3FOLD) { |
||||||
| 690 | $log = []; |
||||||
| 691 | } |
||||||
| 692 | |||||||
| 693 | $chessgame = new Chess\ChessGame($gamedata); |
||||||
|
0 ignored issues
–
show
|
|||||||
| 694 | |||||||
| 695 | // board position against which to check for repetitions |
||||||
| 696 | |||||||
| 697 | $last_board_state = "{$gamedata['fen_piece_placement']} {$gamedata['fen_active_color']} {$gamedata['fen_castling_availability']} {$gamedata['fen_en_passant_target_square']}"; |
||||||
| 698 | |||||||
| 699 | $last_move_number = $gamedata['fen_fullmove_number']; |
||||||
| 700 | |||||||
| 701 | #echo "last_board_state='$last_board_state'<br>\n";#*#DEBUG# |
||||||
| 702 | |||||||
| 703 | if (CHESS_LOG_3FOLD) { |
||||||
| 704 | $log[] = sprintf('%08x %03d%1s %s', crc32($last_board_state), $gamedata['fen_fullmove_number'], $gamedata['fen_active_color'], $last_board_state); |
||||||
| 705 | } |
||||||
| 706 | |||||||
| 707 | $chessgame = new Chess\ChessGame($gamedata['pgn_fen']); |
||||||
| 708 | |||||||
| 709 | empty($chessgame->error) or trigger_error('chessgame invalid', E_USER_ERROR); |
||||||
| 710 | |||||||
| 711 | $tmp_gamedata = $chessgame->gamestate(); |
||||||
| 712 | |||||||
| 713 | is_array($tmp_gamedata) or trigger_error('gamestate invalid', E_USER_ERROR); |
||||||
| 714 | |||||||
| 715 | #*#DEBUG# - start |
||||||
| 716 | |||||||
| 717 | /*** |
||||||
| 718 | * if (function_exists('posix_times')) { |
||||||
| 719 | * $posix_times = posix_times(); |
||||||
| 720 | * var_dump('posix_times', $posix_times); |
||||||
| 721 | * } |
||||||
| 722 | * if (function_exists('getrusage')) { |
||||||
| 723 | * $rusage = getrusage(); |
||||||
| 724 | * var_dump('rusage', $rusage); |
||||||
| 725 | * } |
||||||
| 726 | ***/ |
||||||
| 727 | |||||||
| 728 | #*#DEBUG# - end |
||||||
| 729 | |||||||
| 730 | // $repeats is the list of moves for which the board positions are identical. |
||||||
| 731 | |||||||
| 732 | // For example, '6w' would represent the board position immediately before white's sixth move. |
||||||
| 733 | |||||||
| 734 | // The current position is included, since that's the position against which the other positions will be compared. |
||||||
| 735 | |||||||
| 736 | $repeats[] = $gamedata['fen_fullmove_number'] . $gamedata['fen_active_color']; |
||||||
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||||||
| 737 | |||||||
| 738 | // Compare initial board position with last board position, unless the move number is the same, meaning that there haven't been any moves. |
||||||
| 739 | |||||||
| 740 | #echo "FEN: '{$tmp_gamedata['fen_piece_placement']} {$tmp_gamedata['fen_active_color']} {$tmp_gamedata['fen_castling_availability']} {$tmp_gamedata['fen_en_passant_target_square']} {$tmp_gamedata['fen_halfmove_clock']} {$tmp_gamedata['fen_fullmove_number']}'<br>\n";#*#DEBUG# |
||||||
| 741 | |||||||
| 742 | $board_state = "{$tmp_gamedata['fen_piece_placement']} {$tmp_gamedata['fen_active_color']} {$tmp_gamedata['fen_castling_availability']} {$tmp_gamedata['fen_en_passant_target_square']}"; |
||||||
| 743 | |||||||
| 744 | if ($tmp_gamedata['fen_fullmove_number'] != $last_move_number && $board_state == $last_board_state) { |
||||||
| 745 | $repeats[] = $tmp_gamedata['fen_fullmove_number'] . $tmp_gamedata['fen_active_color']; |
||||||
| 746 | |||||||
| 747 | if (CHESS_LOG_3FOLD) { |
||||||
| 748 | $log[] = sprintf('%08x %03d%1s %s', crc32($board_state), $tmp_gamedata['fen_fullmove_number'], $tmp_gamedata['fen_active_color'], $board_state); |
||||||
| 749 | } |
||||||
| 750 | |||||||
| 751 | #*#DEBUG# - start |
||||||
| 752 | /*** |
||||||
| 753 | * if (count($repeats) >= 3) { |
||||||
| 754 | * echo "*** Three repetitions! {$repeats[1]},{$repeats[2]},{$repeats[0]} ***<br>\n"; |
||||||
| 755 | * } elseif (count($repeats) >= 2) { |
||||||
| 756 | * echo "*** Two repetitions! {$repeats[1]},{$repeats[0]} ***<br>\n"; |
||||||
| 757 | * } |
||||||
| 758 | ***/ |
||||||
| 759 | #*#DEBUG# - end |
||||||
| 760 | } |
||||||
| 761 | |||||||
| 762 | // Convert pgn_movetext into Nx3 array $movelist. |
||||||
| 763 | |||||||
| 764 | $movelist = chess_make_movelist($gamedata['pgn_movetext']); |
||||||
| 765 | |||||||
| 766 | #var_dump('movelist', $movelist);#*#DEBUG# |
||||||
| 767 | |||||||
| 768 | // Compare board positions after each move with last board position. |
||||||
| 769 | |||||||
| 770 | foreach ($movelist as $fullmove) { |
||||||
| 771 | #echo "'{$fullmove[0]}' '{$fullmove[1]}' '{$fullmove[2]}'<br>\n";#*#DEBUG# |
||||||
| 772 | |||||||
| 773 | if (CHESS_LOG_3FOLD) { |
||||||
| 774 | #$log[] = "'{$fullmove[0]}' '{$fullmove[1]}' '{$fullmove[2]}'";#*#LOG_3FOLD# #*#DEBUG# |
||||||
| 775 | } |
||||||
| 776 | |||||||
| 777 | for ($i = 1; $i <= 2; ++$i) { |
||||||
| 778 | if (!empty($fullmove[$i])) { |
||||||
| 779 | $move = $fullmove[$i]; |
||||||
| 780 | } else { |
||||||
| 781 | continue; // $fullmove[$i] can be empty if last move was white's, or if game was setup with black to move first. |
||||||
| 782 | } |
||||||
| 783 | |||||||
| 784 | // Remove check/checkmate annotation, if present. |
||||||
| 785 | |||||||
| 786 | $move = str_replace('+', '', $move); |
||||||
| 787 | |||||||
| 788 | $move = str_replace('#', '', $move); |
||||||
| 789 | |||||||
| 790 | #echo "Performing move: '$move'<br>\n";#*#DEBUG# |
||||||
| 791 | |||||||
| 792 | [$tmp_move_performed, $tmp_move_result_text] = $chessgame->move($move); |
||||||
| 793 | |||||||
| 794 | #echo "Move result: '$tmp_move_result_text'<br>\n";#*#DEBUG# |
||||||
| 795 | |||||||
| 796 | $tmp_move_performed or trigger_error("Failed to perform move $move: $tmp_move_result_text", E_USER_ERROR); |
||||||
| 797 | |||||||
| 798 | $tmp_gamedata = $chessgame->gamestate(); |
||||||
| 799 | |||||||
| 800 | #echo "FEN: '{$tmp_gamedata['fen_piece_placement']} {$tmp_gamedata['fen_active_color']} {$tmp_gamedata['fen_castling_availability']} {$tmp_gamedata['fen_en_passant_target_square']} {$tmp_gamedata['fen_halfmove_clock']} {$tmp_gamedata['fen_fullmove_number']}'<br>\n";#*#DEBUG# |
||||||
| 801 | |||||||
| 802 | $board_state = "{$tmp_gamedata['fen_piece_placement']} {$tmp_gamedata['fen_active_color']} {$tmp_gamedata['fen_castling_availability']} {$tmp_gamedata['fen_en_passant_target_square']}"; |
||||||
| 803 | |||||||
| 804 | if (CHESS_LOG_3FOLD) { |
||||||
| 805 | $log[] = sprintf('%08x %03d%1s %s', crc32($board_state), $tmp_gamedata['fen_fullmove_number'], $tmp_gamedata['fen_active_color'], $board_state); |
||||||
| 806 | } |
||||||
| 807 | |||||||
| 808 | if ($tmp_gamedata['fen_fullmove_number'] != $last_move_number && $board_state == $last_board_state) { |
||||||
| 809 | $repeats[] = $tmp_gamedata['fen_fullmove_number'] . $tmp_gamedata['fen_active_color']; |
||||||
| 810 | |||||||
| 811 | #*#DEBUG# - start |
||||||
| 812 | |||||||
| 813 | /*** |
||||||
| 814 | * if (count($repeats) >= 3) { |
||||||
| 815 | * echo "*** Three repetitions! {$repeats[1]},{$repeats[2]},{$repeats[0]} ***<br>\n"; |
||||||
| 816 | * } elseif (count($repeats) >= 2) { |
||||||
| 817 | * echo "*** Two repetitions! {$repeats[1]},{$repeats[0]} ***<br>\n"; |
||||||
| 818 | * } |
||||||
| 819 | ***/ |
||||||
| 820 | |||||||
| 821 | #*#DEBUG# - end |
||||||
| 822 | |||||||
| 823 | if (count($repeats) >= 3) { |
||||||
| 824 | break 2; |
||||||
| 825 | } |
||||||
| 826 | } |
||||||
| 827 | } |
||||||
| 828 | } |
||||||
| 829 | |||||||
| 830 | #*#DEBUG# - start |
||||||
| 831 | |||||||
| 832 | /*** |
||||||
| 833 | * if (function_exists('posix_times')) { |
||||||
| 834 | * $posix_times = posix_times(); |
||||||
| 835 | * var_dump('posix_times', $posix_times); |
||||||
| 836 | * } |
||||||
| 837 | * if (function_exists('getrusage')) { |
||||||
| 838 | * $rusage = getrusage(); |
||||||
| 839 | * var_dump('rusage', $rusage); |
||||||
| 840 | * } |
||||||
| 841 | ***/ |
||||||
| 842 | |||||||
| 843 | #*#DEBUG# - end |
||||||
| 844 | |||||||
| 845 | if (count($repeats) >= 3) { |
||||||
| 846 | $draw_claim_valid = true; |
||||||
| 847 | |||||||
| 848 | $draw_claim_text = sprintf(_MD_CHESS_DRAW_3, "{$repeats[1]},{$repeats[2]},{$repeats[0]}"); |
||||||
| 849 | } else { |
||||||
| 850 | $draw_claim_valid = false; |
||||||
| 851 | |||||||
| 852 | $draw_claim_text = _MD_CHESS_NO_DRAW_3; |
||||||
| 853 | } |
||||||
| 854 | |||||||
| 855 | if (CHESS_LOG_3FOLD) { |
||||||
| 856 | $logfile = XOOPS_ROOT_PATH . '/cache/' . date('Ymd_His') . '_3fold.log'; |
||||||
| 857 | |||||||
| 858 | sort($log); |
||||||
| 859 | |||||||
| 860 | error_log(implode("\n", $log), 3, $logfile); |
||||||
| 861 | } |
||||||
| 862 | |||||||
| 863 | return [$draw_claim_valid, $draw_claim_text]; |
||||||
| 864 | } |
||||||
| 865 | |||||||
| 866 | /** |
||||||
| 867 | * Convert pgn_movetext into Nx3 array. |
||||||
| 868 | * |
||||||
| 869 | * @param array $movetext pgn_movetext |
||||||
| 870 | * @return array Nx3 array |
||||||
| 871 | */ |
||||||
| 872 | function chess_make_movelist($movetext) |
||||||
| 873 | { |
||||||
| 874 | $movelist = []; |
||||||
| 875 | |||||||
| 876 | $move_tokens = explode(' ', preg_replace('/\{.*\}/', '', $movetext)); |
||||||
|
0 ignored issues
–
show
preg_replace('/\{.*\}/', '', $movetext) of type string[] is incompatible with the type string expected by parameter $string of explode().
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 877 | |||||||
| 878 | $index = -1; |
||||||
| 879 | |||||||
| 880 | while ($move_tokens) { |
||||||
|
0 ignored issues
–
show
The expression
$move_tokens of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||||||
| 881 | $move_token = array_shift($move_tokens); |
||||||
| 882 | |||||||
| 883 | if (in_array($move_token, ['1-0', '0-1', '1/2-1/2', '*'])) { |
||||||
| 884 | break; |
||||||
| 885 | } elseif (preg_match('/^\d+(\.|\.\.\.)$/', $move_token, $matches)) { |
||||||
| 886 | ++$index; |
||||||
| 887 | |||||||
| 888 | $movelist[$index][] = $move_token; |
||||||
| 889 | |||||||
| 890 | if ('...' == $matches[1]) { // setup-game with initial black move - add padding for white's move |
||||||
| 891 | $movelist[$index][] = ''; |
||||||
| 892 | } |
||||||
| 893 | } else { |
||||||
| 894 | $movelist[$index][] = $move_token; |
||||||
| 895 | } |
||||||
| 896 | } |
||||||
| 897 | |||||||
| 898 | return $movelist; |
||||||
| 899 | } |
||||||
| 900 | |||||||
| 901 | /** |
||||||
| 902 | * Display chess board. |
||||||
| 903 | * |
||||||
| 904 | * @param array $gamedata Game data |
||||||
| 905 | * @param string $orientation _CHESS_ORIENTATION_ACTIVE, _CHESS_ORIENTATION_WHITE or _CHESS_ORIENTATION_BLACK |
||||||
| 906 | * @param string $user_color 'w', 'b' or '' (empty string indicates that current user is not a player in this game) |
||||||
| 907 | * @param bool $move_performed True if move was performed |
||||||
| 908 | * @param string $move_result_text Text describing move |
||||||
| 909 | * @param string $draw_claim_error_text Non-empty if draw claim invalid |
||||||
| 910 | * @param bool $show_arbiter_ctrl True if arbiter controls are to be displayed |
||||||
| 911 | */ |
||||||
| 912 | function chess_show_board($gamedata, $orientation, $user_color, $move_performed, $move_result_text = '', $draw_claim_error_text = '', $show_arbiter_ctrl = false) |
||||||
| 913 | { |
||||||
| 914 | global $xoopsTpl; |
||||||
| 915 | |||||||
| 916 | $xoopsTpl->assign( |
||||||
| 917 | 'xoops_module_header', |
||||||
| 918 | ' |
||||||
| 919 | <link rel="stylesheet" type="text/css" media="screen" href="' . XOOPS_URL . '/modules/chess/assets/css/style.css"> |
||||||
| 920 | ' |
||||||
| 921 | ); |
||||||
| 922 | |||||||
| 923 | $memberHandler = xoops_getHandler('member'); |
||||||
| 924 | |||||||
| 925 | $white_user = $memberHandler->getUser($gamedata['white_uid']); |
||||||
|
0 ignored issues
–
show
The method
getUser() does not exist on XoopsObjectHandler. It seems like you code against a sub-type of XoopsObjectHandler such as XoopsAvatarHandler or XoopsPersistableObjectHandler.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 926 | |||||||
| 927 | $white_username = is_object($white_user) ? $white_user->getVar('uname') : '?'; |
||||||
| 928 | |||||||
| 929 | $black_user = $memberHandler->getUser($gamedata['black_uid']); |
||||||
| 930 | |||||||
| 931 | $black_username = is_object($black_user) ? $black_user->getVar('uname') : '?'; |
||||||
| 932 | |||||||
| 933 | // Determine whether board is flipped (black at bottom) or "normal" (white at bottom). |
||||||
| 934 | |||||||
| 935 | switch ($orientation) { |
||||||
| 936 | default: |
||||||
| 937 | case _CHESS_ORIENTATION_ACTIVE: |
||||||
| 938 | $flip = 'b' == $gamedata['fen_active_color']; |
||||||
| 939 | break; |
||||||
| 940 | case _CHESS_ORIENTATION_WHITE: |
||||||
| 941 | $flip = false; |
||||||
| 942 | break; |
||||||
| 943 | case _CHESS_ORIENTATION_BLACK: |
||||||
| 944 | $flip = true; |
||||||
| 945 | break; |
||||||
| 946 | } |
||||||
| 947 | |||||||
| 948 | // Convert fen_piece_placement string into 8x8-array $tiles. |
||||||
| 949 | |||||||
| 950 | $tiles = []; |
||||||
| 951 | |||||||
| 952 | $ranks = explode('/', $gamedata['fen_piece_placement']); |
||||||
| 953 | |||||||
| 954 | if ($flip) { |
||||||
| 955 | $ranks = array_reverse($ranks); |
||||||
| 956 | } |
||||||
| 957 | |||||||
| 958 | foreach ($ranks as $rank) { |
||||||
| 959 | $expanded_row = preg_replace_callback( |
||||||
| 960 | '/(\d)/', |
||||||
| 961 | |||||||
| 962 | static function ($matches) { |
||||||
| 963 | return str_repeat('x', $matches[1]); |
||||||
| 964 | }, |
||||||
| 965 | $rank |
||||||
| 966 | ); |
||||||
| 967 | |||||||
| 968 | $rank_tiles = preg_split('//', $expanded_row, -1, PREG_SPLIT_NO_EMPTY); |
||||||
| 969 | |||||||
| 970 | $tiles[] = $flip ? array_reverse($rank_tiles) : $rank_tiles; |
||||||
|
0 ignored issues
–
show
It seems like
$rank_tiles can also be of type false; however, parameter $array of array_reverse() does only seem to accept array, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 971 | } |
||||||
| 972 | |||||||
| 973 | #var_dump('tiles', $tiles);#*#DEBUG# |
||||||
| 974 | |||||||
| 975 | // Convert pgn_movetext into Nx3 array $movelist. |
||||||
| 976 | |||||||
| 977 | $movelist = chess_make_movelist($gamedata['pgn_movetext']); |
||||||
| 978 | |||||||
| 979 | static $file_labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']; |
||||||
| 980 | |||||||
| 981 | if ($flip) { |
||||||
| 982 | $file_labels = array_reverse($file_labels); |
||||||
| 983 | } |
||||||
| 984 | |||||||
| 985 | $xoopsTpl->assign('chess_gamedata', $gamedata); |
||||||
| 986 | |||||||
| 987 | // comment at end of movetext |
||||||
| 988 | |||||||
| 989 | if (preg_match('/\{(.*?)\}\s*$/', $gamedata['pgn_movetext'], $matches)) { |
||||||
| 990 | $xoopsTpl->assign('chess_result_comment', $matches[1]); |
||||||
| 991 | } else { |
||||||
| 992 | $xoopsTpl->assign('chess_result_comment', ''); |
||||||
| 993 | } |
||||||
| 994 | |||||||
| 995 | $xoopsTpl->assign('chess_create_date', '0000-00-00 00:00:00' != $gamedata['create_date'] ? strtotime($gamedata['create_date']) : 0); |
||||||
| 996 | |||||||
| 997 | $xoopsTpl->assign('chess_start_date', '0000-00-00 00:00:00' != $gamedata['start_date'] ? strtotime($gamedata['start_date']) : 0); |
||||||
| 998 | |||||||
| 999 | $xoopsTpl->assign('chess_last_date', '0000-00-00 00:00:00' != $gamedata['last_date'] ? strtotime($gamedata['last_date']) : 0); |
||||||
| 1000 | |||||||
| 1001 | $xoopsTpl->assign('chess_white_user', $white_username); |
||||||
| 1002 | |||||||
| 1003 | $xoopsTpl->assign('chess_black_user', $black_username); |
||||||
| 1004 | |||||||
| 1005 | $xoopsTpl->assign('chess_tiles', $tiles); |
||||||
| 1006 | |||||||
| 1007 | $xoopsTpl->assign('chess_file_labels', $file_labels); |
||||||
| 1008 | |||||||
| 1009 | $xoopsTpl->assign( |
||||||
| 1010 | 'chess_pgn_string', |
||||||
| 1011 | chess_to_pgn_string( |
||||||
| 1012 | [ |
||||||
| 1013 | 'event' => '?', |
||||||
| 1014 | 'site' => $_SERVER['SERVER_NAME'], |
||||||
| 1015 | 'datetime' => $gamedata['start_date'], |
||||||
| 1016 | 'round' => '?', |
||||||
| 1017 | 'white' => $white_username, |
||||||
| 1018 | 'black' => $black_username, |
||||||
| 1019 | 'result' => $gamedata['pgn_result'], |
||||||
| 1020 | 'setup' => !empty($gamedata['pgn_fen']) ? 1 : 0, |
||||||
| 1021 | 'fen' => $gamedata['pgn_fen'], |
||||||
| 1022 | 'movetext' => $gamedata['pgn_movetext'], |
||||||
| 1023 | ] |
||||||
| 1024 | ) |
||||||
| 1025 | ); |
||||||
| 1026 | |||||||
| 1027 | $xoopsTpl->assign('chess_movelist', $movelist); |
||||||
| 1028 | |||||||
| 1029 | $xoopsTpl->assign('chess_date_format', _MEDIUMDATESTRING); |
||||||
| 1030 | |||||||
| 1031 | #if (empty($move_result_text)) {$move_result_text = 'test';}#*#DEBUG# |
||||||
| 1032 | |||||||
| 1033 | $xoopsTpl->assign('chess_move_performed', $move_performed); |
||||||
| 1034 | |||||||
| 1035 | $xoopsTpl->assign('chess_move_result', $move_result_text); |
||||||
| 1036 | |||||||
| 1037 | $xoopsTpl->assign('chess_draw_claim_error_text', $draw_claim_error_text); |
||||||
| 1038 | |||||||
| 1039 | $xoopsTpl->assign('chess_user_color', $user_color); |
||||||
| 1040 | |||||||
| 1041 | $xoopsTpl->assign('chess_confirm', $gamedata['w' == $user_color ? 'white_confirm' : 'black_confirm']); |
||||||
| 1042 | |||||||
| 1043 | $xoopsTpl->assign('chess_orientation', $orientation); |
||||||
| 1044 | |||||||
| 1045 | $xoopsTpl->assign('chess_rank_start', $flip ? 1 : 8); |
||||||
| 1046 | |||||||
| 1047 | $xoopsTpl->assign('chess_rank_direction', $flip ? 'up' : 'down'); |
||||||
| 1048 | |||||||
| 1049 | $xoopsTpl->assign('chess_file_start', $flip ? 8 : 1); |
||||||
| 1050 | |||||||
| 1051 | $xoopsTpl->assign('chess_file_direction', $flip ? 'down' : 'up'); |
||||||
| 1052 | |||||||
| 1053 | static $pieces = [ |
||||||
| 1054 | 'K' => ['color' => 'w', 'name' => 'wking', 'alt' => _MD_CHESS_ALT_WKING], |
||||||
| 1055 | 'Q' => ['color' => 'w', 'name' => 'wqueen', 'alt' => _MD_CHESS_ALT_WQUEEN], |
||||||
| 1056 | 'R' => ['color' => 'w', 'name' => 'wrook', 'alt' => _MD_CHESS_ALT_WROOK], |
||||||
| 1057 | 'B' => ['color' => 'w', 'name' => 'wbishop', 'alt' => _MD_CHESS_ALT_WBISHOP], |
||||||
| 1058 | 'N' => ['color' => 'w', 'name' => 'wknight', 'alt' => _MD_CHESS_ALT_WKNIGHT], |
||||||
| 1059 | 'P' => ['color' => 'w', 'name' => 'wpawn', 'alt' => _MD_CHESS_ALT_WPAWN], |
||||||
| 1060 | 'k' => ['color' => 'b', 'name' => 'bking', 'alt' => _MD_CHESS_ALT_BKING], |
||||||
| 1061 | 'q' => ['color' => 'b', 'name' => 'bqueen', 'alt' => _MD_CHESS_ALT_BQUEEN], |
||||||
| 1062 | 'r' => ['color' => 'b', 'name' => 'brook', 'alt' => _MD_CHESS_ALT_BROOK], |
||||||
| 1063 | 'b' => ['color' => 'b', 'name' => 'bbishop', 'alt' => _MD_CHESS_ALT_BBISHOP], |
||||||
| 1064 | 'n' => ['color' => 'b', 'name' => 'bknight', 'alt' => _MD_CHESS_ALT_BKNIGHT], |
||||||
| 1065 | 'p' => ['color' => 'b', 'name' => 'bpawn', 'alt' => _MD_CHESS_ALT_BPAWN], |
||||||
| 1066 | 'x' => ['color' => 'x', 'name' => 'empty', 'alt' => _MD_CHESS_ALT_EMPTY], |
||||||
| 1067 | ]; |
||||||
| 1068 | |||||||
| 1069 | $xoopsTpl->assign('chess_pieces', $pieces); |
||||||
| 1070 | |||||||
| 1071 | $xoopsTpl->assign('chess_show_arbitration_controls', $show_arbiter_ctrl); |
||||||
| 1072 | |||||||
| 1073 | if ($show_arbiter_ctrl && $gamedata['suspended']) { |
||||||
| 1074 | [$susp_date, $susp_uid, $susp_type, $susp_explain] = explode('|', $gamedata['suspended']); |
||||||
| 1075 | |||||||
| 1076 | switch ($susp_type) { |
||||||
| 1077 | case 'arbiter_suspend': |
||||||
| 1078 | $susp_type_display = _MD_CHESS_SUSP_TYPE_ARBITER; |
||||||
| 1079 | break; |
||||||
| 1080 | case 'want_arbitration': |
||||||
| 1081 | $susp_type_display = _MD_CHESS_SUSP_TYPE_PLAYER; |
||||||
| 1082 | break; |
||||||
| 1083 | default: |
||||||
| 1084 | $susp_type_display = _MD_CHESS_LABEL_ERROR; |
||||||
| 1085 | break; |
||||||
| 1086 | } |
||||||
| 1087 | |||||||
| 1088 | $susp_user = $memberHandler->getUser($susp_uid); |
||||||
| 1089 | |||||||
| 1090 | $susp_username = is_object($susp_user) ? $susp_user->getVar('uname') : _MD_CHESS_UNKNOWN; |
||||||
| 1091 | |||||||
| 1092 | $suspend_info = [ |
||||||
| 1093 | 'date' => strtotime($susp_date), |
||||||
| 1094 | 'user' => $susp_username, |
||||||
| 1095 | 'type' => $susp_type_display, |
||||||
| 1096 | 'reason' => $susp_explain, |
||||||
| 1097 | ]; |
||||||
| 1098 | |||||||
| 1099 | $xoopsTpl->assign('chess_suspend_info', $suspend_info); |
||||||
| 1100 | } |
||||||
| 1101 | |||||||
| 1102 | // Initialize $captured_pieces_all to indicate all pieces captured, then subtract off the pieces remaining on the board. |
||||||
| 1103 | |||||||
| 1104 | $captured_pieces_all = [ |
||||||
| 1105 | 'Q' => 1, |
||||||
| 1106 | 'R' => 2, |
||||||
| 1107 | 'B' => 2, |
||||||
| 1108 | 'N' => 2, |
||||||
| 1109 | 'P' => 8, |
||||||
| 1110 | 'q' => 1, |
||||||
| 1111 | 'r' => 2, |
||||||
| 1112 | 'b' => 2, |
||||||
| 1113 | 'n' => 2, |
||||||
| 1114 | 'p' => 8, |
||||||
| 1115 | ]; |
||||||
| 1116 | |||||||
| 1117 | for ($i = 0, $iMax = mb_strlen($gamedata['fen_piece_placement']); $i < $iMax; ++$i) { |
||||||
| 1118 | $piece = $gamedata['fen_piece_placement'][$i]; |
||||||
| 1119 | |||||||
| 1120 | if (!empty($captured_pieces_all[$piece])) { |
||||||
| 1121 | --$captured_pieces_all[$piece]; |
||||||
| 1122 | } |
||||||
| 1123 | } |
||||||
| 1124 | |||||||
| 1125 | // Construct lists of white's and black's captured pieces. |
||||||
| 1126 | |||||||
| 1127 | $captured_pieces = ['white' => [], 'black' => []]; |
||||||
| 1128 | |||||||
| 1129 | foreach ($captured_pieces_all as $piece => $count) { |
||||||
| 1130 | if ($count > 0) { |
||||||
| 1131 | if (ctype_upper($piece)) { |
||||||
| 1132 | $captured_pieces['white'] = array_merge($captured_pieces['white'], array_pad([], $count, $piece)); |
||||||
| 1133 | } elseif (ctype_lower($piece)) { |
||||||
| 1134 | $captured_pieces['black'] = array_merge($captured_pieces['black'], array_pad([], $count, $piece)); |
||||||
| 1135 | } |
||||||
| 1136 | } |
||||||
| 1137 | } |
||||||
| 1138 | |||||||
| 1139 | #var_dump('captured_pieces_all', $captured_pieces_all);#*#DEBUG# |
||||||
| 1140 | |||||||
| 1141 | #var_dump('captured_pieces', $captured_pieces);#*#DEBUG# |
||||||
| 1142 | |||||||
| 1143 | $xoopsTpl->assign('chess_captured_pieces', $captured_pieces); |
||||||
| 1144 | |||||||
| 1145 | $xoopsTpl->assign('chess_pawn_promote_choices', 'w' == $gamedata['fen_active_color'] ? ['Q', 'R', 'B', 'N'] : ['q', 'r', 'b', 'n']); |
||||||
| 1146 | |||||||
| 1147 | $xoopsTpl->assign('chess_allow_delete', chess_can_delete()); |
||||||
| 1148 | |||||||
| 1149 | // popup window contents for selecting piece to which pawn is promoted |
||||||
| 1150 | |||||||
| 1151 | // (Note that template is compiled here by fetch(), so any template variables it uses must already be defined.) |
||||||
| 1152 | |||||||
| 1153 | $xoopsTpl->assign('chess_pawn_promote_popup', $user_color ? $xoopsTpl->fetch('db:chess_game_promote_popup.tpl') : ''); |
||||||
| 1154 | |||||||
| 1155 | $xoopsTpl->assign('chess_ratings_enabled', 'none' != chess_moduleConfig('rating_system')); |
||||||
| 1156 | |||||||
| 1157 | // security token |
||||||
| 1158 | |||||||
| 1159 | $xoopsTpl->assign('chess_xoops_request_token', is_object($GLOBALS['xoopsSecurity']) ? $GLOBALS['xoopsSecurity']->getTokenHTML() : ''); |
||||||
| 1160 | } |
||||||
| 1161 | |||||||
| 1162 | ?> |
||||||
|
0 ignored issues
–
show
It is not recommended to use PHP's closing tag
?> in files other than templates.
Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore. A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever. Loading history...
|
|||||||
| 1163 |