RubyShogi 0.2 → 0.22
Sign up to get free protection for your applications and to get access to all the features.
- 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
|