khetai 0.2.3 → 0.3.2
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 +4 -4
- data/.clang-format +14 -0
- data/Gemfile.lock +1 -1
- data/ext/khetai/dev/fltk-ui/ai_loader.cpp +20 -40
- data/ext/khetai/dev/fltk-ui/ai_loader.h +4 -5
- data/ext/khetai/dev/fltk-ui/game_board.cpp +98 -204
- data/ext/khetai/dev/fltk-ui/game_board.h +12 -19
- data/ext/khetai/dev/fltk-ui/game_board_util.cpp +16 -36
- data/ext/khetai/dev/fltk-ui/game_board_util.h +1 -1
- data/ext/khetai/dev/fltk-ui/khet.cpp +9 -14
- data/ext/khetai/dev/main.c +4 -6
- data/ext/khetai/khetai.c +25 -33
- data/ext/khetai/khetai_lib.c +252 -272
- data/ext/khetai/khetai_lib.h +88 -104
- data/lib/khetai/version.rb +1 -1
- metadata +3 -2
data/ext/khetai/khetai_lib.c
CHANGED
@@ -1,33 +1,50 @@
|
|
1
|
-
#include
|
1
|
+
#include "khetai_lib.h"
|
2
2
|
#include <ctype.h>
|
3
|
+
#include <stdio.h>
|
3
4
|
#include <stdlib.h>
|
4
|
-
#include <time.h>
|
5
|
-
#include "khetai_lib.h"
|
6
5
|
|
7
6
|
int max_time;
|
8
7
|
time_t start_time;
|
9
8
|
|
10
|
-
Square board[120] = {0};
|
11
|
-
int pharaoh_loc[2] = {0};
|
12
|
-
enum Player whose_turn;
|
13
|
-
enum Player starter;
|
14
|
-
int initial_depth = 0;
|
9
|
+
static Square board[120] = {0};
|
10
|
+
static int pharaoh_loc[2] = {0};
|
11
|
+
static enum Player whose_turn;
|
12
|
+
static enum Player starter;
|
13
|
+
static int initial_depth = 0;
|
15
14
|
|
16
|
-
Move undo_moves[MAX_DEPTH] = {0};
|
17
|
-
int undo_capture_indices[MAX_DEPTH] = {0};
|
18
|
-
Square undo_capture_squares[MAX_DEPTH] = {0};
|
15
|
+
static Move undo_moves[MAX_DEPTH] = {0};
|
16
|
+
static int undo_capture_indices[MAX_DEPTH] = {0};
|
17
|
+
static Square undo_capture_squares[MAX_DEPTH] = {0};
|
19
18
|
|
20
|
-
|
21
|
-
uint64_t hashes[MAX_DEPTH] = {0};
|
22
|
-
uint64_t keys[0xFF][120] = {0};
|
23
|
-
uint64_t turn_key = 0;
|
24
|
-
|
25
|
-
int undo_index = 0;
|
26
|
-
int move_num = 0;
|
27
|
-
bool checkmate = false;
|
19
|
+
PieceTracker piece_trackers[2] = {0};
|
28
20
|
|
29
|
-
|
30
|
-
{
|
21
|
+
HashEntry table[TABLE_SIZE] = {0};
|
22
|
+
static uint64_t hashes[MAX_DEPTH] = {0};
|
23
|
+
static uint64_t keys[0xFF][120] = {0};
|
24
|
+
static uint64_t turn_key = 0;
|
25
|
+
|
26
|
+
static int undo_index = 0;
|
27
|
+
static int hashes_index = 0;
|
28
|
+
static bool checkmate = false;
|
29
|
+
|
30
|
+
static int alphabeta(int depth, enum Player player, int alpha, int beta);
|
31
|
+
static void insert_table(HashEntry *entry, uint64_t key, int depth, int flag, int score, Move move);
|
32
|
+
static int calculate_score(void);
|
33
|
+
static int distance_from_pharaoh(int i, int p);
|
34
|
+
static void fire_laser(uint64_t *hash);
|
35
|
+
static void undo_move();
|
36
|
+
static void find_valid_moves(Move *valid_moves, int *vi);
|
37
|
+
static void find_valid_anubis_pyramid_moves(int i, Move *valid_moves, int *vi);
|
38
|
+
static void find_valid_scarab_moves(int i, Move *valid_moves, int *vi);
|
39
|
+
static void find_valid_pharaoh_moves(int i, Move *valid_moves, int *vi);
|
40
|
+
static void find_valid_sphinx_moves(int i, Move *valid_moves, int *vi);
|
41
|
+
static uint64_t get_board_hash();
|
42
|
+
static void init_piece_trackers();
|
43
|
+
static bool is_move_legal(Move move);
|
44
|
+
static Square str_to_square(char *str);
|
45
|
+
static void print_piece(Square s);
|
46
|
+
|
47
|
+
Move alphabeta_root(int depth, enum Player player) {
|
31
48
|
whose_turn = player;
|
32
49
|
starter = player;
|
33
50
|
initial_depth = depth;
|
@@ -38,16 +55,14 @@ Move alphabeta_root(int depth, enum Player player)
|
|
38
55
|
Move valid_moves[NUM_VALID_MOVES] = {0};
|
39
56
|
int vi = 0;
|
40
57
|
find_valid_moves(valid_moves, &vi);
|
41
|
-
for (int i = 0; i < NUM_VALID_MOVES; i++)
|
42
|
-
{
|
58
|
+
for (int i = 0; i < NUM_VALID_MOVES; i++) {
|
43
59
|
if (valid_moves[i] == 0)
|
44
60
|
break;
|
45
61
|
make_move(valid_moves[i]);
|
46
62
|
int score = -alphabeta(depth - 1, opposite_player(player), -beta, -alpha);
|
47
63
|
undo_move();
|
48
64
|
whose_turn = player;
|
49
|
-
if (score > best_score)
|
50
|
-
{
|
65
|
+
if (score > best_score) {
|
51
66
|
best_score = score;
|
52
67
|
best_move = valid_moves[i];
|
53
68
|
}
|
@@ -62,12 +77,10 @@ Move alphabeta_root(int depth, enum Player player)
|
|
62
77
|
return best_move;
|
63
78
|
}
|
64
79
|
|
65
|
-
int alphabeta(int depth, enum Player player, int alpha, int beta)
|
66
|
-
{
|
80
|
+
int alphabeta(int depth, enum Player player, int alpha, int beta) {
|
67
81
|
whose_turn = player;
|
68
|
-
if (depth == 0 || checkmate)
|
69
|
-
|
70
|
-
return player == Red ? calculate_score() : -calculate_score();
|
82
|
+
if (depth == 0 || checkmate) {
|
83
|
+
return player == RED ? calculate_score() : -calculate_score();
|
71
84
|
}
|
72
85
|
|
73
86
|
int alpha_orig = alpha;
|
@@ -75,43 +88,33 @@ int alphabeta(int depth, enum Player player, int alpha, int beta)
|
|
75
88
|
int vi = 0;
|
76
89
|
|
77
90
|
int table_depth = initial_depth - depth;
|
78
|
-
HashEntry *entry = search_table(hashes[
|
79
|
-
if (entry->key == hashes[
|
80
|
-
|
91
|
+
HashEntry *entry = search_table(hashes[hashes_index]);
|
92
|
+
if (entry->key == hashes[hashes_index] && entry->depth > table_depth && is_move_legal(entry->move)) {
|
93
|
+
valid_moves[vi++] = entry->move;
|
94
|
+
|
81
95
|
if (entry->flag == EXACT)
|
82
96
|
return entry->score;
|
83
|
-
else if (entry->flag ==
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
}
|
88
|
-
else
|
89
|
-
{
|
90
|
-
if (entry->score < beta)
|
91
|
-
beta = entry->score;
|
92
|
-
}
|
97
|
+
else if (entry->flag == LOWERBOUND && entry->score > alpha)
|
98
|
+
alpha = entry->score;
|
99
|
+
else if (entry->flag == UPPERBOUND && entry->score < beta)
|
100
|
+
beta = entry->score;
|
93
101
|
|
94
102
|
if (alpha >= beta)
|
95
103
|
return entry->score;
|
96
|
-
|
97
|
-
if (is_move_legal(entry->move))
|
98
|
-
valid_moves[vi++] = entry->move;
|
99
104
|
}
|
100
105
|
|
101
106
|
find_valid_moves(valid_moves, &vi);
|
102
107
|
int best_score = -MAX_SCORE;
|
103
108
|
Move best_move = (Move)0;
|
104
109
|
|
105
|
-
for (int i = 0; (i < NUM_VALID_MOVES && (time(NULL) - start_time < max_time)); i++)
|
106
|
-
{
|
110
|
+
for (int i = 0; (i < NUM_VALID_MOVES && (time(NULL) - start_time < max_time)); i++) {
|
107
111
|
if (valid_moves[i] == 0)
|
108
112
|
break;
|
109
113
|
make_move(valid_moves[i]);
|
110
114
|
int score = -alphabeta(depth - 1, opposite_player(player), -beta, -alpha);
|
111
115
|
undo_move();
|
112
116
|
whose_turn = player;
|
113
|
-
if (score > best_score)
|
114
|
-
{
|
117
|
+
if (score > best_score) {
|
115
118
|
best_score = score;
|
116
119
|
best_move = valid_moves[i];
|
117
120
|
}
|
@@ -123,30 +126,16 @@ int alphabeta(int depth, enum Player player, int alpha, int beta)
|
|
123
126
|
|
124
127
|
int flag = EXACT;
|
125
128
|
if (best_score <= alpha_orig)
|
126
|
-
flag =
|
129
|
+
flag = UPPERBOUND;
|
127
130
|
else if (best_score >= beta)
|
128
|
-
flag =
|
131
|
+
flag = LOWERBOUND;
|
129
132
|
|
130
|
-
|
131
|
-
insert_table(entry, hashes[move_num], table_depth, flag, best_score, best_move);
|
133
|
+
insert_table(entry, hashes[hashes_index], table_depth, flag, best_score, best_move);
|
132
134
|
return best_score;
|
133
135
|
}
|
134
136
|
|
135
|
-
void insert_table(HashEntry *entry, uint64_t key, int table_depth, int flag, int score, Move move)
|
136
|
-
{
|
137
|
-
if (entry->key != 0)
|
138
|
-
{
|
139
|
-
if (table_depth > entry->depth)
|
140
|
-
{
|
141
|
-
entry->key = key;
|
142
|
-
entry->depth = table_depth;
|
143
|
-
entry->flag = flag;
|
144
|
-
entry->score = score;
|
145
|
-
entry->move = move;
|
146
|
-
}
|
147
|
-
}
|
148
|
-
else
|
149
|
-
{
|
137
|
+
void insert_table(HashEntry *entry, uint64_t key, int table_depth, int flag, int score, Move move) {
|
138
|
+
if (entry->key == 0 || table_depth > entry->depth) {
|
150
139
|
entry->key = key;
|
151
140
|
entry->depth = table_depth;
|
152
141
|
entry->flag = flag;
|
@@ -155,47 +144,47 @@ void insert_table(HashEntry *entry, uint64_t key, int table_depth, int flag, int
|
|
155
144
|
}
|
156
145
|
}
|
157
146
|
|
158
|
-
int calculate_score()
|
159
|
-
{
|
147
|
+
int calculate_score() {
|
160
148
|
int score = 0;
|
161
149
|
int anubis_score = 800;
|
162
150
|
int pyramid_score = 1000;
|
163
151
|
int pharaoh_score = 100000;
|
164
|
-
|
165
|
-
{
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
152
|
+
|
153
|
+
for (int j = 0; j < 2; j++) {
|
154
|
+
enum Player player = j;
|
155
|
+
for (int k = 0; k < 13; k++) {
|
156
|
+
int i = get_board_index(player, k);
|
157
|
+
if (i != EPT) {
|
158
|
+
Square s = board[i];
|
159
|
+
int value = 0;
|
160
|
+
switch (get_piece(s)) {
|
161
|
+
case ANUBIS:
|
162
|
+
value += anubis_score;
|
163
|
+
value -= distance_from_pharaoh(i, pharaoh_loc[player]) * 10;
|
164
|
+
break;
|
165
|
+
case PYRAMID:
|
166
|
+
value += pyramid_score;
|
167
|
+
value += (rand() % 51) - 25;
|
168
|
+
break;
|
169
|
+
case SCARAB:
|
170
|
+
int max_distance = 16;
|
171
|
+
int base_score = 1000;
|
172
|
+
value += (max_distance - distance_from_pharaoh(i, pharaoh_loc[opposite_player(player)])) * base_score / max_distance;
|
173
|
+
break;
|
174
|
+
case PHARAOH:
|
175
|
+
value += pharaoh_score;
|
176
|
+
break;
|
177
|
+
default:
|
178
|
+
break;
|
179
|
+
}
|
180
|
+
score += get_owner(s) == RED ? value : -value;
|
190
181
|
}
|
191
|
-
score += get_owner(s) == Red ? value : -value;
|
192
182
|
}
|
193
183
|
}
|
194
184
|
return score;
|
195
185
|
}
|
196
186
|
|
197
|
-
int distance_from_pharaoh(int i, int p)
|
198
|
-
{
|
187
|
+
int distance_from_pharaoh(int i, int p) {
|
199
188
|
int px = p / 12;
|
200
189
|
int py = p % 12;
|
201
190
|
int ix = i / 12;
|
@@ -204,9 +193,8 @@ int distance_from_pharaoh(int i, int p)
|
|
204
193
|
return m_distance;
|
205
194
|
}
|
206
195
|
|
207
|
-
void make_move(Move move)
|
208
|
-
|
209
|
-
uint64_t hash = hashes[move_num++];
|
196
|
+
void make_move(Move move) {
|
197
|
+
uint64_t hash = hashes[hashes_index++];
|
210
198
|
|
211
199
|
int start = get_start(move);
|
212
200
|
// remove starting piece
|
@@ -214,15 +202,12 @@ void make_move(Move move)
|
|
214
202
|
int end = get_end(move);
|
215
203
|
int rotation = get_rotation(move);
|
216
204
|
|
217
|
-
if (rotation != 0)
|
218
|
-
{
|
205
|
+
if (rotation != 0) {
|
219
206
|
board[start] = rotate(board[start], rotation);
|
220
207
|
// add starting piece back with rotation
|
221
208
|
hash ^= keys[board[start]][start];
|
222
|
-
}
|
223
|
-
|
224
|
-
{
|
225
|
-
// remove ending piece if swapping
|
209
|
+
} else {
|
210
|
+
// remove ending piece
|
226
211
|
if (is_piece(board[end]))
|
227
212
|
hash ^= keys[board[end]][end];
|
228
213
|
|
@@ -232,11 +217,18 @@ void make_move(Move move)
|
|
232
217
|
// add starting piece to end location
|
233
218
|
hash ^= keys[board[end]][end];
|
234
219
|
|
220
|
+
enum Player moving_player = get_owner(moving_piece);
|
221
|
+
update_piece_tracker(moving_player, start, end);
|
222
|
+
|
235
223
|
// add ending piece to start location if swapping
|
236
|
-
if (is_piece(board[start]))
|
224
|
+
if (is_piece(board[start])) {
|
237
225
|
hash ^= keys[board[start]][start];
|
238
226
|
|
239
|
-
|
227
|
+
enum Player other_player = get_owner(board[start]);
|
228
|
+
update_piece_tracker(other_player, end, start);
|
229
|
+
}
|
230
|
+
|
231
|
+
if (get_piece(moving_piece) == PHARAOH)
|
240
232
|
pharaoh_loc[get_owner(moving_piece)] = end;
|
241
233
|
}
|
242
234
|
|
@@ -248,65 +240,60 @@ void make_move(Move move)
|
|
248
240
|
// testing that hashing works properly
|
249
241
|
// printf("\nHASH:\t%lu\nBOARD:\t%lu\n", hash, get_board_hash());
|
250
242
|
|
251
|
-
hashes[
|
243
|
+
hashes[hashes_index] = hash;
|
252
244
|
undo_index++;
|
253
245
|
}
|
254
246
|
|
255
|
-
void fire_laser(uint64_t *hash)
|
256
|
-
{
|
247
|
+
void fire_laser(uint64_t *hash) {
|
257
248
|
int i = sphinx_loc[whose_turn];
|
258
249
|
int laser_dir = get_orientation(board[i]);
|
259
250
|
bool traversing = true;
|
260
|
-
while (traversing)
|
261
|
-
{
|
251
|
+
while (traversing) {
|
262
252
|
i = i + directions[laser_dir];
|
263
|
-
if (i >= 0 && i < 120 && on_board[i] == 1)
|
264
|
-
{
|
253
|
+
if (i >= 0 && i < 120 && on_board[i] == 1) {
|
265
254
|
Square s = board[i];
|
266
|
-
if (is_piece(s))
|
267
|
-
{
|
255
|
+
if (is_piece(s)) {
|
268
256
|
int piece = get_piece(s) - 1;
|
269
257
|
int orientation = get_orientation(s);
|
270
258
|
int result = reflections[laser_dir][piece][orientation];
|
271
|
-
if (result ==
|
272
|
-
|
273
|
-
if (get_piece(s) == Pharaoh)
|
259
|
+
if (result == DEAD) {
|
260
|
+
if (get_piece(s) == PHARAOH)
|
274
261
|
checkmate = true;
|
275
262
|
// remove piece
|
276
263
|
*hash ^= keys[s][i];
|
264
|
+
|
265
|
+
enum Player remove_player = get_owner(s);
|
266
|
+
remove_from_piece_tracker(remove_player, i);
|
267
|
+
|
277
268
|
undo_capture_indices[undo_index] = i;
|
278
269
|
undo_capture_squares[undo_index] = s;
|
279
270
|
board[i] = (Square)0;
|
280
271
|
traversing = false;
|
281
|
-
}
|
282
|
-
else if (result == Absorbed)
|
283
|
-
{
|
272
|
+
} else if (result == ABSORBED) {
|
284
273
|
traversing = false;
|
285
|
-
}
|
286
|
-
else
|
287
|
-
{
|
274
|
+
} else {
|
288
275
|
laser_dir = result;
|
289
276
|
}
|
290
277
|
}
|
291
|
-
}
|
292
|
-
else
|
293
|
-
{
|
278
|
+
} else {
|
294
279
|
traversing = false;
|
295
280
|
}
|
296
281
|
}
|
297
282
|
}
|
298
283
|
|
299
|
-
void undo_move()
|
300
|
-
|
301
|
-
move_num--;
|
284
|
+
void undo_move() {
|
285
|
+
hashes_index--;
|
302
286
|
undo_index--;
|
303
287
|
|
304
288
|
Square captured = (Square)undo_capture_squares[undo_index];
|
305
289
|
undo_capture_squares[undo_index] = 0;
|
306
|
-
if (captured > 0)
|
307
|
-
|
308
|
-
board[
|
290
|
+
if (captured > 0) {
|
291
|
+
uint8_t board_pos = undo_capture_indices[undo_index];
|
292
|
+
board[board_pos] = captured;
|
309
293
|
undo_capture_indices[undo_index] = 0;
|
294
|
+
|
295
|
+
enum Player captured_player = get_owner(captured);
|
296
|
+
add_to_piece_tracker(captured_player, board_pos);
|
310
297
|
}
|
311
298
|
|
312
299
|
Move move = undo_moves[undo_index];
|
@@ -315,47 +302,47 @@ void undo_move()
|
|
315
302
|
int end = get_end(move);
|
316
303
|
int rotation = get_rotation(move);
|
317
304
|
|
318
|
-
if (rotation != 0)
|
319
|
-
{
|
305
|
+
if (rotation != 0) {
|
320
306
|
board[start] = rotate(board[start], rotation);
|
321
|
-
}
|
322
|
-
else
|
323
|
-
{
|
307
|
+
} else {
|
324
308
|
Square moving_piece = board[start];
|
325
309
|
board[start] = board[end];
|
326
310
|
board[end] = moving_piece;
|
327
311
|
|
328
|
-
|
312
|
+
enum Player moving_player = get_owner(moving_piece);
|
313
|
+
update_piece_tracker(moving_player, start, end);
|
314
|
+
|
315
|
+
if (board[start] != 0) {
|
316
|
+
enum Player other_player = get_owner(board[start]);
|
317
|
+
update_piece_tracker(other_player, end, start);
|
318
|
+
}
|
319
|
+
|
320
|
+
if (get_piece(moving_piece) == PHARAOH)
|
329
321
|
pharaoh_loc[get_owner(moving_piece)] = end;
|
330
322
|
}
|
331
323
|
checkmate = false;
|
332
324
|
}
|
333
325
|
|
334
|
-
void find_valid_moves(Move *valid_moves, int *vi)
|
335
|
-
{
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
enum Piece piece = get_piece(s);
|
343
|
-
switch (piece)
|
344
|
-
{
|
345
|
-
case Anubis:
|
346
|
-
find_valid_anubis_pyramid_moves(i, valid_moves, vi);
|
326
|
+
void find_valid_moves(Move *valid_moves, int *vi) {
|
327
|
+
for (int i = 0; i < 13; i++) {
|
328
|
+
uint8_t board_pos = piece_trackers[whose_turn].positions[i];
|
329
|
+
if (board_pos != EPT) {
|
330
|
+
enum Piece piece = get_piece(board[board_pos]);
|
331
|
+
switch (piece) {
|
332
|
+
case ANUBIS:
|
333
|
+
find_valid_anubis_pyramid_moves(board_pos, valid_moves, vi);
|
347
334
|
break;
|
348
|
-
case
|
349
|
-
find_valid_anubis_pyramid_moves(
|
335
|
+
case PYRAMID:
|
336
|
+
find_valid_anubis_pyramid_moves(board_pos, valid_moves, vi);
|
350
337
|
break;
|
351
|
-
case
|
352
|
-
find_valid_scarab_moves(
|
338
|
+
case SCARAB:
|
339
|
+
find_valid_scarab_moves(board_pos, valid_moves, vi);
|
353
340
|
break;
|
354
|
-
case
|
355
|
-
find_valid_pharaoh_moves(
|
341
|
+
case PHARAOH:
|
342
|
+
find_valid_pharaoh_moves(board_pos, valid_moves, vi);
|
356
343
|
break;
|
357
|
-
case
|
358
|
-
find_valid_sphinx_moves(
|
344
|
+
case SPHINX:
|
345
|
+
find_valid_sphinx_moves(board_pos, valid_moves, vi);
|
359
346
|
break;
|
360
347
|
default:
|
361
348
|
break;
|
@@ -364,78 +351,60 @@ void find_valid_moves(Move *valid_moves, int *vi)
|
|
364
351
|
}
|
365
352
|
}
|
366
353
|
|
367
|
-
void find_valid_anubis_pyramid_moves(int i, Move *valid_moves, int *vi)
|
368
|
-
{
|
369
|
-
for (int j = 0; j < 8; j++)
|
370
|
-
{
|
354
|
+
void find_valid_anubis_pyramid_moves(int i, Move *valid_moves, int *vi) {
|
355
|
+
for (int j = 0; j < 8; j++) {
|
371
356
|
int dest = i + directions[j];
|
372
|
-
if (!is_piece(board[dest]) && can_move[whose_turn][dest])
|
373
|
-
{
|
357
|
+
if (!is_piece(board[dest]) && can_move[whose_turn][dest]) {
|
374
358
|
valid_moves[(*vi)++] = new_move(i, dest, 0);
|
375
359
|
}
|
376
360
|
}
|
377
|
-
for (int j = 0; j < 2; j++)
|
378
|
-
{
|
361
|
+
for (int j = 0; j < 2; j++) {
|
379
362
|
valid_moves[(*vi)++] = new_move(i, i, rotations[j]);
|
380
363
|
}
|
381
364
|
}
|
382
365
|
|
383
|
-
void find_valid_scarab_moves(int i, Move *valid_moves, int *vi)
|
384
|
-
{
|
385
|
-
for (int j = 0; j < 8; j++)
|
386
|
-
{
|
366
|
+
void find_valid_scarab_moves(int i, Move *valid_moves, int *vi) {
|
367
|
+
for (int j = 0; j < 8; j++) {
|
387
368
|
int dest = i + directions[j];
|
388
|
-
if (can_move[whose_turn][dest])
|
389
|
-
|
390
|
-
if (!is_piece(board[dest]) || get_piece(board[dest]) != Pharaoh)
|
391
|
-
{
|
369
|
+
if (can_move[whose_turn][dest]) {
|
370
|
+
if (!is_piece(board[dest]) || (get_owner(board[dest]) != whose_turn && get_piece(board[dest]) != PHARAOH)) {
|
392
371
|
valid_moves[(*vi)++] = new_move(i, dest, 0);
|
393
372
|
}
|
394
373
|
}
|
395
374
|
}
|
396
|
-
for (int j = 0; j < 2; j++)
|
397
|
-
{
|
375
|
+
for (int j = 0; j < 2; j++) {
|
398
376
|
valid_moves[(*vi)++] = new_move(i, i, rotations[j]);
|
399
377
|
}
|
400
378
|
}
|
401
379
|
|
402
|
-
void find_valid_pharaoh_moves(int i, Move *valid_moves, int *vi)
|
403
|
-
{
|
404
|
-
for (int j = 0; j < 8; j++)
|
405
|
-
{
|
380
|
+
void find_valid_pharaoh_moves(int i, Move *valid_moves, int *vi) {
|
381
|
+
for (int j = 0; j < 8; j++) {
|
406
382
|
int dest = i + directions[j];
|
407
|
-
if (!is_piece(board[dest]) && can_move[whose_turn][dest])
|
408
|
-
{
|
383
|
+
if (!is_piece(board[dest]) && can_move[whose_turn][dest]) {
|
409
384
|
valid_moves[(*vi)++] = new_move(i, dest, 0);
|
410
385
|
}
|
411
386
|
}
|
412
387
|
}
|
413
388
|
|
414
|
-
void find_valid_sphinx_moves(int i, Move *valid_moves, int *vi)
|
415
|
-
{
|
389
|
+
void find_valid_sphinx_moves(int i, Move *valid_moves, int *vi) {
|
416
390
|
enum Player player = get_owner(board[i]);
|
417
391
|
enum Orientation orientation = get_orientation(board[i]);
|
418
|
-
int rotation = player ==
|
392
|
+
int rotation = player == SILVER ? (orientation == NORTH ? -1 : 1) : (orientation == SOUTH ? -1 : 1);
|
419
393
|
valid_moves[(*vi)++] = new_move(i, i, rotation);
|
420
394
|
}
|
421
395
|
|
422
|
-
void init_zobrist()
|
423
|
-
{
|
424
|
-
|
425
|
-
{
|
426
|
-
for (int j = 0; j < 120; j++)
|
427
|
-
{
|
396
|
+
void init_zobrist() {
|
397
|
+
for (int i = 0; i < 0xFF; i++) {
|
398
|
+
for (int j = 0; j < 120; j++) {
|
428
399
|
keys[i][j] = random_number();
|
429
400
|
}
|
430
401
|
}
|
431
402
|
turn_key = random_number();
|
432
403
|
}
|
433
404
|
|
434
|
-
uint64_t get_board_hash()
|
435
|
-
{
|
405
|
+
uint64_t get_board_hash() {
|
436
406
|
uint64_t hash = 0;
|
437
|
-
for (int i = 0; i < 120; i++)
|
438
|
-
{
|
407
|
+
for (int i = 0; i < 120; i++) {
|
439
408
|
if (is_piece(board[i]))
|
440
409
|
hash ^= keys[board[i]][i];
|
441
410
|
}
|
@@ -444,97 +413,116 @@ uint64_t get_board_hash()
|
|
444
413
|
return hash;
|
445
414
|
}
|
446
415
|
|
447
|
-
|
448
|
-
{
|
416
|
+
void init_piece_trackers() {
|
417
|
+
for (int i = 0; i < 13; i++) {
|
418
|
+
piece_trackers[SILVER].positions[i] = EPT;
|
419
|
+
piece_trackers[RED].positions[i] = EPT;
|
420
|
+
}
|
421
|
+
|
422
|
+
int si = 0;
|
423
|
+
int ri = 0;
|
424
|
+
|
425
|
+
for (int i = 0; i < 120; i++) {
|
426
|
+
Square s = board[i];
|
427
|
+
if (is_piece(s)) {
|
428
|
+
if (get_owner(s) == SILVER) {
|
429
|
+
piece_trackers[SILVER].positions[si] = i;
|
430
|
+
piece_trackers[SILVER].board_idx_position[i] = si;
|
431
|
+
si++;
|
432
|
+
} else if (get_owner(s) == RED) {
|
433
|
+
piece_trackers[RED].positions[ri] = i;
|
434
|
+
piece_trackers[RED].board_idx_position[i] = ri;
|
435
|
+
ri++;
|
436
|
+
}
|
437
|
+
} else {
|
438
|
+
piece_trackers[SILVER].board_idx_position[i] = EPT;
|
439
|
+
piece_trackers[RED].board_idx_position[i] = EPT;
|
440
|
+
}
|
441
|
+
}
|
442
|
+
}
|
443
|
+
|
444
|
+
bool is_move_legal(Move move) {
|
449
445
|
int start = get_start(move);
|
450
446
|
int end = get_end(move);
|
451
|
-
if (is_piece(board[start]) && get_owner(board[start]) == whose_turn)
|
452
|
-
{
|
447
|
+
if (is_piece(board[start]) && get_owner(board[start]) == whose_turn) {
|
453
448
|
if (!is_piece(board[end]) || get_rotation(move) != 0)
|
454
449
|
return true;
|
455
|
-
else if (is_piece(board[end]) && get_piece(board[start]) ==
|
450
|
+
else if (is_piece(board[end]) && get_piece(board[start]) == SCARAB && get_piece(board[end]) <= 3)
|
456
451
|
return true;
|
457
452
|
}
|
458
453
|
return false;
|
459
454
|
}
|
460
455
|
|
461
|
-
void reset_undo()
|
462
|
-
{
|
456
|
+
void reset_undo() {
|
463
457
|
undo_index = 0;
|
464
|
-
for (int i = 0; i < MAX_DEPTH; i++)
|
465
|
-
{
|
458
|
+
for (int i = 0; i < MAX_DEPTH; i++) {
|
466
459
|
undo_moves[i] = 0;
|
467
460
|
undo_capture_indices[i] = 0;
|
468
461
|
undo_capture_squares[i] = 0;
|
469
462
|
}
|
470
463
|
}
|
471
464
|
|
472
|
-
void setup_board(char *init_board[120])
|
473
|
-
|
474
|
-
move_num = 0;
|
465
|
+
void setup_board(char *init_board[120]) {
|
466
|
+
hashes_index = 0;
|
475
467
|
uint64_t hash = 0;
|
476
|
-
for (int i = 0; i < 120; i++)
|
477
|
-
{
|
468
|
+
for (int i = 0; i < 120; i++) {
|
478
469
|
board[i] = str_to_square(init_board[i]);
|
479
470
|
Square s = board[i];
|
480
|
-
if (is_piece(s))
|
481
|
-
{
|
471
|
+
if (is_piece(s)) {
|
482
472
|
hash ^= keys[s][i];
|
483
|
-
if (get_piece(s) ==
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
pharaoh_loc[Red] = i;
|
473
|
+
if (get_piece(s) == PHARAOH) {
|
474
|
+
if (get_owner(s) == SILVER)
|
475
|
+
pharaoh_loc[SILVER] = i;
|
476
|
+
else if (get_owner(s) == RED)
|
477
|
+
pharaoh_loc[RED] = i;
|
489
478
|
}
|
490
479
|
}
|
491
480
|
}
|
492
|
-
hashes[
|
481
|
+
hashes[hashes_index] = hash;
|
493
482
|
|
494
|
-
for (int i = 0; i < TABLE_SIZE; i++)
|
495
|
-
{
|
483
|
+
for (int i = 0; i < TABLE_SIZE; i++) {
|
496
484
|
table[i].key = 0;
|
497
485
|
table[i].depth = 0;
|
498
486
|
table[i].flag = 0;
|
499
487
|
table[i].score = 0;
|
500
488
|
table[i].move = 0;
|
501
489
|
}
|
490
|
+
|
491
|
+
init_piece_trackers();
|
502
492
|
}
|
503
493
|
|
504
|
-
Square str_to_square(char *str)
|
505
|
-
{
|
494
|
+
Square str_to_square(char *str) {
|
506
495
|
enum Player player;
|
507
496
|
enum Piece piece;
|
508
497
|
enum Orientation orientation;
|
509
498
|
|
510
|
-
if (str[0] != '-')
|
511
|
-
{
|
499
|
+
if (str[0] != '-') {
|
512
500
|
if (islower(str[0]))
|
513
|
-
player =
|
501
|
+
player = SILVER;
|
514
502
|
else
|
515
|
-
player =
|
503
|
+
player = RED;
|
516
504
|
|
517
505
|
char p = tolower(str[0]);
|
518
506
|
if (p == 'a')
|
519
|
-
piece =
|
507
|
+
piece = ANUBIS;
|
520
508
|
else if (p == 'p')
|
521
|
-
piece =
|
509
|
+
piece = PYRAMID;
|
522
510
|
else if (p == 's')
|
523
|
-
piece =
|
511
|
+
piece = SCARAB;
|
524
512
|
else if (p == 'x')
|
525
|
-
piece =
|
513
|
+
piece = PHARAOH;
|
526
514
|
else
|
527
|
-
piece =
|
515
|
+
piece = SPHINX;
|
528
516
|
|
529
517
|
char o = str[1];
|
530
518
|
if (o == '0')
|
531
|
-
orientation =
|
519
|
+
orientation = NORTH;
|
532
520
|
else if (o == '1')
|
533
|
-
orientation =
|
521
|
+
orientation = EAST;
|
534
522
|
else if (o == '2')
|
535
|
-
orientation =
|
523
|
+
orientation = SOUTH;
|
536
524
|
else
|
537
|
-
orientation =
|
525
|
+
orientation = WEST;
|
538
526
|
|
539
527
|
return (Square)((int)player << 1 | (int)piece << 2 | (int)orientation << 5);
|
540
528
|
}
|
@@ -542,55 +530,50 @@ Square str_to_square(char *str)
|
|
542
530
|
return (Square)0;
|
543
531
|
}
|
544
532
|
|
545
|
-
void print_board()
|
546
|
-
{
|
547
|
-
for (int i = 0; i < 120; i++)
|
548
|
-
{
|
533
|
+
void print_board() {
|
534
|
+
for (int i = 0; i < 120; i++) {
|
549
535
|
print_piece(board[i]);
|
550
536
|
if ((i + 1) % 12 == 0)
|
551
537
|
printf("\n");
|
552
538
|
}
|
553
539
|
}
|
554
540
|
|
555
|
-
void print_piece(Square s)
|
556
|
-
{
|
541
|
+
void print_piece(Square s) {
|
557
542
|
enum Player player = get_owner(s);
|
558
|
-
if (is_piece(s))
|
559
|
-
{
|
543
|
+
if (is_piece(s)) {
|
560
544
|
enum Piece piece = get_piece(s);
|
561
545
|
enum Orientation orientation = get_orientation(s);
|
562
|
-
switch (piece)
|
563
|
-
|
564
|
-
|
565
|
-
if (player == Silver)
|
546
|
+
switch (piece) {
|
547
|
+
case ANUBIS:
|
548
|
+
if (player == SILVER)
|
566
549
|
printf("a");
|
567
550
|
else
|
568
551
|
printf("A");
|
569
552
|
break;
|
570
553
|
|
571
|
-
case
|
572
|
-
if (player ==
|
554
|
+
case PYRAMID:
|
555
|
+
if (player == SILVER)
|
573
556
|
printf("p");
|
574
557
|
else
|
575
558
|
printf("P");
|
576
559
|
break;
|
577
560
|
|
578
|
-
case
|
579
|
-
if (player ==
|
561
|
+
case SCARAB:
|
562
|
+
if (player == SILVER)
|
580
563
|
printf("s");
|
581
564
|
else
|
582
565
|
printf("S");
|
583
566
|
break;
|
584
567
|
|
585
|
-
case
|
586
|
-
if (player ==
|
568
|
+
case PHARAOH:
|
569
|
+
if (player == SILVER)
|
587
570
|
printf("x");
|
588
571
|
else
|
589
572
|
printf("X");
|
590
573
|
break;
|
591
574
|
|
592
|
-
case
|
593
|
-
if (player ==
|
575
|
+
case SPHINX:
|
576
|
+
if (player == SILVER)
|
594
577
|
printf("l");
|
595
578
|
else
|
596
579
|
printf("L");
|
@@ -599,26 +582,24 @@ void print_piece(Square s)
|
|
599
582
|
printf("-");
|
600
583
|
break;
|
601
584
|
}
|
602
|
-
switch (orientation)
|
603
|
-
|
604
|
-
case North:
|
585
|
+
switch (orientation) {
|
586
|
+
case NORTH:
|
605
587
|
printf("0");
|
606
588
|
break;
|
607
|
-
case
|
589
|
+
case EAST:
|
608
590
|
printf("1");
|
609
591
|
break;
|
610
|
-
case
|
592
|
+
case SOUTH:
|
611
593
|
printf("2");
|
612
594
|
break;
|
613
|
-
case
|
595
|
+
case WEST:
|
614
596
|
printf("3");
|
615
597
|
break;
|
616
598
|
default:
|
617
599
|
printf("-");
|
618
600
|
break;
|
619
601
|
}
|
620
|
-
}
|
621
|
-
else
|
602
|
+
} else
|
622
603
|
printf("--");
|
623
604
|
}
|
624
605
|
|
@@ -626,8 +607,7 @@ int get_start_wrapper(Move move) { return get_start(move); }
|
|
626
607
|
int get_end_wrapper(Move move) { return get_end(move); }
|
627
608
|
int get_rotation_wrapper(Move move) { return get_rotation(move); }
|
628
609
|
|
629
|
-
void set_time_parameters(int _max_time, time_t _start_time)
|
630
|
-
{
|
610
|
+
void set_time_parameters(int _max_time, time_t _start_time) {
|
631
611
|
max_time = _max_time;
|
632
612
|
start_time = _start_time;
|
633
613
|
}
|