class PGN::Parser

Public Class Methods

new(pgn_content) click to toggle source
# File lib/pgn_parser.rb, line 6
def initialize(pgn_content)
  @pgn_content = pgn_content
  @headers = []
  @movelist = []
  @game_attributes = {}
end

Public Instance Methods

attributes() click to toggle source
# File lib/pgn_parser.rb, line 17
def attributes
  @game_attributes
end
headers() click to toggle source
# File lib/pgn_parser.rb, line 13
def headers
  @headers
end
movelist() click to toggle source
# File lib/pgn_parser.rb, line 21
def movelist
  @movelist
end
parse() click to toggle source
# File lib/pgn_parser.rb, line 25
def parse
  current_index = 0
  state = :initial
  buffer = ''
  while (current_index < @pgn_content.size)
    current_char = @pgn_content[current_index]
    current_index+=1
    if state==:initial
      if current_char=='['
        state = :start_parse_header
        next
      elsif (current_char == ' ' || current_char == "\n" || current_char == "\r")
        next
      else
        break
      end
    end

    if state==:start_parse_header
      if current_char == ']'
        state = :initial
        hd = parse_header(buffer)
        @headers << hd
        @game_attributes[hd[:type]] = hd[:value]
        buffer = ''
        next
      else
        buffer << current_char
        next
      end
    end
  end


  @movelist = parse_moves(@pgn_content,current_index - 1)[0]
  {moves: @movelist}.merge(@game_attributes)
end
parse_header(header) click to toggle source
# File lib/pgn_parser.rb, line 255
def parse_header(header)
  event_type = ""
  event_value = ""
  state = :parse_type
  current_index = 0
  buffer = ''
  while (current_index < header.size)
    current_char = header[current_index]
    current_index+=1
    if state==:parse_type
      if current_char == ' '
        event_type = buffer.dup
        buffer = ''
        state=:start_parse_value
        next
      else
        buffer << current_char
        next
      end
    elsif state==:start_parse_value
      if current_char=='"'
        state=:parse_value
        next
      else
        next
      end
    elsif state==:parse_value
      if current_char=='"'
        event_value = buffer.dup
        buffer = ''
      else
        buffer << current_char
      end

    end
  end
  {type: event_type, value: event_value}
end
parse_moves(content, current_index, initial_state = :parse_moves) click to toggle source
# File lib/pgn_parser.rb, line 63
def parse_moves(content, current_index, initial_state = :parse_moves)
  state = initial_state
  buffer = ''
  state_before = nil
  current_move = {}
  current_alternative = {}
  movelist = []
  while (current_index < content.size)
    current_char = content[current_index]
    current_index+=1
    if state == :parse_moves
      if current_char == ' '
        next
      elsif current_char == '('
        x = nil
        x, current_index = parse_moves(content, current_index)
      elsif current_char == ')'
        current_index+=1
        break
      elsif current_char == '{'
        state = :start_parse_comment_section_paren
        next
      elsif current_char >= '0' && current_char <= '9'
        state =:parse_move_text_number
        buffer << current_char
        next
      end
    end

    if state == :parse_move_text_number
      if current_char == '.'
        current_move[:num] = buffer.to_i
        buffer = ''
        state = :parse_move_first_position
        next
      else
        buffer << current_char
        next
      end
    end

    if state == :parse_move_first_position
      if (current_char == ' ')
        next
      elsif (current_char == '.')
        state = :continuation_indicator
        current_move[:cont] = true
        next
      else
        buffer << current_char
        state = :begin_parse_move_first_position
        next
      end
    end

    if state == :continuation_indicator
      if (current_char == '.' )
        next
      elsif (current_char == ' ')
        state = :parse_move_second_position
        next
      else
        buffer << current_char
        state = :parse_move_second_position
      end
    end

    if state == :begin_parse_move_first_position
      if (current_char == ' ')
        current_move[:w] = buffer
        buffer = ''
        state = :parse_move_second_position
        next
      elsif (current_char == "\n")
        break
      else
        buffer << current_char
        next
      end
    end

    if state == :parse_move_second_position
      if (current_char == ' ')
        next
      elsif (current_char == ')')
        current_index+=1
        break
      elsif (current_char == '$')
        buf = ''
        while (content[current_index] >='0') &&  (content[current_index]<='9') && (current_index < content.size)
          buf << content[current_index]
          current_index+=1
        end
        current_move[:w_nag] = buf
        next
      elsif (current_char == '{')
        state = :start_parse_comment_section_paren
        next
      elsif (current_char == '(')
        current_move[:w_alt] = [] if current_move[:w_alt].nil?
        alternate, current_index = parse_moves(content, current_index + 1)
        current_move[:w_alt] << alternate
        next
      elsif (current_char >= '0' && current_char <= '9')
        buffer = ''
        movelist << current_move.dup
        current_move = {}
        buffer << current_char
        state = :parse_move_text_number
      else
        buffer << current_char
        state = :begin_parse_move_second_position
        next
      end
    end

    if state == :begin_parse_move_second_position
      if (current_char == ' ')
        current_move[:b] = buffer
        buffer = ''
        state = :start_comment_section
        next
      elsif (current_char == "\n")
        current_move[:b] = buffer
        movelist << current_move.dup
        break
      else
        buffer << current_char
        next
      end
    end

    if state == :start_comment_section
      if (current_char == ' ')
        next
      elsif (current_char == '$')
        buf = ''
        while (content[current_index] >='0') && (content[current_index]<='9') && (current_index < content.size)
          buf << content[current_index]
          current_index+=1
        end
        current_move[:b_nag] = buf
        next
      elsif (current_char == '{')
        state = :start_parse_comment_section_paren
        next
      elsif (current_char == ')')
        current_index+=1
        break
      elsif (current_char == '(')
        current_move[:b_alt] = [] if current_move[:b_alt].nil?
        alternate, current_index = parse_moves(content, current_index)
        current_move[:b_alt] << alternate
        next
      elsif current_char >= '0' && current_char <= '9'
        buffer = ''
        movelist << current_move.dup
        current_move = {}
        buffer << current_char
        state =:parse_move_text_number
        next
      end
    end

    if state == :start_parse_comment_section_paren
      if (current_char == '}')
        current_move[:comment] = buffer.dup
        buffer = ''
        movelist << current_move.dup
        current_move = {}
        state = :parse_moves
        next
      else
        buffer << current_char
        next
      end
    end
  end

  if state ==  :start_comment_section
    movelist << current_move.dup
  elsif state == :begin_parse_move_first_position
    current_move[:w] = buffer
    movelist << current_move.dup
  elsif state == :start_parse_comment_section
    movelist << current_move.dup
  elsif state == :parse_move_second_position
    movelist << current_move.dup
  end
  [movelist, current_index]
end