X-Git-Url: https://git.sesse.net/?p=remoteglot;a=blobdiff_plain;f=Board.pm;h=d6a0f5524869360b4f171f226aa17086fb34c8da;hp=6af89f39819d16e520d4ff753f0b3db161b901e2;hb=aab426550a1da4daea35eb0b0691fe8bd7907348;hpb=762b4cb898d3300233b773eff370a1562a445efe diff --git a/Board.pm b/Board.pm index 6af89f3..d6a0f55 100644 --- a/Board.pm +++ b/Board.pm @@ -103,20 +103,19 @@ sub make_move { # en passant? if ($board->[$to_row][$to_col] eq '-') { if ($piece eq 'p') { - $nb->[$to_row + 1][$to_col] = '-'; - } else { $nb->[$to_row - 1][$to_col] = '-'; - } - } - } else { - if ($promo ne '') { - if ($piece eq 'p') { - $piece = $promo; } else { - $piece = uc($promo); + $nb->[$to_row + 1][$to_col] = '-'; } } } + if (defined($promo) && $promo ne '') { + if ($piece eq 'p') { + $piece = lc($promo); + } else { + $piece = uc($promo); + } + } } # update the board @@ -131,12 +130,86 @@ sub _pos_to_square { return sprintf("%c%d", ord('a') + $col, 8 - $row); } +sub _col_letter_to_num { + return ord(shift) - ord('a'); +} + +sub _row_letter_to_num { + return 7 - (ord(shift) - ord('1')); +} + +sub _square_to_pos { + my ($square) = @_; + $square =~ /^([a-h])([1-8])$/ or die "Invalid square $square"; + return (_row_letter_to_num($2), _col_letter_to_num($1)); +} + sub _move_to_uci_notation { my ($from_row, $from_col, $to_row, $to_col, $promo) = @_; $promo //= ""; return _pos_to_square($from_row, $from_col) . _pos_to_square($to_row, $to_col) . $promo; } +sub parse_pretty_move { + my ($board, $move, $toplay) = @_; + + # 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')); + } 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')); + } else { + return (_square_to_pos('e8'), _square_to_pos('c8')); + } + } + + # Parse promo + my $promo; + if ($move =~ s/=([QRNB])$//) { + $promo = $1; + } + + $move =~ /^([KQRBN])?([a-h])?([1-8])?x?([a-h][1-8])$/ or die "Invalid move $move"; + my $piece = $1 // 'P'; + my $from_col = defined($2) ? _col_letter_to_num($2) : undef; + my $from_row = defined($3) ? _row_letter_to_num($3) : undef; + my ($to_row, $to_col) = _square_to_pos($4); + + # Find all possible from-squares that could have been meant. + my @squares = (); + if ($toplay eq 'B') { + $piece = lc($piece); + } + for my $row (0..7) { + next if (defined($from_row) && $from_row != $row); + for my $col (0..7) { + next if (defined($from_col) && $from_col != $col); + next if ($board->[$row][$col] ne $piece); + next if (!$board->can_reach($piece, $row, $col, $to_row, $to_col)); + + # See if doing this move would put us in check + # (yes, there are clients that expect us to do this). + my $check = $board->make_move($row, $col, $to_row, $to_col, $promo)->in_check(); + next if ($check eq 'both' || + ($toplay eq 'W' && $check eq 'white') || + ($toplay eq 'B' && $check eq 'black')); + + push @squares, [ $row, $col ]; + } + } + if (scalar @squares != 1) { + die "Ambigious or impossible move $move"; + } + return (@{$squares[0]}, $to_row, $to_col, $promo); +} + sub fen { my ($board) = @_; my @rows = (); @@ -224,7 +297,6 @@ sub can_reach { can_reach($board, 'B', $from_row, $from_col, $to_row, $to_col)); } - # TODO: en passant if ($piece eq 'p') { # black pawn if ($to_col == $from_col && $to_row == $from_row + 1) { @@ -235,7 +307,12 @@ sub can_reach { return ($dest_piece eq '-' && $middle_piece eq '-'); } if (abs($to_col - $from_col) == 1 && $to_row == $from_row + 1) { - return ($dest_piece ne '-'); + if ($dest_piece eq '-') { + # En passant. TODO: check that the last move was indeed an EP move + return ($to_row == 5 && $board->[4][$to_col] eq 'P'); + } else { + return 1; + } } return 0; } @@ -249,7 +326,12 @@ sub can_reach { return ($dest_piece eq '-' && $middle_piece eq '-'); } if (abs($to_col - $from_col) == 1 && $to_row == $from_row - 1) { - return ($dest_piece ne '-'); + if ($dest_piece eq '-') { + # En passant. TODO: check that the last move was indeed an EP move + return ($to_row == 2 && $board->[3][$to_col] eq 'p'); + } else { + return 1; + } } return 0; }