khetai 0.2.2 → 0.3.0
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/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
|
}
|