khetai 0.2.3 → 0.3.2
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/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
|
}
|