quack kind of works
This commit is contained in:
parent
03e61a59cf
commit
ffbc98e1a2
239
quack/quack.c
239
quack/quack.c
|
@ -2,6 +2,12 @@
|
||||||
|
|
||||||
static PyObject* QuackError;
|
static PyObject* QuackError;
|
||||||
|
|
||||||
|
typedef struct board_list board_list;
|
||||||
|
struct board_list {
|
||||||
|
int size;
|
||||||
|
PyObject** list;
|
||||||
|
};
|
||||||
|
|
||||||
/* Utility functions */
|
/* Utility functions */
|
||||||
int sign(int x) {
|
int sign(int x) {
|
||||||
return (x > 0) - (x < 0);
|
return (x > 0) - (x < 0);
|
||||||
|
@ -88,6 +94,8 @@ int can_bear_off(int board[], int player, int from_idx) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* end helper functions */
|
/* end helper functions */
|
||||||
|
|
||||||
int is_move_valid(int board[], int player, int face_value, int move[]) {
|
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 */
|
/* 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*
|
static PyObject*
|
||||||
quack_is_move_valid(PyObject *self, PyObject *args) {
|
quack_is_move_valid(PyObject *self, PyObject *args) {
|
||||||
int board[26];
|
int board[26];
|
||||||
|
@ -136,31 +264,8 @@ quack_is_move_valid(PyObject *self, PyObject *args) {
|
||||||
&PyTuple_Type, &move_tuple_obj))
|
&PyTuple_Type, &move_tuple_obj))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
long numValuesBoard;
|
if (extract_board(board, board_tuple_obj)) return NULL;
|
||||||
numValuesBoard = PyTuple_Size(board_tuple_obj);
|
if (extract_move(move, move_tuple_obj)) return NULL;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
validity = is_move_valid(board, player, face_value, move);
|
validity = is_move_valid(board, player, face_value, move);
|
||||||
return Py_BuildValue("i", validity);
|
return Py_BuildValue("i", validity);
|
||||||
|
@ -181,31 +286,76 @@ quack_idxs_with_checkers_of_player(PyObject *self, PyObject *args) {
|
||||||
&player))
|
&player))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
long numValuesBoard;
|
if (extract_board(board, board_tuple_obj)) return NULL;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
idxs = idxs_with_checkers_of_player(board, player);
|
idxs = idxs_with_checkers_of_player(board, player);
|
||||||
PyObject* idxs_list = PyList_New(0);
|
PyObject* idxs_list = PyList_New(0);
|
||||||
|
|
||||||
for (int i = 1; i <= idxs[0]; i++) {
|
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);
|
free(idxs);
|
||||||
|
|
||||||
return Py_BuildValue("O", idxs_list);
|
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[] = {
|
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,
|
"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}
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user