From e21d704046b725affbc698224d7a6adaa4648052 Mon Sep 17 00:00:00 2001 From: Alex Clink Date: Tue, 7 Sep 2021 00:12:35 -0400 Subject: [PATCH] Add notation parser --- src/lx_chess.cr | 11 ++++ src/lx_chess/error.cr | 4 ++ src/lx_chess/fen.cr | 6 +- src/lx_chess/notation.cr | 115 +++++++++++++++++++++++++++++++++++++ src/lx_chess/term_board.cr | 1 + 5 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 src/lx_chess/error.cr create mode 100644 src/lx_chess/notation.cr diff --git a/src/lx_chess.cr b/src/lx_chess.cr index ca0c335..f3cae00 100644 --- a/src/lx_chess.cr +++ b/src/lx_chess.cr @@ -4,6 +4,7 @@ require "./lx_chess/terminal" require "./lx_chess/term_board" require "./lx_chess/game" require "./lx_chess/fen" +require "./lx_chess/notation" require "option_parser" @@ -37,6 +38,16 @@ gb = LxChess::TermBoard.new(game.board) gb.draw puts +loop do + print " > " + input = gets + if input + puts input.chomp + notation = LxChess::Notation.new(input) + puts notation.to_h + end +end + # gb.flip! # gb.draw # puts diff --git a/src/lx_chess/error.cr b/src/lx_chess/error.cr new file mode 100644 index 0000000..1102861 --- /dev/null +++ b/src/lx_chess/error.cr @@ -0,0 +1,4 @@ +module LxChess + class Error < Exception + end +end diff --git a/src/lx_chess/fen.cr b/src/lx_chess/fen.cr index 6ee512c..00dbfc2 100644 --- a/src/lx_chess/fen.cr +++ b/src/lx_chess/fen.cr @@ -1,13 +1,13 @@ require "./board" require "./piece" +require "./error" module LxChess class Fen - class Error < Exception - end + class InvalidFen < Error; end def self.parse(fen : String) - raise "Invalid FEN" unless fen =~ /[rnbqkp\d\/]+\s+[a-z]+\s[a-z\-]+\s+[a-z\-]+\s\d+\s\d+/i + raise InvalidFen.new("Invalid FEN") unless fen =~ /[rnbqkp\d\/]+\s+[a-z]+\s[a-z\-]+\s+[a-z\-]+\s\d+\s\d+/i placement, turn, castling, en_passant, halfmove_clock, fullmove_counter = fen.split(/\s+/) board = self.parse_placement(placement) diff --git a/src/lx_chess/notation.cr b/src/lx_chess/notation.cr new file mode 100644 index 0000000..a2abb79 --- /dev/null +++ b/src/lx_chess/notation.cr @@ -0,0 +1,115 @@ +require "./error" + +module LxChess + class Notation + class InvalidNotation < LxChess::Error; end + + NOTATION_REGEX = %r{\A\s* + (^[O0]-[O0])?\s* # 1. castles kingside + (^[O0]-[O0]-[O0])?\s* # 2. castles queenside + (^[RNBQKP](?!\d$))?\s* # 3. piece abbreviation + ((?:[a-z]|\d|[a-z]\d)(?=.*?[a-z]\d))?\s* # 4. origin square + (x)?\s* # 5. takes + ([a-z]\d)?\s* # 6. destination square + (\=\s*[RNBQ])?\s* # 7. promotion + (\+)?\s* # 8. check + (\#)?\s* # 9. checkmate + (e\.?p\.?)?\s* # 10. en passant + \z}ix + + getter notation : String + @match : Regex::MatchData? + + def initialize(@notation) + raise InvalidNotation.new("Notation cannot be blank") if @notation =~ /^\s*$/ + raise InvalidNotation.new("'#{notation}` is not valid notation") if @notation !~ NOTATION_REGEX + @match = @notation.match(NOTATION_REGEX) + raise InvalidNotation.new("Unable to determine destination") unless castles? || square + end + + def castles? + castles_k? || castles_q? + end + + def castles_k? + match? 1 + end + + def castles_q? + match? 2 + end + + def piece_abbr + if _piece_abbr = match 3 + _piece_abbr.upcase + end + end + + def origin + if _origin = match 4 + _origin.downcase + end + end + + def takes? + match? 5 + end + + def square + if _square = match 6 + _square.downcase + end + end + + def promotion + if _promo = match 7 + _promo[-1].upcase + end + end + + def check? + match? 8 + end + + def checkmate? + match? 9 + end + + def en_passant? + match? 10 + end + + # ~~~~~~~~~~~~~~~~~~~ + + def pawn? + piece_abbr == 'P' || piece_abbr.nil? + end + + # ~~~~~~~~~~~~~~~~~~~ + + def to_h + { + "square" => square, + "castles_k" => castles_k?, + "castles_q" => castles_q?, + "en_passant" => en_passant?, + "check" => check?, + "checkmate" => checkmate?, + "takes" => takes?, + "piece_abbr" => piece_abbr, + "origin" => origin, + "promotion" => promotion, + } + end + + private def match?(n : Int) + match(n) ? true : false + end + + private def match(n : Int) + return nil unless @match + match = @match.as(Regex::MatchData) + match[n]? + end + end +end diff --git a/src/lx_chess/term_board.cr b/src/lx_chess/term_board.cr index 7e331b9..950ff61 100644 --- a/src/lx_chess/term_board.cr +++ b/src/lx_chess/term_board.cr @@ -8,6 +8,7 @@ module LxChess def initialize(@board : Board) @flipped = false + @bg_dark = :green @bg_light = :light_green @fg_dark = :black