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