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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 436d061edb50eee96d957a656caab3673b93183494b33d67324d68a4c006dd4e
4
- data.tar.gz: 18a2ad1204d24f8f17cd099ae48f08530ebabdc18fca03c984cd754e462d3c92
3
+ metadata.gz: 6701c33167fe944ca928ebd9bcf6ffccda09f294a416f6dafc8730b9f668a879
4
+ data.tar.gz: b8ea182ba133ac2e99f0da4d0434c7227a6f13abd2331178f179350c6c21e639
5
5
  SHA512:
6
- metadata.gz: b5319bc2ea8d8368b22f94afd7869b25462c139d04ba34e8bc576fe562a258465a00512e3b117d913f3b6d9a9f794c4ac94b97e65cd89cf3625dc83e4e925e86
7
- data.tar.gz: ef8812338d72cce94172439336f356b78fab48a21133aa2a1f819142c87331af40b36c17011575c5073284e6e147203bdc701d32992339c3268c59178b1c6165
6
+ metadata.gz: f24bf303d7e6fd9f2dd76559673bbf2eed9dff4dfe6e0a14eb6fd1e4311ea9a929522baf23b538752928047d86f641f4384f5834d14a7949f1f7641dd14169a5
7
+ data.tar.gz: 4f249d08e78e8adc31476e12bdeafd49a5269739cfea6e9ff785a6ecf46cac9362986bfde156be498478af9b05bb060c88d955e04316baccdbf5be09ec7eb6ad
@@ -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(pos = nil)
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] == 0
190
+ @brd[i].zero?
188
191
  end
189
192
 
190
193
  def walkable_w?(square)
191
- @brd[square] < 1
194
+ @brd[square] <= 0
192
195
  end
193
196
 
194
197
  def walkable_b?(square)
195
- @brd[square] > -1
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 randpos
428
+ def randpos2
415
429
  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) }
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 |
@@ -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
- suite(peek_argint(4))
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(peek_argint(5))
44
+ p.perft(n)
42
45
  end
43
46
 
44
47
  def randperft
45
- n = peek_argint(3)
48
+ n = peek_argint(10)
49
+ puts "~~~ randperft( #{n} ) ~~~"
46
50
  n.times do |i|
47
51
  p = RubyShogi::Perft.new
48
- puts "#{i} / ..."
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(5))
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
- n, val = 100, @tokens.peek(1)
65
- if val != nil && val.match(/\d+/)
66
- @tokens.forward
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.fen(@fen)
83
+ board.fen2(@fen)
86
84
  mgen = board.mgen_generator
87
85
  moves = mgen.generate_moves
88
- moves.each_with_index { |b, i| puts "> #{i}: #{b.move_str}" }
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("2+P+P+P4/8P/3k3+P1/1+b2P1p2/3p2Pp1/2p5l/+p3+p3p/1p+l+p5/+p4K2+p[NNRSSGGnnbrllssgg] b 1 ")
100
- b.print_board
101
- mgen = b.mgen_generator
102
- mgen.generate_moves
103
- mgen.print_move_list
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
@@ -228,7 +228,6 @@ class Engine
228
228
  else
229
229
  search(moves)
230
230
  moves = func.call
231
- #print_move_list(moves)
232
231
  @board = moves[0]
233
232
  end
234
233
  print_move_list(moves) if @debug
@@ -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
@@ -54,17 +54,8 @@ class Mgen
54
54
  end
55
55
 
56
56
  def remove_from_array(array, x)
57
- found, a = false, []
58
- array.each do |q|
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?#(here)
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?#(here)
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
- #fail if copy.find_black_king != copy.bking
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 = @from_gen
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 = ! 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
- #fail if copy.find_black_king != copy.bking
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 > 2 && @from_gen / 9 > 2
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 = -9 * i + 8 * 9 + c
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
- ret
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] == 0
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] == 0
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.each do |piece|
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
- #fail if copy.find_white_king != copy.wking
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 = @from_gen
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 = ! 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
- #fail if copy.find_white_king != copy.wking
63
+ copy.mustbeok
55
64
  @board = copy
56
- if !checks_b? && !(me == -1 && pawn_drop_checkmate?(to))
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
- ret
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] == 0
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] == 0
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.each do |piece|
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
@@ -9,18 +9,50 @@ module RubyShogi
9
9
  class Perft
10
10
  attr_accessor :board
11
11
 
12
- NUMS = { # https://groups.google.com/forum/#!topic/shogi-l/U7hmtThbk1k
13
- 0 => 1,
14
- 1 => 30,
15
- 2 => 900,
16
- 3 => 25470,
17
- 4 => 719731,
18
- 5 => 19861490,
19
- 6 => 547581517
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(fen)
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 suite(depth)
66
- puts "~~~ suite( #{depth} ) ~~~"
67
- total_time = 0
68
- total_nodes = 0
69
- copy = @board
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"][NUMS[i] - n == 0 ? 0 : 1]
79
- break if i >= NUMS.length - 1
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
 
@@ -40,7 +40,7 @@ $stderr.reopen("ruby_shogi-error.txt", "a+")
40
40
 
41
41
  module RubyShogi
42
42
  NAME = "RubyShogi"
43
- VERSION = "0.2"
43
+ VERSION = "0.22"
44
44
  AUTHOR = "Toni Helminen"
45
45
 
46
46
  def RubyShogi.init
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.2'
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-08-13 00:00:00.000000000 Z
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