class Jkf::Parser::Kif

KIF Parser

Protected Instance Methods

make_hand(str) click to toggle source

generate motigoma

# File lib/jkf/parser/kif.rb, line 614
def make_hand(str)
  # Kifu for iPhoneは半角スペース区切り
  ret = { "FU" => 0, "KY" => 0, "KE" => 0, "GI" => 0, "KI" => 0, "KA" => 0, "HI" => 0 }
  return ret if str.empty?

  str.split(/[  ]/).each do |kind|
    next if kind.empty?
    ret[kind2csa(kind[0])] = kind.length == 1 ? 1 : kan2n2(kind[1..-1])
  end

  ret
end
parse_comment() click to toggle source

comment : “*” nonls nl | “&” nonls nl

# File lib/jkf/parser/kif.rb, line 476
def parse_comment
  s0 = @current_pos
  if match_str("*") != :failed
    s2 = parse_nonls
    if parse_nl != :failed
      @reported_pos = s0
      s0 = s2.join
    else
      @current_pos = s0
      s0 = :failed
    end
  else
    @current_pos = s0
    s0 = :failed
  end
  if s0 == :failed
    s0 = @current_pos
    s1 = match_str("&")
    if s1 != :failed
      s2 = parse_nonls
      if parse_nl != :failed
        @reported_pos = s0
        s0 = "&" + s2.join
      else
        @current_pos = s0
        s0 = :failed
      end
    else
      @current_pos = s0
      s0 = :failed
    end
  end
  s0
end
parse_firstboard() click to toggle source

firstboard : comment* pointer?

# File lib/jkf/parser/kif.rb, line 179
def parse_firstboard
  s0 = @current_pos
  s1 = []
  s2 = parse_comment
  while s2 != :failed
    s1 << s2
    s2 = parse_comment
  end
  parse_pointer
  @reported_pos = s0
  s0 = s1.empty? ? {} : { "comments" => s1 }
  s0
end
parse_fork() click to toggle source

fork : “変化:” “ ”* [0-9]+ “手” nl moves

# File lib/jkf/parser/kif.rb, line 512
def parse_fork
  s0 = @current_pos
  if match_str("変化:") != :failed
    match_spaces
    s3 = parse_te
    if s3 != :failed
      if match_str("手") != :failed
        if parse_nl != :failed
          s6 = parse_moves
          if s6 != :failed
            @reported_pos = s0
            s0 = { "te" => s3.join.to_i, "moves" => s6[1..-1] }
          else
            @current_pos = s0
            s0 = :failed
          end
        else
          @current_pos = s0
          s0 = :failed
        end
      else
        @current_pos = s0
        s0 = :failed
      end
    else
      @current_pos = s0
      s0 = :failed
    end
  else
    @current_pos = s0
    s0 = :failed
  end
  s0
end
parse_from() click to toggle source

from : “打” | “(” [1-9] [1-9] “)”

# File lib/jkf/parser/kif.rb, line 327
def parse_from
  s0 = @current_pos
  s1 = match_str("打")
  if s1 != :failed
    @reported_pos = s0
    s1 = nil
  end
  s0 = s1
  if s0 == :failed
    s0 = @current_pos
    if match_str("(") != :failed
      s2 = match_regexp(/^[1-9]/)
      if s2 != :failed
        s3 = match_regexp(/^[1-9]/)
        if s3 != :failed
          if match_str(")") != :failed
            @reported_pos = s0
            s0 = { "x" => s2.to_i, "y" => s3.to_i }
          else
            @current_pos = s0
            s0 = :failed
          end
        else
          @current_pos = s0
          s0 = :failed
        end
      else
        @current_pos = s0
        s0 = :failed
      end
    else
      @current_pos = s0
      s0 = :failed
    end
  end
  s0
end
parse_fugou() click to toggle source

fugou : place piece “成”?

# File lib/jkf/parser/kif.rb, line 276
def parse_fugou
  s0 = @current_pos
  s1 = parse_place
  if s1 != :failed
    s2 = parse_piece
    if s2 != :failed
      s3 = match_str("成")
      s3 = nil if s3 == :failed
      @reported_pos = s0
      s0 = { "to" => s1, "piece" => s2, "promote" => !!s3 }
    else
      @current_pos = s0
      s0 = :failed
    end
  else
    @current_pos = s0
    s0 = :failed
  end
  s0
end
parse_header() click to toggle source

header : [^:rn]+ “:” nonls nl

| turn "手番" nl
| "盤面回転" nl
# File lib/jkf/parser/kif.rb, line 59
def parse_header
  s0 = @current_pos
  s2 = match_regexp(/^[^:\r\n]/)
  if s2 != :failed
    s1 = []
    while s2 != :failed
      s1 << s2
      s2 = match_regexp(/^[^:\r\n]/)
    end
  else
    s1 = :failed
  end
  if s1 != :failed
    if match_str(":") != :failed
      s3 = parse_nonls
      if parse_nl != :failed
        @reported_pos = s0
        s1 = { "k" => s1.join, "v" => s3.join }
        s0 = s1
      else
        @current_pos = s0
        s0 = :failed
      end
    else
      @current_pos = s0
      s0 = :failed
    end
  else
    @current_pos = s0
    s0 = :failed
  end
  if s0 == :failed
    s0 = @current_pos
    s1 = parse_turn
    if s1 != :failed
      if match_str("手番") != :failed
        if parse_nl != :failed
          @reported_pos = s0
          s0 = { "k" => "手番", "v" => s1 }
        else
          @current_pos = s0
          s0 = :failed
        end
      else
        @current_pos = s0
        s0 = :failed
      end
    else
      @current_pos = s0
      s0 = :failed
    end
    if s0 == :failed
      s0 = @current_pos
      if match_str("盤面回転") != :failed
        if parse_nl != :failed
          @reported_pos = s0
          s0 = nil
        else
          @current_pos = s0
          s0 = :failed
        end
      else
        @current_pos = s0
        s0 = :failed
      end
    end
  end

  s0
end
parse_hms() click to toggle source

hms : [0-9]+ “:” [0-9]+ “:” [0-9]+

# File lib/jkf/parser/kif.rb, line 406
def parse_hms
  s0 = @current_pos
  s1 = match_digits!

  if s1 != :failed
    if match_str(":") != :failed
      s3 = match_digits!
      if s3 != :failed
        if match_str(":") != :failed
          s5 = match_digits!
          if s5 != :failed
            @reported_pos = s0
            s0 = { "h" => s1.join.to_i, "m" => s3.join.to_i, "s" => s5.join.to_i }
          else
            @current_pos = s0
            s0 = :failed
          end
        else
          @current_pos = s0
          s0 = :failed
        end
      else
        @current_pos = s0
        s0 = :failed
      end
    else
      @current_pos = s0
      s0 = :failed
    end
  else
    @current_pos = s0
    s0 = :failed
  end
  s0
end
parse_line() click to toggle source

line : “ ”* te “ ”* (fugou from | [^rn ]*) “ ”* time? “+”? nl

# File lib/jkf/parser/kif.rb, line 215
def parse_line
  s0 = @current_pos
  match_spaces
  s2 = parse_te
  if s2 != :failed
    match_spaces
    s4 = @current_pos
    s5 = parse_fugou
    if s5 != :failed
      s6 = parse_from
      if s6 != :failed
        @reported_pos = s4
        s4 = transform_teban_fugou_from(s2, s5, s6)
      else
        @current_pos = s4
        s4 = :failed
      end
    else
      @current_pos = s4
      s4 = :failed
    end
    if s4 == :failed
      s4 = @current_pos
      s5 = []
      s6 = match_regexp(/^[^\r\n ]/)
      while s6 != :failed
        s5 << s6
        s6 = match_regexp(/^[^\r\n ]/)
      end
      @reported_pos = s4
      s4 = s5.join
    end
    if s4 != :failed
      match_spaces
      s6 = parse_time
      s6 = nil if s6 == :failed
      match_str("+")
      if parse_nl != :failed
        @reported_pos = s0
        s0 = { "move" => s4, "time" => s6 }
      else
        @current_pos = s0
        s0 = :failed
      end
    else
      @current_pos = s0
      s0 = :failed
    end
  else
    @current_pos = s0
    s0 = :failed
  end
  s0
end
parse_move() click to toggle source

move : line comment* pointer?

# File lib/jkf/parser/kif.rb, line 194
def parse_move
  s0 = @current_pos
  s1 = parse_line
  if s1 != :failed
    s2 = []
    s3 = parse_comment
    while s3 != :failed
      s2 << s3
      s3 = parse_comment
    end
    parse_pointer
    @reported_pos = s0
    s0 = transform_move(s1, s2)
  else
    @current_pos = s0
    s0 = :failed
  end
  s0
end
parse_moves() click to toggle source

moves : firstboard split? move* result?

# File lib/jkf/parser/kif.rb, line 157
def parse_moves
  s0 = @current_pos
  s1 = parse_firstboard
  if s1 != :failed
    parse_split
    s2 = []
    s3 = parse_move
    while s3 != :failed
      s2 << s3
      s3 = parse_move
    end
    parse_result
    @reported_pos = s0
    s0 = s2.unshift(s1)
  else
    @current_pos = s0
    s0 = :failed
  end
  s0
end
parse_ms(with_hour: false) click to toggle source

ms : [0-9]+ “:” [0-9]+

# File lib/jkf/parser/kif.rb, line 443
def parse_ms(with_hour: false)
  s0 = @current_pos
  s1 = match_digits!
  if s1 != :failed
    if match_str(":") != :failed
      s3 = match_digits!
      if s3 != :failed
        @reported_pos = s0
        m = s1.join.to_i
        s = s3.join.to_i
        if with_hour
          h = m / 60
          m = m % 60
          s0 = { "h" => h, "m" => m, "s" => s }
        else
          s0 = { "m" => m, "s" => s }
        end
      else
        @current_pos = s0
        s0 = :failed
      end
    else
      @current_pos = s0
      s0 = :failed
    end
  else
    @current_pos = s0
    s0 = :failed
  end
  s0
end
parse_place() click to toggle source

place : num numkan | “同 ”

# File lib/jkf/parser/kif.rb, line 298
def parse_place
  s0 = @current_pos
  s1 = parse_num
  if s1 != :failed
    s2 = parse_numkan
    if s2 != :failed
      @reported_pos = s0
      s0 = { "x" => s1, "y" => s2 }
    else
      @current_pos = s0
      s0 = :failed
    end
  else
    @current_pos = s0
    s0 = :failed
  end
  if s0 == :failed
    s0 = @current_pos
    s1 = match_str("同 ")
    if s1 != :failed
      @reported_pos = s0
      s1 = nil
    end
    s0 = s1
  end
  s0
end
parse_root() click to toggle source

kifu : skipline* header* initialboard? header* split? moves fork* nl?

# File lib/jkf/parser/kif.rb, line 11
def parse_root
  @input += "\n" unless @input.end_with?("\n")

  s0 = @current_pos
  s1 = []
  s2 = parse_skipline
  while s2 != :failed
    s1 << s2
    s2 = parse_skipline
  end

  s2 = []
  s3 = parse_header
  while s3 != :failed
    s2 << s3
    s3 = parse_header
  end
  s3 = parse_initialboard
  s3 = nil if s3 == :failed
  s4 = []
  s5 = parse_header
  while s5 != :failed
    s4 << s5
    s5 = parse_header
  end
  parse_split
  s6 = parse_moves
  if s6 != :failed
    s7 = []
    s8 = parse_fork
    while s8 != :failed
      s7 << s8
      s8 = parse_fork
    end
    parse_nl
    @reported_pos = s0
    s0 = transform_root(s2, s3, s4, s6, s7)
  else
    @current_pos = s0
    s0 = :failed
  end

  s0
end
parse_split() click to toggle source

split : “手数—-指手–” “——-消費時間–”? nl

# File lib/jkf/parser/kif.rb, line 136
def parse_split
  s0 = @current_pos
  s1 = match_str("手数----指手--")
  if s1 != :failed
    s2 = match_str("-------消費時間--")
    s2 = nil if s2 == :failed
    s3 = parse_nl
    if s3 != :failed
      s0 = [s1, s2, s3]
    else
      @current_pos = s0
      s0 = :failed
    end
  else
    @current_pos = s0
    s0 = :failed
  end
  s0
end
parse_te() click to toggle source

te : [0-9]+

# File lib/jkf/parser/kif.rb, line 271
def parse_te
  match_digits!
end
parse_time() click to toggle source

time : “(” “ ”* ms “ ”* “/” “ ”* (hms | ms) “ ”* “)”

# File lib/jkf/parser/kif.rb, line 366
def parse_time
  s0 = @current_pos
  if match_str("(") != :failed
    match_spaces
    s3 = parse_ms
    if s3 != :failed
      match_spaces
      if match_str("/") != :failed
        match_spaces
        s5 = parse_hms
        s5 = parse_ms(with_hour: true) if s5 == :failed
        if s5 != :failed
          match_spaces
          if match_str(")") != :failed
            @reported_pos = s0
            s0 = { "now" => s3, "total" => s5 }
          else
            @current_pos = s0
            s0 = :failed
          end
        else
          @current_pos = s0
          s0 = :failed
        end
      else
        @current_pos = s0
        s0 = :failed
      end
    else
      @current_pos = s0
      s0 = :failed
    end
  else
    @current_pos = s0
    s0 = :failed
  end
  s0
end
parse_turn() click to toggle source

turn : [先後上下]

# File lib/jkf/parser/kif.rb, line 131
def parse_turn
  match_regexp(/^[先後上下]/)
end
reverse_color(moves) click to toggle source

exchange sente gote

# File lib/jkf/parser/kif.rb, line 628
def reverse_color(moves)
  moves.each do |move|
    if move["move"] && move["move"]["color"]
      move["move"]["color"] = (move["move"]["color"] + 1) % 2
    end
    move["forks"].each { |_fork| reverse_color(_fork) } if move["forks"]
  end
end
special2csa(str) click to toggle source

special string to csa

# File lib/jkf/parser/kif.rb, line 593
def special2csa(str)
  {
    "中断" => "CHUDAN",
    "投了" => "TORYO",
    "持将棋" => "JISHOGI",
    "千日手" => "SENNICHITE",
    "詰み" => "TSUMI",
    "不詰" => "FUZUMI",
    "切れ負け" => "TIME_UP",
    "反則勝ち" => "ILLEGAL_ACTION", # 直前の手が反則(先頭に+か-で反則した側の情報を含める必要が有る)
    "反則負け" => "ILLEGAL_MOVE" # ここで手番側が反則,反則の内容はコメントで表現
  }[str] || (raise ParseError)
end
teban2color(teban) click to toggle source

teban to color

# File lib/jkf/parser/kif.rb, line 608
def teban2color(teban)
  teban = teban.to_i unless teban.is_a? Fixnum
  (teban + 1) % 2
end
transform_move(line, c) click to toggle source

transform move to jkf

# File lib/jkf/parser/kif.rb, line 567
def transform_move(line, c)
  ret = {}
  ret["comments"] = c if !c.empty?
  if line["move"].is_a? Hash
    ret["move"] = line["move"]
  else
    ret["special"] = special2csa(line["move"])
  end
  ret["time"] = line["time"] if line["time"]
  ret
end
transform_root(headers, ini, headers2, moves, forks) click to toggle source

transfrom to jkf

# File lib/jkf/parser/kif.rb, line 548
def transform_root(headers, ini, headers2, moves, forks)
  ret = { "header" => {}, "moves" => moves }
  headers.compact.each { |h| ret["header"][h["k"]] = h["v"] }
  headers2.compact.each { |h| ret["header"][h["k"]] = h["v"] }
  if ini
    ret["initial"] = ini
  elsif ret["header"]["手合割"]
    preset = preset2str(ret["header"]["手合割"])
    ret["initial"] = { "preset" => preset } if preset && preset != "OTHER"
  end
  transform_root_header_data(ret) if ret["initial"] && ret["initial"]["data"]
  transform_root_forks(forks, moves)
  if ret["initial"] && ret["initial"]["data"] && ret["initial"]["data"]["color"] == 1
    reverse_color(ret["moves"])
  end
  ret
end
transform_teban_fugou_from(teban, fugou, from) click to toggle source

transform teban-fugou-from to jkf

# File lib/jkf/parser/kif.rb, line 580
def transform_teban_fugou_from(teban, fugou, from)
  ret = { "color" => teban2color(teban.join), "piece" => fugou["piece"] }
  if fugou["to"]
    ret["to"] = fugou["to"]
  else
    ret["same"] = true
  end
  ret["promote"] = true if fugou["promote"]
  ret["from"] = from if from
  ret
end