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