khetai 0.1.7 → 0.2.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/.gitignore +5 -0
- data/Gemfile.lock +2 -2
- data/README.md +36 -22
- data/ext/khetai/dev/README.md +15 -0
- data/ext/khetai/dev/fltk-ui/Makefile +65 -0
- data/ext/khetai/dev/fltk-ui/Makefile.khetai +46 -0
- data/ext/khetai/dev/fltk-ui/README.md +34 -0
- data/ext/khetai/dev/fltk-ui/ai_loader.cpp +93 -0
- data/ext/khetai/dev/fltk-ui/ai_loader.h +33 -0
- data/ext/khetai/dev/fltk-ui/assets/anubis_red_e.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/anubis_red_n.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/anubis_red_s.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/anubis_red_w.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/anubis_silver_e.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/anubis_silver_n.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/anubis_silver_s.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/anubis_silver_w.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/example_board.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/laser_red_e.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/laser_red_n.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/laser_red_s.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/laser_red_w.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/laser_silver_e.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/laser_silver_n.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/laser_silver_s.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/laser_silver_w.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/pharaoh_red.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/pharaoh_silver.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/pyramid_red_e.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/pyramid_red_n.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/pyramid_red_s.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/pyramid_red_w.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/pyramid_silver_e.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/pyramid_silver_n.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/pyramid_silver_s.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/pyramid_silver_w.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/scarab_red_e.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/scarab_red_n.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/scarab_red_s.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/scarab_red_w.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/scarab_silver_e.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/scarab_silver_n.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/scarab_silver_s.png +0 -0
- data/ext/khetai/dev/fltk-ui/assets/scarab_silver_w.png +0 -0
- data/ext/khetai/dev/fltk-ui/build_khetai.sh +9 -0
- data/ext/khetai/dev/fltk-ui/game_board.cpp +896 -0
- data/ext/khetai/dev/fltk-ui/game_board.h +105 -0
- data/ext/khetai/dev/fltk-ui/game_board_util.cpp +119 -0
- data/ext/khetai/dev/fltk-ui/game_board_util.h +15 -0
- data/ext/khetai/dev/fltk-ui/khet.cpp +59 -0
- data/ext/khetai/dev/main.c +8 -7
- data/ext/khetai/dev/main.rb +9 -10
- data/ext/khetai/khetai.c +22 -6
- data/ext/khetai/khetai_lib.c +24 -13
- data/ext/khetai/khetai_lib.h +51 -24
- data/lib/khetai/version.rb +1 -1
- metadata +50 -4
- data/README_ORIGINAL.md +0 -40
@@ -0,0 +1,105 @@
|
|
1
|
+
#ifndef GAMEBOARD_H
|
2
|
+
#define GAMEBOARD_H
|
3
|
+
|
4
|
+
#include "ai_loader.h"
|
5
|
+
|
6
|
+
#include <FL/Fl_Widget.H>
|
7
|
+
#include <FL/Fl_PNG_Image.H>
|
8
|
+
#include <FL/Fl_Input.H>
|
9
|
+
#include <string>
|
10
|
+
#include <vector>
|
11
|
+
#include <unordered_map>
|
12
|
+
|
13
|
+
class GameBoard : public Fl_Widget
|
14
|
+
{
|
15
|
+
public:
|
16
|
+
GameBoard(int X, int Y, int W, int H, const char *L = 0);
|
17
|
+
Fl_Input *max_time_input, *max_depth_input;
|
18
|
+
void draw() override;
|
19
|
+
int handle(int event) override;
|
20
|
+
void init(const std::vector<std::vector<std::string>> &pieces);
|
21
|
+
|
22
|
+
enum Color
|
23
|
+
{
|
24
|
+
SILVER = 1,
|
25
|
+
RED = 2
|
26
|
+
};
|
27
|
+
enum LaserDirection
|
28
|
+
{
|
29
|
+
NORTH = 1,
|
30
|
+
EAST = 2,
|
31
|
+
SOUTH = 3,
|
32
|
+
WEST = 4
|
33
|
+
};
|
34
|
+
enum PieceType
|
35
|
+
{
|
36
|
+
ANUBIS,
|
37
|
+
PYRAMID,
|
38
|
+
SCARAB,
|
39
|
+
PHARAOH,
|
40
|
+
SPHINX
|
41
|
+
};
|
42
|
+
enum PieceOrientation
|
43
|
+
{
|
44
|
+
ORIENT_NORTH,
|
45
|
+
ORIENT_EAST,
|
46
|
+
ORIENT_SOUTH,
|
47
|
+
ORIENT_WEST
|
48
|
+
};
|
49
|
+
enum ReflectionResult
|
50
|
+
{
|
51
|
+
RESULT_DEAD,
|
52
|
+
RESULT_ABSORBED,
|
53
|
+
RESULT_EAST,
|
54
|
+
RESULT_WEST,
|
55
|
+
RESULT_SOUTH,
|
56
|
+
RESULT_NORTH
|
57
|
+
};
|
58
|
+
enum MovePermission
|
59
|
+
{
|
60
|
+
S = 1,
|
61
|
+
R = 2,
|
62
|
+
B = 3
|
63
|
+
};
|
64
|
+
|
65
|
+
static std::string getPieceFilename(char piece, int direction);
|
66
|
+
static std::pair<PieceType, PieceOrientation> getPieceTypeAndOrientation(const std::string &piece_str);
|
67
|
+
static void laser_timer_cb(void *data);
|
68
|
+
|
69
|
+
private:
|
70
|
+
AILoader ai_loader;
|
71
|
+
int rows = 8, cols = 10, clicked_row = -1, clicked_col = -1, square_selected_num = -1;
|
72
|
+
int cell_width, cell_height;
|
73
|
+
bool square_selected = false;
|
74
|
+
bool laser_active = false;
|
75
|
+
int laser_step = 3;
|
76
|
+
LaserDirection laser_direction;
|
77
|
+
float laser_y, laser_x;
|
78
|
+
bool remove_piece = false;
|
79
|
+
int laser_square_row, laser_square_col, remove_row, remove_col;
|
80
|
+
int l_idx;
|
81
|
+
std::vector<std::vector<std::string>> board_pieces;
|
82
|
+
std::vector<Fl_Image *> piece_images;
|
83
|
+
std::vector<std::tuple<int, int, int, int>> laser_path;
|
84
|
+
std::vector<std::tuple<int, int, int, int>> laser_path_squares;
|
85
|
+
|
86
|
+
static std::unordered_map<LaserDirection, std::unordered_map<PieceType, std::unordered_map<PieceOrientation, ReflectionResult>>> reflections_map;
|
87
|
+
static std::unordered_map<char, std::string> piece_map;
|
88
|
+
static std::unordered_map<int, int> rotate_left_map;
|
89
|
+
static std::unordered_map<int, int> rotate_right_map;
|
90
|
+
static const MovePermission move_permissions[8][10];
|
91
|
+
|
92
|
+
void drawInnerSquares();
|
93
|
+
void rotateSelectedPiece(bool clockwise);
|
94
|
+
void moveSelectedPiece(int end_square);
|
95
|
+
void swapPieces(int swap_square);
|
96
|
+
void deletePiece();
|
97
|
+
void resetPieces();
|
98
|
+
void fireLaser(Color color);
|
99
|
+
void updateLaserPosition();
|
100
|
+
void calculateLaserPathSquares();
|
101
|
+
bool squareContainsPiece(int square_num);
|
102
|
+
void rebuildReloadKhetAILib();
|
103
|
+
};
|
104
|
+
|
105
|
+
#endif
|
@@ -0,0 +1,119 @@
|
|
1
|
+
#include "game_board_util.h"
|
2
|
+
|
3
|
+
#include <iostream>
|
4
|
+
#include <cstring>
|
5
|
+
|
6
|
+
std::vector<std::string> flatten_2d_vector_with_buffer(const std::vector<std::vector<std::string>> &vec2d)
|
7
|
+
{
|
8
|
+
size_t new_rows = vec2d.size() + 2;
|
9
|
+
size_t new_cols = vec2d.empty() ? 0 : vec2d[0].size() + 2;
|
10
|
+
|
11
|
+
std::vector<std::vector<std::string>> buffered_vec2d(new_rows, std::vector<std::string>(new_cols, "--"));
|
12
|
+
|
13
|
+
for (size_t i = 0; i < vec2d.size(); ++i)
|
14
|
+
{
|
15
|
+
for (size_t j = 0; j < vec2d[i].size(); ++j)
|
16
|
+
{
|
17
|
+
buffered_vec2d[i + 1][j + 1] = vec2d[i][j];
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
std::vector<std::string> flattened;
|
22
|
+
for (const auto &row : buffered_vec2d)
|
23
|
+
{
|
24
|
+
for (const auto &elem : row)
|
25
|
+
{
|
26
|
+
flattened.push_back(elem);
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
return flattened;
|
31
|
+
}
|
32
|
+
|
33
|
+
char **vector_to_c_array(const std::vector<std::string> &vec)
|
34
|
+
{
|
35
|
+
char **c_array = new char *[vec.size()];
|
36
|
+
for (size_t i = 0; i < vec.size(); ++i)
|
37
|
+
{
|
38
|
+
c_array[i] = new char[vec[i].size() + 1];
|
39
|
+
std::strcpy(c_array[i], vec[i].c_str());
|
40
|
+
}
|
41
|
+
|
42
|
+
return c_array;
|
43
|
+
}
|
44
|
+
|
45
|
+
void free_c_array(char **c_array, size_t size)
|
46
|
+
{
|
47
|
+
for (size_t i = 0; i < size; ++i)
|
48
|
+
{
|
49
|
+
delete[] c_array[i];
|
50
|
+
}
|
51
|
+
delete[] c_array;
|
52
|
+
}
|
53
|
+
|
54
|
+
Move call_ai_move(AILoader &ai_loader, const std::vector<std::vector<std::string>> &board_pieces, Player player, int max_depth, int max_time)
|
55
|
+
{
|
56
|
+
auto init_zobrist = ai_loader.get_init_zobrist();
|
57
|
+
auto setup_board = ai_loader.get_setup_board();
|
58
|
+
auto print_board = ai_loader.get_print_board();
|
59
|
+
auto set_time_parameters = ai_loader.get_set_time_parameters();
|
60
|
+
auto alphabeta_root = ai_loader.get_alphabeta_root();
|
61
|
+
auto make_move = ai_loader.get_make_move();
|
62
|
+
auto get_start = ai_loader.get_get_start();
|
63
|
+
auto get_end = ai_loader.get_get_end();
|
64
|
+
auto get_rotation = ai_loader.get_get_rotation();
|
65
|
+
|
66
|
+
char **c_board = vector_to_c_array(flatten_2d_vector_with_buffer(board_pieces));
|
67
|
+
|
68
|
+
init_zobrist();
|
69
|
+
srand((unsigned)time(NULL));
|
70
|
+
|
71
|
+
setup_board(c_board);
|
72
|
+
printf("\nStarting Board:\n");
|
73
|
+
print_board();
|
74
|
+
|
75
|
+
time_t start_time = time(NULL);
|
76
|
+
set_time_parameters(max_time, start_time);
|
77
|
+
|
78
|
+
int depth = 1;
|
79
|
+
Move best_move = (Move)0;
|
80
|
+
Move current_move = (Move)0;
|
81
|
+
while (depth <= max_depth)
|
82
|
+
{
|
83
|
+
printf("\nDEPTH: %-3d-> ", depth);
|
84
|
+
current_move = alphabeta_root(depth, player);
|
85
|
+
printf("MOVE -> START: %d, END: %d, ROTATION: %d\n", get_start(current_move), get_end(current_move), get_rotation(current_move));
|
86
|
+
if ((time(NULL) - start_time < max_time))
|
87
|
+
best_move = current_move;
|
88
|
+
else
|
89
|
+
break;
|
90
|
+
depth++;
|
91
|
+
}
|
92
|
+
make_move(best_move);
|
93
|
+
|
94
|
+
printf("\n========================\n\n");
|
95
|
+
printf("Ending Board:\n");
|
96
|
+
print_board();
|
97
|
+
|
98
|
+
printf("\nDEPTH: %d\n", depth - 1);
|
99
|
+
|
100
|
+
int start = get_start(best_move);
|
101
|
+
int end = get_end(best_move);
|
102
|
+
int rotation = get_rotation(best_move);
|
103
|
+
std::cout << "START: " << start << ", END: " << end << ", ROTATION: " << rotation << std::endl;
|
104
|
+
return best_move;
|
105
|
+
}
|
106
|
+
|
107
|
+
void get_row_col(int index, int &row, int &col)
|
108
|
+
{
|
109
|
+
int border_width = 1;
|
110
|
+
int width_with_border = 10 + 2 * border_width;
|
111
|
+
|
112
|
+
int adjusted_index = index;
|
113
|
+
|
114
|
+
int row_with_border = adjusted_index / width_with_border;
|
115
|
+
int col_with_border = adjusted_index % width_with_border;
|
116
|
+
|
117
|
+
row = row_with_border - border_width;
|
118
|
+
col = col_with_border - border_width;
|
119
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#ifndef GAME_BOARD_UTIL_H
|
2
|
+
#define GAME_BOARD_UTIL_H
|
3
|
+
|
4
|
+
#include "ai_loader.h"
|
5
|
+
|
6
|
+
#include <vector>
|
7
|
+
#include <string>
|
8
|
+
|
9
|
+
std::vector<std::string> flatten_2d_vector_with_buffer(const std::vector<std::vector<std::string>> &vec2d);
|
10
|
+
char **vector_to_c_array(const std::vector<std::string> &vec);
|
11
|
+
void free_c_array(char **c_array, size_t size);
|
12
|
+
Move call_ai_move(AILoader &ai_loader, const std::vector<std::vector<std::string>> &board_pieces, Player player, int max_depth, int _max_time);
|
13
|
+
void get_row_col(int index, int &row, int &col);
|
14
|
+
|
15
|
+
#endif
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#include <FL/Fl.H>
|
2
|
+
#include <FL/Fl_Double_Window.H>
|
3
|
+
#include <FL/Fl_Input.H>
|
4
|
+
#include <FL/Fl_Int_Input.H>
|
5
|
+
#include <FL/Fl_Box.H>
|
6
|
+
#include "game_board.h"
|
7
|
+
|
8
|
+
class PositiveIntInput : public Fl_Int_Input
|
9
|
+
{
|
10
|
+
public:
|
11
|
+
PositiveIntInput(int X, int Y, int W, int H, const char *L = 0)
|
12
|
+
: Fl_Int_Input(X, Y, W, H, L) {}
|
13
|
+
|
14
|
+
int handle(int event) override
|
15
|
+
{
|
16
|
+
int result = Fl_Int_Input::handle(event);
|
17
|
+
if (event == FL_KEYDOWN || event == FL_KEYUP || event == FL_PASTE)
|
18
|
+
{
|
19
|
+
const char *value = this->value();
|
20
|
+
if (value[0] == '-')
|
21
|
+
{
|
22
|
+
this->value("");
|
23
|
+
}
|
24
|
+
}
|
25
|
+
return result;
|
26
|
+
}
|
27
|
+
};
|
28
|
+
|
29
|
+
int main(int argc, char **argv)
|
30
|
+
{
|
31
|
+
Fl_Double_Window *window = new Fl_Double_Window(800, 600, "Khet AI");
|
32
|
+
GameBoard *board = new GameBoard(50, 50, 700, 504);
|
33
|
+
|
34
|
+
std::vector<std::vector<std::string>> init_board = {
|
35
|
+
{"L2", "--", "--", "--", "A2", "X2", "A2", "P1", "--", "--"},
|
36
|
+
{"--", "--", "P2", "--", "--", "--", "--", "--", "--", "--"},
|
37
|
+
{"--", "--", "--", "p3", "--", "--", "--", "--", "--", "--"},
|
38
|
+
{"P0", "--", "p2", "--", "S2", "S3", "--", "P1", "--", "p3"},
|
39
|
+
{"P1", "--", "p3", "--", "s1", "s0", "--", "P0", "--", "p2"},
|
40
|
+
{"--", "--", "--", "--", "--", "--", "P1", "--", "--", "--"},
|
41
|
+
{"--", "--", "--", "--", "--", "--", "--", "p0", "--", "--"},
|
42
|
+
{"--", "--", "p3", "a0", "x0", "a0", "--", "--", "--", "l0"}};
|
43
|
+
|
44
|
+
board->init(init_board);
|
45
|
+
|
46
|
+
Fl_Box *max_time_label = new Fl_Box(50, 10, 80, 30, "Max Time:");
|
47
|
+
PositiveIntInput *max_time_input = new PositiveIntInput(125, 15, 30, 20);
|
48
|
+
max_time_input->value("5");
|
49
|
+
board->max_time_input = max_time_input;
|
50
|
+
|
51
|
+
Fl_Box *max_depth_label = new Fl_Box(250, 10, 80, 30, "Max Depth:");
|
52
|
+
PositiveIntInput *max_depth_input = new PositiveIntInput(325, 15, 30, 20);
|
53
|
+
max_depth_input->value("10");
|
54
|
+
board->max_depth_input = max_depth_input;
|
55
|
+
|
56
|
+
window->end();
|
57
|
+
window->show(argc, argv);
|
58
|
+
return Fl::run();
|
59
|
+
}
|
data/ext/khetai/dev/main.c
CHANGED
@@ -15,9 +15,6 @@ char *init_board[120] =
|
|
15
15
|
"--", "--", "--", "p3", "a0", "x0", "a0", "--", "--", "--", "l0", "--",
|
16
16
|
"--", "--", "--", "--", "--", "--", "--", "--", "--", "--", "--", "--"};
|
17
17
|
|
18
|
-
time_t start_time;
|
19
|
-
int max_time;
|
20
|
-
|
21
18
|
int main()
|
22
19
|
{
|
23
20
|
init_zobrist();
|
@@ -26,17 +23,21 @@ int main()
|
|
26
23
|
setup_board(init_board);
|
27
24
|
print_board();
|
28
25
|
|
29
|
-
start_time = time(NULL);
|
30
|
-
max_time = 5;
|
26
|
+
time_t start_time = time(NULL);
|
27
|
+
int max_time = 5;
|
28
|
+
set_time_parameters(max_time, start_time);
|
31
29
|
int max_depth = 25;
|
32
30
|
|
33
31
|
int depth = 1;
|
34
32
|
Move best_move = (Move)0;
|
35
33
|
Move current_move = (Move)0;
|
36
|
-
while (
|
34
|
+
while (depth <= max_depth)
|
37
35
|
{
|
38
|
-
best_move = current_move;
|
39
36
|
current_move = alphabeta_root(depth, Red);
|
37
|
+
if (time(NULL) - start_time < max_time)
|
38
|
+
best_move = current_move;
|
39
|
+
else
|
40
|
+
break;
|
40
41
|
depth++;
|
41
42
|
}
|
42
43
|
make_move(best_move);
|
data/ext/khetai/dev/main.rb
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
require_relative "../../../lib/khetai/khetai.so"
|
2
2
|
|
3
|
-
board = ["
|
4
|
-
"--", "
|
5
|
-
"--", "--", "--", "
|
6
|
-
"
|
7
|
-
"
|
8
|
-
"--", "
|
9
|
-
"--", "--", "--", "--", "--", "--", "--", "
|
10
|
-
"--", "--", "
|
11
|
-
|
12
|
-
"--", "--", "--", "--", "--", "--", "--", "--", "--", "--", "--", "--"]
|
3
|
+
board = ["L2", "--", "--", "--", "A2", "X2", "A2", "P1", "--", "--",
|
4
|
+
"--", "--", "P2", "--", "--", "--", "--", "--", "--", "--",
|
5
|
+
"--", "--", "--", "p3", "--", "--", "--", "--", "--", "--",
|
6
|
+
"P0", "--", "p2", "--", "S2", "S3", "--", "P1", "--", "p3",
|
7
|
+
"P1", "--", "p3", "--", "s1", "s0", "--", "P0", "--", "p2",
|
8
|
+
"--", "--", "--", "--", "--", "--", "P1", "--", "--", "--",
|
9
|
+
"--", "--", "--", "--", "--", "--", "--", "p0", "--", "--",
|
10
|
+
"--", "--", "p3", "a0", "x0", "a0", "--", "--", "--", "l0"]
|
11
|
+
|
13
12
|
|
14
13
|
move = KhetAI.move(board, 1, 6, 5)
|
15
14
|
puts move.to_s
|
data/ext/khetai/khetai.c
CHANGED
@@ -3,28 +3,44 @@
|
|
3
3
|
#include <time.h>
|
4
4
|
#include "khetai_lib.h"
|
5
5
|
|
6
|
-
time_t start_time;
|
7
|
-
int max_time;
|
8
|
-
|
9
6
|
VALUE move(VALUE self, VALUE board_array, VALUE player, VALUE max_depth, VALUE _max_time)
|
10
7
|
{
|
11
8
|
srand((unsigned)time(NULL));
|
12
9
|
|
10
|
+
// khetai_lib assumes an extra level of padding around the board
|
13
11
|
char *init_board[120];
|
14
12
|
unsigned int array_size = (unsigned int)RARRAY_LEN(board_array);
|
13
|
+
|
14
|
+
// top and bottom row padding
|
15
|
+
for (unsigned int i = 0; i < 12; i++)
|
16
|
+
{
|
17
|
+
init_board[i] = "--";
|
18
|
+
init_board[108 + i] = "--";
|
19
|
+
}
|
20
|
+
|
21
|
+
// left and right column padding
|
22
|
+
for (unsigned int i = 0; i < 8; i++)
|
23
|
+
{
|
24
|
+
init_board[12 * (i + 1)] = "--";
|
25
|
+
init_board[12 * (i + 2) - 1] = "--";
|
26
|
+
}
|
27
|
+
|
28
|
+
// fill in the rest of the baord passed from ruby
|
15
29
|
for (unsigned int i = 0; i < array_size; i++)
|
16
30
|
{
|
17
31
|
VALUE square = rb_ary_entry(board_array, i);
|
18
|
-
init_board[i] = StringValueCStr(square);
|
32
|
+
init_board[13 + ((i % 10) + ((i / 10) * 12))] = StringValueCStr(square);
|
19
33
|
}
|
20
34
|
|
21
35
|
reset_undo();
|
22
36
|
init_zobrist();
|
23
37
|
setup_board(init_board);
|
24
38
|
|
25
|
-
start_time = time(NULL);
|
26
|
-
max_time = NUM2INT(_max_time);
|
39
|
+
time_t start_time = time(NULL);
|
40
|
+
int max_time = NUM2INT(_max_time);
|
41
|
+
set_time_parameters(max_time, start_time);
|
27
42
|
|
43
|
+
// iterative deepening
|
28
44
|
int depth = 1;
|
29
45
|
Move best_move = (Move)0;
|
30
46
|
Move current_move = (Move)0;
|
data/ext/khetai/khetai_lib.c
CHANGED
@@ -4,6 +4,9 @@
|
|
4
4
|
#include <time.h>
|
5
5
|
#include "khetai_lib.h"
|
6
6
|
|
7
|
+
int max_time;
|
8
|
+
time_t start_time;
|
9
|
+
|
7
10
|
Square board[120] = {0};
|
8
11
|
int pharaoh_loc[2] = {0};
|
9
12
|
enum Player whose_turn;
|
@@ -51,6 +54,9 @@ Move alphabeta_root(int depth, enum Player player)
|
|
51
54
|
if (alpha >= beta)
|
52
55
|
break;
|
53
56
|
}
|
57
|
+
|
58
|
+
// print final score for testing purposes:
|
59
|
+
// printf("SCORE: %-10d\n", best_score);
|
54
60
|
return best_move;
|
55
61
|
}
|
56
62
|
|
@@ -91,6 +97,7 @@ int alphabeta(int depth, enum Player player, int alpha, int beta)
|
|
91
97
|
find_valid_moves(valid_moves, &vi);
|
92
98
|
int best_score = -MAX_SCORE;
|
93
99
|
Move best_move = (Move)0;
|
100
|
+
|
94
101
|
for (int i = 0; (i < NUM_VALID_MOVES && (time(NULL) - start_time < max_time)); i++)
|
95
102
|
{
|
96
103
|
if (valid_moves[i] == 0)
|
@@ -125,7 +132,7 @@ void insert_table(uint64_t key, int depth, int flag, int score, Move move)
|
|
125
132
|
HashEntry *entry = search_table(key);
|
126
133
|
if (entry->key != 0)
|
127
134
|
{
|
128
|
-
if (depth
|
135
|
+
if (depth < entry->depth)
|
129
136
|
{
|
130
137
|
entry->key = key;
|
131
138
|
entry->depth = depth;
|
@@ -167,8 +174,9 @@ int calculate_score()
|
|
167
174
|
value += rand() % 20;
|
168
175
|
break;
|
169
176
|
case Scarab:
|
170
|
-
|
171
|
-
|
177
|
+
int max_distance = 16;
|
178
|
+
int base_score = 1000;
|
179
|
+
value += (max_distance - distance_from_pharaoh(i, pharaoh_loc[opposite_player(get_owner(s))])) * base_score / max_distance;
|
172
180
|
break;
|
173
181
|
case Pharaoh:
|
174
182
|
value += pharaoh_score;
|
@@ -225,7 +233,7 @@ void make_move(Move move)
|
|
225
233
|
hash ^= keys[board[start]][start];
|
226
234
|
|
227
235
|
if (get_piece(moving_piece) == Pharaoh)
|
228
|
-
pharaoh_loc[
|
236
|
+
pharaoh_loc[get_owner(moving_piece)] = end;
|
229
237
|
}
|
230
238
|
|
231
239
|
undo_moves[undo_index] = new_move(end, start, -rotation);
|
@@ -314,7 +322,7 @@ void undo_move()
|
|
314
322
|
board[end] = moving_piece;
|
315
323
|
|
316
324
|
if (get_piece(moving_piece) == Pharaoh)
|
317
|
-
pharaoh_loc[get_owner(
|
325
|
+
pharaoh_loc[get_owner(moving_piece)] = end;
|
318
326
|
}
|
319
327
|
checkmate = false;
|
320
328
|
}
|
@@ -375,14 +383,7 @@ void find_valid_scarab_moves(int i, Move *valid_moves, int *vi)
|
|
375
383
|
int dest = i + directions[j];
|
376
384
|
if (can_move[whose_turn][dest])
|
377
385
|
{
|
378
|
-
if (is_piece(board[dest]))
|
379
|
-
{
|
380
|
-
if (get_piece(board[dest]) == Anubis || get_piece(board[dest]) == Pyramid)
|
381
|
-
{
|
382
|
-
valid_moves[(*vi)++] = new_move(i, dest, 0);
|
383
|
-
}
|
384
|
-
}
|
385
|
-
else
|
386
|
+
if (!is_piece(board[dest]) || get_piece(board[dest]) != Pharaoh)
|
386
387
|
{
|
387
388
|
valid_moves[(*vi)++] = new_move(i, dest, 0);
|
388
389
|
}
|
@@ -615,3 +616,13 @@ void print_piece(Square s)
|
|
615
616
|
else
|
616
617
|
printf("--");
|
617
618
|
}
|
619
|
+
|
620
|
+
int get_start_wrapper(Move move) { return get_start(move); }
|
621
|
+
int get_end_wrapper(Move move) { return get_end(move); }
|
622
|
+
int get_rotation_wrapper(Move move) { return get_rotation(move); }
|
623
|
+
|
624
|
+
void set_time_parameters(int _max_time, time_t _start_time)
|
625
|
+
{
|
626
|
+
max_time = _max_time;
|
627
|
+
start_time = _start_time;
|
628
|
+
}
|
data/ext/khetai/khetai_lib.h
CHANGED
@@ -4,6 +4,10 @@
|
|
4
4
|
#include <stdint.h>
|
5
5
|
#include <stdbool.h>
|
6
6
|
|
7
|
+
#ifdef __cplusplus
|
8
|
+
#include <ctime>
|
9
|
+
#endif
|
10
|
+
|
7
11
|
typedef uint8_t Square;
|
8
12
|
typedef uint32_t Move;
|
9
13
|
|
@@ -83,27 +87,42 @@ static const int on_board[120] = {
|
|
83
87
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
|
84
88
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
85
89
|
|
86
|
-
extern
|
87
|
-
extern
|
88
|
-
|
89
|
-
|
90
|
-
extern
|
90
|
+
extern time_t start_time;
|
91
|
+
extern int max_time;
|
92
|
+
|
93
|
+
#ifdef __cplusplus
|
94
|
+
extern "C"
|
95
|
+
{
|
96
|
+
#endif
|
97
|
+
|
98
|
+
void set_time_parameters(int _max_time, time_t _start_time);
|
99
|
+
void reset_undo();
|
100
|
+
void init_zobrist();
|
101
|
+
void setup_board(char *board[]);
|
102
|
+
Move alphabeta_root(int depth, enum Player player);
|
103
|
+
void make_move(Move move);
|
104
|
+
void print_board();
|
105
|
+
|
106
|
+
#ifdef __cplusplus
|
107
|
+
}
|
108
|
+
#endif
|
109
|
+
|
110
|
+
Square str_to_square(char *str);
|
111
|
+
void print_piece(Square s);
|
91
112
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
113
|
+
void find_valid_moves(Move *valid_moves, int *vi);
|
114
|
+
void find_valid_anubis_pyramid_moves(int i, Move *valid_moves, int *vi);
|
115
|
+
void find_valid_scarab_moves(int i, Move *valid_moves, int *vi);
|
116
|
+
void find_valid_pharaoh_moves(int i, Move *valid_moves, int *vi);
|
117
|
+
void find_valid_sphinx_moves(int i, Move *valid_moves, int *vi);
|
97
118
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
extern int distance_from_pharaoh(int i, int p);
|
119
|
+
int alphabeta(int depth, enum Player player, int alpha, int beta);
|
120
|
+
int calculate_score();
|
121
|
+
int distance_from_pharaoh(int i, int p);
|
102
122
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
extern bool is_move_legal(Move move);
|
123
|
+
void undo_move();
|
124
|
+
void fire_laser(uint64_t *hash);
|
125
|
+
bool is_move_legal(Move move);
|
107
126
|
|
108
127
|
static inline bool is_piece(Square s) { return s > 0; }
|
109
128
|
|
@@ -116,6 +135,17 @@ static inline int get_start(Move m) { return m >> 1 & 0x7F; }
|
|
116
135
|
static inline int get_end(Move m) { return m >> 8 & 0x7F; }
|
117
136
|
static inline int get_rotation(Move m) { return (m >> 15 & 0x3) - 2; }
|
118
137
|
|
138
|
+
#ifdef __cplusplus
|
139
|
+
extern "C"
|
140
|
+
{
|
141
|
+
#endif
|
142
|
+
int get_start_wrapper(Move move);
|
143
|
+
int get_end_wrapper(Move move);
|
144
|
+
int get_rotation_wrapper(Move move);
|
145
|
+
#ifdef __cplusplus
|
146
|
+
}
|
147
|
+
#endif
|
148
|
+
|
119
149
|
static inline Square rotate(Square s, int rotation)
|
120
150
|
{
|
121
151
|
int orientation = get_orientation(s);
|
@@ -161,16 +191,13 @@ static const int reflections[4][5][4] = {
|
|
161
191
|
{Dead, Dead, Dead, Dead},
|
162
192
|
{Absorbed, Absorbed, Absorbed, Absorbed}}};
|
163
193
|
|
164
|
-
extern time_t start_time;
|
165
|
-
extern int max_time;
|
166
194
|
extern uint64_t keys[0xFF][120];
|
167
195
|
extern uint64_t hashes[MAX_DEPTH];
|
168
196
|
extern uint64_t turn_key;
|
169
197
|
extern int move_num;
|
170
198
|
extern bool checkmate;
|
171
199
|
|
172
|
-
|
173
|
-
extern uint64_t get_board_hash();
|
200
|
+
uint64_t get_board_hash();
|
174
201
|
static uint64_t seed = 1070372;
|
175
202
|
static inline uint64_t random_number()
|
176
203
|
{
|
@@ -196,6 +223,6 @@ typedef struct HashEntry
|
|
196
223
|
|
197
224
|
extern HashEntry table[TABLE_SIZE];
|
198
225
|
static inline HashEntry *search_table(uint64_t key) { return &table[key % TABLE_SIZE]; };
|
199
|
-
|
226
|
+
void insert_table(uint64_t key, int depth, int flag, int score, Move move);
|
200
227
|
|
201
|
-
#endif // KHET_LIB_H_INCLUDED
|
228
|
+
#endif // KHET_LIB_H_INCLUDED
|
data/lib/khetai/version.rb
CHANGED