khetai 0.1.7 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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