X-Git-Url: https://git.sesse.net/?p=remoteglot;a=blobdiff_plain;f=Board.pm;h=8565c845c279860abf9e029b2abbc50b5b597398;hp=3e0fd33a52b4fa72a4264a4eff58962dc93cc197;hb=b4059a786029132eb27769a42ca52eca6d8b44cc;hpb=f81eecb0383fd76f0735836744dd9be169e73268 diff --git a/Board.pm b/Board.pm index 3e0fd33..8565c84 100644 --- a/Board.pm +++ b/Board.pm @@ -42,56 +42,60 @@ sub make_move { die "Invalid move $move"; } - # white short castling - if ($move eq 'e1g1' && $piece eq 'K') { - # king - $nb->[7][4] = '-'; - $nb->[7][6] = $piece; - - # rook - $nb->[7][7] = '-'; - $nb->[7][5] = 'R'; - - return $nb; - } - - # white long castling - if ($move eq 'e1c1' && $piece eq 'K') { - # king - $nb->[7][4] = '-'; - $nb->[7][2] = $piece; - - # rook - $nb->[7][0] = '-'; - $nb->[7][3] = 'R'; + if ($piece eq 'K') { + # Convert to Chess960 king-takes-rook. + $to_col = 7 if ($move eq 'e1g1'); + $to_col = 0 if ($move eq 'e1c1'); + + my $dst_piece = $board->[$to_row][$to_col]; + + # White short castling. + if ($dst_piece eq 'R' && $to_col > $from_col) { + # king + $nb->[7][$from_col] = '-'; + $nb->[7][$to_col] = '-'; + $nb->[7][6] = 'K'; + $nb->[7][5] = 'R'; + + return $nb; + } - return $nb; - } + # Black short castling. + if ($dst_piece eq 'R' && $to_col < $from_col) { + $nb->[7][$from_col] = '-'; + $nb->[7][$to_col] = '-'; + $nb->[7][2] = 'K'; + $nb->[7][3] = 'R'; - # black short castling - if ($move eq 'e8g8' && $piece eq 'k') { - # king - $nb->[0][4] = '-'; - $nb->[0][6] = $piece; + return $nb; + } + } elsif ($piece eq 'k') { + # Convert to Chess960 king-takes-rook. + $to_col = 7 if ($move eq 'e8g8'); + $to_col = 0 if ($move eq 'e8c8'); - # rook - $nb->[0][7] = '-'; - $nb->[0][5] = 'r'; + my $dst_piece = $board->[$to_row][$to_col]; - return $nb; - } + # Black short castling. + if ($dst_piece eq 'r' && $to_col > $from_col) { + $nb->[0][$from_col] = '-'; + $nb->[0][$to_col] = '-'; + $nb->[0][6] = 'k'; + $nb->[0][5] = 'r'; - # black long castling - if ($move eq 'e8c8' && $piece eq 'k') { - # king - $nb->[0][4] = '-'; - $nb->[0][2] = $piece; + return $nb; + } - # rook - $nb->[0][0] = '-'; - $nb->[0][3] = 'r'; + # Black long castling. + if ($dst_piece eq 'r' && $to_col < $from_col) { + # king + $nb->[0][$from_col] = '-'; + $nb->[0][$to_col] = '-'; + $nb->[0][2] = 'k'; + $nb->[0][3] = 'r'; - return $nb; + return $nb; + } } # check if the from-piece is a pawn @@ -136,9 +140,12 @@ sub _row_letter_to_num { return 7 - (ord(shift) - ord('1')); } +use Carp; + sub _square_to_pos { my ($square) = @_; - $square =~ /^([a-h])([1-8])$/ or die "Invalid square $square"; + #$square =~ /^([a-h])([1-8])$/ or die "Invalid square $square"; + $square =~ /^([a-h])([1-8])$/ or Carp::confess("Invalid square $square"); return (_row_letter_to_num($2), _col_letter_to_num($1)); } @@ -148,25 +155,53 @@ sub move_to_uci_notation { return _pos_to_square($from_row, $from_col) . _pos_to_square($to_row, $to_col) . $promo; } +sub _find_piece_col { + my ($row, $piece) = @_; + for my $col (0..7) { + return $col if ($row->[$col] eq $piece); + } + die "Could not find piece $piece"; +} + # Note: This is in general not a validation that the move is actually allowed # (e.g. you can castle even though you're in check). sub parse_pretty_move { - my ($board, $move, $toplay) = @_; + my ($board, $move, $toplay, $chess960, $white_castle_k, $white_castle_q, $black_castle_k, $black_castle_q) = @_; # Strip check or mate $move =~ s/[+#]$//; if ($move eq '0-0' or $move eq 'O-O') { if ($toplay eq 'W') { - return (_square_to_pos('e1'), _square_to_pos('g1')); + if ($chess960) { + # King takes rook. + return (7, _find_piece_col($board->[7], 'K'), _square_to_pos($white_castle_k . '1')); + } else { + return (_square_to_pos('e1'), _square_to_pos('g1')); + } } else { - return (_square_to_pos('e8'), _square_to_pos('g8')); + if ($chess960) { + # King takes rook. + return (0, _find_piece_col($board->[0], 'k'), _square_to_pos($black_castle_k . '8')); + } else { + return (_square_to_pos('e8'), _square_to_pos('g8')); + } } } elsif ($move eq '0-0-0' or $move eq 'O-O-O') { if ($toplay eq 'W') { - return (_square_to_pos('e1'), _square_to_pos('c1')); + if ($chess960) { + # King takes rook. + return (7, _find_piece_col($board->[7], 'K'), _square_to_pos($white_castle_q . '1')); + } else { + return (_square_to_pos('e1'), _square_to_pos('c1')); + } } else { - return (_square_to_pos('e8'), _square_to_pos('c8')); + if ($chess960) { + # King takes rook. + return (0, _find_piece_col($board->[0], 'k'), _square_to_pos($black_castle_q . '8')); + } else { + return (_square_to_pos('e8'), _square_to_pos('c8')); + } } } @@ -230,49 +265,11 @@ sub fen { return join('/', @rows); } -# Returns a compact bit string describing the same data as fen(). -# This is encoded using a Huffman-like encoding, and should be -# typically about 1/3 the number of bytes. -sub bitpacked_fen { - my ($board) = @_; - my $bits = ""; - - for my $row (0..7) { - for my $col (0..7) { - my $piece = $board->[$row][$col]; - if ($piece eq '-') { - $bits .= "0"; - next; - } - - my $color = (lc($piece) eq $piece) ? 0 : 1; - $bits .= "1" . $color; - - if (lc($piece) eq 'p') { - $bits .= "0"; - } elsif (lc($piece) eq 'n') { - $bits .= "100"; - } elsif (lc($piece) eq 'b') { - $bits .= "101"; - } elsif (lc($piece) eq 'r') { - $bits .= "1110"; - } elsif (lc($piece) eq 'q') { - $bits .= "11110"; - } elsif (lc($piece) eq 'k') { - $bits .= "11111"; - } else { - die "Unknown piece $piece"; - } - } - } - - return pack('b*', $bits); -} - sub can_reach { my ($board, $piece, $from_row, $from_col, $to_row, $to_col) = @_; - # can't eat your own piece + # Can't eat your own piece (Chess960 uses king-takes-rook for castling, + # but castling is irrelevant for reachability) my $dest_piece = $board->[$to_row][$to_col]; if ($dest_piece ne '-') { return 0 if (($piece eq lc($piece)) == ($dest_piece eq lc($dest_piece))); @@ -512,24 +509,26 @@ sub _prettyprint_move_no_check_or_mate { die "Invalid move $move"; } - # white short castling - if ($move eq 'e1g1' && $piece eq 'K') { - return 'O-O'; - } + if ($piece eq 'K') { + # white short/long castling + return 'O-O' if ($move eq 'e1g1'); + return 'O-O-O' if ($move eq 'e1c1'); - # white long castling - if ($move eq 'e1c1' && $piece eq 'K') { - return 'O-O-O'; - } - - # black short castling - if ($move eq 'e8g8' && $piece eq 'k') { - return 'O-O'; - } - - # black long castling - if ($move eq 'e8c8' && $piece eq 'k') { - return 'O-O-O'; + # white short/long chess960-style castling (king takes own rook) + my $dst_piece = $board->[$to_row][$to_col]; + if ($dst_piece eq 'R') { + return ($to_col > $from_col) ? 'O-O' : 'O-O-O'; + } + } elsif ($piece eq 'k') { + # black short/long castling + return 'O-O' if ($move eq 'e8g8'); + return 'O-O-O' if ($move eq 'e8c8'); + + # black short/long chess960-style castling (king takes own rook) + my $dst_piece = $board->[$to_row][$to_col]; + if ($dst_piece eq 'r') { + return ($to_col > $from_col) ? 'O-O' : 'O-O-O'; + } } my $pretty;