khetai 0.3.2 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 397d91c1cb38ed6a3c61ef8132415e88c74fcd80c933b124b028515109c656a1
4
- data.tar.gz: 24b234943d22a75d358a3c4caa5723469d6ee98665e710ecdcc981288b975f11
3
+ metadata.gz: b0de4779baa3060126c239bcb22e4ed4cff09168f223d282b4653ee0b48a49c0
4
+ data.tar.gz: add3d7364b84a82e2268b2ae2e17ee3169a63e1191f7bbfefe036ffb9b727a64
5
5
  SHA512:
6
- metadata.gz: 1bd6ceb6036f2a11bdce881f176ccccfe247d2884aa647b2da423b81cc3ff36120fa56fac338b4aacb55edcb2e11a4b722c85b3633c7c307e0419f0cf5b5bb07
7
- data.tar.gz: ed3131f4fefe5bc2050a396bb39036b73782bbabc39756445806dbf6b07485a4503e119fcef4baaa491033d3c695bfde451efac6a9ca83aa5287197b0af18d55
6
+ metadata.gz: adeeb8e3bd8605661ad1a3a7a58cdcae7728bafc6c1fb329f4ba602600e103c25adcfbfbdbfc29390a28272df04d4f15a92ea84c55034c5b1ed77e7b0d103249
7
+ data.tar.gz: 184800f1ddfc7db6d7366a29e611e8edf8149177423ce9236ee685b6ed7aa6c3b6ecb1faffd520d6da6a68041daee91c34b00d5800cefd63f1a23e50b7f9437e
data/.gitignore CHANGED
@@ -7,6 +7,7 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
  /build/
10
+ /scripts/
10
11
  /ext/khetai/dev/build/
11
12
  /ext/khetai/dev/fltk-ui/build/
12
13
  /ext/khetai/dev/fltk-ui/build_khetai/
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 3.3.6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- khetai (0.3.2)
4
+ khetai (0.3.4)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # KhetAI
2
2
 
3
+ An AI engine for the board game Khet. This gem provides move calculation for a specified color with configurable search depth and time limits.
4
+
3
5
  ## Installation
4
6
 
5
7
  $ gem install khetai
@@ -45,8 +47,19 @@ The representation of the board gets converted an array of 8-bit integers once i
45
47
 
46
48
  The internals of the gem are written in C, located in `ext/khetai`.
47
49
 
50
+ ## Development System Requirements
51
+
52
+ To build the gem from source, you'll need:
53
+ - Ruby >= 2.0.0
54
+ - GCC or compatible C compiler
55
+ - Development headers (usually provided by ruby-dev or ruby-devel package)
56
+
48
57
  ## Build and Deploy Commands
49
58
 
59
+ This project uses `asdf` as the version manager for Ruby. However, any Ruby version greater than `2.0.0` should work to compile this gem.
60
+
61
+ $ gem install bundler
62
+ $ bundle install
50
63
  $ bundle exec rake compile
51
64
  $ bundle exec rake build
52
65
  $ gem install pkg/khetai-<version>.gem
@@ -134,6 +134,11 @@ int GameBoard::handle(int event) {
134
134
  if (key == 'r') {
135
135
  resetPieces();
136
136
  } else if (key == FL_Enter) {
137
+ square_selected = false;
138
+ square_selected_num = -1;
139
+ redraw();
140
+ Fl::flush();
141
+
137
142
  const char *max_time_value = max_time_input->value();
138
143
  if (!max_time_value || max_time_value[0] == '\0') {
139
144
  max_time_input->value("5");
@@ -507,7 +512,6 @@ void GameBoard::updateLaserPosition() {
507
512
  if (laser_y >= y() + (rows * cell_height) || laser_y <= y() || laser_x >= x() + (cols * cell_width) || laser_x <= x()) {
508
513
  laser_active = false;
509
514
  laser_path.clear();
510
- redraw();
511
515
  return;
512
516
  }
513
517
 
@@ -65,7 +65,7 @@ class GameBoard : public Fl_Widget {
65
65
  int cell_width, cell_height;
66
66
  bool square_selected = false;
67
67
  bool laser_active = false;
68
- int laser_step = 3;
68
+ int laser_step = 5;
69
69
  LaserDirection laser_direction;
70
70
  float laser_y, laser_x;
71
71
  bool remove_piece = false;
@@ -154,7 +154,7 @@ int calculate_score() {
154
154
  enum Player player = j;
155
155
  for (int k = 0; k < 13; k++) {
156
156
  int i = get_board_index(player, k);
157
- if (i != EPT) {
157
+ if (i != EMPTY) {
158
158
  Square s = board[i];
159
159
  int value = 0;
160
160
  switch (get_piece(s)) {
@@ -211,25 +211,32 @@ void make_move(Move move) {
211
211
  if (is_piece(board[end]))
212
212
  hash ^= keys[board[end]][end];
213
213
 
214
- Square moving_piece = board[start];
215
- board[start] = board[end];
216
- board[end] = moving_piece;
217
- // add starting piece to end location
218
- hash ^= keys[board[end]][end];
219
-
220
- enum Player moving_player = get_owner(moving_piece);
221
- update_piece_tracker(moving_player, start, end);
214
+ Square starting_square = board[start];
215
+ Square ending_square = board[end];
216
+ board[start] = ending_square;
217
+ board[end] = starting_square;
222
218
 
223
- // add ending piece to start location if swapping
224
- if (is_piece(board[start])) {
225
- hash ^= keys[board[start]][start];
219
+ // add starting piece to end location
220
+ hash ^= keys[starting_square][end];
226
221
 
227
- enum Player other_player = get_owner(board[start]);
228
- update_piece_tracker(other_player, end, start);
222
+ enum Player moving_player = get_owner(starting_square);
223
+ if (!is_piece(ending_square)) {
224
+ update_piece_tracker(moving_player, start, end, false);
225
+ } else {
226
+ // add ending piece to start location if swapping
227
+ hash ^= keys[ending_square][start];
228
+
229
+ enum Player other_player = get_owner(ending_square);
230
+ if (get_owner(starting_square) == other_player)
231
+ update_piece_tracker(other_player, end, start, true);
232
+ else {
233
+ update_piece_tracker(moving_player, start, end, false);
234
+ update_piece_tracker(other_player, end, start, false);
235
+ }
229
236
  }
230
237
 
231
- if (get_piece(moving_piece) == PHARAOH)
232
- pharaoh_loc[get_owner(moving_piece)] = end;
238
+ if (get_piece(starting_square) == PHARAOH)
239
+ pharaoh_loc[get_owner(starting_square)] = end;
233
240
  }
234
241
 
235
242
  undo_moves[undo_index] = new_move(end, start, -rotation);
@@ -305,20 +312,27 @@ void undo_move() {
305
312
  if (rotation != 0) {
306
313
  board[start] = rotate(board[start], rotation);
307
314
  } else {
308
- Square moving_piece = board[start];
309
- board[start] = board[end];
310
- board[end] = moving_piece;
311
-
312
- enum Player moving_player = get_owner(moving_piece);
313
- update_piece_tracker(moving_player, start, end);
315
+ Square starting_square = board[start];
316
+ Square ending_square = board[end];
317
+ board[start] = ending_square;
318
+ board[end] = starting_square;
319
+
320
+ enum Player moving_player = get_owner(starting_square);
321
+ if (ending_square == 0) {
322
+ update_piece_tracker(moving_player, start, end, false);
323
+ } else {
324
+ enum Player other_player = get_owner(ending_square);
314
325
 
315
- if (board[start] != 0) {
316
- enum Player other_player = get_owner(board[start]);
317
- update_piece_tracker(other_player, end, start);
326
+ if (get_owner(starting_square) == other_player)
327
+ update_piece_tracker(other_player, end, start, true);
328
+ else {
329
+ update_piece_tracker(moving_player, start, end, false);
330
+ update_piece_tracker(other_player, end, start, false);
331
+ }
318
332
  }
319
333
 
320
- if (get_piece(moving_piece) == PHARAOH)
321
- pharaoh_loc[get_owner(moving_piece)] = end;
334
+ if (get_piece(starting_square) == PHARAOH)
335
+ pharaoh_loc[get_owner(starting_square)] = end;
322
336
  }
323
337
  checkmate = false;
324
338
  }
@@ -326,7 +340,7 @@ void undo_move() {
326
340
  void find_valid_moves(Move *valid_moves, int *vi) {
327
341
  for (int i = 0; i < 13; i++) {
328
342
  uint8_t board_pos = piece_trackers[whose_turn].positions[i];
329
- if (board_pos != EPT) {
343
+ if (board_pos != EMPTY) {
330
344
  enum Piece piece = get_piece(board[board_pos]);
331
345
  switch (piece) {
332
346
  case ANUBIS:
@@ -367,7 +381,7 @@ void find_valid_scarab_moves(int i, Move *valid_moves, int *vi) {
367
381
  for (int j = 0; j < 8; j++) {
368
382
  int dest = i + directions[j];
369
383
  if (can_move[whose_turn][dest]) {
370
- if (!is_piece(board[dest]) || (get_owner(board[dest]) != whose_turn && get_piece(board[dest]) != PHARAOH)) {
384
+ if (!is_piece(board[dest]) || (get_piece(board[dest]) != SCARAB && get_piece(board[dest]) != PHARAOH)) {
371
385
  valid_moves[(*vi)++] = new_move(i, dest, 0);
372
386
  }
373
387
  }
@@ -415,8 +429,8 @@ uint64_t get_board_hash() {
415
429
 
416
430
  void init_piece_trackers() {
417
431
  for (int i = 0; i < 13; i++) {
418
- piece_trackers[SILVER].positions[i] = EPT;
419
- piece_trackers[RED].positions[i] = EPT;
432
+ piece_trackers[SILVER].positions[i] = EMPTY;
433
+ piece_trackers[RED].positions[i] = EMPTY;
420
434
  }
421
435
 
422
436
  int si = 0;
@@ -435,8 +449,8 @@ void init_piece_trackers() {
435
449
  ri++;
436
450
  }
437
451
  } else {
438
- piece_trackers[SILVER].board_idx_position[i] = EPT;
439
- piece_trackers[RED].board_idx_position[i] = EPT;
452
+ piece_trackers[SILVER].board_idx_position[i] = EMPTY;
453
+ piece_trackers[RED].board_idx_position[i] = EMPTY;
440
454
  }
441
455
  }
442
456
  }
@@ -445,9 +459,9 @@ bool is_move_legal(Move move) {
445
459
  int start = get_start(move);
446
460
  int end = get_end(move);
447
461
  if (is_piece(board[start]) && get_owner(board[start]) == whose_turn) {
448
- if (!is_piece(board[end]) || get_rotation(move) != 0)
462
+ if (!is_piece(board[end]) || (get_rotation(move) != 0 && start == end))
449
463
  return true;
450
- else if (is_piece(board[end]) && get_piece(board[start]) == SCARAB && get_piece(board[end]) <= 3)
464
+ else if (is_piece(board[end]) && (get_piece(board[start]) == SCARAB && get_piece(board[end]) < 3))
451
465
  return true;
452
466
  }
453
467
  return false;
@@ -182,7 +182,10 @@ typedef struct HashEntry {
182
182
  extern HashEntry table[TABLE_SIZE];
183
183
  static inline HashEntry *search_table(uint64_t key) { return &table[key & TABLE_MASK]; };
184
184
 
185
- #define EPT 0xFF
185
+ #define NO_SWAP 0
186
+ #define SWAP_SAME 1
187
+ #define SWAP_OTHER 2
188
+ #define EMPTY 0xFF
186
189
  typedef struct PieceTracker {
187
190
  uint8_t positions[13];
188
191
  uint8_t board_idx_position[120];
@@ -191,20 +194,28 @@ extern PieceTracker piece_trackers[2];
191
194
 
192
195
  static inline uint8_t get_board_index(enum Player player, uint8_t pos_idx) { return piece_trackers[player].positions[pos_idx]; }
193
196
  static inline uint8_t get_position_index(enum Player player, uint8_t board_idx) { return piece_trackers[player].board_idx_position[board_idx]; }
194
- static inline void update_piece_tracker(enum Player player, uint8_t old_board_idx, uint8_t new_board_idx) {
197
+ static inline void update_piece_tracker(enum Player player, uint8_t old_board_idx, uint8_t new_board_idx, bool swap) {
195
198
  uint8_t pos_idx = get_position_index(player, old_board_idx);
196
- piece_trackers[player].positions[pos_idx] = new_board_idx;
197
- piece_trackers[player].board_idx_position[old_board_idx] = EPT;
198
- piece_trackers[player].board_idx_position[new_board_idx] = pos_idx;
199
+ if (!swap) {
200
+ piece_trackers[player].positions[pos_idx] = new_board_idx;
201
+ piece_trackers[player].board_idx_position[old_board_idx] = EMPTY;
202
+ piece_trackers[player].board_idx_position[new_board_idx] = pos_idx;
203
+ } else {
204
+ uint8_t other_pos_idx = get_position_index(player, new_board_idx);
205
+ piece_trackers[player].positions[pos_idx] = new_board_idx;
206
+ piece_trackers[player].positions[other_pos_idx] = old_board_idx;
207
+ piece_trackers[player].board_idx_position[new_board_idx] = pos_idx;
208
+ piece_trackers[player].board_idx_position[old_board_idx] = other_pos_idx;
209
+ }
199
210
  }
200
211
  static inline void remove_from_piece_tracker(enum Player player, uint8_t board_idx) {
201
212
  uint8_t pos_idx = get_position_index(player, board_idx);
202
- piece_trackers[player].positions[pos_idx] = EPT;
203
- piece_trackers[player].board_idx_position[board_idx] = EPT;
213
+ piece_trackers[player].positions[pos_idx] = EMPTY;
214
+ piece_trackers[player].board_idx_position[board_idx] = EMPTY;
204
215
  }
205
216
  static inline void add_to_piece_tracker(enum Player player, uint8_t board_idx) {
206
217
  uint8_t pos_idx = 0;
207
- while (piece_trackers[player].positions[pos_idx] != EPT)
218
+ while (piece_trackers[player].positions[pos_idx] != EMPTY)
208
219
  pos_idx++;
209
220
  piece_trackers[player].positions[pos_idx] = board_idx;
210
221
  piece_trackers[player].board_idx_position[board_idx] = pos_idx;
@@ -1,3 +1,3 @@
1
1
  module KhetAI
2
- VERSION = "0.3.2"
2
+ VERSION = "0.3.4"
3
3
  end
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.3.2
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - jkugs
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-12-07 00:00:00.000000000 Z
11
+ date: 2024-12-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -20,6 +20,7 @@ extra_rdoc_files: []
20
20
  files:
21
21
  - ".clang-format"
22
22
  - ".gitignore"
23
+ - ".tool-versions"
23
24
  - Gemfile
24
25
  - Gemfile.lock
25
26
  - LICENSE.txt
@@ -105,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
106
  - !ruby/object:Gem::Version
106
107
  version: '0'
107
108
  requirements: []
108
- rubygems_version: 3.4.10
109
+ rubygems_version: 3.5.22
109
110
  signing_key:
110
111
  specification_version: 4
111
112
  summary: Khet AI