ext/khetai/khetai.c in khetai-0.2.0 vs ext/khetai/khetai.c in khetai-0.2.1
- old
+ new
@@ -1,17 +1,69 @@
#include <ruby.h>
#include <stdlib.h>
#include <time.h>
#include "khetai_lib.h"
-VALUE move(VALUE self, VALUE board_array, VALUE player, VALUE max_depth, VALUE _max_time)
+VALUE move(VALUE self, VALUE board_array, VALUE _player, VALUE _max_depth, VALUE _max_time)
{
+ // verify parameters
+ int player = NUM2INT(_player);
+ if (player < 0 || player > 1)
+ {
+ rb_raise(rb_eArgError, "player must be 0 (silver) or 1 (red)");
+ }
+
+ int max_time = NUM2INT(_max_time);
+ if (max_time < 1)
+ {
+ rb_raise(rb_eArgError, "max_time (seconds) must be 1 or greater");
+ }
+
+ int max_depth = NUM2INT(_max_depth);
+ if (max_depth < 2 || max_depth > 25)
+ {
+ rb_raise(rb_eArgError, "max_depth (ply) must be between 2 and 25");
+ }
+
srand((unsigned)time(NULL));
+ unsigned int array_size = (unsigned int)RARRAY_LEN(board_array);
+
+ // verify board_array is valid
+ if (array_size != 80)
+ {
+ rb_raise(rb_eArgError, "board_array must have exactly 80 elements");
+ }
+ const char valid_pieces[] = {'L', 'A', 'X', 'P', 'S', 'p', 'a', 'x', 's', 'l'};
+ size_t valid_pieces_count = 10;
+ for (unsigned int i = 0; i < array_size; i++)
+ {
+ VALUE element = rb_ary_entry(board_array, i);
+ if (!RB_TYPE_P(element, T_STRING) || RSTRING_LEN(element) != 2)
+ {
+ rb_raise(rb_eArgError, "each element in the board_array must be 2 characters");
+ }
+
+ // check if element in board_array is a valid string
+ const char *element_str = RSTRING_PTR(element);
+ int is_valid = 0;
+ for (unsigned int j = 0; j < valid_pieces_count; j++)
+ {
+ if ((element_str[0] == valid_pieces[j] && element_str[1] >= '0' && element_str[1] <= '3') || strcmp(element_str, "--") == 0)
+ {
+ is_valid = 1;
+ break;
+ }
+ }
+ if (!is_valid)
+ {
+ rb_raise(rb_eArgError, "each element in the board_array must be a valid piece (example: 'p1') or empty ('--')");
+ }
+ }
+
// khetai_lib assumes an extra level of padding around the board
char *init_board[120];
- unsigned int array_size = (unsigned int)RARRAY_LEN(board_array);
// top and bottom row padding
for (unsigned int i = 0; i < 12; i++)
{
init_board[i] = "--";
@@ -23,11 +75,11 @@
{
init_board[12 * (i + 1)] = "--";
init_board[12 * (i + 2) - 1] = "--";
}
- // fill in the rest of the baord passed from ruby
+ // fill in the rest of the board passed from ruby
for (unsigned int i = 0; i < array_size; i++)
{
VALUE square = rb_ary_entry(board_array, i);
init_board[13 + ((i % 10) + ((i / 10) * 12))] = StringValueCStr(square);
}
@@ -35,20 +87,19 @@
reset_undo();
init_zobrist();
setup_board(init_board);
time_t start_time = time(NULL);
- int max_time = NUM2INT(_max_time);
set_time_parameters(max_time, start_time);
// iterative deepening
int depth = 1;
Move best_move = (Move)0;
Move current_move = (Move)0;
- while ((time(NULL) - start_time < max_time) && (depth <= NUM2INT(max_depth)))
+ while ((time(NULL) - start_time < max_time) && (depth <= max_depth))
{
best_move = current_move;
- current_move = alphabeta_root(depth, NUM2INT(player));
+ current_move = alphabeta_root(depth, player);
depth++;
}
make_move(best_move);
VALUE out = rb_ary_new2(3);