khetai 0.2.3 → 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/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 +13 -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 -257
- 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,97 +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
|
-
|
474
|
-
move_num = 0;
|
448
|
+
void setup_board(char *init_board[120]) {
|
449
|
+
hashes_index = 0;
|
475
450
|
uint64_t hash = 0;
|
476
|
-
for (int i = 0; i < 120; i++)
|
477
|
-
{
|
451
|
+
for (int i = 0; i < 120; i++) {
|
478
452
|
board[i] = str_to_square(init_board[i]);
|
479
453
|
Square s = board[i];
|
480
|
-
if (is_piece(s))
|
481
|
-
{
|
454
|
+
if (is_piece(s)) {
|
482
455
|
hash ^= keys[s][i];
|
483
|
-
if (get_piece(s) ==
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
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;
|
489
461
|
}
|
490
462
|
}
|
491
463
|
}
|
492
|
-
hashes[
|
464
|
+
hashes[hashes_index] = hash;
|
493
465
|
|
494
|
-
for (int i = 0; i < TABLE_SIZE; i++)
|
495
|
-
{
|
466
|
+
for (int i = 0; i < TABLE_SIZE; i++) {
|
496
467
|
table[i].key = 0;
|
497
468
|
table[i].depth = 0;
|
498
469
|
table[i].flag = 0;
|
499
470
|
table[i].score = 0;
|
500
471
|
table[i].move = 0;
|
501
472
|
}
|
473
|
+
|
474
|
+
init_piece_trackers();
|
502
475
|
}
|
503
476
|
|
504
|
-
Square str_to_square(char *str)
|
505
|
-
{
|
477
|
+
Square str_to_square(char *str) {
|
506
478
|
enum Player player;
|
507
479
|
enum Piece piece;
|
508
480
|
enum Orientation orientation;
|
509
481
|
|
510
|
-
if (str[0] != '-')
|
511
|
-
{
|
482
|
+
if (str[0] != '-') {
|
512
483
|
if (islower(str[0]))
|
513
|
-
player =
|
484
|
+
player = SILVER;
|
514
485
|
else
|
515
|
-
player =
|
486
|
+
player = RED;
|
516
487
|
|
517
488
|
char p = tolower(str[0]);
|
518
489
|
if (p == 'a')
|
519
|
-
piece =
|
490
|
+
piece = ANUBIS;
|
520
491
|
else if (p == 'p')
|
521
|
-
piece =
|
492
|
+
piece = PYRAMID;
|
522
493
|
else if (p == 's')
|
523
|
-
piece =
|
494
|
+
piece = SCARAB;
|
524
495
|
else if (p == 'x')
|
525
|
-
piece =
|
496
|
+
piece = PHARAOH;
|
526
497
|
else
|
527
|
-
piece =
|
498
|
+
piece = SPHINX;
|
528
499
|
|
529
500
|
char o = str[1];
|
530
501
|
if (o == '0')
|
531
|
-
orientation =
|
502
|
+
orientation = NORTH;
|
532
503
|
else if (o == '1')
|
533
|
-
orientation =
|
504
|
+
orientation = EAST;
|
534
505
|
else if (o == '2')
|
535
|
-
orientation =
|
506
|
+
orientation = SOUTH;
|
536
507
|
else
|
537
|
-
orientation =
|
508
|
+
orientation = WEST;
|
538
509
|
|
539
510
|
return (Square)((int)player << 1 | (int)piece << 2 | (int)orientation << 5);
|
540
511
|
}
|
@@ -542,55 +513,50 @@ Square str_to_square(char *str)
|
|
542
513
|
return (Square)0;
|
543
514
|
}
|
544
515
|
|
545
|
-
void print_board()
|
546
|
-
{
|
547
|
-
for (int i = 0; i < 120; i++)
|
548
|
-
{
|
516
|
+
void print_board() {
|
517
|
+
for (int i = 0; i < 120; i++) {
|
549
518
|
print_piece(board[i]);
|
550
519
|
if ((i + 1) % 12 == 0)
|
551
520
|
printf("\n");
|
552
521
|
}
|
553
522
|
}
|
554
523
|
|
555
|
-
void print_piece(Square s)
|
556
|
-
{
|
524
|
+
void print_piece(Square s) {
|
557
525
|
enum Player player = get_owner(s);
|
558
|
-
if (is_piece(s))
|
559
|
-
{
|
526
|
+
if (is_piece(s)) {
|
560
527
|
enum Piece piece = get_piece(s);
|
561
528
|
enum Orientation orientation = get_orientation(s);
|
562
|
-
switch (piece)
|
563
|
-
|
564
|
-
|
565
|
-
if (player == Silver)
|
529
|
+
switch (piece) {
|
530
|
+
case ANUBIS:
|
531
|
+
if (player == SILVER)
|
566
532
|
printf("a");
|
567
533
|
else
|
568
534
|
printf("A");
|
569
535
|
break;
|
570
536
|
|
571
|
-
case
|
572
|
-
if (player ==
|
537
|
+
case PYRAMID:
|
538
|
+
if (player == SILVER)
|
573
539
|
printf("p");
|
574
540
|
else
|
575
541
|
printf("P");
|
576
542
|
break;
|
577
543
|
|
578
|
-
case
|
579
|
-
if (player ==
|
544
|
+
case SCARAB:
|
545
|
+
if (player == SILVER)
|
580
546
|
printf("s");
|
581
547
|
else
|
582
548
|
printf("S");
|
583
549
|
break;
|
584
550
|
|
585
|
-
case
|
586
|
-
if (player ==
|
551
|
+
case PHARAOH:
|
552
|
+
if (player == SILVER)
|
587
553
|
printf("x");
|
588
554
|
else
|
589
555
|
printf("X");
|
590
556
|
break;
|
591
557
|
|
592
|
-
case
|
593
|
-
if (player ==
|
558
|
+
case SPHINX:
|
559
|
+
if (player == SILVER)
|
594
560
|
printf("l");
|
595
561
|
else
|
596
562
|
printf("L");
|
@@ -599,26 +565,24 @@ void print_piece(Square s)
|
|
599
565
|
printf("-");
|
600
566
|
break;
|
601
567
|
}
|
602
|
-
switch (orientation)
|
603
|
-
|
604
|
-
case North:
|
568
|
+
switch (orientation) {
|
569
|
+
case NORTH:
|
605
570
|
printf("0");
|
606
571
|
break;
|
607
|
-
case
|
572
|
+
case EAST:
|
608
573
|
printf("1");
|
609
574
|
break;
|
610
|
-
case
|
575
|
+
case SOUTH:
|
611
576
|
printf("2");
|
612
577
|
break;
|
613
|
-
case
|
578
|
+
case WEST:
|
614
579
|
printf("3");
|
615
580
|
break;
|
616
581
|
default:
|
617
582
|
printf("-");
|
618
583
|
break;
|
619
584
|
}
|
620
|
-
}
|
621
|
-
else
|
585
|
+
} else
|
622
586
|
printf("--");
|
623
587
|
}
|
624
588
|
|
@@ -626,8 +590,7 @@ int get_start_wrapper(Move move) { return get_start(move); }
|
|
626
590
|
int get_end_wrapper(Move move) { return get_end(move); }
|
627
591
|
int get_rotation_wrapper(Move move) { return get_rotation(move); }
|
628
592
|
|
629
|
-
void set_time_parameters(int _max_time, time_t _start_time)
|
630
|
-
{
|
593
|
+
void set_time_parameters(int _max_time, time_t _start_time) {
|
631
594
|
max_time = _max_time;
|
632
595
|
start_time = _start_time;
|
633
596
|
}
|