class Pgn2Fen::Game

Constants

CLOSE_BRACE
CLOSE_PAREN
HEADER_KEY_REGEX
HEADER_VALUE_REGEX
OPEN_BRACE
OPEN_PAREN
START_FEN

constants

Attributes

board_color_from_fen[RW]
can_black_castle_kingside[RW]
can_black_castle_queenside[RW]
can_white_castle_kingside[RW]
fen_array[RW]

attr_accessors

attr_accessor :event, :site, :date, :eventdate, :round, :white, :black, :whiteelo, :blackelo, :result, :eco, :plycount, :fen
fullmove[RW]
halfmove[RW]
pgn[RW]

attr_accessors

attr_accessor :event, :site, :date, :eventdate, :round, :white, :black, :whiteelo, :blackelo, :result, :eco, :plycount, :fen
potential_enpassent_ply[RW]
promotion[RW]
promotion_piece[RW]

Public Class Methods

new(pgn_data) click to toggle source
# File lib/pgn2fen.rb, line 98
def initialize(pgn_data)
  @pgn_data = pgn_data
  @board = []
  @board_start_fen = START_FEN
  @fen = nil
  @potential_enpassent_ply = nil
  @halfmove = 0
  @fullmove = 1
  @promotion = false
  @promotion_piece = nil
  @board_color_from_fen = nil
end

Public Instance Methods

board_to_fen() click to toggle source

return fen representation from board

# File lib/pgn2fen.rb, line 514
def board_to_fen
  fen = ""
  empty_square_counter = 0;
  @board.each_with_index { |tok, idx|
    if (idx % 8 == 0 && idx > 0)
      if empty_square_counter != 0
        fen.concat(empty_square_counter.to_s)
        empty_square_counter = 0
      end
      fen.concat("/")
    end
    if tok.empty?
      empty_square_counter = empty_square_counter + 1
    else
      if empty_square_counter != 0
        fen.concat(empty_square_counter.to_s)
        empty_square_counter = 0
      end
      fen.concat(tok)
    end
  }
  # last squares could be empty
  if empty_square_counter != 0
    fen.concat(empty_square_counter.to_s)
    empty_square_counter = 0
  end
  fen
end
clean_comments(pgn) click to toggle source
# File lib/pgn2fen.rb, line 347
def clean_comments(pgn)
  remove_text_between_tokens_inclusive(pgn, OPEN_BRACE, CLOSE_BRACE)
end
clean_pgn(pgn) click to toggle source

clean pgn - remove comments and other unrequired text

# File lib/pgn2fen.rb, line 331
def clean_pgn(pgn)
  pgn.strip!
  # clean result
  pgn.sub!("1-0", ""); pgn.sub!("0-1", ""); pgn.sub!("1/2-1/2", "")
  # clean mate and incomplete game marker
  pgn.gsub!("#", ""); pgn.gsub!("*", "")
  #remove all chessbase $ characters
  pgn.gsub!(/\$(\w+)/, "")
  #remove all comments - content within {}
  #pgn.gsub!(/(\{[^}]+\})+?/, "")
  pgn = clean_comments(pgn)
  #remove all subvariations - content within ()
  #pgn.gsub!(/(\([^}]+\))+?/, "")
  pgn = clean_subvariations(pgn)
end
clean_subvariations(pgn) click to toggle source
# File lib/pgn2fen.rb, line 351
def clean_subvariations(pgn)
  remove_text_between_tokens_inclusive(pgn, OPEN_PAREN, CLOSE_PAREN)
end
dark_square_by_number(square_number) click to toggle source
# File lib/pgn2fen.rb, line 257
def dark_square_by_number square_number
  @@dark_squares.include?(square_number)
end
dark_square_by_pgn(square_pgn) click to toggle source
# File lib/pgn2fen.rb, line 249
def dark_square_by_pgn square_pgn
  @@dark_squares.include?(@@pgn_number_hash[square_pgn])
end
fen_array_from_plies(plies) click to toggle source

get FEN array from plies

# File lib/pgn2fen.rb, line 374
def fen_array_from_plies(plies)
  fen_array = []
  fen_array << @board_start_fen
  ply_number = 1 #ply_number starts at 1 for regular game
  unless @fen.nil?
    if @board_color_from_fen == "w"
      ply_number = (@fullmove.to_i * 2) + 1
    else
      ply_number = (@fullmove.to_i * 2)
    end
  end
  plies.each{|ply|
    #puts "ply=#{ply}, ply_number=#{ply_number}, move_number=#{ply_number/2 + 1}"
    fen_array << fen_for_ply(ply, ply_number)
    ply_number += 1
  }
  fen_array
end
fen_castle_text() click to toggle source

get FEN castle text based on castling availability

# File lib/pgn2fen.rb, line 458
def fen_castle_text
  text = ""
  if @can_white_castle_kingside; text.concat("K"); end
  if @can_white_castle_queenside; text.concat("Q"); end
  if @can_black_castle_kingside; text.concat("k"); end
  if @can_black_castle_queenside; text.concat("q"); end
  if text.empty?; text = "-"; end
  text
end
fen_for_ply(ply, ply_number) click to toggle source

get FEN from a ply and ply number

# File lib/pgn2fen.rb, line 395
def fen_for_ply(ply, ply_number)
  #puts ply
  is_white = (ply_number % 2 != 0)
  @halfmove = @halfmove + 1
  long_ply = short_ply_to_long_ply(ply, is_white)

  if long_ply.eql? "O-O"
    if is_white
      make_ply_on_board("e1g1")
      make_ply_on_board("h1f1")
      @can_white_castle_kingside = false
      @can_white_castle_queenside = false
    else
      make_ply_on_board("e8g8")
      make_ply_on_board("h8f8")
      @can_black_castle_kingside = false
      @can_black_castle_queenside = false
    end
  elsif long_ply.eql? "O-O-O"
    if is_white
      make_ply_on_board("e1c1")
      make_ply_on_board("a1d1")
      @can_white_castle_kingside = false
      @can_white_castle_queenside = false
    else
      make_ply_on_board("e8c8")
      make_ply_on_board("a8d8")
      @can_black_castle_kingside = false
      @can_black_castle_queenside = false
    end
  else # rest of moves
    if is_white
      if @can_white_castle_kingside && long_ply[0,2] == "h1"; @can_white_castle_kingside = false; end
      if @can_white_castle_queenside && long_ply[0,2] == "a1"; @can_white_castle_queenside = false; end
    else
      if @can_black_castle_kingside && long_ply[0,2] == "h8"; @can_white_castle_kingside = false; end
      if @can_black_castle_queenside && long_ply[0,2] == "a8"; @can_white_castle_queenside = false; end
    end
    make_ply_on_board(long_ply)
  end

  fen = board_to_fen
  fen.concat(" ").concat(is_white ? "b": "w")
  fen.concat(" ").concat(fen_castle_text)
  #enpassent square
  unless @potential_enpassent_ply.nil?
    fen.concat(" ").concat(@potential_enpassent_ply)
    @potential_enpassent_ply = nil
  else
    fen.concat(" ").concat("-")
  end
  fen.concat(" ").concat(@halfmove.to_s)
  if is_white 
    fen.concat(" ").concat((@fullmove).to_s)
  else
    fen.concat(" ").concat((@fullmove += 1).to_s)
  end
  #pp_board
  fen
end
file_for_hint(hint) click to toggle source
# File lib/pgn2fen.rb, line 222
def file_for_hint(hint)
  case hint
  when 'a'
    return @@aFile
  when 'b'
    return @@bFile
  when 'c'
    return @@cFile
  when 'd'
    return @@dFile
  when 'e'
    return @@eFile
  when 'f'
    return @@fFile
  when 'g'
    return @@gFile
  when 'h'
    return @@hFile
  else
    return nil
  end
end
games_from_pgn(pgn) click to toggle source
# File lib/pgn2fen.rb, line 276
def games_from_pgn(pgn)
  games = []
  pos_array = pgn.enum_for(:scan, /\[Event/).map{Regexp.last_match.begin(0)}
    pos_array.each_with_index {|pos, index|
      if (pos_array.size > index + 1) # all elements but last
        single_game_pgn = pgn[pos..pos_array[index+1]-1]
      else # last element
        single_game_pgn = pgn[pos..-1]
      end
      games << game_from_pgn(single_game_pgn)
    }
    games
end
init_board() click to toggle source
# File lib/pgn2fen.rb, line 261
def init_board
  @board_start_fen.split(" ").first.each_char {|c|
    case c
    when 'r', 'n', 'b', 'q', 'k', 'p'
      @board << c
    when 'R', 'N', 'B', 'Q', 'K', 'P'
      @board << c
    when '1', '2', '3', '4', '5', '6', '7', '8'
      (0...c.to_i).each {|n| @board << "" }
    else
      # do nothing
    end
  }
end
is_single_game() click to toggle source

check to verify PGN includes only a single game

# File lib/pgn2fen.rb, line 292
def is_single_game
  count = @pgn_data.scan(/\[Event /).count
    #puts "Event count:#{count}"
    if count > 1; return false; end

    # result header also includes result, hence compare with 2
    count = @pgn_data.scan(/1-0/).count
    #puts "1-0 count:#{count}"
    if count > 2; return false; end

    count = @pgn_data.scan(/0-1/).count
    #puts "0-1 count:#{count}"
    if count > 2; return false; end

    count = @pgn_data.scan(/1\/2-1\/2/).count
    #puts "1/2-1/2 count:#{count}"
    if count > 2; return false; end

    true
end
light_square_by_number(square_number) click to toggle source
# File lib/pgn2fen.rb, line 253
def light_square_by_number square_number
  @@light_squares.include?(square_number)
end
light_square_by_pgn(square_pgn) click to toggle source
# File lib/pgn2fen.rb, line 245
def light_square_by_pgn square_pgn
  @@light_squares.include?(@@pgn_number_hash[square_pgn])
end
make_ply_on_board(long_ply) click to toggle source

make a ply on the board

# File lib/pgn2fen.rb, line 492
def make_ply_on_board(long_ply)
  from_pgn = long_ply[0,2] 
  to_pgn = long_ply[2,2] 
  from_idx = @@pgn_number_hash[from_pgn]
  to_idx = @@pgn_number_hash[to_pgn]
  #puts "from_pgn:#{from_pgn}, to_pgn:#{to_pgn}, from_idx:#{from_idx}, to_idx:#{to_idx}"
  if @promotion
    if "P" == @board[from_idx] #white
      @board[to_idx] = @promotion_piece.upcase
    else #black
      @board[to_idx] = @promotion_piece.downcase
    end
    @promotion = false
    @promotion_piece = nil
  else #general case
    @board[to_idx] = @board[from_idx]
  end
  @board[from_idx] = ""
end
parse_headers(headers) click to toggle source
# File lib/pgn2fen.rb, line 119
def parse_headers(headers)
  #puts headers
  headers.each {|header|
    key = HEADER_KEY_REGEX.match(header)[1]
    value = HEADER_VALUE_REGEX.match(header)[1]
    instance_variable_set(:"@#{key.downcase.to_sym}", value)
  }
end
parse_pgn() click to toggle source
# File lib/pgn2fen.rb, line 128
def parse_pgn
  unless is_single_game
    raise Pgn2FenError, 'Only a single game PGN is supported right now.'
  end
  headers = []
  @pgn_data.strip!
  pgn_data_array = @pgn_data.split("\n")
  pgn_data_array.each {|line|
    if line.index("[") == 0
      headers << line
    else
      break
    end
  }
  parse_headers(headers)
  pgn_data_array = pgn_data_array[headers.size..-1]
  # get pgn
  @pgn = ""
  pgn_data_array.each {|line|
      @pgn = pgn.concat(line).concat(" ")
  }
  @pgn = clean_pgn(@pgn)

  #if fen does exist, use that as start board
  unless @fen.nil?
    tokens = @fen.split
    unless tokens.size == 6
      raise Pgn2FenError, "Invalid FEN header #{@fen}"
    end
    @board_start_fen = @fen
    @board_color_from_fen = tokens[1]
    @fullmove = tokens[5].to_i
    castle_options = tokens[3]
    update_castle_options_from_fen(castle_options)
  else
    reset_castle_options(true)
  end 

  init_board
  @plies = plies_from_pgn(@pgn)
  @fen_array = fen_array_from_plies(@plies)
  self # allow chaining
end
plies_from_pgn(pgn) click to toggle source

get plies from pgn

# File lib/pgn2fen.rb, line 315
def plies_from_pgn(pgn)
  moves = pgn.split(/[0-9]+\./)
  moves.shift # remove first ""
  plies = []
  moves.each {|move|
    move.strip!
    move.gsub!(".", "")
    move.split(" ").each {|ply|
      plies << ply
    }
  }
  plies
end
pp_board() click to toggle source
# File lib/pgn2fen.rb, line 543
def pp_board
  str = ""
  @board.each_with_index { |sq, idx|
    if sq.empty?; sq = "*"; end
    if (idx % 8 == 0 && idx != 0); str << "\n"; end
    str << sq << " "
  }
  puts "= = = = = = = ="
  puts str
  puts "= = = = = = = =\n\n\n"
end
rank_for_hint(hint) click to toggle source
# File lib/pgn2fen.rb, line 199
def rank_for_hint(hint)
  case hint
  when '1'
    return @@firstRank
  when '2'
    return @@secondRank
  when '3'
    return @@thirdRank
  when '4'
    return @@fourthRank
  when '5'
    return @@fifthRank
  when '6'
    return @@sixthRank
  when '7'
    return @@seventhRank
  when '8'
    return @@eighthRank
  else
    return nil
  end
end
remove_text_between_tokens_inclusive(text, open_token, close_token) click to toggle source
# File lib/pgn2fen.rb, line 355
def remove_text_between_tokens_inclusive(text, open_token, close_token)
  open_token_count = 0
  new_text = ""
  text.split("").each {|c|
    if c == open_token
      open_token_count += 1
    elsif c == close_token
      open_token_count -= 1
    else
      if open_token_count == 0
        new_text << c
      end
    end
  }
  new_text
end
reset_castle_options(option) click to toggle source
# File lib/pgn2fen.rb, line 111
def reset_castle_options(option)
  @can_white_castle_kingside = option
  @can_white_castle_queenside = option
  @can_black_castle_kingside = option
  @can_black_castle_queenside = option
end
short_ply_to_long_ply(ply, is_white) click to toggle source

convert short ply to long ply

# File lib/pgn2fen.rb, line 557
    def short_ply_to_long_ply(ply, is_white)
      from_idx = -1
      to_idx = -1
      from_pgn = ""
      to_pgn = ""
      hint = nil

      if ply.eql?("O-O"); return ply; end
      if ply.eql?("O-O-O"); return ply; end
      unless ply.index('+').nil?; ply.sub!("+", ""); end
      unless ply.index('x').nil?; ply.sub!("x", ""); @halfmove = 0; end
      unless ply.index('=').nil?
        @promotion = true
        @promotion_piece = ply[-1]
        ply = ply.chop.chop
      end

      if ply.length == 2 # pawn non-capture
        to_pgn = ply
        to_idx = @@pgn_number_hash[to_pgn]
        if is_white
          if !@board[to_idx+8].empty?
            from_idx = to_idx+8
          else
            from_idx = to_idx+16
#            if @board[to_idx-1].eql?"p" or @board[to_idx+1].eql?"p"
              @potential_enpassent_ply = @@number_pgn_hash[from_idx-8]
#            end
          end
        else  # isBlack
          if !@board[to_idx-8].empty?
            from_idx = to_idx-8
          else
            from_idx = to_idx-16
#            if @board[to_idx-1].eql?"P" or @board[to_idx+1].eql?"P"
              @potential_enpassent_ply = @@number_pgn_hash[from_idx+8]
#            end
          end
        end
        from_pgn = @@number_pgn_hash[from_idx]
        @halfmove = 0
        return from_pgn + to_pgn
      end

      if ('a'..'h').include?(ply[0]) && ply.length == 3 #pawn capture, non-enpassent
        to_pgn = ply[1..-1]
        to_idx = @@pgn_number_hash[to_pgn]
        if is_white
          if @board[to_idx+7].eql?("P") && file_for_hint(ply[0]).include?(to_idx+7)
            from_idx = to_idx+7
          elsif @board[to_idx+9].eql?("P")&& file_for_hint(ply[0]).include?(to_idx+9)
            from_idx = to_idx+9
          end
        else #is_black
          if @board[to_idx-7].eql?("p") && file_for_hint(ply[0]).include?(to_idx-7)
            from_idx = to_idx-7
          elsif @board[to_idx-9].eql?("p") && file_for_hint(ply[0]).include?(to_idx-9)
            from_idx = to_idx-9
          end
        end
        if from_idx == -1; raise Pgn2FenError, "Error parsing pawn capture at ply #{ply}"; end
        from_pgn = @@number_pgn_hash[from_idx]
        @halfmove = 0
        return from_pgn + to_pgn
      end

      if ply.length == 3; to_pgn = ply[1,2]; end
      if ply.length() == 4
        to_pgn = ply[2,2]
        hint = ply[1]
      end
      to_idx = @@pgn_number_hash[to_pgn]

      if ply[0].downcase.eql?('r'); return short_ply_to_long_ply_for_rook(to_idx, to_pgn, hint, is_white); end
      if ply[0].downcase.eql?('n'); return short_ply_to_long_ply_for_knight(to_idx, to_pgn, hint, is_white); end
      if ply[0].downcase.eql?('b'); return short_ply_to_long_ply_for_bishop(to_idx, to_pgn, hint, is_white); end
      if ply[0].downcase.eql?('q'); return short_ply_to_long_ply_for_queen(to_idx, to_pgn, hint, is_white); end
      if ply[0].downcase.eql?('k'); return short_ply_to_long_ply_for_king(to_idx, to_pgn, hint, is_white); end
      return from_pgn + to_pgn
    end
short_ply_to_long_ply_for_bishop(to_idx, to_pgn, hint, is_white) click to toggle source
# File lib/pgn2fen.rb, line 763
    def short_ply_to_long_ply_for_bishop(to_idx, to_pgn, hint, is_white)
      from_idx = -1
      from_pgn = ""
      piece = is_white ? "B" : "b"
      is_light = light_square_by_number(to_idx) ? true : false
      if (!hint.nil?)
        if @@one_thru_eight.include?(hint)
          from_pgn = to_pgn[0,1] + h
        end
        if @@a_thru_h.include?(hint)
          from_pgn = h + to_pgn[1,1]
        end
        return from_pgn + to_pgn
      else
        # check nw direction
        nw = to_idx
        while(nw > -1) do
          nw = nw - 9
          if (nw < 0)
            break
          end
#          puts "nw=#{nw}"
          if light_square_by_number(nw) != is_light # square colors don't match - overflow
            break
          elsif @board[nw].eql?(piece)
            from_idx = nw
            from_pgn = @@number_pgn_hash[from_idx]
            return from_pgn + to_pgn
          elsif @board[nw].eql?("")
            next
          else
            break
          end
        end
        # check ne direction
        ne = to_idx
        while(ne > 0) do
          ne = ne - 7
          if (ne < 1)
            break
          end
#          puts "ne=#{ne}"
          if light_square_by_number(ne) != is_light # square colors don't match - overflow
            break
          elsif @board[ne].eql?(piece)
            from_idx = ne
            from_pgn = @@number_pgn_hash[from_idx]
            return from_pgn + to_pgn
          elsif @board[ne].eql?("")
            next
          else
            break
          end
        end
        # check sw direction
        sw = to_idx
        while(sw < 63) do
          sw = sw + 7
          if (sw > 62)
            break
          end
#          puts "sw=#{sw}"
          if light_square_by_number(sw) != is_light # square colors don't match - overflow
            break
          elsif @board[sw].eql?(piece)
            from_idx = sw
            from_pgn = @@number_pgn_hash[from_idx]
            return from_pgn + to_pgn
          elsif @board[sw].eql?("")
            next
          else
            break
          end
        end
        # check se direction
        se = to_idx
        while(se < 64) do
          se = se + 9
          if (se > 63)
            break
          end
#          puts "se=#{se}"
          if light_square_by_number(se) != is_light # square colors don't match - overflow
            break
          elsif @board[se].eql?(piece)
            from_idx = se
            from_pgn = @@number_pgn_hash[from_idx]
            return from_pgn + to_pgn
          elsif @board[se].eql?("")
            next
          else
            break
          end
        end
      end
      return from_pgn + to_pgn
    end
short_ply_to_long_ply_for_king(to_idx, to_pgn, hint, is_white) click to toggle source
# File lib/pgn2fen.rb, line 1037
def short_ply_to_long_ply_for_king(to_idx, to_pgn, hint, is_white)
  from_idx = -1
  from_pgn = ""
  if is_white
    @board.reverse.each_with_index {|i,idx| if i.eql?("K"); from_idx = 63 - idx; break; end }
  else
   @board.each_with_index {|i,idx| if i.eql?("k"); from_idx = idx; break; end }
  end
  from_pgn = @@number_pgn_hash[from_idx]
  return from_pgn + to_pgn
end
short_ply_to_long_ply_for_knight(to_idx, to_pgn, hint, is_white) click to toggle source
# File lib/pgn2fen.rb, line 722
def short_ply_to_long_ply_for_knight(to_idx, to_pgn, hint, is_white)
  from_idx = -1
  from_pgn = ""
  piece = is_white ? "N" : "n"
  if !hint.nil?
    # -17,-15, 10, -6, 6, 10, 15, 17 are possible knight moves
    knight_moves = [17+to_idx, 17+to_idx, -15+to_idx, 15+to_idx, -10+to_idx, 10+to_idx, -6+to_idx, 6+to_idx]
    if @@one_thru_eight.include?(hint) 
      rank = rank_for_hint(hint)
      knight_moves = knight_moves & rank.to_a # intersection
    end
    if @@a_thru_h.include?(hint) 
      file = file_for_hint(hint)
      knight_moves = knight_moves & file.to_a #intersection
    end
    knight_moves.each {|idx|
      if @board[idx].eql?(piece)
        from_idx = idx
        from_pgn = @@number_pgn_hash[from_idx]
        return from_pgn + to_pgn
      end
    }
  else
    # -17,-15, 10, -6, 6, 10, 15, 17 are possible knight moves
    knight_moves = [-17, 17, -15, 15, -10, 10, -6, 6]
    knight_moves.each {|i|
      idx = to_idx + i
      if (idx < 0 && idx > 63)
        next
      end
      if @board[idx].eql?(piece)
        from_idx = idx
        from_pgn = @@number_pgn_hash[from_idx]
        return from_pgn + to_pgn
      end
    }
  end
  #return from_pgn + to_pgn
  raise Pgn2FenError, "Error parsing knight move to square #{to_pgn}"
end
short_ply_to_long_ply_for_queen(to_idx, to_pgn, hint, is_white) click to toggle source
# File lib/pgn2fen.rb, line 861
def short_ply_to_long_ply_for_queen(to_idx, to_pgn, hint, is_white)
  # check bishop type moves
  from_idx = -1
  from_pgn = ""
  piece = is_white ? "Q" : "q"
  is_light = light_square_by_number(to_idx) ? true : false
  if (!hint.nil?)
    if @@one_thru_eight.include?(hint)
      from_pgn = to_pgn[0,1] + hint
    end
    if @@a_thru_h.include?(hint)
      from_pgn = hint + to_pgn[1,1]
    end
    return from_pgn + to_pgn
  else
    # check nw direction
    nw = to_idx
    while(nw > -1) do
      nw = nw - 9
      if (nw < 0)
        break
      end
      if light_square_by_number(nw) != is_light # square colors don't match - overflow
        break
      elsif @board[nw].eql?(piece)
        from_idx = nw
        from_pgn = @@number_pgn_hash[from_idx]
        return from_pgn + to_pgn
      elsif @board[nw].eql?("")
        next
      else
        break
      end
    end
    # check ne direction
    ne = to_idx
    while(ne > 0) do
      ne = ne - 7
      if (ne < 1)
        break
      end
      if light_square_by_number(ne) != is_light # square colors don't match - overflow
        break
      elsif @board[ne].eql?(piece)
        from_idx = ne
        from_pgn = @@number_pgn_hash[from_idx]
        return from_pgn + to_pgn
      elsif @board[ne].eql?("")
        next
      else
        break
      end
    end
    # check sw direction
    sw = to_idx
    while(sw < 63) do
      sw = sw + 7
      if (sw > 62)
        break
      end
      if light_square_by_number(sw) != is_light # square colors don't match - overflow
        break
      elsif @board[sw].eql?(piece)
        from_idx = sw
        from_pgn = @@number_pgn_hash[from_idx]
        return from_pgn + to_pgn
      elsif @board[sw].eql?("")
        next
      else
        break
      end
    end
    # check se direction
    se = to_idx
    while(se < 64) do
      se = se + 9
      if (se > 63)
        break
      end
      if light_square_by_number(se) != is_light # square colors don't match - overflow
        break
      elsif @board[se].eql?(piece)
        from_idx = se
        from_pgn = @@number_pgn_hash[from_idx]
        return from_pgn + to_pgn
      elsif @board[se].eql?("")
        next
      else
        break
      end
    end
  end
  if (from_pgn.length == 2)
    return from_pgn + to_pgn
  end
  # check rook type moves
  if !hint.nil?
    if @@one_thru_eight.include?(hint)
      from_pgn = to_pgn[0,1] + hint
    end
    if @@a_thru_h.include?(hint)
      from_pgn = hint + to_pgn[1,1]
    end
    return from_pgn + to_pgn
  else # no hint
    # check file
    up = to_idx
    while up > -1 do
      up = up - 8
      if (up < 0)
        break
      end
      if @board[up].eql?(piece)
        from_idx = up
        from_pgn = @@number_pgn_hash[from_idx]
        return from_pgn + to_pgn
      elsif @board[up].eql?("")
        next
      else
        break
      end
    end
    down = to_idx
    while down < 64 do
      down = down + 8
      if down > 63
        break
      end
      if @board[down].eql?(piece)
        from_idx = down
        from_pgn = @@number_pgn_hash[from_idx]
        return from_pgn + to_pgn
      elsif @board[down].eql?("")
        next
      else
        break
      end
    end

    # check rank
    left = to_idx
    while left > -1 do
      left = left  - 1
      if left % 8 == 7
        break
      end
      if @board[left].eql?(piece)
        from_idx = left
        from_pgn = @@number_pgn_hash[from_idx]
        return from_pgn + to_pgn
      elsif @board[left].eql?("")
        next
      else
        break
      end
    end
    right = to_idx
    while right < 64 do
      right = right + 1
      if right % 8 == 0
        break
      end
      if @board[right].eql?(piece)
        from_idx = right
        from_pgn = @@number_pgn_hash[from_idx]
        return from_pgn + to_pgn
      elsif @board[right].eql?("")
        next
      else 
        break
      end
    end
  end
  from_pgn + to_pgn
end
short_ply_to_long_ply_for_rook(to_idx, to_pgn, hint, is_white) click to toggle source
# File lib/pgn2fen.rb, line 638
def short_ply_to_long_ply_for_rook(to_idx, to_pgn, hint, is_white)
  from_idx = -1
  from_pgn = ""
  piece = is_white ? "R" : "r"
  if !hint.nil?
    if @@one_thru_eight.include?(hint)
      from_pgn = to_pgn[0,1] + hint
    end
    if @@a_thru_h.include?(hint)
      from_pgn = hint + to_pgn[1,1]
    end
    return from_pgn + to_pgn
  else # no hint
    # check file
    up = to_idx
    while up > -1 do
      up = up - 8
      if (up < 0)
        break
      end
      if @board[up].eql?(piece)
        from_idx = up
        from_pgn = @@number_pgn_hash[from_idx]
        return from_pgn + to_pgn
      elsif @board[up].eql?("")
        next
      else
        break
      end
    end
    down = to_idx
    while down < 64 do
      down = down + 8
      if down > 63
        break
      end
      if @board[down].eql?(piece)
        from_idx = down
        from_pgn = @@number_pgn_hash[from_idx]
        return from_pgn + to_pgn
      elsif @board[down].eql?("")
        next
      else
        break
      end
    end

    # check rank
    left = to_idx
    while left > -1 do
      left = left  - 1
      if left % 8 == 7
        break
      end
      if @board[left].eql?(piece)
        from_idx = left
        from_pgn = @@number_pgn_hash[from_idx]
        return from_pgn + to_pgn
      elsif @board[left].eql?("")
        next
      else
        break
      end
    end
    right = to_idx
    while right < 64 do
      right = right + 1
      if right % 8 == 0
        break
      end
      if @board[right].eql?(piece)
        from_idx = right
        from_pgn = @@number_pgn_hash[from_idx]
        return from_pgn + to_pgn
      elsif @board[right].eql?("")
        next
      else
        break
      end
    end
  end
  from_pgn + to_pgn
end
to_s() click to toggle source
# File lib/pgn2fen.rb, line 172
def to_s
  str = ""
  str << "Event: #{@event}\n"
  str << "Site: #{@site}\n"
  str << "Date: #{@date}\n"
  str << "EventDate: #{@eventdate}\n"
  str << "Round: #{@round}\n"
  str << "White: #{@white}\n"
  str << "Black: #{@black}\n"
  str << "WhiteElo: #{@whiteElo}\n"
  str << "BlackElo: #{@blackElo}\n"
  str << "Result: #{@result}\n"
  str << "Eco: #{@eco}\n"
  str << "Plycount: #{@plycount}\n"
  str << "FEN: #{@fen}\n"

  str << "PGN: #{@pgn}\n"
  str << "Plies: #{@plies}\n"
  str << "FEN Array:\n"
  unless @fen_array.nil?
    @fen_array.each {|fen|
      str << fen << "\n"
    }
  end
  str
end
update_castle_options_from_fen(castle_options) click to toggle source

update castling options from FEN header

# File lib/pgn2fen.rb, line 470
def update_castle_options_from_fen castle_options
  reset_castle_options(false)
  if castle_options == "-"
    return
  end
  tokens = castle_options.split("")
  tokens.each {|token|
    case token
    when "K" 
      @can_white_castle_kingside = true
    when "Q"
      @can_white_castle_queenside = true
    when "k"
      @can_black_castle_kingside = true
    when "q"
      @can_black_castle_queenside = true
    end
  }
end