diff --git a/shard.yml b/shard.yml index 6d5a502..8c1f6ff 100644 --- a/shard.yml +++ b/shard.yml @@ -1,5 +1,5 @@ name: lx_chess -version: 0.1.0 +version: 0.1.3 authors: - Alex Clink diff --git a/spec/lx_chess/game/move_to_san_spec.cr b/spec/lx_chess/game/move_to_san_spec.cr new file mode 100644 index 0000000..1dc4f80 --- /dev/null +++ b/spec/lx_chess/game/move_to_san_spec.cr @@ -0,0 +1,100 @@ +require "../../spec_helper" + +include LxChess + +describe Game do + describe "#move_to_san" do + it "converts pawn captures" do + game = Game.new players: [Player.new, Player.new] + place(game.board, { + "e4" => 'P', + "d5" => 'p', + }) + debug_board(game, ["e4", "d5"]) + san = game.move_to_san(from: "e4", to: "d5", turn: 0) + puts san.to_s + san.to_s.should eq("exd5") + end + + it "converts pawn moves" do + game = Game.new players: [Player.new, Player.new] + place(game.board, {"e2" => 'P'}) + debug_board(game, ["e2", "e4"]) + san = game.move_to_san(from: "e2", to: "e4", turn: 0) + puts san.to_s + san.to_s.should eq("e4") + end + + it "disambiguates pawn captures" do + game = Game.new players: [Player.new, Player.new] + place(game.board, { + "c4" => 'P', + "e4" => 'P', + "d5" => 'p', + }) + debug_board(game, ["e4", "d5"]) + san = game.move_to_san(from: "e4", to: "d5", turn: 0) + puts san.to_s + san.to_s.should eq("exd5") + debug_board(game, ["c4", "d5"]) + san = game.move_to_san(from: "c4", to: "d5", turn: 0) + puts san.to_s + san.to_s.should eq("cxd5") + end + + it "disambiguates rook moves" do + game = Game.new players: [Player.new, Player.new] + place(game.board, { + "e4" => 'R', + "d5" => 'R', + }) + debug_board(game, ["e4", "e5"]) + san = game.move_to_san(from: "e4", to: "e5", turn: 0) + puts san.to_s + san.to_s.should eq("Ree5") + end + + it "disambiguates knight moves" do + game = Game.new players: [Player.new, Player.new] + place(game.board, { + "f3" => 'N', + "e2" => 'N', + }) + debug_board(game, ["e2", "d4"]) + san = game.move_to_san(from: "e2", to: "d4", turn: 0) + puts san.to_s + san.to_s.should eq("Ned4") + end + + it "disambiguates knight moves on the same file" do + game = Game.new players: [Player.new, Player.new] + place(game.board, { + "e4" => 'N', + "e2" => 'N', + }) + debug_board(game, ["e2", "c3"]) + san = game.move_to_san(from: "e2", to: "c3", turn: 0) + puts san.to_s + san.to_s.should eq("Ne2c3") + end + + it "detects check" do + game = Game.new players: [Player.new, Player.new] + game.board["e1"] = Piece.from_fen('K') + game.board["c8"] = Piece.from_fen('r') + debug_board(game, ["c8", "e8"]) + san = game.move_to_san(from: "c8", to: "e8", turn: 1) + puts san.to_s + san.to_s.should eq("Re8+") + end + + it "detects checkmate" do + fen = Fen.parse("r1bqkb1r/pppp1ppp/2n2n2/4p2Q/2B1P3/8/PPPP1PPP/RNB1K1NR w KQkq - 4 4") + game = Game.new(board: fen.board, players: [Player.new, Player.new]) + san = game.move_to_san(from: "h5", to: "f7", turn: 0) + debug_board(game, ["h5", "f7"]) + puts san.to_s + san.to_s.should eq("Qxf7#") + end + end +end diff --git a/spec/lx_chess/game_spec.cr b/spec/lx_chess/game_spec.cr index 93df397..378556a 100644 --- a/spec/lx_chess/game_spec.cr +++ b/spec/lx_chess/game_spec.cr @@ -74,25 +74,6 @@ describe Game do end end - describe "#move_to_san" do - it "detects check" do - game = Game.new players: [Player.new, Player.new] - game.board["e1"] = Piece.from_fen('K') - game.board["c8"] = Piece.from_fen('r') - debug_board(game, ["c8", "e8"]) - san = game.move_to_san(from: "c8", to: "e8", turn: 1) - san.to_s.should eq("Re8+") - end - - it "detects checkmate" do - fen = Fen.parse("r1bqkb1r/pppp1ppp/2n2n2/4p2Q/2B1P3/8/PPPP1PPP/RNB1K1NR w KQkq - 4 4") - game = Game.new(board: fen.board, players: [Player.new, Player.new]) - san = game.move_to_san(from: "h5", to: "f7", turn: 0) - debug_board(game, ["h5", "f7"]) - san.to_s.should eq("Qxf7#") - end - end - describe "#in_check?" do it "detects if the player is in check" do game = Game.new players: [Player.new, Player.new] diff --git a/src/lx_chess/game.cr b/src/lx_chess/game.cr index 4d95d48..18a8ec5 100644 --- a/src/lx_chess/game.cr +++ b/src/lx_chess/game.cr @@ -175,18 +175,46 @@ module LxChess end end + candidate_move_sets = @board.select do |candidate| + next unless candidate + next if candidate == piece + candidate.fen_symbol == piece.fen_symbol + end.compact.map do |candidate| + moves(candidate.index) + end.compact.select do |move_set| + move_set.moves.includes?(to) + end + + origin = nil + takes = en_passant || !@board[to].nil? + + if candidate_move_sets.any? + origin ||= "" + origin += @board.cord(from)[0] + end + + if candidate_move_sets.any? { |set| @board.cord(set.piece.index)[0] == @board.cord(from)[0] } + origin ||= "" + origin += @board.cord(from)[1] + end + + if origin.nil? && piece.pawn? && takes + origin = @board.cord(from)[0].to_s + end + Notation.new( square: @board.cord(to), promotion: promotion, piece_abbr: piece.fen_symbol, from: @board.cord(from), to: @board.cord(to), - takes: en_passant || !@board[to].nil?, + takes: takes, en_passant: en_passant, check: check && !checkmate, checkmate: checkmate, castles_k: castles_k, - castles_q: castles_q + castles_q: castles_q, + origin: origin ) end diff --git a/src/lx_chess/notation.cr b/src/lx_chess/notation.cr index 8cbacf2..c84d6f9 100644 --- a/src/lx_chess/notation.cr +++ b/src/lx_chess/notation.cr @@ -156,7 +156,7 @@ module LxChess when castles_q? "O-O-O" else - piece_abbr != 'P' || @takes ? piece_abbr : nil + piece_abbr unless piece_abbr == 'P' end if @en_passant diff --git a/src/lx_chess/version.cr b/src/lx_chess/version.cr index 3896496..4f09533 100644 --- a/src/lx_chess/version.cr +++ b/src/lx_chess/version.cr @@ -1,3 +1,3 @@ module LxChess - VERSION = "0.1.2" + VERSION = "0.1.3" end