class Egd::FenDifferenceDiscerner

Attributes

end_fen[R]

Theoretically a start and end fen would suffice, but having move in SAN, which we do, allows skipping some hard procesing parts.

move[R]

Theoretically a start and end fen would suffice, but having move in SAN, which we do, allows skipping some hard procesing parts.

start_fen[R]

Theoretically a start and end fen would suffice, but having move in SAN, which we do, allows skipping some hard procesing parts.

Public Class Methods

new(start_fen: nil, move:, end_fen:) click to toggle source

Egd::FenDifferenceDiscerner.new(start_fen:, end_fen:).call

# File lib/egd/fen_difference_discerner.rb, line 13
def initialize(start_fen: nil, move:, end_fen:)
  @start_fen = start_fen || Egd::FenBuilder::NULL_FEN
  @move = move
  @end_fen = end_fen
end

Public Instance Methods

call() click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 19
def call
  # quickreturn with possible special cases
  case move
  when "O-O"
    return special_case_short_castle(Egd::Procedures.parse_fen(start_fen)[:to_move])
  when "O-O-O"
    return special_case_long_castle(Egd::Procedures.parse_fen(start_fen)[:to_move])
  when %r'\A[a-h]x[a-h]\d' # pawn x pawn, possible en-passant
    return special_case_ep_capture if special_case_ep_capture
  end

  # entering long processing of regular moves

  changes = {
    "lran" => lran, # FEN
    "from_square" => from_square, # FEN # b2
    "to_square" => to_square, # move b3
    "piece" => piece, # move p
    "move_type" => move_type,
  }

  changes.merge!("captured_piece" => captured_piece) if captured_piece
  changes.merge!("promotion" => promotion) if promotion

  changes
end

Private Instance Methods

bishop_color(on_square) click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 201
def bishop_color(on_square)
  Egd::Procedures.square_color(on_square) == "w" ? "l" : "d"
end
board1() click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 85
def board1
  @board1 ||= Egd::FenToBoard.new(start_fen)
end
board2() click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 89
def board2
  @board2 ||= Egd::FenToBoard.new(end_fen)
end
captured_piece() click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 151
def captured_piece
  @captured_piece ||=
    if move_type[%r'capture']
      captured_piece = changed_squares.detect do |hash|
        hash[:square] == to_square
      end[:from].upcase

      captured_piece.downcase! if captured_piece[%r'p'i]

      captured_piece << bishop_color(to_square) if captured_piece == "B"

      captured_piece
    else
      nil
    end
end
changed_squares() click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 93
def changed_squares
  return @changed_squares if defined?(@changed_squares)

  @changed_squares = []

  (1..64).to_a.each do |fen_index|
    i = fen_index - 1

    if board1.boardline[i] != board2.boardline[i]
      square = Egd::Procedures.fen_index_to_square(fen_index)

      @changed_squares << {
        square: square, from: board1.boardline[i], to: board2.boardline[i]
      }
    end
  end

  @changed_squares
end
from_square() click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 113
def from_square
  @from_square ||= changed_squares.reject do |hash|
    hash[:square] == to_square
  end.detect do |hash|
    hash[:to] == "-"
  end[:square]
end
lran() click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 181
def lran
  return @lran if defined?(@lran)

  @lran = "#{piece_in_lran(piece)}#{from_square}"

  @lran << (
    captured_piece ?
      "x#{piece_in_lran(captured_piece)}#{to_square}" :
      "-#{to_square}"
  )

  @lran << "=#{promotion[0]}" if promotion

  @lran
end
move_type() click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 137
def move_type
  @move_type ||=
    case move
    when %r'x.*='i
      "promotion_capture"
    when %r'x'i
      "capture"
    when %r'='i
      "promotion"
    else
      "move"
    end
end
piece() click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 125
def piece
  return @piece if defined?(@piece)

  possible_piece = move[0]

  @piece = (Egd::SAN_CHESS_PIECES.include?(possible_piece) ? possible_piece : "p" )

  @piece << bishop_color(to_square) if @piece == "B"

  @piece
end
piece_in_lran(pc) click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 197
def piece_in_lran(pc)
  pc == "p" ? "" : pc[0]
end
promotion() click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 168
def promotion
  @promotion ||=
    if move_type[%r'promotion']
      promoted_to = move.match(%r'=(?<promo>.)\z')[:promo]

      promoted_to << bishop_color(to_square) if promoted_to == "B"

      promoted_to
    else
      nil
    end
end
special_case_ep_capture() click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 48
def special_case_ep_capture
  return @ep_capture if defined?(@ep_capture)

  return @ep_capture = false if Egd::Procedures.parse_fen(start_fen)[:ep_square] != to_square

  from = move[0] + (move[-1] == "6" ? "5" : "4")

  @ep_capture = {
    "lran" => "#{from}x#{to_square}", # FEN
    "from_square" => from, # FEN
    "to_square" => to_square, # move
    "piece" => "p", # move
    "move_type" => "ep_capture", # FEN
    "captured_piece" => "p", # move
  }
end
special_case_long_castle(player) click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 75
def special_case_long_castle(player)
  {
    "lran" => "O-O-O", # FEN
    "from_square" => (player == "w" ? "e1" : "e8"), # FEN
    "to_square" => (player == "w" ? "c1" : "c8"), # move
    "piece" => "K", # move
    "move_type" => "long_castle", # FEN
  }
end
special_case_short_castle(player) click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 65
def special_case_short_castle(player)
  {
    "lran" => "O-O", # FEN
    "from_square" => (player == "w" ? "e1" : "e8"), # FEN
    "to_square" => (player == "w" ? "g1" : "g8"), # move
    "piece" => "K", # move
    "move_type" => "short_castle", # FEN
  }
end
to_square() click to toggle source
# File lib/egd/fen_difference_discerner.rb, line 121
def to_square
  @to_square ||= move.match(%r'\A(?<basemove>.*\d)(?<drek>.*)?\z')[:basemove][-2..-1]
end