stockfish 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e5fbcce6e53ddc0054fa5a20f9957ef7e188c16a
4
+ data.tar.gz: 32299448619d85bfe4da70f202a67d146a815d4f
5
+ SHA512:
6
+ metadata.gz: 298dd6eb8771f2dc7dfd776389369e83ee14f724f826423dd77061ebfb9b9ac0daf49803189a1b0e16c766a068aa3591754b499a054dae108fe9290b7f458463
7
+ data.tar.gz: 8de4387d5b82eb9f7a7d75eae6f1dc57585f8a2437482e55139238bc46ab129545f933a772aea9a9c043de4281d7c58027f4addc6686eb7a6d1a20b60dde8b1b
@@ -0,0 +1,3 @@
1
+ *.gem
2
+ .ruby-version
3
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,51 @@
1
+ # Ruby Stockfish
2
+
3
+ A ruby client for the [Stockfish](https://stockfishchess.org/) chess engine
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ $ gem install stockfish
9
+ ```
10
+
11
+ Or add it to your application's Gemfile and install via bundler
12
+
13
+ ```
14
+ gem 'stockfish'
15
+ ```
16
+
17
+ ## Analyzing positions
18
+
19
+ Load a position in [FEN](https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation) notation that you want to analyze
20
+
21
+ ```ruby
22
+ fen = "3qr3/1b1rb2Q/p2pk1p1/1p1np3/4P3/P2BB3/1PP3PP/4R2K w - - 2 24"
23
+ ```
24
+
25
+ Set the search depth (in number of half-moves) you want to use
26
+
27
+ ```ruby
28
+ Stockfish.analyze fen, { :depth => 12 }
29
+ ```
30
+
31
+ And request multiple variations if you'd like
32
+
33
+ ```ruby
34
+ Stockfish.analyze fen, { :depth => 6, :multipv => 3 }
35
+ ```
36
+
37
+ ## Requirements
38
+
39
+ Stockfish 6+ must be installed and available in your $PATH
40
+
41
+ ```bash
42
+ $ which stockfish
43
+ ```
44
+
45
+ If Stockfish is not in your $PATH, you can pass the path to the Stockfish binary directly
46
+
47
+ ```ruby
48
+ engine = Stockfish::Engine.new("/usr/local/bin/stockfish")
49
+ engine.multipv(3)
50
+ engine.analyze fen, { :depth => 6 }
51
+ ```
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift "./lib"
4
+
5
+ require 'pry'
6
+ require 'stockfish'
7
+
8
+
9
+ engine = Stockfish::Engine.new
10
+
11
+ # puts engine.analyze "rqb2rk1/1p3p2/p1nb1n1p/2pp4/2P4Q/N2P1N2/PP2BPPP/R4RK1 w - - 1 15", { :nodes => 100000 }
12
+ # puts engine.analyze "2r2rk1/p2q1pbp/4b1p1/1p1p4/3P4/1Q2B1P1/PP3PBP/2RR2K1 w - b6 1 17", { :movetime => 2000 }
13
+ # puts engine.analyze "r3k2r/1bqp1pp1/pp1bp3/8/1PP1PP2/3QB1P1/P2N4/1R3RK1 b kq b3 1 18", { :depth => 10 }
14
+
15
+ # analysis_output = open("test/fixtures/analysis_outputs/multipv_3.txt").read
16
+ # parser = Stockfish::AnalysisParser.new(analysis_output)
17
+
18
+ binding.pry
@@ -0,0 +1,14 @@
1
+ require "stockfish/engine"
2
+ require "stockfish/analysis_parser"
3
+
4
+
5
+ module Stockfish
6
+
7
+ def self.analyze(fen, options = {})
8
+ multipv = options.delete(:multipv)
9
+ engine = Engine.new
10
+ engine.multipv(multipv) if multipv
11
+ AnalysisParser.new(engine.analyze(fen, options)).parse
12
+ end
13
+
14
+ end
@@ -0,0 +1,108 @@
1
+ module Stockfish
2
+
3
+ # Converts raw analysis output into a hash
4
+ #
5
+ class AnalysisParser
6
+
7
+ ROW_SCANNER = %r{
8
+ \Ainfo\s
9
+ depth\s
10
+ (?<depth>\d+)\s
11
+ seldepth\s
12
+ (?<seldepth>\d+)\s
13
+ (multipv\s(?<multipv>\d+)\s)?
14
+ score\s
15
+ (?<score_type>\w+)?\s
16
+ (?<score>[-\d]+)\s
17
+ (lowerbound\s|upperbound\s)?
18
+ nodes
19
+ }x
20
+
21
+
22
+ attr_accessor :raw_analysis, :analysis
23
+
24
+ def initialize(raw_analysis = nil)
25
+ @raw_analysis = raw_analysis
26
+ @analysis = {}
27
+ end
28
+
29
+ def parse
30
+ return handle_game_over if game_over?
31
+ if @raw_analysis.include?("multipv")
32
+ handle_multipv
33
+ else
34
+ handle_singlepv
35
+ end
36
+ end
37
+
38
+ def game_over?
39
+ !!@raw_analysis[/^bestmove \(none\)$/]
40
+ end
41
+
42
+ def handle_game_over
43
+ game_over = @raw_analysis.match(/^info depth 0 score (?<outcome>[a-z]+) 0$/)
44
+ score = case game_over[:outcome]
45
+ when "mate" then "mate 0"
46
+ when "cp" then 0
47
+ end
48
+ @analysis = {
49
+ :bestmove => nil,
50
+ :variations => [{ :score => score, :sequence => [], :depth => 0 }]
51
+ }
52
+ end
53
+
54
+ def best_move_uci
55
+ @raw_analysis[/^bestmove (\w+)/, 1]
56
+ end
57
+
58
+ def parse_variation_row(row)
59
+ sequence = row.match(/ pv (?<moves>.*)/)
60
+ return if sequence.nil?
61
+ analysis = row.match(ROW_SCANNER)
62
+ score = case analysis[:score_type]
63
+ when "cp" then analysis[:score].to_f/100
64
+ when "mate" then "mate #{analysis[:score]}"
65
+ end
66
+ variation = {
67
+ :score => score,
68
+ :sequence => sequence[:moves].split(/\s+/),
69
+ :depth => analysis[:depth].to_i,
70
+ }
71
+ variation[:multipv] = analysis[:multipv].to_i if analysis[:multipv]
72
+ variation
73
+ end
74
+
75
+ def handle_singlepv
76
+ @raw_analysis.strip.split("\n").reverse.each do |row|
77
+ variation = parse_variation_row(row)
78
+ next if variation.nil? || variation[:sequence].split(" ")[0] != best_move_uci
79
+ @analysis = {
80
+ :bestmove => best_move_uci,
81
+ :variations => [variation]
82
+ }
83
+ return @analysis
84
+ end
85
+ @analysis || {}
86
+ end
87
+
88
+ def handle_multipv
89
+ multipv = nil
90
+ count = 0
91
+ @analysis = {
92
+ :bestmove => best_move_uci,
93
+ :variations => []
94
+ }
95
+ @raw_analysis.strip.split("\n").reverse.each do |row|
96
+ variation = parse_variation_row(row)
97
+ next if variation.nil?
98
+ multipv = variation[:multipv] if multipv.nil?
99
+ @analysis[:variations].push variation
100
+ count += 1
101
+ break if count >= multipv
102
+ end
103
+ @analysis || {}
104
+ end
105
+
106
+ end
107
+
108
+ end
@@ -0,0 +1,70 @@
1
+ require 'open3'
2
+ require 'io/wait'
3
+
4
+
5
+ module Stockfish
6
+
7
+ class InvalidBinary < StandardError; end
8
+ class InvalidCommand < StandardError; end
9
+ class InvalidOption < StandardError; end
10
+
11
+ class Engine
12
+ attr_reader :stdin, :stdout, :stderr, :wait_threads, :version, :pid
13
+
14
+ COMMANDS = %w( uci isready setoption ucinewgame position go stop ponderhit quit )
15
+
16
+ def initialize(bin_path = `which stockfish`)
17
+ @stdin, @stdout, @stderr, @wait_threads = Open3.popen3(bin_path)
18
+ @pid = @wait_threads[:pid]
19
+ @version = @stdout.readline.strip
20
+ raise InvalidBinary.new("Not a valid Stockfish binary!") unless @version =~ /^Stockfish/
21
+ end
22
+
23
+ def execute(str)
24
+ command = str.split(" ")[0]
25
+ @stdin.puts str
26
+ raise InvalidCommand.new(@stdout.readline.strip) unless COMMANDS.include?(command)
27
+ output = ""
28
+ case command
29
+ when "uci"
30
+ loop do
31
+ output << (line = @stdout.readline)
32
+ break if line =~ /^uciok/
33
+ end
34
+ when "go"
35
+ loop do
36
+ output << (line = @stdout.readline)
37
+ break if line =~ /^bestmove/
38
+ end
39
+ when "setoption"
40
+ sleep 0.1
41
+ raise InvalidOption.new(@stdout.readline.strip) if @stdout.ready?
42
+ when "isready"
43
+ output << @stdout.readline
44
+ end
45
+ output
46
+ end
47
+
48
+ def multipv(n)
49
+ execute "setoption name MultiPV value #{n}"
50
+ end
51
+
52
+ def ready?
53
+ execute("isready").strip == "readyok"
54
+ end
55
+
56
+ def running?
57
+ @wait_threads.alive?
58
+ end
59
+
60
+ def analyze(fen, options)
61
+ execute "position fen #{fen}"
62
+ %w( depth movetime nodes ).each do |command|
63
+ if (x = options[command.to_sym])
64
+ return execute "go #{command} #{x}"
65
+ end
66
+ end
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,3 @@
1
+ module Stockfish
2
+ VERSION = "0.3.0"
3
+ end
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $:.unshift(lib) unless $:.include?(lib)
5
+
6
+ require 'stockfish/version'
7
+
8
+
9
+ Gem::Specification.new do |s|
10
+ s.name = "stockfish"
11
+ s.version = Stockfish::VERSION
12
+ s.authors = ["Linmiao Xu"]
13
+ s.email = ["linmiao.xu@gmail.com"]
14
+
15
+ s.summary = "Ruby client for the Stockfish chess engine"
16
+ s.description = "Ruby client for the Stockfish chess engine"
17
+ s.license = "MIT"
18
+
19
+ s.files = `git ls-files -z`.split("\0")
20
+
21
+ s.add_development_dependency "rake", "~> 10.0"
22
+ s.add_development_dependency "minitest", "~> 5.0"
23
+ s.add_development_dependency "pry", "~> 0.10"
24
+ end
@@ -0,0 +1,63 @@
1
+ require 'test_helper'
2
+
3
+
4
+ class AnalysisParserTest < Minitest::Test
5
+
6
+ def setup
7
+ @klass = Stockfish::AnalysisParser
8
+ end
9
+
10
+ def parsed_fixture(fixture_path)
11
+ analysis_output = read_fixture(fixture_path)
12
+ @klass.new(analysis_output).parse
13
+ end
14
+
15
+ def test_parser_suggests_a_move_for_a_normal_position
16
+ output = parsed_fixture("analysis_outputs/tough_midgame.txt")
17
+ assert output[:variations].length == 1
18
+ assert output[:variations][0][:score] == -12.51
19
+ end
20
+
21
+ def test_parser_suggests_three_variations_for_multipv_3
22
+ output = parsed_fixture("analysis_outputs/multipv_3.txt")
23
+ assert output[:variations].length == 3
24
+ end
25
+
26
+ def test_parser_detects_stalemate
27
+ output = parsed_fixture("analysis_outputs/stalemate.txt")
28
+ assert output[:bestmove] == nil
29
+ assert output[:variations].length == 1
30
+ move = output[:variations][0]
31
+ assert move[:score] == 0
32
+ end
33
+
34
+ def test_parser_detects_checkmate
35
+ output = parsed_fixture("analysis_outputs/checkmate.txt")
36
+ assert output[:bestmove] == nil
37
+ assert output[:variations].length == 1
38
+ move = output[:variations][0]
39
+ assert move[:score] == "mate 0"
40
+ end
41
+
42
+ def test_parser_detects_imminent_win_by_checkmate
43
+ output = parsed_fixture("analysis_outputs/mate_in_1.txt")
44
+ assert output[:variations].length == 1
45
+ move = output[:variations][0]
46
+ assert move[:score] == "mate 1"
47
+ end
48
+
49
+ def test_parser_detects_win_by_checkmate
50
+ output = parsed_fixture("analysis_outputs/white_wins_in_4.txt")
51
+ assert output[:variations].length == 1
52
+ move = output[:variations][0]
53
+ assert move[:score] == "mate 4"
54
+ end
55
+
56
+ def test_parser_detects_loss_by_checkmate
57
+ output = parsed_fixture("analysis_outputs/black_loses_in_3.txt")
58
+ assert output[:variations].length == 1
59
+ move = output[:variations][0]
60
+ assert move[:score] == "mate -3"
61
+ end
62
+
63
+ end
@@ -0,0 +1,38 @@
1
+ require 'test_helper'
2
+
3
+
4
+ class EngineTest < Minitest::Test
5
+
6
+ def setup
7
+ @klass = Stockfish::Engine
8
+ end
9
+
10
+ def test_engine_version_is_valid
11
+ assert @klass.new.version[/^Stockfish \d+/]
12
+ end
13
+
14
+ def test_engine_is_ready?
15
+ assert @klass.new.ready?
16
+ end
17
+
18
+ def test_engine_returns_position_analysis
19
+ fen = read_fixture("positions/stalemate.txt")
20
+ analysis_output = @klass.new.analyze(fen, { :depth => 6 })
21
+ assert analysis_output[/^info/]
22
+ assert analysis_output[/^bestmove/]
23
+ fen = read_fixture("positions/start.txt")
24
+ analysis_output = @klass.new.analyze(fen, { :depth => 6 })
25
+ assert analysis_output[/^info/]
26
+ assert analysis_output[/^bestmove/]
27
+ end
28
+
29
+ def test_multipv_mode_returns_multipv_output
30
+ engine = @klass.new
31
+ engine.multipv(3)
32
+ fen = read_fixture("positions/white_wins_in_4.txt")
33
+ analysis_output = engine.analyze(fen, { :depth => 6 })
34
+ assert analysis_output[/multipv 3/]
35
+ assert analysis_output[/^bestmove/]
36
+ end
37
+
38
+ end
@@ -0,0 +1,13 @@
1
+ info depth 1 seldepth 1 multipv 1 score mate -3 nodes 10 nps 5000 tbhits 0 time 2 pv g7f6
2
+ info depth 2 seldepth 3 multipv 1 score mate -3 nodes 35 nps 17500 tbhits 0 time 2 pv g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
3
+ info depth 3 seldepth 5 multipv 1 score mate -3 nodes 76 nps 38000 tbhits 0 time 2 pv g7f6 c3d5 f6g5 f2f4 g5g4
4
+ info depth 4 seldepth 7 multipv 1 score mate -3 nodes 112 nps 56000 tbhits 0 time 2 pv g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
5
+ info depth 5 seldepth 7 multipv 1 score mate -3 nodes 144 nps 72000 tbhits 0 time 2 pv g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
6
+ info depth 6 seldepth 7 multipv 1 score mate -3 nodes 174 nps 87000 tbhits 0 time 2 pv g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
7
+ info depth 7 seldepth 7 multipv 1 score mate -3 nodes 219 nps 109500 tbhits 0 time 2 pv g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
8
+ info depth 8 seldepth 7 multipv 1 score mate -3 nodes 263 nps 131500 tbhits 0 time 2 pv g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
9
+ info depth 9 seldepth 7 multipv 1 score mate -3 nodes 309 nps 154500 tbhits 0 time 2 pv g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
10
+ info depth 10 seldepth 7 multipv 1 score mate -3 nodes 352 nps 176000 tbhits 0 time 2 pv g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
11
+ info depth 11 seldepth 7 multipv 1 score mate -3 nodes 430 nps 215000 tbhits 0 time 2 pv g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
12
+ info depth 12 seldepth 7 multipv 1 score mate -3 nodes 575 nps 287500 tbhits 0 time 2 pv g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
13
+ bestmove g7f6 ponder c3d5
@@ -0,0 +1,2 @@
1
+ info depth 0 score mate 0
2
+ bestmove (none)
@@ -0,0 +1,11 @@
1
+ info depth 1 seldepth 1 multipv 1 score cp -6 nodes 9 nps 9000 tbhits 0 time 1 pv d3c2
2
+ info depth 2 seldepth 2 multipv 1 score cp 6 nodes 30 nps 30000 tbhits 0 time 1 pv d3c2 e6d5
3
+ info depth 3 seldepth 3 multipv 1 score cp -6 nodes 93 nps 93000 tbhits 0 time 1 pv d3c2 e6d5 c2b1
4
+ info depth 4 seldepth 4 multipv 1 score cp 6 nodes 245 nps 245000 tbhits 0 time 1 pv d3c2 e6d5 c2b1 d5d6
5
+ info depth 5 seldepth 5 multipv 1 score cp -6 nodes 764 nps 382000 tbhits 0 time 2 pv d3c2 e6d5 c2b1 d5d6 b1a1
6
+ info depth 6 seldepth 6 multipv 1 score cp 6 nodes 1316 nps 658000 tbhits 0 time 2 pv d3c2 e6d5 c2b1 d5d6 b1a1 d6d5
7
+ info depth 7 seldepth 7 multipv 1 score cp -6 nodes 2876 nps 719000 tbhits 0 time 4 pv d3c2 e6d5 c2b1 d5d6 b1a1 d6c6 a1b1
8
+ info depth 8 seldepth 8 multipv 1 score cp 6 nodes 5134 nps 855666 tbhits 0 time 6 pv d3e4 e6d6 e4f3 d6d5 f3g2 d5c6 g2g1 c6d5
9
+ info depth 9 seldepth 10 multipv 1 score cp 0 nodes 8781 nps 1097625 tbhits 0 time 8 pv d3e4 e6d6 e4f3 d6d5 f3g2 d5c6 g2g1 c6c7 g1g2
10
+ info depth 10 seldepth 10 multipv 1 score cp 0 nodes 10472 nps 1163555 tbhits 0 time 9 pv d3e4 e6d6 e4f3 d6d5 f3g2 d5e5 g2g1 e5d5 g1g2
11
+ bestmove d3e4 ponder e6d6
@@ -0,0 +1,11 @@
1
+ info depth 1 seldepth 2 multipv 1 score mate 1 nodes 47 nps 23500 tbhits 0 time 2 pv f3f7
2
+ info depth 2 seldepth 2 multipv 1 score mate 1 nodes 90 nps 45000 tbhits 0 time 2 pv f3f7
3
+ info depth 3 seldepth 2 multipv 1 score mate 1 nodes 133 nps 66500 tbhits 0 time 2 pv f3f7
4
+ info depth 4 seldepth 2 multipv 1 score mate 1 nodes 176 nps 88000 tbhits 0 time 2 pv f3f7
5
+ info depth 5 seldepth 2 multipv 1 score mate 1 nodes 219 nps 109500 tbhits 0 time 2 pv f3f7
6
+ info depth 6 seldepth 2 multipv 1 score mate 1 nodes 262 nps 131000 tbhits 0 time 2 pv f3f7
7
+ info depth 7 seldepth 2 multipv 1 score mate 1 nodes 305 nps 152500 tbhits 0 time 2 pv f3f7
8
+ info depth 8 seldepth 2 multipv 1 score mate 1 nodes 348 nps 174000 tbhits 0 time 2 pv f3f7
9
+ info depth 9 seldepth 2 multipv 1 score mate 1 nodes 391 nps 195500 tbhits 0 time 2 pv f3f7
10
+ info depth 10 seldepth 2 multipv 1 score mate 1 nodes 434 nps 217000 tbhits 0 time 2 pv f3f7
11
+ bestmove f3f7
@@ -0,0 +1,31 @@
1
+ info depth 1 seldepth 1 multipv 1 score cp -72 nodes 102 nps 51000 tbhits 0 time 2 pv c8f5
2
+ info depth 1 seldepth 1 multipv 2 score cp -114 nodes 102 nps 51000 tbhits 0 time 2 pv c8d7
3
+ info depth 1 seldepth 1 multipv 3 score cp -118 nodes 102 nps 51000 tbhits 0 time 2 pv f7f5
4
+ info depth 2 seldepth 2 multipv 1 score cp 374 nodes 303 nps 101000 tbhits 0 time 3 pv f7f5 e4e8 d8e8
5
+ info depth 2 seldepth 2 multipv 2 score cp 307 nodes 303 nps 101000 tbhits 0 time 3 pv c8f5 c4a6 f5e4 a6b7
6
+ info depth 2 seldepth 2 multipv 3 score cp 86 nodes 303 nps 101000 tbhits 0 time 3 pv b7b5 b2b3 b5c4
7
+ info depth 3 seldepth 3 multipv 1 score cp 374 nodes 477 nps 159000 tbhits 0 time 3 pv f7f5 e4e8 d8e8
8
+ info depth 3 seldepth 3 multipv 2 score cp 307 nodes 477 nps 159000 tbhits 0 time 3 pv c8f5 c4a6 f5e4
9
+ info depth 3 seldepth 3 multipv 3 score cp 86 nodes 477 nps 159000 tbhits 0 time 3 pv b7b5 b2b3 b5c4
10
+ info depth 4 seldepth 4 multipv 1 score cp 358 nodes 757 nps 252333 tbhits 0 time 3 pv f7f5 e4e8 d8e8 a2a3
11
+ info depth 4 seldepth 4 multipv 2 score cp 307 nodes 757 nps 252333 tbhits 0 time 3 pv c8f5 c4a6 f5e4 a6b7
12
+ info depth 4 seldepth 4 multipv 3 score cp 72 nodes 757 nps 252333 tbhits 0 time 3 pv b7b5 f3d2 b5c4 d2c4
13
+ info depth 5 seldepth 7 multipv 1 score cp 239 nodes 2060 nps 343333 tbhits 0 time 6 pv f7f5 f3d2 f5e4 d2e4 a6a5
14
+ info depth 5 seldepth 7 multipv 2 score cp 237 nodes 2060 nps 343333 tbhits 0 time 6 pv c8f5 f3d2 b7b5 f2f3 f5e4
15
+ info depth 5 seldepth 7 multipv 3 score cp 16 nodes 2060 nps 343333 tbhits 0 time 6 pv b7b5 a1e1 b5c4 e4e8 d8e8 e1e8 d6f8
16
+ info depth 6 seldepth 7 multipv 1 score cp -97 nodes 6166 nps 474307 tbhits 0 time 13 pv c8f5 e4e2 d6f4 a1e1 b7b5 g2g3 b5c4
17
+ info depth 6 seldepth 7 multipv 2 score cp -124 nodes 6166 nps 474307 tbhits 0 time 13 pv c8d7 c4d3 d7f5 e4e3 f5d3 e3d3
18
+ info depth 6 seldepth 7 multipv 3 score cp -131 nodes 6166 nps 474307 tbhits 0 time 13 pv h7h5 e4e2 c8f5 a1e1 f7f6 c4d3 f5d3
19
+ info depth 7 seldepth 7 multipv 1 score cp -63 nodes 9227 nps 542764 tbhits 0 time 17 pv b7b5 c4d3 c8b7 e4e1 b7d5 c2c3 f7f6
20
+ info depth 7 seldepth 7 multipv 2 score cp -97 nodes 9227 nps 542764 tbhits 0 time 17 pv c8f5 e4e2 d6f4 a1e1 b7b5 g2g3 b5c4
21
+ info depth 7 seldepth 7 multipv 3 score cp -128 nodes 9227 nps 542764 tbhits 0 time 17 pv g7g5 c4d3 g5g4 f3d2 c8f5 e4e3 f5d3
22
+ info depth 8 seldepth 10 multipv 1 score cp -97 nodes 15550 nps 706818 tbhits 0 time 22 pv c8f5 e4e2 d6f4 a1e1 b7b5 g2g3 b5c4 g3f4
23
+ info depth 8 seldepth 10 multipv 2 score cp -124 nodes 15550 nps 706818 tbhits 0 time 22 pv c8d7 c4d3 c7c6 d5c6 d7c6 e4e1 b7b5 c2c4
24
+ info depth 8 seldepth 10 multipv 3 score cp -130 nodes 15550 nps 706818 tbhits 0 time 22 pv b7b5 c4d3 c8b7 c2c4 b5c4 d3c4 f7f5 e4e3
25
+ info depth 9 seldepth 13 multipv 1 score cp -109 nodes 33905 nps 997205 tbhits 0 time 34 pv c8f5 e4e2 f5g4 a1e1 g4f3 g2f3 d6f4 e2e7 b7b5 c4d3
26
+ info depth 9 seldepth 13 multipv 2 score cp -124 nodes 33905 nps 997205 tbhits 0 time 34 pv f7f6 c4d3 c8f5 e4e3 f5d3 e3d3 g8f7 c2c4 c7c6 d5c6
27
+ info depth 9 seldepth 13 multipv 3 score cp -132 nodes 33905 nps 997205 tbhits 0 time 34 pv b7b5 c4d3 c8b7 c2c4 f7f5 e4e1 b5c4 d3c4 d6f4
28
+ info depth 10 seldepth 15 multipv 1 score cp -108 nodes 79802 nps 1308229 tbhits 0 time 61 pv c8f5 e4e2 f5g4 a1e1 g4f3 g2f3 b7b5 c4d3 g7g6 c2c3 g8g7 g1g2 f7f5 e2e3
29
+ info depth 10 seldepth 15 multipv 2 score cp -108 nodes 79802 nps 1308229 tbhits 0 time 61 pv g7g6 a1e1 c8f5 e4e2 f5g4 c4d3 g4f3 g2f3 b7b5 c2c3
30
+ info depth 10 seldepth 15 multipv 3 score cp -114 nodes 79802 nps 1308229 tbhits 0 time 61 pv b7b5 c4b3 c8f5 e4e1 f7f6 c2c3 f5g4 a2a3 g4f3 g2f3
31
+ bestmove c8f5 ponder e4e2
@@ -0,0 +1,2 @@
1
+ info depth 0 score cp 0
2
+ bestmove (none)
@@ -0,0 +1,26 @@
1
+ info depth 1 seldepth 1 multipv 1 score cp 0 nodes 31 nps 31000 tbhits 0 time 1 pv d5e4
2
+ info depth 2 seldepth 2 multipv 1 score cp 0 nodes 75 nps 75000 tbhits 0 time 1 pv d5e4 h7f7
3
+ info depth 3 seldepth 3 multipv 1 score cp 0 nodes 131 nps 131000 tbhits 0 time 1 pv d5e4 h7f7 e7f6
4
+ info depth 4 seldepth 5 multipv 1 score cp 0 nodes 232 nps 116000 tbhits 0 time 2 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
5
+ info depth 5 seldepth 7 multipv 1 score cp 0 nodes 346 nps 173000 tbhits 0 time 2 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
6
+ info depth 6 seldepth 8 multipv 1 score cp 0 nodes 478 nps 239000 tbhits 0 time 2 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
7
+ info depth 7 seldepth 8 multipv 1 score cp 0 nodes 636 nps 318000 tbhits 0 time 2 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
8
+ info depth 8 seldepth 8 multipv 1 score cp 0 nodes 836 nps 418000 tbhits 0 time 2 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
9
+ info depth 9 seldepth 8 multipv 1 score cp 0 nodes 1186 nps 593000 tbhits 0 time 2 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
10
+ info depth 10 seldepth 8 multipv 1 score cp 0 nodes 1584 nps 792000 tbhits 0 time 2 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
11
+ info depth 11 seldepth 8 multipv 1 score cp 0 nodes 2168 nps 1084000 tbhits 0 time 2 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
12
+ info depth 12 seldepth 8 multipv 1 score cp 0 nodes 2744 nps 914666 tbhits 0 time 3 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
13
+ info depth 13 seldepth 8 multipv 1 score cp 0 nodes 3486 nps 1162000 tbhits 0 time 3 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
14
+ info depth 14 seldepth 8 multipv 1 score cp 0 nodes 4444 nps 1481333 tbhits 0 time 3 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
15
+ info depth 15 seldepth 8 multipv 1 score cp 0 nodes 5649 nps 1412250 tbhits 0 time 4 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
16
+ info depth 16 seldepth 8 multipv 1 score cp 0 nodes 6979 nps 1744750 tbhits 0 time 4 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
17
+ info depth 17 seldepth 8 multipv 1 score cp 0 nodes 8532 nps 1706400 tbhits 0 time 5 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
18
+ info depth 18 seldepth 8 multipv 1 score cp 0 nodes 10474 nps 1745666 tbhits 0 time 6 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
19
+ info depth 19 seldepth 8 multipv 1 score cp 0 nodes 12770 nps 2128333 tbhits 0 time 6 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
20
+ info depth 20 seldepth 8 multipv 1 score cp 0 nodes 15352 nps 2193142 tbhits 0 time 7 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
21
+ info depth 21 seldepth 8 multipv 1 score cp 0 nodes 18208 nps 2276000 tbhits 0 time 8 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
22
+ info depth 22 seldepth 8 multipv 1 score cp 0 nodes 21852 nps 2185200 tbhits 0 time 10 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
23
+ info depth 23 seldepth 8 multipv 1 score cp 0 nodes 60706 nps 1839575 tbhits 0 time 33 pv d5e4 h7f7 e7f6 e3d2 e4d4 d2e3 d4e4
24
+ info depth 24 currmove d5c4 currmovenumber 3
25
+ info depth 24 seldepth 57 multipv 1 score cp -1251 nodes 7541511 nps 2078123 tbhits 0 time 3629 pv d5e6 h7g6 e7f6 g6f5 e6f7 f5h7 f7f8 e3h6 d7g7 e1f1 f8e7 h6g7 b7e4 g7f6 e7e6 h7h3 e6d5 f6d8 e8d8 h3e3 e4g6 e3f3 g6e4 f1d1 d5c6 f3e4 c6c7 d1f1 d8d7 f1f6 d7d8 f6f7 d8d7 f7d7 c7d7 e4b7 d7e6 b2b4 e6f6 b7a6 f6e6
26
+ bestmove d5e6 ponder h7g6
@@ -0,0 +1,13 @@
1
+ info depth 1 seldepth 1 multipv 1 score cp 846 nodes 79 nps 39500 tbhits 0 time 2 pv c3d5 c6d4
2
+ info depth 2 seldepth 3 multipv 1 score cp 878 nodes 244 nps 122000 tbhits 0 time 2 pv h3h7 g7f6 g5f7
3
+ info depth 3 seldepth 4 multipv 1 score cp 887 nodes 434 nps 144666 tbhits 0 time 3 pv h3h7 g7f6 g5f7 f8f7 c3d5 f6e6 h7g6 f7f6
4
+ info depth 4 seldepth 8 multipv 1 score mate 4 nodes 616 nps 205333 tbhits 0 time 3 pv h3h7 g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
5
+ info depth 5 seldepth 8 multipv 1 score mate 4 nodes 700 nps 233333 tbhits 0 time 3 pv h3h7 g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
6
+ info depth 6 seldepth 8 multipv 1 score mate 4 nodes 786 nps 262000 tbhits 0 time 3 pv h3h7 g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
7
+ info depth 7 seldepth 8 multipv 1 score mate 4 nodes 942 nps 314000 tbhits 0 time 3 pv h3h7 g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
8
+ info depth 8 seldepth 8 multipv 1 score mate 4 nodes 1104 nps 276000 tbhits 0 time 4 pv h3h7 g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
9
+ info depth 9 seldepth 8 multipv 1 score mate 4 nodes 1445 nps 361250 tbhits 0 time 4 pv h3h7 g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
10
+ info depth 10 seldepth 8 multipv 1 score mate 4 nodes 1862 nps 372400 tbhits 0 time 5 pv h3h7 g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
11
+ info depth 11 seldepth 8 multipv 1 score mate 4 nodes 2430 nps 405000 tbhits 0 time 6 pv h3h7 g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
12
+ info depth 12 seldepth 8 multipv 1 score mate 4 nodes 3489 nps 436125 tbhits 0 time 8 pv h3h7 g7f6 c3d5 f6g5 f2f4 g5g4 f1e2
13
+ bestmove h3h7 ponder g7f6
@@ -0,0 +1 @@
1
+ 8/8/8/8/8/1k6/p7/K7 w - - 0 1
@@ -0,0 +1 @@
1
+ rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
@@ -0,0 +1 @@
1
+ r1bq1r2/p1ppppk1/1pn3p1/3n2N1/3PP3/2N4Q/PPP2PPP/R3KB1R w KQ - 2 10
@@ -0,0 +1,10 @@
1
+ gem 'minitest'
2
+ require 'minitest/autorun'
3
+
4
+ $:.unshift File.expand_path('../../lib', __FILE__)
5
+ require 'stockfish'
6
+
7
+
8
+ def read_fixture(path)
9
+ open("#{File.dirname(__FILE__)}/fixtures/#{path}").read
10
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stockfish
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Linmiao Xu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '10.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '10.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '0.10'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0.10'
55
+ description: Ruby client for the Stockfish chess engine
56
+ email:
57
+ - linmiao.xu@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - README.md
65
+ - Rakefile
66
+ - bin/console
67
+ - lib/stockfish.rb
68
+ - lib/stockfish/analysis_parser.rb
69
+ - lib/stockfish/engine.rb
70
+ - lib/stockfish/version.rb
71
+ - ruby-stockfish.gemspec
72
+ - test/analysis_parser_test.rb
73
+ - test/engine_test.rb
74
+ - test/fixtures/analysis_outputs/black_loses_in_3.txt
75
+ - test/fixtures/analysis_outputs/checkmate.txt
76
+ - test/fixtures/analysis_outputs/kvk_endgame.txt
77
+ - test/fixtures/analysis_outputs/mate_in_1.txt
78
+ - test/fixtures/analysis_outputs/multipv_3.txt
79
+ - test/fixtures/analysis_outputs/stalemate.txt
80
+ - test/fixtures/analysis_outputs/tough_midgame.txt
81
+ - test/fixtures/analysis_outputs/white_wins_in_4.txt
82
+ - test/fixtures/positions/stalemate.txt
83
+ - test/fixtures/positions/start.txt
84
+ - test/fixtures/positions/white_wins_in_4.txt
85
+ - test/test_helper.rb
86
+ homepage:
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.1.11
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: Ruby client for the Stockfish chess engine
110
+ test_files: []