RubyShogi 0.1
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 +7 -0
- data/bin/ruby_shogi +11 -0
- data/lib/ruby_shogi.rb +7 -0
- data/lib/ruby_shogi/bench.rb +127 -0
- data/lib/ruby_shogi/board.rb +451 -0
- data/lib/ruby_shogi/cmd.rb +188 -0
- data/lib/ruby_shogi/engine.rb +276 -0
- data/lib/ruby_shogi/eval.rb +102 -0
- data/lib/ruby_shogi/history.rb +63 -0
- data/lib/ruby_shogi/mgen.rb +169 -0
- data/lib/ruby_shogi/mgen_black.rb +238 -0
- data/lib/ruby_shogi/mgen_white.rb +237 -0
- data/lib/ruby_shogi/perft.rb +87 -0
- data/lib/ruby_shogi/ruby_shogi.rb +66 -0
- data/lib/ruby_shogi/tactics.rb +33 -0
- data/lib/ruby_shogi/tokens.rb +42 -0
- data/lib/ruby_shogi/utils.rb +15 -0
- data/lib/ruby_shogi/xboard.rb +117 -0
- data/lib/ruby_shogi/zobrist.rb +25 -0
- metadata +62 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2b3979a80f7a932007c0a2dc821befcf794f95f63681b4da2623ef74d3d7f9d4
|
4
|
+
data.tar.gz: 4749eee553d260501697177086c02e1cb483acbbcb379f4af13da8da8b89f935
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b62f9d942059d2c9275152930b72b7550dfd1f4ef9d66578dbd17694ea8c8d165e1fc79d34693b3d9e061ed2cb6b913962cb8652b3c290c91c04d464fa447695
|
7
|
+
data.tar.gz: 7fb81aec4dd6595376326a8934f5ce7db33001a7ed08094a7f414975b821e0a07833029e4fc308a78bd47dba503e497c56502c00d75ee4c2925b78c9f02f3406
|
data/bin/ruby_shogi
ADDED
data/lib/ruby_shogi.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
##
|
2
|
+
# RubyShogi, a Shogi Engine
|
3
|
+
# Author: Toni Helminen
|
4
|
+
# License: GPLv3
|
5
|
+
##
|
6
|
+
|
7
|
+
module RubyShogi
|
8
|
+
|
9
|
+
require 'benchmark'
|
10
|
+
|
11
|
+
module Bench
|
12
|
+
def Bench.f1
|
13
|
+
n = 0
|
14
|
+
1000_000.times { |i| n += (i%80) }
|
15
|
+
n
|
16
|
+
end
|
17
|
+
|
18
|
+
def Bench.f2
|
19
|
+
n = 0
|
20
|
+
1000_000.times { |i| n += (i%80) }
|
21
|
+
n
|
22
|
+
end
|
23
|
+
|
24
|
+
def Bench.f3
|
25
|
+
n, i = 0, 0
|
26
|
+
while i < 1000_000
|
27
|
+
n, i = n + (i%80), i + 1
|
28
|
+
end
|
29
|
+
n
|
30
|
+
end
|
31
|
+
|
32
|
+
def Bench.f3_1
|
33
|
+
n = 0
|
34
|
+
for i in 0..1000_000 do
|
35
|
+
n = n + (i%80)
|
36
|
+
end
|
37
|
+
n
|
38
|
+
end
|
39
|
+
|
40
|
+
def Bench.loops
|
41
|
+
header("loops")
|
42
|
+
Benchmark.bm(10) do |x|
|
43
|
+
x.report("each") { f1 }
|
44
|
+
x.report("times") { f2 }
|
45
|
+
x.report("while") { f3 }
|
46
|
+
x.report("for") { f3_1 }
|
47
|
+
#x.compare!
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def Bench.f4
|
52
|
+
n = 0
|
53
|
+
1000_000.times { |i| n += i%42 }
|
54
|
+
n
|
55
|
+
end
|
56
|
+
|
57
|
+
def Bench.f5
|
58
|
+
n = 0
|
59
|
+
1000_000.times { |i| n += i.modulo 42 }
|
60
|
+
n
|
61
|
+
end
|
62
|
+
|
63
|
+
def Bench.modulo
|
64
|
+
header("modulo")
|
65
|
+
Benchmark.bm(10) do |x|
|
66
|
+
x.report("%") { f4 }
|
67
|
+
x.report("modulo") { f5 }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def Bench.f6
|
72
|
+
s, caps = ["abc", "def", "ghi", "jkl"], ""
|
73
|
+
100_000.times { caps = s.map { |str| str.upcase } }
|
74
|
+
caps
|
75
|
+
end
|
76
|
+
|
77
|
+
def Bench.f7
|
78
|
+
s, caps = ["abc", "def", "ghi", "jkl"], ""
|
79
|
+
100_000.times { caps = s.map(&:upcase) }
|
80
|
+
caps
|
81
|
+
end
|
82
|
+
|
83
|
+
def Bench.caps
|
84
|
+
header("caps")
|
85
|
+
Benchmark.bm(10) do |x|
|
86
|
+
x.report(".upcase") { f6 }
|
87
|
+
x.report("&:upcase") { f7 }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def Bench.f8
|
92
|
+
s, s2 = "a", "abc"
|
93
|
+
20_000.times { s += s2 }
|
94
|
+
end
|
95
|
+
|
96
|
+
def Bench.f9
|
97
|
+
s, s2 = "a", "abc"
|
98
|
+
20_000.times { s << s2 }
|
99
|
+
end
|
100
|
+
|
101
|
+
def Bench.f10
|
102
|
+
s, s2 = "a", "abc"
|
103
|
+
20_000.times { s = "#{s}#{s2}" }
|
104
|
+
end
|
105
|
+
|
106
|
+
def Bench.header(msg)
|
107
|
+
puts "... #{msg} ..."
|
108
|
+
end
|
109
|
+
|
110
|
+
def Bench.strings
|
111
|
+
header("strings")
|
112
|
+
Benchmark.bm(10) do |x|
|
113
|
+
x.report("+=") { f8 }
|
114
|
+
x.report("<<") { f9 }
|
115
|
+
x.report("\#\{\}") { f10 }
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def Bench.go
|
120
|
+
loops
|
121
|
+
modulo
|
122
|
+
caps
|
123
|
+
strings
|
124
|
+
end
|
125
|
+
end # module Bench
|
126
|
+
|
127
|
+
end # module RubyShogi
|
@@ -0,0 +1,451 @@
|
|
1
|
+
##
|
2
|
+
# RubyShogi, a Shogi Engine
|
3
|
+
# Author: Toni Helminen
|
4
|
+
# License: GPLv3
|
5
|
+
##
|
6
|
+
|
7
|
+
module RubyShogi
|
8
|
+
|
9
|
+
class Board
|
10
|
+
START_POS = "lnsgkgsnl/1r5b1/ppppppppp/9/9/9/PPPPPPPPP/1B5R1/LNSGKGSNL[-] w 0 1"
|
11
|
+
|
12
|
+
PIECES = {
|
13
|
+
".": 0,
|
14
|
+
"P": 1, # Pawn
|
15
|
+
"p": -1,
|
16
|
+
"+P": 2, # Promoted Pawn
|
17
|
+
"+p": -2,
|
18
|
+
"L": 3, # Lance
|
19
|
+
"l": -3,
|
20
|
+
"+L": 4, # Promoted Lance
|
21
|
+
"+l": -4,
|
22
|
+
"N": 5, # Knight
|
23
|
+
"n": -5,
|
24
|
+
"+N": 6, # Promoted Knight
|
25
|
+
"+n": -6,
|
26
|
+
"S": 7, # Silver
|
27
|
+
"s": -7,
|
28
|
+
"+S": 8, # Promoted Silver
|
29
|
+
"+s": -8,
|
30
|
+
"G": 9, # Gold
|
31
|
+
"g": -9,
|
32
|
+
"B": 10, # Bishop
|
33
|
+
"b": -10,
|
34
|
+
"+B": 11, # Promoted Bishop
|
35
|
+
"+b": -11,
|
36
|
+
"R": 12, # Rook
|
37
|
+
"r": -12,
|
38
|
+
"+R": 13, # Promoted Rook
|
39
|
+
"+r": -13,
|
40
|
+
"K": 14, # King
|
41
|
+
"k": -14
|
42
|
+
}.freeze
|
43
|
+
|
44
|
+
attr_accessor :brd, :wking, :bking, :white_pocket, :black_pocket, :variant, :nodetype, :r50, :drop, :hash, :fullmoves, :wtm, :eat, :from, :to, :score, :promo, :index
|
45
|
+
|
46
|
+
def initialize(pos = nil)
|
47
|
+
initme
|
48
|
+
fen(pos)
|
49
|
+
end
|
50
|
+
|
51
|
+
def initme
|
52
|
+
@brd = [0] * 81
|
53
|
+
@wtm, @from, @to, @eat = true, 0, 0, 0
|
54
|
+
@score, @promo = 0, 0
|
55
|
+
@white_pocket = []
|
56
|
+
@black_pocket = []
|
57
|
+
@index = 0
|
58
|
+
@r50 = 0
|
59
|
+
@drop = 0
|
60
|
+
@hash = 0
|
61
|
+
@wking = 0
|
62
|
+
@bking = 0
|
63
|
+
@fullmoves = 2
|
64
|
+
@nodetype = 0 # 2 draw 1 win -1 loss
|
65
|
+
end
|
66
|
+
|
67
|
+
def brd2str
|
68
|
+
s, empty, counter = "", 0, 0
|
69
|
+
80.times do |j|
|
70
|
+
i = 10 * (7 - j / 10) + ( j % 10 )
|
71
|
+
p = @brd[i]
|
72
|
+
if p != 0
|
73
|
+
if empty > 0
|
74
|
+
s += empty.to_s
|
75
|
+
empty = 0
|
76
|
+
end
|
77
|
+
s += "fcakqrbnp.PNBRQKACF"[p + 9]
|
78
|
+
else
|
79
|
+
empty += 1
|
80
|
+
end
|
81
|
+
counter += 1
|
82
|
+
if counter % 10 == 0
|
83
|
+
s += empty.to_s if empty > 0
|
84
|
+
s += "/" if counter < 80
|
85
|
+
empty = 0
|
86
|
+
end
|
87
|
+
end
|
88
|
+
s
|
89
|
+
end
|
90
|
+
|
91
|
+
def wtm2str
|
92
|
+
@wtm ? "w" : "b"
|
93
|
+
end
|
94
|
+
|
95
|
+
def tofen
|
96
|
+
"#{brd2str} #{wtm2str}"
|
97
|
+
end
|
98
|
+
|
99
|
+
def mgen_generator
|
100
|
+
@wtm ? RubyShogi::MgenWhite.new(self) : RubyShogi::MgenBlack.new(self)
|
101
|
+
end
|
102
|
+
|
103
|
+
def create_hash
|
104
|
+
@hash = 0
|
105
|
+
81.times { | i | @hash ^= RubyShogi::Zobrist.get(20 * i + 8 + @brd[i]) }
|
106
|
+
@hash ^= RubyShogi::Zobrist.get(20 * 80 + (@wtm ? 1 : 0))
|
107
|
+
end
|
108
|
+
|
109
|
+
def legal?
|
110
|
+
pieces = [0] * 20
|
111
|
+
@brd.each { |p| pieces[p + 9] += 1 }
|
112
|
+
return false if pieces[-6 + 9] == 0 || pieces[6 + 9] == 0
|
113
|
+
true
|
114
|
+
end
|
115
|
+
|
116
|
+
def make_move(me, from, to)
|
117
|
+
#fail unless (good_coord?(from) && good_coord?(to))
|
118
|
+
@eat = @brd[to]
|
119
|
+
@brd[to] = me
|
120
|
+
@brd[from] = 0
|
121
|
+
end
|
122
|
+
|
123
|
+
def find_white_king
|
124
|
+
@brd.index { | x | x == 14 }
|
125
|
+
end
|
126
|
+
|
127
|
+
def find_black_king
|
128
|
+
@brd.index { | x | x == -14 }
|
129
|
+
end
|
130
|
+
|
131
|
+
def find_piece_all(piece)
|
132
|
+
@brd.index { | x | x == piece }
|
133
|
+
end
|
134
|
+
|
135
|
+
# scans ->
|
136
|
+
def find_piece(start_square, end_square, me, diff = 1)
|
137
|
+
i = start_square
|
138
|
+
loop do
|
139
|
+
return i if @brd[i] == me
|
140
|
+
fail "ShurikenShogi Error: Couldn't Find: '#{me}'" if i == end_square
|
141
|
+
i += diff
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# scans ->
|
146
|
+
def just_kings?
|
147
|
+
81.times do |i|
|
148
|
+
return false if @brd[i] != 14 && @brd[i] != -14
|
149
|
+
end
|
150
|
+
true
|
151
|
+
end
|
152
|
+
|
153
|
+
def material_draw?
|
154
|
+
81.times do |i|
|
155
|
+
return false if @brd[i] != 14 && @brd[i] != -14 && @brd[i] != 0
|
156
|
+
end
|
157
|
+
true
|
158
|
+
end
|
159
|
+
|
160
|
+
def copy_me()
|
161
|
+
copy = RubyShogi::Board.new
|
162
|
+
copy.brd = @brd.dup
|
163
|
+
copy.white_pocket = @white_pocket.dup
|
164
|
+
copy.black_pocket = @black_pocket.dup
|
165
|
+
copy.wtm = @wtm
|
166
|
+
copy.from = @from
|
167
|
+
copy.to = @to
|
168
|
+
copy.r50 = @r50
|
169
|
+
copy.wking = @wking
|
170
|
+
copy.bking = @bking
|
171
|
+
copy
|
172
|
+
end
|
173
|
+
|
174
|
+
def startpos
|
175
|
+
fen(START_POS)
|
176
|
+
end
|
177
|
+
|
178
|
+
def last_rank?(square)
|
179
|
+
y_coord(square) == 8
|
180
|
+
end
|
181
|
+
|
182
|
+
def first_rank?(x)
|
183
|
+
y_coord(x) == 0
|
184
|
+
end
|
185
|
+
|
186
|
+
def empty?(i)
|
187
|
+
@brd[i] == 0
|
188
|
+
end
|
189
|
+
|
190
|
+
def walkable_w?(square)
|
191
|
+
@brd[square] < 1
|
192
|
+
end
|
193
|
+
|
194
|
+
def walkable_b?(square)
|
195
|
+
@brd[square] > -1
|
196
|
+
end
|
197
|
+
|
198
|
+
def is_on_board?(x, y)
|
199
|
+
x >= 0 && x <= 8 && y >= 0 && y <= 8
|
200
|
+
end
|
201
|
+
|
202
|
+
def good_coord?(i)
|
203
|
+
i >= 0 && i < 81
|
204
|
+
end
|
205
|
+
|
206
|
+
def distance(p1, p2)
|
207
|
+
[(p1 % 9 - p2 % 9 ).abs, (p1 / 9 - p2 / 9).abs].max
|
208
|
+
end
|
209
|
+
|
210
|
+
def jishogi_likely_w?(wking)
|
211
|
+
res = 0
|
212
|
+
81.times { |i| res += 1 if @brd[i] > 0 && distance(wking, i) < 3 }
|
213
|
+
res > 5
|
214
|
+
end
|
215
|
+
|
216
|
+
def jishogi_likely_b?(bking)
|
217
|
+
res = 0
|
218
|
+
81.times { |i| res += 1 if @brd[i] < 0 && distance(bking, i) < 3 }
|
219
|
+
res > 5
|
220
|
+
end
|
221
|
+
|
222
|
+
# TODO improve likely?
|
223
|
+
def jishogi?
|
224
|
+
wking, bking = find_white_king, find_black_king
|
225
|
+
if wking / 9 >= 6 && bking / 9 <= 2 && jishogi_likely_w?(wking) && jishogi_likely_b?(bking)
|
226
|
+
return true
|
227
|
+
end
|
228
|
+
false
|
229
|
+
end
|
230
|
+
|
231
|
+
def count_jishogi_w
|
232
|
+
res = 0
|
233
|
+
81.times do |i|
|
234
|
+
if [10, 12].include?(@brd[i])
|
235
|
+
res += 5
|
236
|
+
elsif @brd[i] != 14
|
237
|
+
res += 1
|
238
|
+
end
|
239
|
+
end
|
240
|
+
res
|
241
|
+
end
|
242
|
+
|
243
|
+
def count_jishogi_b
|
244
|
+
res = 0
|
245
|
+
81.times do |i|
|
246
|
+
if [-10, -12].include?(@brd[i])
|
247
|
+
res += 5
|
248
|
+
elsif @brd[i] != -14
|
249
|
+
res += 1
|
250
|
+
end
|
251
|
+
end
|
252
|
+
res
|
253
|
+
end
|
254
|
+
|
255
|
+
def mirror_board
|
256
|
+
(4*9).times do | i |
|
257
|
+
x, y = i % 9, i / 9
|
258
|
+
flip_y = x + (8 - y) * 9
|
259
|
+
p1 = @brd[i]
|
260
|
+
p2 = @brd[flip_y]
|
261
|
+
@brd[i] = p2
|
262
|
+
@brd[flip_y] = p1
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def flip_coord(coord)
|
267
|
+
(9 - 1 - y_coord(coord)) * 9 + x_coord(coord)
|
268
|
+
end
|
269
|
+
|
270
|
+
# TODO optimize
|
271
|
+
def number2piece(num)
|
272
|
+
ret = 0
|
273
|
+
PIECES.each { |piece2, num2|
|
274
|
+
if num.to_i == num2.to_i
|
275
|
+
ret = piece2
|
276
|
+
break
|
277
|
+
end
|
278
|
+
}
|
279
|
+
ret.to_s
|
280
|
+
end
|
281
|
+
|
282
|
+
# TODO optimize
|
283
|
+
def piece2number(piece)
|
284
|
+
ret = 0
|
285
|
+
PIECES.each { |piece2, num|
|
286
|
+
if piece == piece2.to_s
|
287
|
+
ret = num
|
288
|
+
break
|
289
|
+
end
|
290
|
+
}
|
291
|
+
ret
|
292
|
+
end
|
293
|
+
|
294
|
+
def pos2fen
|
295
|
+
s = ""
|
296
|
+
9.times do |y|
|
297
|
+
empty = 0
|
298
|
+
9.times do |x|
|
299
|
+
p = @brd[9 * (8 - y) + x]
|
300
|
+
if p == 0
|
301
|
+
empty += 1
|
302
|
+
else
|
303
|
+
if empty > 0
|
304
|
+
s << empty.to_s
|
305
|
+
empty = 0
|
306
|
+
end
|
307
|
+
s << number2piece(p)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
s << empty.to_s if empty > 0
|
311
|
+
s << "/" if y < 8
|
312
|
+
end
|
313
|
+
s << "["
|
314
|
+
@white_pocket.each { |p| s << number2piece(p) }
|
315
|
+
@black_pocket.each { |p| s << number2piece(p) }
|
316
|
+
s << "-" if @white_pocket.empty? && @black_pocket.empty?
|
317
|
+
s << "] "
|
318
|
+
s << (@wtm ? "w" : "b")
|
319
|
+
s << " #{@r50.to_s}"
|
320
|
+
s << " #{(@fullmoves/2).to_i}"
|
321
|
+
s
|
322
|
+
end
|
323
|
+
|
324
|
+
def fen_board(s)
|
325
|
+
s = s.gsub(/\d+/) { | m | "_" * m.to_i }
|
326
|
+
.gsub(/\//) { | m | "" }
|
327
|
+
i, k = 0, 0
|
328
|
+
while i < s.length
|
329
|
+
piece = s[i]
|
330
|
+
if s[i] == "+"# && i + 1 < s.length
|
331
|
+
i += 1
|
332
|
+
piece = "+#{s[i]}"
|
333
|
+
end
|
334
|
+
@brd[k] = piece2number(piece)
|
335
|
+
k += 1
|
336
|
+
i += 1
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
def fen_pocket(s)
|
341
|
+
@white_pocket = []
|
342
|
+
@black_pocket = []
|
343
|
+
s.strip!
|
344
|
+
return if s == "-"
|
345
|
+
i = 0
|
346
|
+
while i < s.length
|
347
|
+
num = piece2number(s[i])
|
348
|
+
if num > 0
|
349
|
+
@white_pocket.push(num)
|
350
|
+
elsif num < 0
|
351
|
+
@black_pocket.push(num)
|
352
|
+
end
|
353
|
+
i += 1
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
def fen_wtm(s)
|
358
|
+
@wtm = s == "w" ? true : false
|
359
|
+
end
|
360
|
+
|
361
|
+
def fen(str)
|
362
|
+
return if str.nil?
|
363
|
+
initme
|
364
|
+
s = str.strip.split(" ")
|
365
|
+
fail if s.length < 3
|
366
|
+
t = s[0].strip.split("[")
|
367
|
+
fen_board(t[0])
|
368
|
+
fen_pocket(t[1])
|
369
|
+
@wtm = s[1] == "w" ? true : false
|
370
|
+
@r50 = 2 * s[2].to_i if s.length >= 3
|
371
|
+
@fullmoves = 2 * s[3].to_i if s.length >= 4
|
372
|
+
mirror_board
|
373
|
+
@wking = find_white_king
|
374
|
+
@bking = find_black_king
|
375
|
+
end
|
376
|
+
|
377
|
+
def eval
|
378
|
+
Eval.eval(self)
|
379
|
+
end
|
380
|
+
|
381
|
+
def material
|
382
|
+
Eval.material(self)
|
383
|
+
end
|
384
|
+
|
385
|
+
def pocket2str
|
386
|
+
s = ""
|
387
|
+
@white_pocket.each { |num| s << number2piece(num) }
|
388
|
+
@black_pocket.each { |num| s << number2piece(num) }
|
389
|
+
s.strip.length == 0 ? "-" : s
|
390
|
+
end
|
391
|
+
|
392
|
+
def move_str
|
393
|
+
if @drop != 0
|
394
|
+
s = "#{number2piece(@drop).upcase}@"
|
395
|
+
tox, toy = @to % 9, @to / 9
|
396
|
+
s << ("a".ord + tox).chr
|
397
|
+
s << (toy + 1).to_s
|
398
|
+
return s
|
399
|
+
end
|
400
|
+
fromx, fromy = @from % 9, @from / 9
|
401
|
+
tox, toy = @to % 9, @to / 9
|
402
|
+
s = ("a".ord + fromx).chr
|
403
|
+
s << (fromy + 1).to_s
|
404
|
+
s << ("a".ord + tox).chr
|
405
|
+
s << (toy + 1).to_s
|
406
|
+
if @promo == 2
|
407
|
+
s << "+"
|
408
|
+
elsif @promo == 1
|
409
|
+
s << "="
|
410
|
+
end
|
411
|
+
s
|
412
|
+
end
|
413
|
+
|
414
|
+
def randpos
|
415
|
+
copy = RubyShogi::Board.new
|
416
|
+
copy.brd[rand(0.. 32)] = 14
|
417
|
+
copy.brd[rand((81-32)..80)] = -14
|
418
|
+
32.times { |i| copy.brd[32 + i] = rand(-14..14) if rand < 0.3 }
|
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) }
|
421
|
+
copy
|
422
|
+
end
|
423
|
+
|
424
|
+
def print_board
|
425
|
+
s =""
|
426
|
+
81.times do | i |
|
427
|
+
x, y = i % 9, i / 9
|
428
|
+
p = @brd[9 * (8 - y) + x]
|
429
|
+
ch = "."
|
430
|
+
PIECES.each do |pie, num|
|
431
|
+
if num.to_i == p.to_i
|
432
|
+
ch = pie.to_s
|
433
|
+
break
|
434
|
+
end
|
435
|
+
end
|
436
|
+
s << " " if ch.length < 2
|
437
|
+
s << ch
|
438
|
+
if (i + 1) % 9 == 0
|
439
|
+
s << " #{((9 - i / 9).to_i).to_s}\n"
|
440
|
+
end
|
441
|
+
end
|
442
|
+
9.times { |i| s << " " << ("a".ord + i).chr }
|
443
|
+
s << "\n[ wtm: #{@wtm} ]\n"
|
444
|
+
s << "[ r50: #{(@r50/2).to_i} ]\n"
|
445
|
+
s << "[ pocket: #{pocket2str} ]\n"
|
446
|
+
s << "[ fen: #{pos2fen} ]\n"
|
447
|
+
puts s
|
448
|
+
end
|
449
|
+
end # class Board
|
450
|
+
|
451
|
+
end # module RubyShogi
|