shurikenengine 0.31
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/shuriken +5 -0
- data/lib/shuriken.rb +1 -0
- data/lib/shuriken/bench.rb +118 -0
- data/lib/shuriken/board.rb +70 -0
- data/lib/shuriken/board_caparandom.rb +422 -0
- data/lib/shuriken/cmd.rb +185 -0
- data/lib/shuriken/engine.rb +53 -0
- data/lib/shuriken/engine_caparandom.rb +226 -0
- data/lib/shuriken/eval_caparandom.rb +110 -0
- data/lib/shuriken/falcon_moves.rb +40 -0
- data/lib/shuriken/fen.rb +52 -0
- data/lib/shuriken/history.rb +60 -0
- data/lib/shuriken/mgen_caparandom.rb +181 -0
- data/lib/shuriken/mgen_caparandom_black.rb +222 -0
- data/lib/shuriken/mgen_caparandom_white.rb +225 -0
- data/lib/shuriken/perft_capablanca_caparandom.rb +26 -0
- data/lib/shuriken/perft_caparandom.rb +77 -0
- data/lib/shuriken/perft_falcon_caparandom.rb +20 -0
- data/lib/shuriken/perft_gothic_caparandom.rb +26 -0
- data/lib/shuriken/shuriken.rb +75 -0
- data/lib/shuriken/tactics_caparandom.rb +72 -0
- data/lib/shuriken/tokens.rb +42 -0
- data/lib/shuriken/utils.rb +25 -0
- data/lib/shuriken/xboard.rb +134 -0
- data/lib/shuriken/zobrist.rb +25 -0
- metadata +69 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Shuriken, a Ruby chess variant engine
|
|
3
|
+
# Author: Toni Helminen
|
|
4
|
+
# License: GPLv3
|
|
5
|
+
##
|
|
6
|
+
|
|
7
|
+
module Shuriken
|
|
8
|
+
|
|
9
|
+
module EvalCaparandom
|
|
10
|
+
MATERIAL_SCORE = {
|
|
11
|
+
1 => 1,
|
|
12
|
+
2 => 3,
|
|
13
|
+
3 => 3,
|
|
14
|
+
4 => 5,
|
|
15
|
+
5 => 9,
|
|
16
|
+
6 => 6,
|
|
17
|
+
7 => 8,
|
|
18
|
+
8 => 8
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
CENTRAL_BONUS_X = [1,2,3,4,5,5,4,3,2,1].freeze
|
|
22
|
+
CENTRAL_BONUS_Y = [1,2,3,4,4,3,2,1].freeze
|
|
23
|
+
|
|
24
|
+
CENTRAL_SCORE = {
|
|
25
|
+
1 => 0.5,
|
|
26
|
+
2 => 5,
|
|
27
|
+
3 => 5,
|
|
28
|
+
4 => 3,
|
|
29
|
+
5 => 2,
|
|
30
|
+
6 => 0.2,
|
|
31
|
+
7 => 3,
|
|
32
|
+
8 => 3
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
EVAL_PST_MG = []
|
|
36
|
+
|
|
37
|
+
def EvalCaparandom.init
|
|
38
|
+
return if EVAL_PST_MG.length > 0
|
|
39
|
+
7.times do |i|
|
|
40
|
+
arr = []
|
|
41
|
+
79.times do |j|
|
|
42
|
+
score = 0.1 * (MATERIAL_SCORE[i + 1] + 2 * CENTRAL_SCORE[i + 1] * (CENTRAL_BONUS_X[j % 10 ] + CENTRAL_BONUS_Y[j / 10]))
|
|
43
|
+
arr.push(score)
|
|
44
|
+
end
|
|
45
|
+
EVAL_PST_MG.push(arr)
|
|
46
|
+
end
|
|
47
|
+
EVAL_PST_MG.freeze
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def EvalCaparandom.eval(board)
|
|
51
|
+
score = 0
|
|
52
|
+
board.brd.each_with_index do |p, i|
|
|
53
|
+
score += case p
|
|
54
|
+
when 1 then
|
|
55
|
+
EVAL_PST_MG[0][i]
|
|
56
|
+
when 2 then
|
|
57
|
+
EVAL_PST_MG[1][i]
|
|
58
|
+
when 3 then
|
|
59
|
+
EVAL_PST_MG[2][i]
|
|
60
|
+
when 4 then
|
|
61
|
+
EVAL_PST_MG[3][i]
|
|
62
|
+
when 5 then
|
|
63
|
+
EVAL_PST_MG[4][i]
|
|
64
|
+
when 6 then
|
|
65
|
+
EVAL_PST_MG[5][i]
|
|
66
|
+
when 7 then
|
|
67
|
+
EVAL_PST_MG[6][i]
|
|
68
|
+
when 8 then
|
|
69
|
+
EVAL_PST_MG[7][i]
|
|
70
|
+
when -1 then
|
|
71
|
+
-EVAL_PST_MG[0][board.flip_coord(i)]
|
|
72
|
+
when -2 then
|
|
73
|
+
-EVAL_PST_MG[1][board.flip_coord(i)]
|
|
74
|
+
when -3 then
|
|
75
|
+
-EVAL_PST_MG[2][board.flip_coord(i)]
|
|
76
|
+
when -4 then
|
|
77
|
+
-EVAL_PST_MG[3][board.flip_coord(i)]
|
|
78
|
+
when -5 then
|
|
79
|
+
-EVAL_PST_MG[4][board.flip_coord(i)]
|
|
80
|
+
when -6 then
|
|
81
|
+
-EVAL_PST_MG[5][board.flip_coord(i)]
|
|
82
|
+
when -7 then
|
|
83
|
+
-EVAL_PST_MG[6][board.flip_coord(i)]
|
|
84
|
+
when -8 then
|
|
85
|
+
-EVAL_PST_MG[7][board.flip_coord(i)]
|
|
86
|
+
else
|
|
87
|
+
0
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
#score += 0.05 * rand()
|
|
91
|
+
0.01 * score
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def EvalCaparandom.material(board)
|
|
95
|
+
score = 0
|
|
96
|
+
board.brd.each do |p|
|
|
97
|
+
score += case p
|
|
98
|
+
when 1..8 then
|
|
99
|
+
MATERIAL_SCORE[p]
|
|
100
|
+
when -8..-1 then
|
|
101
|
+
-MATERIAL_SCORE[-p]
|
|
102
|
+
else
|
|
103
|
+
0
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
score
|
|
107
|
+
end
|
|
108
|
+
end # module EvalCaparandom
|
|
109
|
+
|
|
110
|
+
end # module Shuriken
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Shuriken, a Ruby chess variant engine
|
|
3
|
+
# Author: Toni Helminen
|
|
4
|
+
# License: GPLv3
|
|
5
|
+
##
|
|
6
|
+
|
|
7
|
+
module Shuriken
|
|
8
|
+
|
|
9
|
+
module FalconMoves
|
|
10
|
+
MOVES = []
|
|
11
|
+
|
|
12
|
+
def FalconMoves.init
|
|
13
|
+
return if MOVES.length > 0
|
|
14
|
+
[
|
|
15
|
+
[[1, 0], [1, 1]],
|
|
16
|
+
[[1, 0], [1, -1]],
|
|
17
|
+
[[-1, 0], [-1, 1]],
|
|
18
|
+
[[-1, 0], [-1, -1]],
|
|
19
|
+
[[0, 1], [1, 1]],
|
|
20
|
+
[[0, 1], [-1, 1]],
|
|
21
|
+
[[0, -1], [-1, -1]],
|
|
22
|
+
[[0, -1], [1, -1]]
|
|
23
|
+
].each do | o |
|
|
24
|
+
s, d = o[0], o[1]
|
|
25
|
+
# ssd,dss,sds,dsd,dds,sdd
|
|
26
|
+
MOVES.push(s + s + d)
|
|
27
|
+
MOVES.push(d + d + s)
|
|
28
|
+
MOVES.push(d + s + s)
|
|
29
|
+
MOVES.push(s + d + d)
|
|
30
|
+
MOVES.push(s + d + s)
|
|
31
|
+
MOVES.push(d + s + d)
|
|
32
|
+
end
|
|
33
|
+
MOVES.freeze
|
|
34
|
+
if false
|
|
35
|
+
MOVES.each { | q | puts ">> #{q}" }
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end # module FalconMoves
|
|
39
|
+
|
|
40
|
+
end # module Shuriken
|
data/lib/shuriken/fen.rb
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Shuriken, a Ruby chess variant engine
|
|
3
|
+
# Author: Toni Helminen
|
|
4
|
+
# License: GPLv3
|
|
5
|
+
##
|
|
6
|
+
|
|
7
|
+
module Shuriken
|
|
8
|
+
|
|
9
|
+
module Fen
|
|
10
|
+
# RR NN BB Q C K A
|
|
11
|
+
def Fen.make_caparandom_pos
|
|
12
|
+
s = "." * 10
|
|
13
|
+
put_piece = -> { i = rand(10); i = rand(10) while s[i] != "."; i }
|
|
14
|
+
|
|
15
|
+
king = rand(1..8)
|
|
16
|
+
l_rook = rand(king)
|
|
17
|
+
r_rook = king + 1 + rand([1, 9 - (king + 1)].max)
|
|
18
|
+
s[king] = "k"
|
|
19
|
+
s[l_rook] = "r"
|
|
20
|
+
s[r_rook] = "r"
|
|
21
|
+
|
|
22
|
+
fail if r_rook == king || l_rook == king
|
|
23
|
+
#puts "> #{king}> #{l_rook}> #{r_rook}"
|
|
24
|
+
|
|
25
|
+
wb = put_piece.()
|
|
26
|
+
s[wb] = "b"
|
|
27
|
+
|
|
28
|
+
bb = rand(10)
|
|
29
|
+
while s[bb] != "." || bb % 2 == wb % 2
|
|
30
|
+
bb = rand(10)
|
|
31
|
+
end
|
|
32
|
+
s[bb] = "b"
|
|
33
|
+
|
|
34
|
+
%|acnnq|.each_char { |p| s[put_piece.()] = p }
|
|
35
|
+
|
|
36
|
+
pieces = s
|
|
37
|
+
|
|
38
|
+
s += "/" + "p" * 10
|
|
39
|
+
s << "/10" * 4
|
|
40
|
+
s << "/" + "P" * 10
|
|
41
|
+
s << "/" + pieces.upcase
|
|
42
|
+
s << " w "
|
|
43
|
+
s << ("A".ord + r_rook).chr
|
|
44
|
+
s << ("A".ord + l_rook).chr
|
|
45
|
+
s << ("a".ord + r_rook).chr
|
|
46
|
+
s << ("a".ord + l_rook).chr
|
|
47
|
+
s << " - 0"
|
|
48
|
+
s
|
|
49
|
+
end
|
|
50
|
+
end # module Fen
|
|
51
|
+
|
|
52
|
+
end # module Shuriken<
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Shuriken, a Ruby chess variant engine
|
|
3
|
+
# Author: Toni Helminen
|
|
4
|
+
# License: GPLv3
|
|
5
|
+
##
|
|
6
|
+
|
|
7
|
+
module Shuriken
|
|
8
|
+
|
|
9
|
+
class History
|
|
10
|
+
def initialize
|
|
11
|
+
reset
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def reset
|
|
15
|
+
@data = []
|
|
16
|
+
@pos = -1
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def debug
|
|
20
|
+
puts "@pos: #{@pos} .. @data: #{@data.length}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def remove
|
|
24
|
+
if @pos > 1
|
|
25
|
+
board = @data[@pos - 2]
|
|
26
|
+
@pos -= 2
|
|
27
|
+
return board
|
|
28
|
+
end
|
|
29
|
+
@data.last
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def undo
|
|
33
|
+
if @pos > 0
|
|
34
|
+
board = @data[@pos - 1]
|
|
35
|
+
@pos -= 1
|
|
36
|
+
return board
|
|
37
|
+
end
|
|
38
|
+
@data.last
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def add(board)
|
|
42
|
+
@data.push(board)
|
|
43
|
+
@pos += 1
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def is_draw?(board, repsn = 2)
|
|
47
|
+
len, hash = @data.length, board.hash
|
|
48
|
+
i, n, reps = len - 1, 0, 0
|
|
49
|
+
return true if board.r50 >= 99
|
|
50
|
+
while i > 0
|
|
51
|
+
break if n >= 100
|
|
52
|
+
reps += 1 if hash == @data[i].hash
|
|
53
|
+
n, i = n + 1, i - 1
|
|
54
|
+
return true if reps >= repsn
|
|
55
|
+
end
|
|
56
|
+
false
|
|
57
|
+
end
|
|
58
|
+
end # class History
|
|
59
|
+
|
|
60
|
+
end # module Shuriken
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
##
|
|
2
|
+
# Shuriken, a Ruby chess variant engine
|
|
3
|
+
# Author: Toni Helminen
|
|
4
|
+
# License: GPLv3
|
|
5
|
+
##
|
|
6
|
+
|
|
7
|
+
module Shuriken
|
|
8
|
+
|
|
9
|
+
class MgenCaparandom
|
|
10
|
+
ROOK_MOVES = [[1, 0], [0, 1], [-1, 0], [0, -1]].freeze
|
|
11
|
+
BISHOP_MOVES = [[1, 1], [-1, 1], [1, -1], [-1, -1]].freeze
|
|
12
|
+
KING_MOVES = (ROOK_MOVES + BISHOP_MOVES).freeze
|
|
13
|
+
KNIGHT_MOVES = [[1, 2], [-1, 2], [1, -2], [-1, -2], [2, 1], [-2, 1], [2, -1], [-2, -1]].freeze
|
|
14
|
+
|
|
15
|
+
MOVE_TYPE_CASTLING = 1
|
|
16
|
+
MOVE_TYPE_PROMO = 2
|
|
17
|
+
MOVE_TYPE_EP = 5
|
|
18
|
+
|
|
19
|
+
attr_accessor :pseudo_moves, :only_captures
|
|
20
|
+
|
|
21
|
+
def initialize(board)
|
|
22
|
+
@board, @moves = board, []
|
|
23
|
+
@x_gen, @y_gen, @from_gen = 0, 0, 0 # move generation
|
|
24
|
+
@x_checks, @y_checks = 0, 0 # checks
|
|
25
|
+
@pseudo_moves = false # 3x speed up
|
|
26
|
+
@only_captures = false # generate only captures
|
|
27
|
+
@promotion_to = @board.variant == "falcon" ? [2, 3, 4, 5, 9] : [2, 3, 4, 5, 7, 8]
|
|
28
|
+
@promotion_to.freeze
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
##
|
|
32
|
+
# Utils
|
|
33
|
+
##
|
|
34
|
+
|
|
35
|
+
def print_move_list
|
|
36
|
+
i = 0
|
|
37
|
+
@moves.each do |board|
|
|
38
|
+
i += 1
|
|
39
|
+
puts "#{i}: #{board.move_str}"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def is_on_board?(x, y)
|
|
44
|
+
(x >= 0 && x <= 9 && y >= 0 && y <= 7) ? true : false
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def good_coord?(i)
|
|
48
|
+
(i >= 0 && i <= 79) ? true : false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def y_coord(n)
|
|
52
|
+
n / 10
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def x_coord(n)
|
|
56
|
+
n % 10
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
##
|
|
60
|
+
# Checks
|
|
61
|
+
##
|
|
62
|
+
|
|
63
|
+
def pawn_checks_w?(here)
|
|
64
|
+
[-1, 1].each do |dir|
|
|
65
|
+
px, py = @x_checks + dir, @y_checks + 1
|
|
66
|
+
return true if is_on_board?(px, py) && px + py * 10 == here
|
|
67
|
+
end
|
|
68
|
+
false
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def pawn_checks_b?(here)
|
|
72
|
+
[-1, 1].each do |dir|
|
|
73
|
+
px, py = @x_checks + dir, @y_checks - 1
|
|
74
|
+
return true if is_on_board?(px, py) && px + py * 10 == here
|
|
75
|
+
end
|
|
76
|
+
false
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def slider_checks_to?(slider, here)
|
|
80
|
+
slider.each do |jmp|
|
|
81
|
+
px, py = @x_checks, @y_checks
|
|
82
|
+
while true do
|
|
83
|
+
px, py = px + jmp[0], py + jmp[1]
|
|
84
|
+
to = px + py * 10
|
|
85
|
+
break if ! is_on_board?(px, py)
|
|
86
|
+
return true if to == here
|
|
87
|
+
break if ! @board.empty?(to)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
false
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def jump_checks_to?(jumps, here)
|
|
94
|
+
jumps.each do |jmp|
|
|
95
|
+
px, py = @x_checks + jmp[0], @y_checks + jmp[1]
|
|
96
|
+
to = px + py * 10
|
|
97
|
+
return true if is_on_board?(px, py) && to == here
|
|
98
|
+
end
|
|
99
|
+
false
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def any_black_checks_here?(no_checks)
|
|
103
|
+
no_checks.each { |square| return true if checks_b?(square) }
|
|
104
|
+
false
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def any_white_checks_here?(no_checks)
|
|
108
|
+
no_checks.each { |square| return true if checks_w?(square) }
|
|
109
|
+
false
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def falcon_checks?(here)
|
|
113
|
+
Shuriken::FalconMoves::MOVES.each do |mv|
|
|
114
|
+
px1, py1 = @x_checks + mv[0], @y_checks + mv[1]
|
|
115
|
+
to1 = px1 + 10 * py1
|
|
116
|
+
px2, py2 = px1 + mv[2], py1 + mv[3]
|
|
117
|
+
to2 = px2 + 10 * py2
|
|
118
|
+
px3, py3 = px2 + mv[4], py2 + mv[5]
|
|
119
|
+
to3 = px3 + 10 * py3
|
|
120
|
+
return true if (is_on_board?(px1, py1) && @board.empty?(to1) && is_on_board?(px2, py2) && @board.empty?(to2) \
|
|
121
|
+
&& is_on_board?(px3, py3) && to3 == here)
|
|
122
|
+
end
|
|
123
|
+
false
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def checks_w?(here)
|
|
127
|
+
80.times do |i|
|
|
128
|
+
@x_checks, @y_checks = x_coord(i), y_coord(i)
|
|
129
|
+
case @board.brd[i]
|
|
130
|
+
when 1
|
|
131
|
+
return true if pawn_checks_w?(here)
|
|
132
|
+
when 2
|
|
133
|
+
return true if jump_checks_to?(KNIGHT_MOVES, here)
|
|
134
|
+
when 3
|
|
135
|
+
return true if slider_checks_to?(BISHOP_MOVES, here)
|
|
136
|
+
when 4
|
|
137
|
+
return true if slider_checks_to?(ROOK_MOVES, here)
|
|
138
|
+
when 5
|
|
139
|
+
return true if slider_checks_to?(ROOK_MOVES + BISHOP_MOVES, here)
|
|
140
|
+
when 6
|
|
141
|
+
return true if jump_checks_to?(KING_MOVES, here)
|
|
142
|
+
when 7
|
|
143
|
+
return true if jump_checks_to?(KNIGHT_MOVES, here) || slider_checks_to?(BISHOP_MOVES, here)
|
|
144
|
+
when 8
|
|
145
|
+
return true if jump_checks_to?(KNIGHT_MOVES, here) || slider_checks_to?(ROOK_MOVES, here)
|
|
146
|
+
when 9
|
|
147
|
+
return true if falcon_checks?(here)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
false
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def checks_b?(here)
|
|
154
|
+
80.times do | i |
|
|
155
|
+
@x_checks, @y_checks = x_coord(i), y_coord(i)
|
|
156
|
+
case @board.brd[i]
|
|
157
|
+
when -1
|
|
158
|
+
return true if pawn_checks_b?(here)
|
|
159
|
+
when -2
|
|
160
|
+
return true if jump_checks_to?(KNIGHT_MOVES, here)
|
|
161
|
+
when -3
|
|
162
|
+
return true if slider_checks_to?(BISHOP_MOVES, here)
|
|
163
|
+
when -4
|
|
164
|
+
return true if slider_checks_to?(ROOK_MOVES, here)
|
|
165
|
+
when -5
|
|
166
|
+
return true if slider_checks_to?(ROOK_MOVES + BISHOP_MOVES, here)
|
|
167
|
+
when -6
|
|
168
|
+
return true if jump_checks_to?(KING_MOVES, here)
|
|
169
|
+
when -7
|
|
170
|
+
return true if jump_checks_to?(KNIGHT_MOVES, here) || slider_checks_to?(BISHOP_MOVES, here)
|
|
171
|
+
when -8
|
|
172
|
+
return true if jump_checks_to?(KNIGHT_MOVES, here) || slider_checks_to?(ROOK_MOVES, here)
|
|
173
|
+
when -9
|
|
174
|
+
return true if falcon_checks?(here)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
false
|
|
178
|
+
end
|
|
179
|
+
end # class MgenCaparandom
|
|
180
|
+
|
|
181
|
+
end # module Shuriken
|