RubyShogi 0.2 → 0.22
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.
- checksums.yaml +4 -4
- data/lib/ruby_shogi/board.rb +43 -13
- data/lib/ruby_shogi/cmd.rb +61 -23
- data/lib/ruby_shogi/engine.rb +0 -1
- data/lib/ruby_shogi/eval.rb +22 -0
- data/lib/ruby_shogi/mgen.rb +14 -21
- data/lib/ruby_shogi/mgen_black.rb +24 -19
- data/lib/ruby_shogi/mgen_white.rb +24 -16
- data/lib/ruby_shogi/perft.rb +86 -22
- data/lib/ruby_shogi/ruby_shogi.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6701c33167fe944ca928ebd9bcf6ffccda09f294a416f6dafc8730b9f668a879
|
4
|
+
data.tar.gz: b8ea182ba133ac2e99f0da4d0434c7227a6f13abd2331178f179350c6c21e639
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f24bf303d7e6fd9f2dd76559673bbf2eed9dff4dfe6e0a14eb6fd1e4311ea9a929522baf23b538752928047d86f641f4384f5834d14a7949f1f7641dd14169a5
|
7
|
+
data.tar.gz: 4f249d08e78e8adc31476e12bdeafd49a5269739cfea6e9ff785a6ecf46cac9362986bfde156be498478af9b05bb060c88d955e04316baccdbf5be09ec7eb6ad
|
data/lib/ruby_shogi/board.rb
CHANGED
@@ -43,9 +43,8 @@ class Board
|
|
43
43
|
|
44
44
|
attr_accessor :brd, :wking, :bking, :white_pocket, :black_pocket, :variant, :nodetype, :r50, :drop, :hash, :fullmoves, :wtm, :eat, :from, :to, :score, :promo, :index
|
45
45
|
|
46
|
-
def initialize
|
46
|
+
def initialize
|
47
47
|
initme
|
48
|
-
fen(pos)
|
49
48
|
end
|
50
49
|
|
51
50
|
def initme
|
@@ -88,6 +87,11 @@ class Board
|
|
88
87
|
s
|
89
88
|
end
|
90
89
|
|
90
|
+
def mustbeok
|
91
|
+
fail if find_white_king != @wking
|
92
|
+
fail if find_black_king != @bking
|
93
|
+
end
|
94
|
+
|
91
95
|
def wtm2str
|
92
96
|
@wtm ? "w" : "b"
|
93
97
|
end
|
@@ -114,7 +118,6 @@ class Board
|
|
114
118
|
end
|
115
119
|
|
116
120
|
def make_move(me, from, to)
|
117
|
-
#fail unless (good_coord?(from) && good_coord?(to))
|
118
121
|
@eat = @brd[to]
|
119
122
|
@brd[to] = me
|
120
123
|
@brd[from] = 0
|
@@ -184,15 +187,15 @@ class Board
|
|
184
187
|
end
|
185
188
|
|
186
189
|
def empty?(i)
|
187
|
-
@brd[i]
|
190
|
+
@brd[i].zero?
|
188
191
|
end
|
189
192
|
|
190
193
|
def walkable_w?(square)
|
191
|
-
@brd[square]
|
194
|
+
@brd[square] <= 0
|
192
195
|
end
|
193
196
|
|
194
197
|
def walkable_b?(square)
|
195
|
-
@brd[square]
|
198
|
+
@brd[square] >= 0
|
196
199
|
end
|
197
200
|
|
198
201
|
def is_on_board?(x, y)
|
@@ -358,8 +361,15 @@ class Board
|
|
358
361
|
@wtm = s == "w" ? true : false
|
359
362
|
end
|
360
363
|
|
364
|
+
def fen2(s = nil)
|
365
|
+
if s.nil?
|
366
|
+
fen(START_POS)
|
367
|
+
else
|
368
|
+
fen(s)
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
361
372
|
def fen(str)
|
362
|
-
return if str.nil?
|
363
373
|
initme
|
364
374
|
s = str.strip.split(" ")
|
365
375
|
fail if s.length < 3
|
@@ -389,6 +399,10 @@ class Board
|
|
389
399
|
s.strip.length == 0 ? "-" : s
|
390
400
|
end
|
391
401
|
|
402
|
+
def move2str
|
403
|
+
move_str
|
404
|
+
end
|
405
|
+
|
392
406
|
def move_str
|
393
407
|
if @drop != 0
|
394
408
|
s = "#{number2piece(@drop).upcase}@"
|
@@ -411,16 +425,32 @@ class Board
|
|
411
425
|
s
|
412
426
|
end
|
413
427
|
|
414
|
-
def
|
428
|
+
def randpos2
|
415
429
|
copy = RubyShogi::Board.new
|
416
|
-
copy.brd[rand(0..
|
417
|
-
copy.brd[rand(
|
418
|
-
|
419
|
-
3.times { |i| copy.white_pocket.push([1, 3, 5, 7, 9].sample) }
|
420
|
-
3.times { |i| copy.black_pocket.push([-1, -3, -5, -7, -9].sample) }
|
430
|
+
copy.brd[rand(0..9)] = 14
|
431
|
+
copy.brd[rand(71..80)] = -14
|
432
|
+
8.times { |i| copy.brd[32 + i] = rand(-13..13) if rand < 0.3 }
|
433
|
+
3.times { |i| copy.white_pocket.push([1, 3, 5, 7, 9].sample) if rand < 0.3 }
|
434
|
+
3.times { |i| copy.black_pocket.push([-1, -3, -5, -7, -9].sample) if rand < 0.3 }
|
435
|
+
copy.wking = copy.find_white_king
|
436
|
+
copy.bking = copy.find_black_king
|
421
437
|
copy
|
422
438
|
end
|
423
439
|
|
440
|
+
|
441
|
+
def randpos
|
442
|
+
brd = nil
|
443
|
+
loop do
|
444
|
+
brd = randpos2
|
445
|
+
brd2 = brd
|
446
|
+
mgen = brd.mgen_generator
|
447
|
+
next if mgen.checks_b? || mgen.checks_w?
|
448
|
+
break
|
449
|
+
end
|
450
|
+
brd.mustbeok
|
451
|
+
brd
|
452
|
+
end
|
453
|
+
|
424
454
|
def print_board
|
425
455
|
s =""
|
426
456
|
81.times do | i |
|
data/lib/ruby_shogi/cmd.rb
CHANGED
@@ -8,7 +8,7 @@ module RubyShogi
|
|
8
8
|
|
9
9
|
class Cmd
|
10
10
|
attr_accessor :engine, :random_mode
|
11
|
-
|
11
|
+
|
12
12
|
def initialize
|
13
13
|
@random_mode = false
|
14
14
|
@tokens = RubyShogi::Tokens.new(ARGV)
|
@@ -33,26 +33,29 @@ class Cmd
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def mbench
|
36
|
-
|
36
|
+
p = RubyShogi::Perft.new
|
37
|
+
p.suite(peek_argint(4))
|
37
38
|
end
|
38
39
|
|
39
40
|
def perft
|
41
|
+
n = peek_argint(5)
|
42
|
+
puts "~~~ perft( #{n} ) ~~~"
|
40
43
|
p = RubyShogi::Perft.new(@fen)
|
41
|
-
p.perft(
|
44
|
+
p.perft(n)
|
42
45
|
end
|
43
46
|
|
44
47
|
def randperft
|
45
|
-
n = peek_argint(
|
48
|
+
n = peek_argint(10)
|
49
|
+
puts "~~~ randperft( #{n} ) ~~~"
|
46
50
|
n.times do |i|
|
47
51
|
p = RubyShogi::Perft.new
|
48
|
-
|
49
|
-
p.randperft(2)
|
52
|
+
p.randperft(2, i, n)
|
50
53
|
end
|
51
54
|
end
|
52
55
|
|
53
56
|
def suite
|
54
57
|
p = RubyShogi::Perft.new
|
55
|
-
p.suite(peek_argint(
|
58
|
+
p.suite(peek_argint(4))
|
56
59
|
end
|
57
60
|
|
58
61
|
def bench
|
@@ -61,14 +64,9 @@ class Cmd
|
|
61
64
|
end
|
62
65
|
|
63
66
|
def stats
|
64
|
-
|
65
|
-
if
|
66
|
-
|
67
|
-
n = val.to_i
|
68
|
-
end
|
69
|
-
e = RubyShogi::Engine.new("falcon", random_mode: @random_mode)
|
70
|
-
e.board.use_fen(@fen) if @fen != nil
|
71
|
-
e.stats(n)
|
67
|
+
e = RubyShogi::Engine.new(random_mode: @random_mode)
|
68
|
+
e.board.fen(@fen) if @fen != nil
|
69
|
+
e.stats(peek_argint(100))
|
72
70
|
end
|
73
71
|
|
74
72
|
def tactics
|
@@ -82,25 +80,62 @@ class Cmd
|
|
82
80
|
|
83
81
|
def list
|
84
82
|
board = RubyShogi::Board.new
|
85
|
-
board.
|
83
|
+
board.fen2(@fen)
|
86
84
|
mgen = board.mgen_generator
|
87
85
|
moves = mgen.generate_moves
|
88
|
-
|
86
|
+
mgen.print_move_list
|
87
|
+
puts "= #{moves.length} moves"
|
89
88
|
end
|
89
|
+
|
90
|
+
#def list
|
91
|
+
# board = RubyShogi::Board.new
|
92
|
+
# board.fen(@fen)
|
93
|
+
# mgen = board.mgen_generator
|
94
|
+
# moves = mgen.generate_moves
|
95
|
+
# moves.each_with_index { |b, i| puts "> #{i}: #{b.move_str}" }
|
96
|
+
#end
|
90
97
|
|
98
|
+
def perft_by_moves
|
99
|
+
#b = RubyShogi::Board.new
|
100
|
+
#b.startpos
|
101
|
+
#b.fen("lnsgkgsnl/2r4b1/ppppp+Pp1p/7p1/9/9/PPPPP1PPP/1B5R1/LNSGKGSNL[P] w 1 5")
|
102
|
+
#b.fen("9/3k5/7+P1/8P/9/9/6P2/R3K4/1NSG1GSNL[PPPPPPPPPNNBRLLSSGGppppppbl] w 19 100")
|
103
|
+
# +P8/9/8L/L3k3R/1KP6/9/3s5/2S6/1+n1g4+B[PPPPPPPPPNBRLLSGpppppppnnsgg] b
|
104
|
+
# b.fen("5K3/2+P6/6+P2/9/4k4/9/9/9/9[PPPPPPPPPNNBRLLSSGGpppppppnnbrllssgg] w 67 185")
|
105
|
+
#b.fen("8+r/5K3/9/9/9/9/k8/9/9[-] w 24 1")
|
106
|
+
#b.fen("9/+l4k3/+P1+r2L1+l1/+l3+B2S1/1n5rR/5+l+l2/9/9/1K7[LGNpgl] w 0 1")
|
107
|
+
#b.print_board
|
108
|
+
#mgen = b.mgen_generator
|
109
|
+
#mgen.generate_moves
|
110
|
+
|
111
|
+
# 5k3/+n8/1G5R1/2+s+P3b1/n+s2l+B+N2/5s+prp/9/7K1/9 w
|
112
|
+
#p = RubyShogi::Perft.new("5k3/+n8/1G5R1/2+s+P3b1/n+s2l+B+N2/5s+prp/9/7K1/9[SPGnpn] w 0 1")
|
113
|
+
p = RubyShogi::Perft.new("5k3/+n8/1G5R1/2+s+P3b1/n+s2l+B+N2/5s+prp/9/8K/9[PSGpnn] b 0 1")
|
114
|
+
|
115
|
+
p.perft_by_moves(peek_argint(1))
|
116
|
+
end
|
117
|
+
|
91
118
|
def test
|
92
|
-
b = RubyShogi::Board.new
|
119
|
+
#b = RubyShogi::Board.new
|
93
120
|
#b.startpos
|
94
121
|
#b.fen("lnsgkgsnl/2r4b1/ppppp+Pp1p/7p1/9/9/PPPPP1PPP/1B5R1/LNSGKGSNL[P] w 1 5")
|
95
122
|
#b.fen("9/3k5/7+P1/8P/9/9/6P2/R3K4/1NSG1GSNL[PPPPPPPPPNNBRLLSSGGppppppbl] w 19 100")
|
96
123
|
# +P8/9/8L/L3k3R/1KP6/9/3s5/2S6/1+n1g4+B[PPPPPPPPPNBRLLSGpppppppnnsgg] b
|
97
124
|
# b.fen("5K3/2+P6/6+P2/9/4k4/9/9/9/9[PPPPPPPPPNNBRLLSSGGpppppppnnbrllssgg] w 67 185")
|
98
125
|
#b.fen("8+r/5K3/9/9/9/9/k8/9/9[-] w 24 1")
|
99
|
-
b.fen("
|
100
|
-
b.print_board
|
101
|
-
mgen = b.mgen_generator
|
102
|
-
mgen.generate_moves
|
103
|
-
|
126
|
+
#b.fen("9/+l4k3/+P1+r2L1+l1/+l3+B2S1/1n5rR/5+l+l2/9/9/1K7[LGNpgl] w 0 1")
|
127
|
+
#b.print_board
|
128
|
+
#mgen = b.mgen_generator
|
129
|
+
#mgen.generate_moves
|
130
|
+
# 5k3/+n8/1G5R1/2+s+P3b1/n+s2l+B+N2/5s+prp/9/7K1/9 w
|
131
|
+
p = RubyShogi::Perft.new("5k3/+n8/1G5R1/2+s+P3b1/n+s2l+B+N2/5s+prp/9/7K1/9[SPGnpn] w 0 1")
|
132
|
+
|
133
|
+
p = RubyShogi::Perft.new("7lk/9/8S/9/9/9/9/7L1/8K[P] w 0 1")
|
134
|
+
|
135
|
+
|
136
|
+
p.board.print_board
|
137
|
+
p.perft_by_moves(peek_argint(1))
|
138
|
+
#p.perft(peek_argint(5))
|
104
139
|
end
|
105
140
|
|
106
141
|
def print_numbers
|
@@ -147,6 +182,7 @@ class Cmd
|
|
147
182
|
puts "-bench: Benchmark ShurikenShogi Engine"
|
148
183
|
puts "-mbench: Benchmark ShurikenShogi Movegen"
|
149
184
|
puts "-perft [NUM]: Run Perft"
|
185
|
+
puts "-perft_by_moves [NUM]: Run Perft By Moves"
|
150
186
|
puts "-profile: Profile ShurikenShogi"
|
151
187
|
puts "-randommode: Activate Random Mode"
|
152
188
|
puts "-fen [FEN]: Set Fen"
|
@@ -170,10 +206,12 @@ class Cmd
|
|
170
206
|
when "-test" then test
|
171
207
|
when "-name" then name
|
172
208
|
when "-fen" then fen
|
209
|
+
when "-list" then list
|
173
210
|
when "-profile" then profile
|
174
211
|
when "-perft" then perft
|
175
212
|
when "-randperft" then randperft
|
176
213
|
when "-suite" then suite
|
214
|
+
when "-perft_by_moves" then perft_by_moves
|
177
215
|
when "-numbers" then print_numbers
|
178
216
|
when "-help" then help
|
179
217
|
else
|
data/lib/ruby_shogi/engine.rb
CHANGED
data/lib/ruby_shogi/eval.rb
CHANGED
@@ -84,6 +84,28 @@ module Eval
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def Eval.material(board)
|
87
|
+
board.print_board
|
88
|
+
puts Eval.material2(board)
|
89
|
+
puts Eval.material3(board)
|
90
|
+
fail if Eval.material2(board) != Eval.material3(board)
|
91
|
+
0
|
92
|
+
end
|
93
|
+
|
94
|
+
def Eval.material3(board)
|
95
|
+
score = board.brd.inject do |sum, p|
|
96
|
+
sum += case p
|
97
|
+
when 1..14 then MATERIAL_SCORE[p]
|
98
|
+
when -14..-1 then -MATERIAL_SCORE[-p]
|
99
|
+
else
|
100
|
+
0
|
101
|
+
end
|
102
|
+
end
|
103
|
+
board.white_pocket.each { |p| score += MATERIAL_HAND_SCORE[p] }
|
104
|
+
board.black_pocket.each { |p| score -= MATERIAL_HAND_SCORE[-p] }
|
105
|
+
score
|
106
|
+
end
|
107
|
+
|
108
|
+
def Eval.material2(board)
|
87
109
|
score = 0
|
88
110
|
board.brd.each do |p|
|
89
111
|
score += case p
|
data/lib/ruby_shogi/mgen.rb
CHANGED
@@ -54,17 +54,8 @@ class Mgen
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def remove_from_array(array, x)
|
57
|
-
|
58
|
-
array
|
59
|
-
if q == x
|
60
|
-
a.push(q) if found
|
61
|
-
found = true
|
62
|
-
else
|
63
|
-
a.push(q)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
fail if !found
|
67
|
-
a
|
57
|
+
array.delete_at(array.index(x) || array.length)
|
58
|
+
array
|
68
59
|
end
|
69
60
|
|
70
61
|
def good_coord?(i)
|
@@ -112,15 +103,16 @@ class Mgen
|
|
112
103
|
def jump_checks_to?(jumps, here)
|
113
104
|
jumps.each do |jmp|
|
114
105
|
px, py = @x_checks + jmp[0], @y_checks + jmp[1]
|
115
|
-
return true if px + py * 9 == here
|
106
|
+
return true if is_on_board?(px, py) && px + py * 9 == here
|
116
107
|
end
|
117
108
|
false
|
118
109
|
end
|
119
110
|
|
120
|
-
def checks_w
|
121
|
-
here = @board.bking
|
111
|
+
def checks_w?(here = nil, useking = true)
|
112
|
+
here = here == nil ? @board.bking : here
|
113
|
+
#fail if @board.find_black_king != here
|
122
114
|
81.times do |i|
|
123
|
-
@x_checks, @y_checks = i % 9, i / 9
|
115
|
+
@x_checks, @y_checks = i % 9, (i / 9).to_i
|
124
116
|
case @board.brd[i]
|
125
117
|
when 1 then return true if pawn_checks_w?(here)
|
126
118
|
when 2 then return true if jump_checks_to?(WHITE_GOLD_GENERAL_MOVES, here)
|
@@ -135,16 +127,17 @@ class Mgen
|
|
135
127
|
when 11 then return true if slider_checks_to?(BISHOP_MOVES, here) || jump_checks_to?(PROMOTED_BISHOP_MOVES, here)
|
136
128
|
when 12 then return true if slider_checks_to?(ROOK_MOVES, here)
|
137
129
|
when 13 then return true if slider_checks_to?(ROOK_MOVES, here) || jump_checks_to?(PROMOTED_ROOK_MOVES, here)
|
138
|
-
when 14 then return true if jump_checks_to?(KING_MOVES, here)
|
130
|
+
when 14 then return true if useking && jump_checks_to?(KING_MOVES, here)
|
139
131
|
end
|
140
132
|
end
|
141
133
|
false
|
142
134
|
end
|
143
|
-
|
144
|
-
def checks_b
|
145
|
-
here = @board.wking
|
135
|
+
|
136
|
+
def checks_b?(here = nil, useking = true)
|
137
|
+
here = here == nil ? @board.wking : here
|
138
|
+
#fail if @board.find_white_king != here
|
146
139
|
81.times do |i|
|
147
|
-
@x_checks, @y_checks = i % 9, i / 9
|
140
|
+
@x_checks, @y_checks = i % 9, (i / 9).to_i
|
148
141
|
case @board.brd[i]
|
149
142
|
when -1 then return true if pawn_checks_b?(here)
|
150
143
|
when -2 then return true if jump_checks_to?(BLACK_GOLD_GENERAL_MOVES, here)
|
@@ -159,7 +152,7 @@ class Mgen
|
|
159
152
|
when -11 then return true if slider_checks_to?(BISHOP_MOVES, here) || jump_checks_to?(PROMOTED_BISHOP_MOVES, here)
|
160
153
|
when -12 then return true if slider_checks_to?(ROOK_MOVES, here)
|
161
154
|
when -13 then return true if slider_checks_to?(ROOK_MOVES, here) || jump_checks_to?(PROMOTED_ROOK_MOVES, here)
|
162
|
-
when -14 then return true if jump_checks_to?(KING_MOVES, here)
|
155
|
+
when -14 then return true if useking && jump_checks_to?(KING_MOVES, here)
|
163
156
|
end
|
164
157
|
end
|
165
158
|
false
|
@@ -44,14 +44,24 @@ class MgenBlack < RubyShogi::Mgen
|
|
44
44
|
copy.brd[@from_gen] = 0
|
45
45
|
copy.brd[to] = me
|
46
46
|
copy.bking = to if me == -14
|
47
|
-
|
47
|
+
copy.mustbeok
|
48
48
|
@board = copy
|
49
49
|
@moves.push << copy if !checks_w?
|
50
50
|
@board = board2
|
51
51
|
end
|
52
52
|
|
53
|
+
def can_white_king_run?(to2)
|
54
|
+
x, y = to2 % 9, to2 / 9
|
55
|
+
KING_MOVES.each do |jmp|
|
56
|
+
px, py = x + jmp[0], y + jmp[1]
|
57
|
+
to = px + 9 * py
|
58
|
+
return true if is_on_board?(px, py) && @board.walkable_w?(to) && !checks_b?(to, false)
|
59
|
+
end
|
60
|
+
false
|
61
|
+
end
|
62
|
+
|
53
63
|
def pawn_drop_checkmate?(to)
|
54
|
-
@board.brd[to - 9] == 14 && !checks_w?(to - 9) ? true : false
|
64
|
+
@board.brd[to - 9] == 14 && (!checks_w?(to, false) && !can_white_king_run?(to - 9)) ? true : false
|
55
65
|
end
|
56
66
|
|
57
67
|
def add_new_drop_move(me, to)
|
@@ -59,19 +69,18 @@ class MgenBlack < RubyShogi::Mgen
|
|
59
69
|
return if me == -5 && to / 9 <= 1
|
60
70
|
board2 = @board
|
61
71
|
copy = @board.copy_me
|
62
|
-
copy.from =
|
72
|
+
copy.from = -1
|
63
73
|
copy.to = to
|
64
74
|
copy.drop = me
|
65
75
|
copy.r50 += 1
|
66
76
|
copy.fullmoves += 1
|
67
77
|
copy.eat = 0
|
68
|
-
copy.wtm = !
|
69
|
-
copy.brd[@from_gen] = 0
|
78
|
+
copy.wtm = !copy.wtm
|
70
79
|
copy.brd[to] = me
|
71
80
|
copy.black_pocket = remove_from_array(copy.black_pocket, me)
|
72
|
-
|
81
|
+
copy.mustbeok
|
73
82
|
@board = copy
|
74
|
-
if !checks_w? && !(me == 1 && pawn_drop_checkmate?(to))
|
83
|
+
if !checks_w? && !(me == -1 && pawn_drop_checkmate?(to))
|
75
84
|
@moves.push << copy
|
76
85
|
end
|
77
86
|
@board = board2
|
@@ -79,7 +88,7 @@ class MgenBlack < RubyShogi::Mgen
|
|
79
88
|
|
80
89
|
def handle_promotion?(me, to)
|
81
90
|
return true if must_promote?(me, to)
|
82
|
-
return false if to / 9
|
91
|
+
return false if to / 9 >= 3 && @from_gen / 9 >= 3
|
83
92
|
case me
|
84
93
|
when -1
|
85
94
|
push_move(-1, to, PROMO_STAY)
|
@@ -163,34 +172,31 @@ class MgenBlack < RubyShogi::Mgen
|
|
163
172
|
end
|
164
173
|
|
165
174
|
def pawn_on_column?(c)
|
166
|
-
ret = false
|
167
175
|
9.times do |i|
|
168
|
-
to =
|
169
|
-
if to != @from_gen && @board.brd[to] == -1
|
170
|
-
ret = true
|
171
|
-
break
|
172
|
-
end
|
176
|
+
to = 9 * i + c
|
177
|
+
return true if to != @from_gen && @board.brd[to] == -1
|
173
178
|
end
|
174
|
-
|
179
|
+
false
|
175
180
|
end
|
176
181
|
|
177
182
|
def put_pawn_drops
|
178
183
|
(9*8).times do |i2|
|
179
184
|
i = i2 + 9
|
180
185
|
@x_gen, @y_gen, @from_gen = i % 9, i / 9, i
|
181
|
-
add_new_drop_move(-1, i) if !pawn_on_column?(i % 9 ) && @board.brd[i]
|
186
|
+
add_new_drop_move(-1, i) if (!pawn_on_column?(i % 9 ) && @board.brd[i].zero?)
|
182
187
|
end
|
183
188
|
end
|
184
189
|
|
185
190
|
def put_drops(piece)
|
186
191
|
81.times do |i|
|
187
192
|
@x_gen, @y_gen, @from_gen = i % 9, i / 9, i
|
188
|
-
add_new_drop_move(piece, i) if @board.brd[i]
|
193
|
+
add_new_drop_move(piece, i) if @board.brd[i].zero?
|
189
194
|
end
|
190
195
|
end
|
191
196
|
|
192
197
|
def generate_drops
|
193
|
-
@board.black_pocket.
|
198
|
+
nodub = @board.black_pocket.dup.uniq
|
199
|
+
nodub.each do |piece|
|
194
200
|
case piece
|
195
201
|
when -1 then put_pawn_drops
|
196
202
|
when -3 then put_drops(-3)
|
@@ -209,7 +215,6 @@ class MgenBlack < RubyShogi::Mgen
|
|
209
215
|
@moves = []
|
210
216
|
81.times do |i|
|
211
217
|
@x_gen, @y_gen, @from_gen = i % 9, i / 9, i
|
212
|
-
#puts @board.brd[i]
|
213
218
|
case @board.brd[i]
|
214
219
|
when -1 then generate_pawn_moves
|
215
220
|
when -2 then generate_jump_moves(BLACK_GOLD_GENERAL_MOVES, -2)
|
@@ -26,34 +26,43 @@ class MgenWhite < RubyShogi::Mgen
|
|
26
26
|
copy.brd[@from_gen] = 0
|
27
27
|
copy.brd[to] = me
|
28
28
|
copy.wking = to if me == 14
|
29
|
-
|
29
|
+
copy.mustbeok
|
30
30
|
@board = copy
|
31
31
|
@moves.push << copy if !checks_b?
|
32
32
|
@board = board2
|
33
33
|
end
|
34
34
|
|
35
|
+
def can_black_king_run?(to2)
|
36
|
+
x, y = to2 % 9, to2 / 9
|
37
|
+
KING_MOVES.each do |jmp|
|
38
|
+
px, py = x + jmp[0], y + jmp[1]
|
39
|
+
return true if is_on_board?(px, py) && @board.walkable_b?(px + 9 * py) && !checks_w?(px + 9 * py, false)
|
40
|
+
end
|
41
|
+
false
|
42
|
+
end
|
43
|
+
|
35
44
|
def pawn_drop_checkmate?(to)
|
36
|
-
@board.brd[to + 9] == -14 && !checks_b?(to + 9) ? true : false
|
45
|
+
@board.brd[to + 9] == -14 && (!checks_b?(to, false) && !can_black_king_run?(to + 9)) ? true : false
|
37
46
|
end
|
38
47
|
|
39
48
|
def add_new_drop_move(me, to)
|
40
49
|
return if me == 3 && to / 9 == 8
|
41
50
|
return if me == 5 && to / 9 >= 7
|
51
|
+
fail if !@board.brd[to].zero?
|
42
52
|
board2 = @board
|
43
53
|
copy = @board.copy_me
|
44
|
-
copy.from =
|
54
|
+
copy.from = -1
|
45
55
|
copy.to = to
|
46
56
|
copy.drop = me
|
47
57
|
copy.eat = 0
|
48
58
|
copy.r50 += 1
|
49
59
|
copy.fullmoves += 1
|
50
|
-
copy.wtm = !
|
51
|
-
copy.brd[@from_gen] = 0
|
60
|
+
copy.wtm = !copy.wtm
|
52
61
|
copy.brd[to] = me
|
53
62
|
copy.white_pocket = remove_from_array(copy.white_pocket, me)
|
54
|
-
|
63
|
+
copy.mustbeok
|
55
64
|
@board = copy
|
56
|
-
if !checks_b? && !(me ==
|
65
|
+
if !checks_b? && !(me == 1 && pawn_drop_checkmate?(to))
|
57
66
|
@moves.push << copy
|
58
67
|
end
|
59
68
|
@board = board2
|
@@ -164,33 +173,30 @@ class MgenWhite < RubyShogi::Mgen
|
|
164
173
|
end
|
165
174
|
|
166
175
|
def pawn_on_column?(c)
|
167
|
-
ret = false
|
168
176
|
9.times do |i|
|
169
177
|
to = 9 * i + c
|
170
|
-
if to != @from_gen && @board.brd[to] == 1
|
171
|
-
ret = true
|
172
|
-
break
|
173
|
-
end
|
178
|
+
return true if to != @from_gen && @board.brd[to] == 1
|
174
179
|
end
|
175
|
-
|
180
|
+
false
|
176
181
|
end
|
177
182
|
|
178
183
|
def put_pawn_drops
|
179
184
|
(9*8).times do |i|
|
180
185
|
@x_gen, @y_gen, @from_gen = i % 9, i / 9, i
|
181
|
-
add_new_drop_move(1, i) if !pawn_on_column?(i % 9 ) && @board.brd[i]
|
186
|
+
add_new_drop_move(1, i) if !pawn_on_column?(i % 9 ) && @board.brd[i].zero?
|
182
187
|
end
|
183
188
|
end
|
184
189
|
|
185
190
|
def put_drops(piece)
|
186
191
|
81.times do |i|
|
187
192
|
@x_gen, @y_gen, @from_gen = i % 9, i / 9, i
|
188
|
-
add_new_drop_move(piece, i) if @board.brd[i]
|
193
|
+
add_new_drop_move(piece, i) if @board.brd[i].zero?
|
189
194
|
end
|
190
195
|
end
|
191
196
|
|
192
197
|
def generate_drops
|
193
|
-
@board.white_pocket.
|
198
|
+
nodub = @board.white_pocket.dup.uniq
|
199
|
+
nodub.each do |piece|
|
194
200
|
case piece
|
195
201
|
when 1 then put_pawn_drops
|
196
202
|
when 3 then put_drops(3)
|
@@ -200,6 +206,8 @@ class MgenWhite < RubyShogi::Mgen
|
|
200
206
|
when 10 then put_drops(10)
|
201
207
|
when 11 then put_drops(11)
|
202
208
|
when 12 then put_drops(12)
|
209
|
+
else
|
210
|
+
fail
|
203
211
|
end
|
204
212
|
end
|
205
213
|
@moves
|
data/lib/ruby_shogi/perft.rb
CHANGED
@@ -9,18 +9,50 @@ module RubyShogi
|
|
9
9
|
class Perft
|
10
10
|
attr_accessor :board
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
12
|
+
SUITE = [
|
13
|
+
|
14
|
+
{
|
15
|
+
# https://groups.google.com/forum/#!topic/shogi-l/U7hmtThbk1k
|
16
|
+
"fen" => "lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL[-] w 0 1",
|
17
|
+
"numbers" => [
|
18
|
+
1,
|
19
|
+
30,
|
20
|
+
900,
|
21
|
+
25470,
|
22
|
+
719731,
|
23
|
+
19861490,
|
24
|
+
547581517
|
25
|
+
]
|
26
|
+
},
|
27
|
+
{
|
28
|
+
# http://talkchess.com/forum3/viewtopic.php?f=7&t=32014
|
29
|
+
"fen" => "7lk/9/8S/9/9/9/9/7L1/8K[P] w 0 1",
|
30
|
+
"numbers" => [
|
31
|
+
1,
|
32
|
+
85,
|
33
|
+
639,
|
34
|
+
10786,
|
35
|
+
167089,
|
36
|
+
3458811
|
37
|
+
]
|
38
|
+
},
|
39
|
+
{
|
40
|
+
"fen" => "2k6/L8/+b6p1/+b1+b2+n2P/5P1s+N/9/9/7K1/9[LPPpsn] w 0 1",
|
41
|
+
"numbers" => [
|
42
|
+
1,
|
43
|
+
122,
|
44
|
+
26689,
|
45
|
+
0,#2308091,
|
46
|
+
0,
|
47
|
+
0,
|
48
|
+
0
|
49
|
+
]
|
50
|
+
}
|
51
|
+
]
|
21
52
|
|
22
53
|
def initialize(fen = nil)
|
23
|
-
@board = RubyShogi::Board.new
|
54
|
+
@board = RubyShogi::Board.new
|
55
|
+
@board.fen2(fen)
|
24
56
|
end
|
25
57
|
|
26
58
|
def perft_number(depth)
|
@@ -37,13 +69,36 @@ class Perft
|
|
37
69
|
n
|
38
70
|
end
|
39
71
|
|
40
|
-
def randperft(depth)
|
72
|
+
def randperft(depth, i, n)
|
41
73
|
@board = @board.randpos
|
74
|
+
puts "\n[ Round: #{i+1} / #{n} ]"
|
42
75
|
perft(depth)
|
43
76
|
end
|
44
77
|
|
78
|
+
def perft_by_moves(depth=2)
|
79
|
+
puts "~~~ perft_by_numbers( #{depth} ) ~~~"
|
80
|
+
puts "[ fen: #{@board.pos2fen} ]"
|
81
|
+
total_time = 0
|
82
|
+
total_nodes = 0
|
83
|
+
copy = @board
|
84
|
+
mgen = @board.mgen_generator
|
85
|
+
n, moves = 0, mgen.generate_moves
|
86
|
+
moves.each_with_index do |m, i|
|
87
|
+
@board = m
|
88
|
+
start = Time.now
|
89
|
+
nn = perft_number(depth-1)
|
90
|
+
diff = Time.now - start
|
91
|
+
total_time += diff
|
92
|
+
total_nodes += nn
|
93
|
+
puts "#{i+1}: #{m.move2str}: #{nn}"
|
94
|
+
#break
|
95
|
+
end
|
96
|
+
@board = copy
|
97
|
+
puts "= #{total_nodes} | #{total_time.round(3)}s | #{(total_nodes/total_time).to_i} nps"
|
98
|
+
end
|
99
|
+
|
45
100
|
def perft(depth)
|
46
|
-
puts "~~~ perft( #{depth} ) ~~~"
|
101
|
+
#puts "~~~ perft( #{depth} ) ~~~"
|
47
102
|
puts "[ fen: #{@board.pos2fen} ]"
|
48
103
|
total_time = 0
|
49
104
|
total_nodes = 0
|
@@ -62,25 +117,34 @@ class Perft
|
|
62
117
|
puts "= #{total_nodes} | #{total_time.round(3)}s | #{(total_nodes/total_time).to_i} nps"
|
63
118
|
end
|
64
119
|
|
65
|
-
def
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
120
|
+
def run_suite(data, i2, depth)
|
121
|
+
fen, nums = data["fen"], data["numbers"]
|
122
|
+
puts "[ round: #{i2+1} / #{SUITE.length} ]"
|
123
|
+
puts "[ fen: #{fen} ]"
|
124
|
+
total_nodes, total_time = 0, 0
|
125
|
+
@board = RubyShogi::Board.new
|
126
|
+
@board.fen2(fen)
|
70
127
|
(depth+1).times do |i|
|
128
|
+
break if nums[i] == 0
|
71
129
|
start = Time.now
|
72
|
-
@board = copy
|
73
130
|
n = perft_number(i)
|
74
131
|
diff = Time.now - start
|
75
|
-
total_time += diff
|
76
132
|
total_nodes += n
|
133
|
+
total_time += diff
|
77
134
|
nps = (diff == 0 or n == 1) ? n : (n / diff).to_i
|
78
|
-
error = ["ok", "error"][
|
79
|
-
break if i >=
|
135
|
+
error = ["ok", "error"][nums[i] - n == 0 ? 0 : 1]
|
136
|
+
break if i >= nums.length - 1
|
80
137
|
puts "#{i}: #{n} | #{diff.round(3)}s | #{nps} nps | #{error}"
|
81
138
|
end
|
82
139
|
total_time = 1 if total_time == 0
|
83
|
-
puts "= #{total_nodes} | #{total_time.round(3)}s | #{(total_nodes/total_time).to_i} nps"
|
140
|
+
puts "= #{total_nodes} | #{total_time.round(3)}s | #{(total_nodes/total_time).to_i} nps\n\n"
|
141
|
+
end
|
142
|
+
|
143
|
+
def suite(depth)
|
144
|
+
puts "~~~ suite( #{depth} ) ~~~"
|
145
|
+
start = Time.now
|
146
|
+
total_nodes = 0
|
147
|
+
SUITE.each_with_index { |s, i| run_suite(s, i, depth) }
|
84
148
|
end
|
85
149
|
end # class Perft
|
86
150
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: RubyShogi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.22'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Toni Helminen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-10-15 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: RubyShogi, a Shogi Engine
|
14
14
|
email: kalleankka1@gmail.com
|