quack kind of works

This commit is contained in:
Christoffer Müller Madsen 2018-05-11 19:00:39 +02:00
parent 03e61a59cf
commit ffbc98e1a2

View File

@ -2,6 +2,12 @@
static PyObject* QuackError;
typedef struct board_list board_list;
struct board_list {
int size;
PyObject** list;
};
/* Utility functions */
int sign(int x) {
return (x > 0) - (x < 0);
@ -88,6 +94,8 @@ int can_bear_off(int board[], int player, int from_idx) {
return 1;
}
/* end helper functions */
int is_move_valid(int board[], int player, int face_value, int move[]) {
@ -116,7 +124,127 @@ int is_move_valid(int board[], int player, int face_value, int move[]) {
;
}
int* do_move(int board[], int player, int move[]) {
int from_idx = move[0];
int to_idx = move[1];
/* "lift" checker */
board[from_idx] -= player;
/* Return early if bearing off */
if (to_idx < 1 || to_idx > 24) return board;
/* Hit opponent checker */
if (board[to_idx] * player == -1) {
/* Move checker to bar */
if (player == 1) board[25] -= player;
else board[0] -= player;
board[to_idx] = 0;
}
/* Put down checker */
board[to_idx] += player;
return board;
}
int* do_move_clone(int board[], int player, int move[]) {
int new_board[26];
for (int i = 0; i < 26; i++) {
new_board[i] = board[i];
}
return do_move(new_board, player, move);
}
void board_to_pyboard(PyObject* board_tuple, int board[]) {
for (int i = 0; i < 26; i++) {
PyTuple_SetItem(board_tuple, i, Py_BuildValue("i", board[i]));
}
return;
}
board_list calc_moves(int board[], int player, int face_value) {
int* checker_idxs = idxs_with_checkers_of_player(board, player);
board_list boards = { .size = 0,
.list = malloc((15 + 1) * sizeof(PyObject*)) };
if (boards.list == NULL) {
fprintf(stderr, "malloc failed\n");
abort();
}
if (checker_idxs[0] == 0) {
boards.size = 1;
PyObject* board_tuple = PyTuple_New(26);
board_to_pyboard(board_tuple, board);
boards.list[0] = board_tuple;
return boards;
}
int ctr = 0;
for (int i = 1; i <= checker_idxs[0]; i++) {
int move[2];
move[0] = checker_idxs[i];
move[1] = checker_idxs[i] + (face_value * player);
for (int i = 0; i < 2; i++) {
printf("move[%i]: %i\n", i, move[i]);
}
if (is_move_valid(board, player, face_value, move)) {
printf("legal\n");
int* new_board = do_move_clone(board, player, move);
PyObject* board_tuple = PyTuple_New(26);
board_to_pyboard(board_tuple, new_board);
// segfault maybe :'(
//free(new_board);
boards.list[i] = board_tuple;
ctr++;
}
}
boards.size = ctr;
printf("boards.size: %i\n\n",boards.size);
return boards;
}
/* Meta definitions */
int extract_board(int *board, PyObject* board_tuple_obj) {
long numValuesBoard;
numValuesBoard = PyTuple_Size(board_tuple_obj);
if (numValuesBoard != 26) {
PyErr_SetString(QuackError, "Board tuple must have 26 entries");
return 1;
}
PyObject* board_val_obj;
// Iterate over tuple to retreive positions
for (int i=0; i<numValuesBoard; i++) {
board_val_obj = PyTuple_GetItem(board_tuple_obj, i);
board[i] = PyLong_AsLong(board_val_obj);
}
return 0;
}
int extract_move(int *move, PyObject* move_tuple_obj) {
long numValuesMove;
numValuesMove = PyTuple_Size(move_tuple_obj);
if (numValuesMove != 2) {
PyErr_SetString(QuackError, "Move tuple must have exactly 2 entries");
return 1;
}
PyObject* move_val_obj;
for (int i=0; i<numValuesMove; i++) {
move_val_obj = PyTuple_GetItem(move_tuple_obj, i);
move[i] = PyLong_AsLong(move_val_obj);
}
return 0;
}
static PyObject*
quack_is_move_valid(PyObject *self, PyObject *args) {
int board[26];
@ -136,31 +264,8 @@ quack_is_move_valid(PyObject *self, PyObject *args) {
&PyTuple_Type, &move_tuple_obj))
return NULL;
long numValuesBoard;
numValuesBoard = PyTuple_Size(board_tuple_obj);
if (numValuesBoard != 26) {
PyErr_SetString(QuackError, "Board tuple must have 26 entries");
return NULL;
}
PyObject* board_val_obj;
// Iterate over tuple to retreive positions
for (int i=0; i<numValuesBoard; i++) {
board_val_obj = PyTuple_GetItem(board_tuple_obj, i);
board[i] = PyLong_AsLong(board_val_obj);
}
long numValuesMove;
numValuesMove = PyTuple_Size(move_tuple_obj);
if (numValuesMove != 2) {
PyErr_SetString(QuackError, "Move tuple must have exactly 2 entries");
return NULL;
}
PyObject* move_val_obj;
for (int i=0; i<numValuesMove; i++) {
move_val_obj = PyTuple_GetItem(move_tuple_obj, i);
move[i] = PyLong_AsLong(move_val_obj);
}
if (extract_board(board, board_tuple_obj)) return NULL;
if (extract_move(move, move_tuple_obj)) return NULL;
validity = is_move_valid(board, player, face_value, move);
return Py_BuildValue("i", validity);
@ -181,31 +286,76 @@ quack_idxs_with_checkers_of_player(PyObject *self, PyObject *args) {
&player))
return NULL;
long numValuesBoard;
numValuesBoard = PyTuple_Size(board_tuple_obj);
if (numValuesBoard != 26) {
PyErr_SetString(QuackError, "Board tuple must have 26 entries");
return NULL;
}
PyObject* board_val_obj;
// Iterate over tuple to retreive positions
for (int i=0; i<numValuesBoard; i++) {
board_val_obj = PyTuple_GetItem(board_tuple_obj, i);
board[i] = PyLong_AsLong(board_val_obj);
}
if (extract_board(board, board_tuple_obj)) return NULL;
idxs = idxs_with_checkers_of_player(board, player);
PyObject* idxs_list = PyList_New(0);
for (int i = 1; i <= idxs[0]; i++) {
PyList_Append(idxs_list, Py_BuildValue("i",idxs[i]));
PyList_Append(idxs_list, Py_BuildValue("i", idxs[i]));
}
free(idxs);
return Py_BuildValue("O", idxs_list);
}
static PyObject*
quack_do_move(PyObject *self, PyObject *args) {
int board[26];
int player;
int move[2];
PyObject* board_tuple_obj;
PyObject* move_tuple_obj;
if (! PyArg_ParseTuple(args, "O!iO!",
&PyTuple_Type, &board_tuple_obj,
&player,
&PyTuple_Type, &move_tuple_obj))
return NULL;
if (extract_board(board, board_tuple_obj)) return NULL;
if (extract_move(move, move_tuple_obj)) return NULL;
do_move(board, player, move);
PyObject* board_tuple = PyTuple_New(26);
board_to_pyboard(board_tuple, board);
return Py_BuildValue("O", board_tuple);
}
static PyObject*
quack_calc_moves(PyObject *self, PyObject *args) {
int board[26];
int player;
int face_value;
PyObject* board_tuple_obj;
if (! PyArg_ParseTuple(args, "O!ii",
&PyTuple_Type, &board_tuple_obj,
&player,
&face_value))
return NULL;
if (extract_board(board, board_tuple_obj)) return NULL;
board_list boards = calc_moves(board, player, face_value);
PyObject* boards_list = PyList_New(0);
for (int i = 0; i < boards.size; i++) {
printf("%i\n",i);
if (PyList_Append(boards_list, boards.list[i])) {
printf("list insertion failed at index %i\n",i);
}
//free(boards.list[i]);
}
//free(boards.list);
return Py_BuildValue("O", boards_list);
}
static PyMethodDef quack_methods[] = {
{
@ -214,7 +364,16 @@ static PyMethodDef quack_methods[] = {
},
{
"idxs_with_checkers_of_player", quack_idxs_with_checkers_of_player, METH_VARARGS,
"Returnes a list of indexes with checkers of the specified player"},
"Returns a list of indexes with checkers of the specified player"
},
{
"do_move", quack_do_move, METH_VARARGS,
"Returns the board after doing the specified move"
},
{
"calc_moves", quack_calc_moves, METH_VARARGS,
"Calculates all legal moves from board with specified face value"
},
{NULL, NULL, 0, NULL}
};