diff --git a/src/lx_chess.cr b/src/lx_chess.cr index bcc29b6..de1bdb7 100644 --- a/src/lx_chess.cr +++ b/src/lx_chess.cr @@ -5,6 +5,7 @@ require "./lx_chess/term_board" require "./lx_chess/game" require "./lx_chess/fen" require "./lx_chess/notation" +require "./lx_chess/term_game" require "option_parser" @@ -38,128 +39,18 @@ OptionParser.parse do |parser| end end -log = [] of String fen = LxChess::Fen.parse(options["fen_string"]? || "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1") - -player_white = LxChess::Player.new -player_black = LxChess::Player.new - -game = LxChess::Game.new(board: fen.board, players: [player_white, player_black]) -game.set_fen_attributes(fen) - -gb = LxChess::TermBoard.new(game.board) +game = LxChess::TermGame.new(fen: fen) if theme = options["theme"]? if LxChess::TermBoard::THEMES[theme]? - gb.board_theme = theme + game.gb.board_theme = theme else STDERR.puts "No theme #{theme}" exit 1 end end -term = LxChess::Terminal.new - -term.clear -term.clear_scroll loop do - term.move 0, 0 - print fen.to_s - term.trunc - term.move x: 0, y: 3 - gb.draw - - game.pgn.strings.each_with_index do |m, i| - term.move game.board.width * 2 + 10, y: 3 + i - print m - end - - term.move x: 0, y: game.board.height + 5 - if game.turn == 0 - print " #{game.full_moves + 1}. " - else - print " #{game.full_moves + 1}. ... " - end - term.trunc - input = gets - case input - when /moves\s+([a-z]\d)/i - next unless input - if matches = input.match(/[a-z]\d/i) - if square = matches[0]? - if index = game.board.index(square) - if set = game.moves(index) - gb.highlight(set.moves, "blue") - from = "#{set.piece.fen_symbol}#{game.board.cord(index)}: " - to = set.moves.map { |m| game.board.cord(m) }.join(", ") - log.unshift from + to - end - end - end - end - when /moves/i - pieces = game.board.select do |piece| - next if piece.nil? - game.turn == 0 ? piece.white? : piece.black? - end - - move_sets = pieces.map do |piece| - next unless piece - game.moves(piece.index.as(Int16)) - end - - move_string = move_sets.map do |set| - next unless set - next if set.moves.empty? - gb.highlight(set.moves, "blue") - from = "#{set.piece.fen_symbol}#{game.board.cord(set.origin)}: " - to = set.moves.map { |m| game.board.cord(m) }.join(", ") - from + to - end.compact.join(" | ") - log.unshift move_string - when /\s*([a-z]\d)\s*([a-z]\d)\s*(?:=\s*)?([RNBQ])?/i - if input - if matches = input.downcase.match(/\s*([a-z]\d)\s*([a-z]\d)\s*(?:=\s*)?([RNBQ])?/i) - from = matches[1] - to = matches[2] - promo = if matches[3]? - matches[3][0] - end - if from && to - gb.clear - san = game.make_move(from, to) - gb.highlight([game.board.index(from), game.board.index(to)]) - log.unshift "#{san.to_s}: #{from} => #{to}" - end - end - end - when nil - else - if input - notation = LxChess::Notation.new(input) - from, to = game.parse_san(notation) - if from && to - gb.clear - san = game.make_move(from, to) - gb.highlight([from.to_i16, to.to_i16]) - log.unshift "#{san.to_s}: #{game.board.cord(from)} => #{game.board.cord(to)}" - end - end - end - - fen.update(game) -rescue e : LxChess::Notation::InvalidNotation | LxChess::Game::SanError | LxChess::Game::IllegalMove - if msg = e.message - log.unshift msg - end -ensure - puts - log.each { |l| print l; term.trunc; puts } - until log.size < 8 - log.pop - end + game.tick end - -# gb.flip! -# gb.draw -# puts diff --git a/src/lx_chess/term_game.cr b/src/lx_chess/term_game.cr new file mode 100644 index 0000000..ff06ca3 --- /dev/null +++ b/src/lx_chess/term_game.cr @@ -0,0 +1,154 @@ +require "./fen" +require "./game" +require "./player" +require "./terminal" +require "./term_board" + +module LxChess + class TermGame + property gb : TermBoard + getter log + + def initialize(@fen : Fen, players = [Player.new, Player.new]) + @term = Terminal.new + @game = Game.new(board: @fen.board, players: players) + @game.set_fen_attributes(fen) + @gb = TermBoard.new(@game.board) + @log = [] of String + clear_screen + end + + def update + input = gets || "" + + case input + when /moves\s+([a-z]\d)/i + if matches = input.match(/[a-z]\d/i) + if square = matches[0]? + if index = @game.board.index(square) + if set = @game.moves(index) + @gb.highlight(set.moves, "blue") + from = "#{set.piece.fen_symbol}#{@game.board.cord(index)}: " + to = set.moves.map { |m| @game.board.cord(m) }.join(", ") + @log.unshift from + to + end + end + end + end + when /moves/i + pieces = @game.board.select do |piece| + next if piece.nil? + @game.turn == 0 ? piece.white? : piece.black? + end + + move_sets = pieces.map do |piece| + next unless piece + @game.moves(piece.index.as(Int16)) + end + + move_string = move_sets.map do |set| + next unless set + next if set.moves.empty? + @gb.highlight(set.moves, "blue") + from = "#{set.piece.fen_symbol}#{@game.board.cord(set.origin)}: " + to = set.moves.map { |m| @game.board.cord(m) }.join(", ") + from + to + end.compact.join(" | ") + @log.unshift move_string + when /\s*([a-z]\d)\s*([a-z]\d)\s*(?:=\s*)?([RNBQ])?/i + if input + if matches = input.downcase.match(/\s*([a-z]\d)\s*([a-z]\d)\s*(?:=\s*)?([RNBQ])?/i) + from = matches[1] + to = matches[2] + promo = if matches[3]? + matches[3][0] + end + if from && to + @gb.clear + san = @game.make_move(from, to) + @gb.highlight([@game.board.index(from), @game.board.index(to)]) + @log.unshift "#{san.to_s}: #{from} => #{to}" + end + end + end + when nil + else + if input + notation = Notation.new(input) + from, to = @game.parse_san(notation) + if from && to + @gb.clear + san = @game.make_move(from, to) + @gb.highlight([from.to_i16, to.to_i16]) + @log.unshift "#{san.to_s}: #{@game.board.cord(from)} => #{@game.board.cord(to)}" + end + end + end + + @fen.update(@game) + rescue e : LxChess::Notation::InvalidNotation | LxChess::Game::SanError | LxChess::Game::IllegalMove + if msg = e.message + @log.unshift msg + end + ensure + until log.size < 8 + log.pop + end + end + + def draw + draw_fen + draw_board + draw_pgn + draw_log + draw_prompt + end + + def tick + draw + update + end + + # =================== + # = Drawing methods = + # =================== + + private def clear_screen + @term.clear + @term.clear_scroll + end + + private def draw_fen + @term.move 0, 0 + print @fen.to_s + @term.trunc + end + + private def draw_board + @term.move x: 0, y: 3 + @gb.draw + end + + private def draw_pgn + @game.pgn.strings.each_with_index do |m, i| + @term.move @game.board.width * 2 + 10, y: 3 + i + print m + end + end + + private def draw_log + @term.move x: 0, y: @game.board.height + 7 + @log.each { |l| print l; @term.trunc; puts } + end + + private def draw_prompt + @term.move x: 0, y: @game.board.height + 5 + if @game.turn == 0 + print " #{@game.full_moves + 1}. " + else + print " #{@game.full_moves + 1}. ... " + end + @term.trunc + end + end +end