From 39010fcdf2faef9e3744a9fee9a133896a88a4b4 Mon Sep 17 00:00:00 2001 From: Alex Clink Date: Sun, 12 Sep 2021 00:01:54 -0400 Subject: [PATCH] Fix fen placement string, disambiguate moves from san --- src/lx_chess.cr | 9 +++++++-- src/lx_chess/board.cr | 9 +++++++-- src/lx_chess/fen.cr | 6 +++--- src/lx_chess/game.cr | 31 ++++++++++++++++++++++++++++++- 4 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/lx_chess.cr b/src/lx_chess.cr index 4cd757b..b16c7dd 100644 --- a/src/lx_chess.cr +++ b/src/lx_chess.cr @@ -39,7 +39,9 @@ term = LxChess::Terminal.new loop do term.move 0, 0 - puts fen.placement + print fen.placement + term.trunc + puts puts gb.draw puts @@ -68,7 +70,10 @@ rescue e : LxChess::Notation::InvalidNotation | LxChess::Game::SanError end ensure puts - log.each { |l| puts l } + log.each { |l| print l; term.trunc; puts } + until log.size < 8 + log.pop + end end # gb.flip! diff --git a/src/lx_chess/board.cr b/src/lx_chess/board.cr index f5b0080..ca2d1db 100644 --- a/src/lx_chess/board.cr +++ b/src/lx_chess/board.cr @@ -68,7 +68,7 @@ module LxChess # Convert human *cord* into an index on the board. # Ex: `A1` => `0` def index(cord : String) - x = LETTERS.index(cord[0]) || 0 + x = LETTERS.index(cord[0].downcase) || 0 y = cord[1].to_i - 1 index(x, y) end @@ -102,11 +102,16 @@ module LxChess index + (@width - dist_left) - 1 end - def rank(index) + def rank(index : Int16) rank, _ = index.divmod(@width) rank end + def file(index : Int16) + _, file = index.divmod(@width) + file + end + def move(from : (String | Int), to : (String | Int)) piece = self[from.to_i16] self[from.to_i16] = nil diff --git a/src/lx_chess/fen.cr b/src/lx_chess/fen.cr index 0040d92..fe6b566 100644 --- a/src/lx_chess/fen.cr +++ b/src/lx_chess/fen.cr @@ -73,10 +73,10 @@ module LxChess end def placement - @board.map { |piece| piece ? piece.fen_symbol : nil } + rows = @board.map { |piece| piece ? piece.fen_symbol : nil } .each_slice(@board.width) - .map { |row| row.chunks { |r| r.nil? }.map { |chunked, values| chunked ? values.size : values.join }.first } - .join('/') + .map { |row| row.chunks { |r| r.nil? }.map { |chunked, values| chunked ? values.size : values.join }.join } + .to_a.reverse.join('/') end end end diff --git a/src/lx_chess/game.cr b/src/lx_chess/game.cr index 0c711fe..e1ed737 100644 --- a/src/lx_chess/game.cr +++ b/src/lx_chess/game.cr @@ -37,7 +37,10 @@ module LxChess end end - raise SanError.new("Ambiguous SAN") if pieces.size > 1 + if pieces.size > 1 + pieces = disambiguate_candidates(notation, pieces) + end + raise SanError.new("#{notation.to_s} is ambiguous") if pieces.size > 1 if piece = pieces.first? # from, to [piece.index, index] @@ -46,6 +49,32 @@ module LxChess end end + # Attempt to reduce ambiguities in candidate moves + def disambiguate_candidates(notation : Notation, pieces : Array(Piece | Nil)) + return pieces unless origin = notation.origin + case origin + when /[a-z]\d/ + piece = @board[origin] + pieces.select { |c| c == piece } + when /[a-z]/ + file = Board::LETTERS.index(origin[0].downcase) || 0 + pieces.select do |c| + next unless c + next unless index = c.index + @board.file(index) == file + end + when /\d/ + rank = origin.to_i16 + pieces.select do |c| + next unless c + next unless index = c.index + @board.rank(index) == rank + end + else + pieces + end + end + # Generate the psuedo-legal moves for a given *square* # TODO: add en passant, add boundaries, remove illegal moves def moves(square : (String | Int))