/** * history_markup() * See decode_history in game_logic.php , it was the template for this * function. The coded history string is analyzed 2 chars at a time, because * the main portion of content will be from-to codes for moves on the board. * If a from-code is a round left paranthesis, these 2 bytes and the following * 2 contain information of a promotion. Those 4 bytes are considered an "empty" * or not counted round, regarding the output move list. */ function history_markup($board, $history, $href_this, $name_white, $name_black, $prompt) { $history .= '__'; // Add code representing the "?" prompt $goto = get_parameter(GET_GOTO); $link = ''; $class = HISTORY_BREAK_UL ? '' : ' class="scrolling"'; $ret = "<h2><strong>{$name_white}</strong>" . " vs. <strong>{$name_black}</strong></h2>\n" . "<ul{$class}>\n"; $current_move = 0; //... Newly introduced. Routine might need cleanup. $promotions = 0; // Nr. of promotions, each leading to 4 chars of // $history being skipped $length = strlen($history); for ($i = 0; $i < $length; $i += 2) { // Extract 2 char instruction from history // (Usually from-field and to-field codes or possibly // promotion of a pawn into another piece) $from_code = substr($history, $i, 1); $to_code = substr($history, $i + 1, 1); if (HISTORY_BREAK_UL && $i > 0 && ($i - 4 * $promotions) % 80 == 0) { $ret .= "</ul><ul>\n"; } switch ($from_code) { case '_': // Last item, show prompt ///////////////////////// if ($i % 4 == 0) { if (HISTORY_LINK_BACK) { $link = $href_this; } $ret .= "\t<li>"; $nr = i_to_round($history, $i); $ret .= $nr . ': '; if (HISTORY_LINK_BACK) { $ret .= "<a href=\"{$link}\">"; } else { $ret .= '<span>'; } } $ret .= $prompt; break; case '(': // Pawn Promotion ///////////////////////////////// //... This section used to be larger and is now almost //... obsolete, integrate into "Move" section! $i += 2; $promotions++; break; default: // Move //////////////////////////////////////////// $new_move = ''; $current_move++; $current_color = $current_move % 2 == WHITES_MOVE; $opponent_color = !$current_color; $from_field = decode_field($from_code); $to_field = decode_field($to_code); list($f_row, $f_col) = field_to_rowcol($from_field); list($t_row, $t_col) = field_to_rowcol($to_field); if ($i % 4 == 0) { if (HISTORY_LINK_BACK) { if ($i < $length) { $link = history_link($href_this, $current_move, WHITES_MOVE); } else { $link = $href_this; } } // Highlight history entry $class = $current_move == $goto ? ' class="selected"' : ''; $nr = i_to_round($history, $i); $new_move .= "\t<li>{$nr}: "; if (HISTORY_LINK_BACK) { $new_move .= "<a href=\"{$link}\"{$class}>"; } else { $new_move .= '<span>'; } } $piece = $board[$f_row][$f_col]; $new_move .= piece_glyph($piece); $new_move .= strtolower($from_field); if ($board[$t_row][$t_col] != '') { $new_move .= ' × ' . piece_glyph($board[$t_row][$t_col]); } else { $new_move .= ' – '; } $new_move .= strtolower($to_field); // Update the board $board = apply_move($board, $f_row, $f_col, $t_row, $t_col); // Promotion if (substr($history, $i + 2, 1) == '(') { $piece = substr($history, $i + 4, 1); $new_move .= piece_glyph($piece); $board[$t_row][$t_col] = substr($history, $i + 4, 1); } // Do we threaten the other king? if (king_in_check($board, !$current_color)) { $new_move .= '+'; } if ($i % 4 == 0) { if (HISTORY_LINK_BACK) { if ($i + 4 < $length) { $link = history_link($href_this, $current_move, BLACKS_MOVE); } else { $link = $href_this; } } $class = $current_move + 1 == $goto ? ' class="selected"' : ''; $new_move .= ','; if (HISTORY_LINK_BACK) { $new_move .= "</a> <a href=\"{$link}\"{$class}>"; } else { $new_move .= '</span> <span>'; } } else { if (HISTORY_LINK_BACK) { $new_move .= '</a>'; } else { $new_move .= '</span>'; } $new_move .= "\n"; } // Reduce opening pawn moves $new_move = simplify_history($new_move); $ret .= $new_move; } // switch $from_code } // for $i if (HISTORY_LINK_BACK) { $ret .= '</a>'; } else { $ret .= '</span>'; } if (substr($ret, -1, 1) != "\n") { $ret .= "\n"; } return $ret . "</ul>\n"; }
function main_control() { // These globals are used in the HTML template global $current_player, $history; global $heading, $name_white, $name_black; global $show_command_form, $flip_board; global $preset_from_value, $preset_to_value, $id_focus; global $chess_board_markup, $history_markup, $promotion_dialog_markup; global $board_encoded, $game_title, $turn_nr; global $history_next, $history_prev; global $href_this, $href_player, $href_flip; global $game_state_link, $hmw_home_link; // Initialize a bit $promotion_popup = false; //...NYI Show pawn promotion dialog $show_command_form = true; // Show the move input dialog $game_status = IN_PROGRESS; // The game has not ended yet $heading = ''; // "White's move" caption $game_title = ''; // Current game info for page title $game_state_link = ''; // "Send this link"-link .. $hmw_home_link = ''; // .. corrected for my stupid router //... Remember an initial double move of a pawn $get_en_passant = get_parameter(GET_EN_PASSANT); $new_en_passant = ''; // Retreive GET data $flip_board = isset($_GET[GET_FLIP_BOARD]); $history = get_parameter(GET_HISTORY); $goto = get_parameter(GET_GOTO); $name_white = get_parameter(GET_WHITE, DEFAULT_NAME_WHITE); $name_black = get_parameter(GET_BLACK, DEFAULT_NAME_BLACK); if (get_parameter(GET_PLAYER, GET_WHITE) != GET_WHITE) { // &player set, but not to "white", is taken as "black" $current_player = BLACKS_MOVE; } else { $current_player = WHITES_MOVE; } // Load base positions of pieces $base_array = decode_board(get_parameter(GET_BASE_BOARD, INITIAL_BOARD_CODED)); // Trace history (Reconstruct the current board from initial positions) //...list( $board_array, $tie_info ) = decode_history( $board_array = decode_history($base_array, $history, $goto); // Execute given command // Retreive FORM input // Move: "from" and "to" must be field names // Edit: "from" must be the code character for a piece and "to" a field $clickable = $selected = array(); $redirect_after_move = false; $cmd_piece = get_parameter(GET_FROM); $cmd_from = strtoupper(get_parameter(GET_FROM)); // Retreive commands $cmd_to = strtoupper(get_parameter(GET_TO)); if ($cmd_from == $cmd_to) { // Deselect a piece $cmd_from = $cmd_to = ''; } if ($cmd_from == '') { $cmd_to = ''; } // Never allow only TO command // Exec: Editor if (strlen($cmd_from) == 1 && valid_field_name($cmd_to)) { if (strpos(WHITE_PIECES . BLACK_PIECES, $cmd_from) !== false) { list($row, $col) = field_to_rowcol($cmd_to); if ($base_array[$row][$col] == $cmd_piece) { // Delete existing piece $base_array[$row][$col] = ''; } else { if ($base_array[$row][$col] == '') { // Add new piece $base_array[$row][$col] = $cmd_piece; } } #$base_array = $board_array; $redirect_after_move = true; } // No other commands with FROM being only one char. $cmd_from = $cmd_to = ''; } // Make sure, no invalid data is being processed as a move if (!valid_field_name($cmd_from)) { $cmd_from = ''; } if (!valid_field_name($cmd_to)) { $cmd_to = ''; } // Exec: Move if ($cmd_from != '' && $cmd_to != '') { $turn_nr = i_to_round($history); if ($turn_nr - floor($turn_nr) == 0.5) { $turn_nr = floor($turn_nr); $color = 'Black'; } else { $color = 'White'; } debug_out($_SERVER['REMOTE_ADDR'] . " - {$name_white} vs. {$name_black}, {$turn_nr}, {$color}: {$cmd_from} - {$cmd_to}\n"); list($f_row, $f_col) = field_to_rowcol($cmd_from); list($t_row, $t_col) = field_to_rowcol($cmd_to); list($clickable, $selected) = select_piece($board_array, $current_player, $cmd_from, $get_en_passant); // Check if it is our//... piece (or a piece at all) if (!in_array($cmd_from, $clickable)) { die("Error: clickable[{$f_row}][{$f_col}] empty."); } if (!in_array($cmd_to, $clickable)) { // Capturing a piece! echo "Capture! clickable = "; print_r($clickable); die; } // En passant $piece = $board_array[$f_row][$f_col]; if ($piece == 'P' && $f_row == 1 || $piece == 'p' && $f_row == 6) { if ($t_row == 3 || $t_row == 4) { $get_en_passant = chr(ord('A') + $f_col); } } if ($piece == 'P' && $t_row - $f_row == +1 || $piece == 'p' && $t_row - $f_row == -1 || $piece != 'P' && $piece != 'p') { $get_en_passant = ''; } // Promotion if ($piece == 'P' && $t_row == 7 || $piece == 'p' && $t_row == 0) { $href_this = update_href($href_this, GET_PROMOTE, chr(ord('A') + $t_col)); $promotion_popup = true; $heading = 'Promote your pawn to:'; $board_array = apply_move($board_array, $f_row, $f_col, $t_row, $t_col); } // New move applied, prepare for fresh move $clickable = $selected = array(); $cmd_from = $cmd_to = ''; // Fall through to NO COMMAND mode $current_player = !$current_player; $history .= encode_move($f_row, $f_col, $t_row, $t_col); // We changed the board, but the user's browser still shows the // move command in its address bar. An HTTP redirect is used to // update that address, but the URL is not determined yet if (!$promotion_popup) { $redirect_after_move = true; } } // Exec: Deselect, continuation of fall throughs above if ($cmd_from == '' && $cmd_to == '') { $clickable = find_movable_pieces($board_array, $current_player); // Get rid of moves with king in check afterwards $new = array(); foreach ($clickable as $from_field) { // Get two arrays (clickable, selected) $temp = select_piece($board_array, $current_player, $from_field); // Ignore moves with only one "deselection entry" if (count($temp[0]) > 1) { $new[] = $from_field; } } $clickable = $new; if (count($clickable) == 0) { if (king_in_check($board_array, $current_player)) { $heading = HEADING_CHECK_MATE; $game_status = $current_player != WHITES_MOVE ? WHITE_WINS : BLACK_WINS; } else { $heading = HEADING_STALE_MATE; $game_status = NOONE_WINS; } } } // Exec: Select piece if ($cmd_from != '' && $cmd_to == '' && $goto == '') { list($clickable, $selected) = select_piece($board_array, $current_player, $cmd_from); $heading = 'Select target'; } // Prepare move command form $preset_from_value = $cmd_from; $preset_to_value = $cmd_to; $id_focus = $preset_from_value == '' ? 'idFrom' : 'idTo'; // Generate links for main menu and board markup (pieces) $board_encoded = encode_board($base_array); // Name parameter as code for who's player's term this is $p = $current_player == WHITES_MOVE ? GET_WHITE : GET_BLACK; $href_this = update_href(); // get base link $href_this = update_href($href_this, GET_FROM, $preset_from_value); $href_this = update_href($href_this, GET_TO, $preset_to_value); $href_this = update_href($href_this, GET_PLAYER, $p); $href_this = update_href($href_this, GET_HISTORY, $history); $href_this = update_href($href_this, GET_WHITE, $name_white); $href_this = update_href($href_this, GET_BLACK, $name_black); $href_this = update_href($href_this, GET_EN_PASSANT, $get_en_passant); $href_this = update_href($href_this, GET_BASE_BOARD, $board_encoded); if ($flip_board) { $href_this = update_href($href_this, GET_FLIP_BOARD, ''); $href_flip = update_href($href_this, GET_FLIP_BOARD, REMOVE_FROM_LINK); } else { $href_flip = update_href($href_this, GET_FLIP_BOARD, ''); } if ($current_player == BLACKS_MOVE) { $href_player = update_href($href_this, GET_PLAYER, GET_WHITE); } else { $href_player = update_href($href_this, GET_PLAYER, GET_BLACK); } // HTTP redirect? if (!false && $redirect_after_move) { if (DEBUG) { #die( "Continue: <a href='$href_this'>$href_this</a>" ); } // Game state has been updated. In case of an executed move, // the browser needs to reload the page with the updated URL: header('HTTP/1.0 303 Found'); header('Location: ' . htmlspecialchars_decode($href_this)); die; } // Create HTML markup // History $history_markup = history_markup($base_array, $history, $href_this, $name_white, $name_black, $game_status); // Promotion if ($promotion_popup) { $promotion_dialog_markup = promotion_dialog_markup($href_this, $current_player, $t_row, $t_col, $history); $clickable = $selected = array(); } else { $promotion_dialog_markup = ''; } // Board if (STEADY_BOARD && $current_player == BLACKS_MOVE) { //... GET switch $flip_board = !$flip_board; } if (isset($_GET[GET_GOTO])) { $clickable = $selected = array(); } else { if ($history > '' && $cmd_from == $cmd_to) { if (substr($history, -4, 1) == '(') { // Skip promotion $selected[] = decode_field(substr($history, -3, 1)); $selected[] = decode_field(substr($history, -6, 1)); } else { // Normal move $selected[] = decode_field(substr($history, -2, 1)); $selected[] = decode_field(substr($history, -1, 1)); } } } $chess_board_markup = chess_board_markup($href_this, $board_array, $clickable, $selected, $current_player, $flip_board); // If no heading was set above, say who's next if ($goto != '') { $current_player = $goto % 2 != 0; } if ($heading == '') { $heading = $current_player ? $name_white : $name_black; $heading = ucfirst($heading) . "'"; if (substr($heading, -2, 1) != 's') { $heading .= 's'; } $heading .= ' move'; } if (king_in_check($board_array, $current_player) && strpos($heading, 'mate') === false) { $heading .= ' - <strong>Check!</strong>'; } if ($goto != '') { $turn_nr = goto_to_round($history, $goto); $heading = "Round {$turn_nr}, {$heading}"; } $heading = get_parameter(GET_COMMENT, $heading); // Game title if (isset($_GET[GET_WHITE])) { $turn_nr = i_to_round($history); $game_title = "{$name_white} vs. {$name_black} - Turn #{$turn_nr} - "; } $turn_nr = floor($turn_nr); // History links $next_goto = ($goto + 1) % (count_moves($history) + 1); $history_next = update_href($href_this, GET_GOTO, $next_goto); $next_goto = ($goto + count_moves($history)) % (count_moves($history) + 1); $history_prev = update_href($href_this, GET_GOTO, $next_goto); // Links for copy and paste if (!isset($_GET[GET_NEW_GAME]) && !isset($_GET[GET_BASE_BOARD]) && isset($_SERVER['HTTP_REFERER']) && $_SERVER['QUERY_STRING'] != '' && $cmd_from == '' && $cmd_to == '') { // Empty referer: Not reached by clicking a link in the browser $t = str_replace('&', '&', $href_this); $game_state_link = str_replace(' ', '+', $t); $home_IPs = array('192.168.14.1', '213.47.94.176', 'local.at'); foreach ($home_IPs as $ip_address) { if (strpos($game_state_link, $ip_address) !== false) { $hmw_home_link = str_replace($ip_address, 'harald.ist.org/home', $game_state_link); } } if ($hmw_home_link != '') { $game_state_link = $hmw_home_link; } $game_state_link = str_replace('flip&', '', $game_state_link); $game_state_link = str_replace('&', '&', $game_state_link); } debug_out("board_encoded = {$board_encoded}\n"); }
/** * history_markup() * See decode_history in game_logic.php , it was the template for this * function. */ function history_markup($board, $history, $href_this, $name_white, $name_black, $prompt) { $history .= '__'; $goto = get_parameter(GET_GOTO); $class = HISTORY_BREAK_UL ? '' : ' class="scrolling"'; $ret = "<h2><strong>{$name_white}</strong>" . " vs. <strong>{$name_black}</strong></h2>\n" . "<ul{$class}>\n"; $current_move = 0; //... Newly introduced. Routine might need cleanup. $skipped_turns = 0; $length = strlen($history); for ($i = 0; $i < $length; $i += 2) { $from_code = substr($history, $i, 1); $to_code = substr($history, $i + 1, 1); $from_field = decode_field($from_code); $to_field = decode_field($to_code); list($f_row, $f_col) = field_to_rowcol($from_field); list($t_row, $t_col) = field_to_rowcol($to_field); if (HISTORY_BREAK_UL && $i > 0 && ($i - 4 * $skipped_turns) % 80 == 0) { $ret .= "</ul><ul>\n"; } switch ($from_code) { case '_': // Last item, show prompt ///////////////////////// if ($i % 4 == 0) { $link = $href_this; $ret .= "\t<li>"; $nr = i_to_round($history, $i); $ret .= $nr . ': '; $ret .= "<a href=\"{$link}\">"; } $ret .= $prompt; break; case '(': // Pawn Promotion ///////////////////////////////// $i += 2; $skipped_turns++; break; default: // Move //////////////////////////////////////////// $new_move = ''; $current_move++; $current_color = $current_move % 2 == WHITES_MOVE; $opponent_color = !$current_color; if ($i % 4 == 0) { if ($i < $length) { $link = history_link($href_this, $current_move, WHITES_MOVE); } else { $link = $href_this; } // Highlight history entry $class = $current_move == $goto ? ' class="selected"' : ''; $nr = i_to_round($history, $i); $new_move .= "\t<li>{$nr}: <a href=\"{$link}\"{$class}>"; } $piece = $board[$f_row][$f_col]; $new_move .= piece_glyph($piece); $new_move .= strtolower($from_field); if ($board[$t_row][$t_col] != '') { $new_move .= ' × ' . piece_glyph($board[$t_row][$t_col]); } else { $new_move .= ' – '; } $new_move .= strtolower($to_field); // Update the board $board = apply_move($board, $f_row, $f_col, $t_row, $t_col); // Promotion if (substr($history, $i + 2, 1) == '(') { $piece = substr($history, $i + 4, 1); $new_move .= piece_glyph($piece); $board[$t_row][$t_col] = substr($history, $i + 4, 1); } // Do we threaten the other king? if (king_in_check($board, !$current_color)) { $new_move .= '+'; } if ($i % 4 == 0) { if ($i + 4 < $length) { $link = history_link($href_this, $current_move, BLACKS_MOVE); } else { $link = $href_this; } $class = $current_move + 1 == $goto ? ' class="selected"' : ''; $new_move .= ",</a> <a href=\"{$link}\"{$class}>"; } else { $new_move .= "</a>\n"; } // Reduce opening pawn moves $new_move = simplify_history($new_move); $ret .= $new_move; } // switch $from_code } // for $i $ret .= '</a>'; if (substr($ret, -1, 1) != "\n") { $ret .= "\n"; } return $ret . "</ul>\n"; }