khetai 0.1.6 → 0.1.7
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/.gitignore +1 -0
- data/Gemfile.lock +1 -1
- data/README.md +6 -1
- data/ext/khetai/dev/CMakeLists.txt +5 -0
- data/ext/khetai/dev/main.c +50 -0
- data/ext/khetai/dev/main.rb +15 -0
- data/ext/khetai/khetai_lib.c +102 -63
- data/ext/khetai/khetai_lib.h +5 -1
- data/lib/khetai/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 57b893b2ca7a9ab8690ce116801bbd6286bc5856c7f87d01b7d51a7bbd6cc8f9
|
4
|
+
data.tar.gz: 433c4c67445b585526e598f6c04c53ca9e3ce67dab012a65aafa9922d18d8a80
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e85bedabf5229ac1abad59889e2d2980e0fe194ad42d3acff67fb72817ed6755b59798af3a7312836cc225bb044f1bc12641edb30f4693e37e91144581ac142
|
7
|
+
data.tar.gz: f7cb8d7735f580752ed50ca8f4cf084a5398bbac70d26b32da6c9a61049de9a79b68aceac685afe5a907ec8bea83ba24e72fcf3c991a88145996c5a8563b85e3
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# KhetAI
|
2
2
|
|
3
|
+
## Install
|
4
|
+
```
|
5
|
+
gem install khetai
|
6
|
+
```
|
7
|
+
|
3
8
|
## Usage
|
4
9
|
```
|
5
10
|
require 'khetai'
|
@@ -40,7 +45,7 @@ move = KhetAI.move(board, whose_turn, max_search_depth, max_search_time)
|
|
40
45
|
## Build and Deploy Commands
|
41
46
|
```
|
42
47
|
bundle exec rake compile
|
43
|
-
bundle
|
48
|
+
bundle exec rake build
|
44
49
|
bundle exec rake release
|
45
50
|
|
46
51
|
gem push pkg/<gem>
|
@@ -0,0 +1,50 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include <time.h>
|
4
|
+
#include "../khetai_lib.h"
|
5
|
+
|
6
|
+
char *init_board[120] =
|
7
|
+
{"--", "--", "--", "--", "--", "--", "--", "--", "--", "--", "--", "--",
|
8
|
+
"--", "L2", "--", "--", "--", "A2", "X2", "A2", "P1", "--", "--", "--",
|
9
|
+
"--", "--", "--", "P2", "--", "--", "--", "--", "--", "--", "--", "--",
|
10
|
+
"--", "--", "--", "--", "p3", "--", "--", "--", "--", "--", "--", "--",
|
11
|
+
"--", "P0", "--", "p2", "--", "S2", "S3", "--", "P1", "--", "p3", "--",
|
12
|
+
"--", "P1", "--", "p3", "--", "s1", "s0", "--", "P0", "--", "p2", "--",
|
13
|
+
"--", "--", "--", "--", "--", "--", "--", "P1", "--", "--", "--", "--",
|
14
|
+
"--", "--", "--", "--", "--", "--", "--", "--", "p0", "--", "--", "--",
|
15
|
+
"--", "--", "--", "p3", "a0", "x0", "a0", "--", "--", "--", "l0", "--",
|
16
|
+
"--", "--", "--", "--", "--", "--", "--", "--", "--", "--", "--", "--"};
|
17
|
+
|
18
|
+
time_t start_time;
|
19
|
+
int max_time;
|
20
|
+
|
21
|
+
int main()
|
22
|
+
{
|
23
|
+
init_zobrist();
|
24
|
+
srand((unsigned)time(NULL));
|
25
|
+
|
26
|
+
setup_board(init_board);
|
27
|
+
print_board();
|
28
|
+
|
29
|
+
start_time = time(NULL);
|
30
|
+
max_time = 5;
|
31
|
+
int max_depth = 25;
|
32
|
+
|
33
|
+
int depth = 1;
|
34
|
+
Move best_move = (Move)0;
|
35
|
+
Move current_move = (Move)0;
|
36
|
+
while ((time(NULL) - start_time < max_time) && (depth <= max_depth))
|
37
|
+
{
|
38
|
+
best_move = current_move;
|
39
|
+
current_move = alphabeta_root(depth, Red);
|
40
|
+
depth++;
|
41
|
+
}
|
42
|
+
make_move(best_move);
|
43
|
+
|
44
|
+
printf("\n========================\n\n");
|
45
|
+
print_board();
|
46
|
+
|
47
|
+
printf("\nDEPTH: %d\n", depth - 1);
|
48
|
+
|
49
|
+
return 0;
|
50
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative "../../../lib/khetai/khetai.so"
|
2
|
+
|
3
|
+
board = ["--", "--", "--", "--", "--", "--", "--", "--", "--", "--", "--", "--",
|
4
|
+
"--", "L2", "--", "--", "--", "A2", "X2", "A2", "P1", "--", "--", "--",
|
5
|
+
"--", "--", "--", "P2", "--", "--", "--", "--", "--", "--", "--", "--",
|
6
|
+
"--", "--", "--", "--", "p3", "--", "--", "--", "--", "--", "--", "--",
|
7
|
+
"--", "P0", "--", "p2", "--", "S2", "S3", "--", "P1", "--", "p3", "--",
|
8
|
+
"--", "P1", "--", "p3", "--", "s1", "s0", "--", "P0", "--", "p2", "--",
|
9
|
+
"--", "--", "--", "--", "--", "--", "--", "P1", "--", "--", "--", "--",
|
10
|
+
"--", "--", "--", "--", "--", "--", "--", "--", "p0", "--", "--", "--",
|
11
|
+
"--", "--", "--", "p3", "a0", "x0", "a0", "--", "--", "--", "l0", "--",
|
12
|
+
"--", "--", "--", "--", "--", "--", "--", "--", "--", "--", "--", "--"]
|
13
|
+
|
14
|
+
move = KhetAI.move(board, 1, 6, 5)
|
15
|
+
puts move.to_s
|
data/ext/khetai/khetai_lib.c
CHANGED
@@ -5,7 +5,9 @@
|
|
5
5
|
#include "khetai_lib.h"
|
6
6
|
|
7
7
|
Square board[120] = {0};
|
8
|
+
int pharaoh_loc[2] = {0};
|
8
9
|
enum Player whose_turn;
|
10
|
+
enum Player starter;
|
9
11
|
|
10
12
|
Move undo_moves[MAX_DEPTH] = {0};
|
11
13
|
int undo_capture_indices[MAX_DEPTH] = {0};
|
@@ -23,6 +25,7 @@ bool checkmate = false;
|
|
23
25
|
Move alphabeta_root(int depth, enum Player player)
|
24
26
|
{
|
25
27
|
whose_turn = player;
|
28
|
+
starter = player;
|
26
29
|
int best_score = -MAX_SCORE;
|
27
30
|
Move best_move = (Move)0;
|
28
31
|
int alpha = -MAX_SCORE;
|
@@ -145,24 +148,27 @@ int calculate_score()
|
|
145
148
|
{
|
146
149
|
int score = 0;
|
147
150
|
int anubis_score = 500;
|
148
|
-
int scarab_score = 750;
|
149
151
|
int pyramid_score = 1000;
|
150
152
|
int pharaoh_score = 100000;
|
151
153
|
for (int i = 0; i < 120; i++)
|
152
154
|
{
|
153
|
-
|
155
|
+
Square s = board[i];
|
156
|
+
if (is_piece(s))
|
154
157
|
{
|
155
158
|
int value = 0;
|
156
|
-
switch (get_piece(
|
159
|
+
switch (get_piece(s))
|
157
160
|
{
|
158
161
|
case Anubis:
|
159
162
|
value += anubis_score;
|
163
|
+
value -= distance_from_pharaoh(i, pharaoh_loc[get_owner(s)]) * 10;
|
160
164
|
break;
|
161
165
|
case Pyramid:
|
162
166
|
value += pyramid_score;
|
167
|
+
value += rand() % 20;
|
163
168
|
break;
|
164
169
|
case Scarab:
|
165
|
-
value +=
|
170
|
+
value += 100 / (distance_from_pharaoh(i, pharaoh_loc[opposite_player(get_owner(s))])) * 10;
|
171
|
+
value += rand() % 10;
|
166
172
|
break;
|
167
173
|
case Pharaoh:
|
168
174
|
value += pharaoh_score;
|
@@ -170,10 +176,20 @@ int calculate_score()
|
|
170
176
|
default:
|
171
177
|
break;
|
172
178
|
}
|
173
|
-
score += get_owner(
|
179
|
+
score += get_owner(s) == Red ? value : -value;
|
174
180
|
}
|
175
181
|
}
|
176
|
-
return score
|
182
|
+
return score;
|
183
|
+
}
|
184
|
+
|
185
|
+
int distance_from_pharaoh(int i, int p)
|
186
|
+
{
|
187
|
+
int px = p / 12;
|
188
|
+
int py = p % 12;
|
189
|
+
int ix = i / 12;
|
190
|
+
int iy = i % 12;
|
191
|
+
int m_distance = abs(px - ix) + abs(py - iy);
|
192
|
+
return m_distance;
|
177
193
|
}
|
178
194
|
|
179
195
|
void make_move(Move move)
|
@@ -204,9 +220,12 @@ void make_move(Move move)
|
|
204
220
|
// add starting piece to end location
|
205
221
|
hash ^= keys[board[end]][end];
|
206
222
|
|
207
|
-
// add ending piece to start
|
223
|
+
// add ending piece to start location if swapping
|
208
224
|
if (is_piece(board[start]))
|
209
225
|
hash ^= keys[board[start]][start];
|
226
|
+
|
227
|
+
if (get_piece(moving_piece) == Pharaoh)
|
228
|
+
pharaoh_loc[whose_turn] = end;
|
210
229
|
}
|
211
230
|
|
212
231
|
undo_moves[undo_index] = new_move(end, start, -rotation);
|
@@ -214,6 +233,9 @@ void make_move(Move move)
|
|
214
233
|
fire_laser(&hash);
|
215
234
|
hash ^= turn_key;
|
216
235
|
|
236
|
+
// testing that hashing works properly
|
237
|
+
// printf("\nHASH:\t%lu\nBOARD:\t%lu\n", hash, get_board_hash());
|
238
|
+
|
217
239
|
hashes[move_num] = hash;
|
218
240
|
undo_index++;
|
219
241
|
}
|
@@ -228,18 +250,20 @@ void fire_laser(uint64_t *hash)
|
|
228
250
|
i = i + directions[laser_dir];
|
229
251
|
if (i >= 0 && i < 120 && on_board[i] == 1)
|
230
252
|
{
|
231
|
-
|
253
|
+
Square s = board[i];
|
254
|
+
if (is_piece(s))
|
232
255
|
{
|
233
|
-
int piece = get_piece(
|
234
|
-
int orientation = get_orientation(
|
256
|
+
int piece = get_piece(s) - 1;
|
257
|
+
int orientation = get_orientation(s);
|
235
258
|
int result = reflections[laser_dir][piece][orientation];
|
236
259
|
if (result == Dead)
|
237
260
|
{
|
238
|
-
if (get_piece(
|
261
|
+
if (get_piece(s) == Pharaoh)
|
239
262
|
checkmate = true;
|
240
|
-
|
263
|
+
// remove piece
|
264
|
+
*hash ^= keys[s][i];
|
241
265
|
undo_capture_indices[undo_index] = i;
|
242
|
-
undo_capture_squares[undo_index] =
|
266
|
+
undo_capture_squares[undo_index] = s;
|
243
267
|
board[i] = (Square)0;
|
244
268
|
traversing = false;
|
245
269
|
}
|
@@ -288,6 +312,9 @@ void undo_move()
|
|
288
312
|
Square moving_piece = board[start];
|
289
313
|
board[start] = board[end];
|
290
314
|
board[end] = moving_piece;
|
315
|
+
|
316
|
+
if (get_piece(moving_piece) == Pharaoh)
|
317
|
+
pharaoh_loc[get_owner(board[end])] = end;
|
291
318
|
}
|
292
319
|
checkmate = false;
|
293
320
|
}
|
@@ -387,14 +414,74 @@ void find_valid_sphinx_moves(int i, Move *valid_moves, int *vi)
|
|
387
414
|
valid_moves[(*vi)++] = new_move(i, i, rotation);
|
388
415
|
}
|
389
416
|
|
417
|
+
void init_zobrist()
|
418
|
+
{
|
419
|
+
for (int i = 0; i < 0xFF; i++)
|
420
|
+
{
|
421
|
+
for (int j = 0; j < 120; j++)
|
422
|
+
{
|
423
|
+
keys[i][j] = random_number();
|
424
|
+
}
|
425
|
+
}
|
426
|
+
turn_key = random_number();
|
427
|
+
}
|
428
|
+
|
429
|
+
uint64_t get_board_hash()
|
430
|
+
{
|
431
|
+
uint64_t hash = 0;
|
432
|
+
for (int i = 0; i < 120; i++)
|
433
|
+
{
|
434
|
+
if (is_piece(board[i]))
|
435
|
+
hash ^= keys[board[i]][i];
|
436
|
+
}
|
437
|
+
if (whose_turn == starter)
|
438
|
+
hash ^= turn_key;
|
439
|
+
return hash;
|
440
|
+
}
|
441
|
+
|
442
|
+
bool is_move_legal(Move move)
|
443
|
+
{
|
444
|
+
int start = get_start(move);
|
445
|
+
int end = get_end(move);
|
446
|
+
if (is_piece(board[start]) && get_owner(board[start]) == whose_turn)
|
447
|
+
{
|
448
|
+
if (!is_piece(board[end]) || get_rotation(move) != 0)
|
449
|
+
return true;
|
450
|
+
else if (is_piece(board[end]) && get_piece(board[start]) == Scarab && get_piece(board[end]) < 3)
|
451
|
+
return true;
|
452
|
+
}
|
453
|
+
return false;
|
454
|
+
}
|
455
|
+
|
456
|
+
void reset_undo()
|
457
|
+
{
|
458
|
+
undo_index = 0;
|
459
|
+
for (int i = 0; i < MAX_DEPTH; i++)
|
460
|
+
{
|
461
|
+
undo_moves[i] = 0;
|
462
|
+
undo_capture_indices[i] = 0;
|
463
|
+
undo_capture_squares[i] = 0;
|
464
|
+
}
|
465
|
+
}
|
466
|
+
|
390
467
|
void setup_board(char *init_board[120])
|
391
468
|
{
|
392
469
|
uint64_t hash = 0;
|
393
470
|
for (int i = 0; i < 120; i++)
|
394
471
|
{
|
395
472
|
board[i] = str_to_square(init_board[i]);
|
396
|
-
|
397
|
-
|
473
|
+
Square s = board[i];
|
474
|
+
if (is_piece(s))
|
475
|
+
{
|
476
|
+
hash ^= keys[s][i];
|
477
|
+
if (get_piece(s) == Pharaoh)
|
478
|
+
{
|
479
|
+
if (get_owner(s) == Silver)
|
480
|
+
pharaoh_loc[Silver] = i;
|
481
|
+
else if (get_owner(s) == Red)
|
482
|
+
pharaoh_loc[Red] = i;
|
483
|
+
}
|
484
|
+
}
|
398
485
|
}
|
399
486
|
hashes[0] = hash;
|
400
487
|
|
@@ -528,51 +615,3 @@ void print_piece(Square s)
|
|
528
615
|
else
|
529
616
|
printf("--");
|
530
617
|
}
|
531
|
-
|
532
|
-
void reset_undo()
|
533
|
-
{
|
534
|
-
undo_index = 0;
|
535
|
-
for (int i = 0; i < MAX_DEPTH; i++)
|
536
|
-
{
|
537
|
-
undo_moves[i] = 0;
|
538
|
-
undo_capture_indices[i] = 0;
|
539
|
-
undo_capture_squares[i] = 0;
|
540
|
-
}
|
541
|
-
}
|
542
|
-
|
543
|
-
void init_zobrist()
|
544
|
-
{
|
545
|
-
for (int i = 0; i < 0xFF; i++)
|
546
|
-
{
|
547
|
-
for (int j = 0; j < 120; j++)
|
548
|
-
{
|
549
|
-
keys[i][j] = random_number();
|
550
|
-
}
|
551
|
-
}
|
552
|
-
turn_key = random_number();
|
553
|
-
}
|
554
|
-
|
555
|
-
bool is_move_legal(Move move)
|
556
|
-
{
|
557
|
-
int start = get_start(move);
|
558
|
-
int end = get_end(move);
|
559
|
-
if (is_piece(board[start]) && get_owner(board[start]) == whose_turn)
|
560
|
-
{
|
561
|
-
if (!is_piece(board[end]) || get_rotation(move) != 0)
|
562
|
-
return true;
|
563
|
-
else if (is_piece(board[end]) && get_piece(board[start]) == Scarab && get_piece(board[end]) < 3)
|
564
|
-
return true;
|
565
|
-
}
|
566
|
-
return false;
|
567
|
-
}
|
568
|
-
|
569
|
-
uint64_t get_board_hash()
|
570
|
-
{
|
571
|
-
uint64_t hash = 0;
|
572
|
-
for (int i = 0; i < 120; i++)
|
573
|
-
{
|
574
|
-
if (board[i] > 0)
|
575
|
-
hash ^= keys[board[i]][i];
|
576
|
-
}
|
577
|
-
return hash;
|
578
|
-
}
|
data/ext/khetai/khetai_lib.h
CHANGED
@@ -33,12 +33,15 @@ enum Orientation
|
|
33
33
|
};
|
34
34
|
|
35
35
|
extern enum Player whose_turn;
|
36
|
+
extern enum Player starter;
|
36
37
|
|
37
38
|
// north, east, south, west, diagonals
|
38
39
|
static const int directions[8] = {-12, 1, 12, -1, (12 + 1), (12 - 1), (-12 + 1), (-12 - 1)};
|
39
40
|
static const int rotations[2] = {1, -1};
|
40
41
|
static const int sphinx_loc[2] = {106, 13};
|
41
42
|
|
43
|
+
extern int pharaoh_loc[2];
|
44
|
+
|
42
45
|
extern Square board[120];
|
43
46
|
extern Move undo_moves[MAX_DEPTH];
|
44
47
|
extern int undo_capture_indices[MAX_DEPTH];
|
@@ -95,6 +98,7 @@ extern void find_valid_sphinx_moves(int i, Move *valid_moves, int *vi);
|
|
95
98
|
extern Move alphabeta_root(int depth, enum Player player);
|
96
99
|
extern int alphabeta(int depth, enum Player player, int alpha, int beta);
|
97
100
|
extern int calculate_score();
|
101
|
+
extern int distance_from_pharaoh(int i, int p);
|
98
102
|
|
99
103
|
extern void make_move(Move move);
|
100
104
|
extern void undo_move();
|
@@ -166,6 +170,7 @@ extern int move_num;
|
|
166
170
|
extern bool checkmate;
|
167
171
|
|
168
172
|
extern void init_zobrist();
|
173
|
+
extern uint64_t get_board_hash();
|
169
174
|
static uint64_t seed = 1070372;
|
170
175
|
static inline uint64_t random_number()
|
171
176
|
{
|
@@ -192,6 +197,5 @@ typedef struct HashEntry
|
|
192
197
|
extern HashEntry table[TABLE_SIZE];
|
193
198
|
static inline HashEntry *search_table(uint64_t key) { return &table[key % TABLE_SIZE]; };
|
194
199
|
extern void insert_table(uint64_t key, int depth, int flag, int score, Move move);
|
195
|
-
extern uint64_t get_board_hash();
|
196
200
|
|
197
201
|
#endif // KHET_LIB_H_INCLUDED extern uint64_t get_board_hash();
|
data/lib/khetai/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: khetai
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jkugs
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-03-05 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -27,6 +27,9 @@ files:
|
|
27
27
|
- Rakefile
|
28
28
|
- bin/console
|
29
29
|
- bin/setup
|
30
|
+
- ext/khetai/dev/CMakeLists.txt
|
31
|
+
- ext/khetai/dev/main.c
|
32
|
+
- ext/khetai/dev/main.rb
|
30
33
|
- ext/khetai/extconf.rb
|
31
34
|
- ext/khetai/khetai.c
|
32
35
|
- ext/khetai/khetai_lib.c
|