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.
@@ -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
@@ -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