Class: Stockfish::AnalysisParser

Inherits:
Object
  • Object
show all
Defined in:
lib/stockfish/analysis_parser.rb

Overview

Converts raw analysis output into a hash

Constant Summary collapse

ROW_SCANNER =
%r{
  \Ainfo\s
  depth\s
  (?<depth>\d+)\s
  seldepth\s
  (?<seldepth>\d+)\s
  (multipv\s(?<multipv>\d+)\s)?
  score\s
  (?<score_type>\w+)?\s
  (?<score>[-\d]+)\s
  (lowerbound\s|upperbound\s)?
  nodes
}x

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(raw_analysis = nil) ⇒ AnalysisParser

Returns a new instance of AnalysisParser.



24
25
26
27
# File 'lib/stockfish/analysis_parser.rb', line 24

def initialize(raw_analysis = nil)
  @raw_analysis = raw_analysis
  @analysis = {}
end

Instance Attribute Details

#analysisObject

Returns the value of attribute analysis.



22
23
24
# File 'lib/stockfish/analysis_parser.rb', line 22

def analysis
  @analysis
end

#raw_analysisObject

Returns the value of attribute raw_analysis.



22
23
24
# File 'lib/stockfish/analysis_parser.rb', line 22

def raw_analysis
  @raw_analysis
end

Instance Method Details

#best_move_uciObject



54
55
56
# File 'lib/stockfish/analysis_parser.rb', line 54

def best_move_uci
  @raw_analysis[/^bestmove (\w+)/, 1]
end

#game_over?Boolean

Returns:

  • (Boolean)


38
39
40
# File 'lib/stockfish/analysis_parser.rb', line 38

def game_over?
  !!@raw_analysis[/^bestmove \(none\)$/]
end

#handle_game_overObject



42
43
44
45
46
47
48
49
50
51
52
# File 'lib/stockfish/analysis_parser.rb', line 42

def handle_game_over
  game_over = @raw_analysis.match(/^info depth 0 score (?<outcome>[a-z]+) 0$/)
  score = case game_over[:outcome]
          when "mate" then "mate 0"
          when "cp" then 0
          end
  @analysis = {
    :bestmove   => nil,
    :variations => [{ :score => score, :sequence => [], :depth => 0 }]
  }
end

#handle_multipvObject



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/stockfish/analysis_parser.rb', line 88

def handle_multipv
  multipv = nil
  count = 0
  @analysis = {
    :bestmove   => best_move_uci,
    :variations => []
  }
  @raw_analysis.strip.split("\n").reverse.each do |row|
    variation = parse_variation_row(row)
    next if variation.nil?
    multipv = variation[:multipv] if multipv.nil?
    @analysis[:variations].push variation
    count += 1
    break if count >= multipv
  end
  @analysis || {}
end

#handle_singlepvObject



75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/stockfish/analysis_parser.rb', line 75

def handle_singlepv
  @raw_analysis.strip.split("\n").reverse.each do |row|
    variation = parse_variation_row(row)
    next if variation.nil? || variation[:sequence].split(" ")[0] != best_move_uci
    @analysis = {
      :bestmove   => best_move_uci,
      :variations => [variation]
    }
    return @analysis
  end
  @analysis || {}
end

#parseObject



29
30
31
32
33
34
35
36
# File 'lib/stockfish/analysis_parser.rb', line 29

def parse
  return handle_game_over if game_over?
  if @raw_analysis.include?("multipv")
    handle_multipv
  else
    handle_singlepv
  end
end

#parse_variation_row(row) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/stockfish/analysis_parser.rb', line 58

def parse_variation_row(row)
  sequence = row.match(/ pv (?<moves>.*)/)
  return if sequence.nil?
  analysis = row.match(ROW_SCANNER)
  score = case analysis[:score_type]
          when "cp" then analysis[:score].to_f/100
          when "mate" then "mate #{analysis[:score]}"
          end
  variation = {
    :score    => score,
    :sequence => sequence[:moves].split(/\s+/),
    :depth    => analysis[:depth].to_i,
  }
  variation[:multipv] = analysis[:multipv] ? analysis[:multipv].to_i : 1
  variation
end