quack without leaks
This commit is contained in:
parent
383dd7aa4b
commit
1aa9cf705f
15
board.py
15
board.py
|
@ -42,13 +42,14 @@ class Board:
|
|||
# quack-fat
|
||||
@staticmethod
|
||||
def board_features_quack_fat(board, player):
|
||||
board = list(board)
|
||||
positives = [x if x > 0 else 0 for x in board]
|
||||
negatives = [x if x < 0 else 0 for x in board]
|
||||
board.append( 15 - sum(positives))
|
||||
board.append(-15 - sum(negatives))
|
||||
board += ([1, 0] if np.sign(player) > 0 else [0, 1])
|
||||
return np.array(board).reshape(1,30)
|
||||
return np.array(quack.board_features_quack_fat(board,player)).reshape(1,30)
|
||||
# board = list(board)
|
||||
# positives = [x if x > 0 else 0 for x in board]
|
||||
# negatives = [x if x < 0 else 0 for x in board]
|
||||
# board.append( 15 - sum(positives))
|
||||
# board.append(-15 - sum(negatives))
|
||||
# board += ([1, 0] if np.sign(player) > 0 else [0, 1])
|
||||
# return np.array(board).reshape(1,30)
|
||||
|
||||
|
||||
# quack-fatter
|
||||
|
|
12
network.py
12
network.py
|
@ -216,10 +216,7 @@ class Network:
|
|||
:return: A pair of the best state to go to, together with the score of that state
|
||||
"""
|
||||
legal_moves = list(Board.calculate_legal_states(board, player, roll))
|
||||
|
||||
legal_states = [list(tmp) for tmp in legal_moves]
|
||||
|
||||
legal_states = np.array([self.board_trans_func(tmp, player)[0] for tmp in legal_states])
|
||||
legal_states = np.array([self.board_trans_func(move, player)[0] for move in legal_moves])
|
||||
|
||||
scores = self.model.predict_on_batch(legal_states)
|
||||
transformed_scores = [x if np.sign(player) > 0 else 1 - x for x in scores]
|
||||
|
@ -260,12 +257,7 @@ class Network:
|
|||
# find all legal states from the given board and the given roll
|
||||
init_legal_states = Board.calculate_legal_states(board, player, roll)
|
||||
|
||||
|
||||
legal_moves = list(Board.calculate_legal_states(board, player, roll))
|
||||
|
||||
legal_states = [list(tmp) for tmp in legal_moves]
|
||||
|
||||
legal_states = np.array([self.board_trans_func(tmp, player)[0] for tmp in legal_states])
|
||||
legal_states = np.array([self.board_trans_func(state, player)[0] for state in init_legal_states])
|
||||
|
||||
scores = self.calc_vals(legal_states)
|
||||
scores = [score.numpy() for score in scores]
|
||||
|
|
119
quack/quack.c
119
quack/quack.c
|
@ -34,7 +34,7 @@ int *idxs_with_checkers_of_player(int board[], int player) {
|
|||
|
||||
int *idxs = malloc((1 + ctr) * sizeof(int));
|
||||
if (idxs == NULL) {
|
||||
fprintf(stderr, "malloc failed\n");
|
||||
PyErr_NoMemory();
|
||||
abort();
|
||||
}
|
||||
|
||||
|
@ -79,15 +79,22 @@ int can_bear_off(int board[], int player, int from_idx) {
|
|||
if (player == 1) {
|
||||
for (int i = 1; i <= checker_idxs[0]; i++) {
|
||||
if ( !((checker_idxs[i] >= from_idx) &&
|
||||
(checker_idxs[i] >= 19)) ) return 0;
|
||||
(checker_idxs[i] >= 19)) ) {
|
||||
free(checker_idxs);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 1; i <= checker_idxs[0]; i++) {
|
||||
if ( !((checker_idxs[i] <= from_idx) &&
|
||||
(checker_idxs[i] <= 6)) ) return 0;
|
||||
(checker_idxs[i] <= 6)) ) {
|
||||
free(checker_idxs);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(checker_idxs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -149,7 +156,7 @@ void do_move(int board[], int player, int move[]) {
|
|||
int* do_move_clone(int board[], int player, int move[]) {
|
||||
int* new_board = malloc(sizeof(int) * 26);
|
||||
if (new_board == NULL) {
|
||||
fprintf(stderr, "malloc failed\n");
|
||||
PyErr_NoMemory();
|
||||
abort();
|
||||
}
|
||||
|
||||
|
@ -161,9 +168,9 @@ int* do_move_clone(int board[], int player, int move[]) {
|
|||
return new_board;
|
||||
}
|
||||
|
||||
PyObject* store_board_to_pyobject(int board[]) {
|
||||
PyObject* board_tuple = PyTuple_New(26);
|
||||
for (int i = 0; i < 26; i++) {
|
||||
PyObject* store_board_to_pytuple(int board[], int size) {
|
||||
PyObject* board_tuple = PyTuple_New(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
PyTuple_SetItem(board_tuple, i, Py_BuildValue("i", board[i]));
|
||||
}
|
||||
return board_tuple;
|
||||
|
@ -175,8 +182,9 @@ board_list calc_moves(int board[], int player, int face_value) {
|
|||
|
||||
if (checker_idxs[0] == 0) {
|
||||
boards.size = 1;
|
||||
PyObject* board_tuple = store_board_to_pyobject(board);
|
||||
PyObject* board_tuple = store_board_to_pytuple(board, 26);
|
||||
boards.list[0] = board_tuple;
|
||||
free(checker_idxs);
|
||||
return boards;
|
||||
}
|
||||
|
||||
|
@ -188,7 +196,7 @@ board_list calc_moves(int board[], int player, int face_value) {
|
|||
|
||||
if (is_move_valid(board, player, face_value, move)) {
|
||||
int* new_board = do_move_clone(board, player, move);
|
||||
PyObject* board_tuple = store_board_to_pyobject(new_board);
|
||||
PyObject* board_tuple = store_board_to_pytuple(new_board, 26);
|
||||
|
||||
// segfault maybe :'(
|
||||
free(new_board);
|
||||
|
@ -198,10 +206,40 @@ board_list calc_moves(int board[], int player, int face_value) {
|
|||
}
|
||||
}
|
||||
|
||||
free(checker_idxs);
|
||||
|
||||
boards.size = ctr;
|
||||
return boards;
|
||||
}
|
||||
|
||||
int* board_features_quack_fat(int board[], int player) {
|
||||
int* new_board = malloc(sizeof(int) * 30);
|
||||
if (new_board == NULL) {
|
||||
PyErr_NoMemory();
|
||||
abort();
|
||||
}
|
||||
|
||||
int pos_sum = 0;
|
||||
int neg_sum = 0;
|
||||
for (int i = 0; i < 26; i++) {
|
||||
new_board[i] = board[i];
|
||||
if (sign(new_board[i] > 0)) pos_sum += new_board[i];
|
||||
else neg_sum += new_board[i];
|
||||
}
|
||||
|
||||
new_board[26] = 15 - pos_sum;
|
||||
new_board[27] = -15 - neg_sum;
|
||||
if (player == 1) {
|
||||
new_board[28] = 1;
|
||||
new_board[29] = 0;
|
||||
} else {
|
||||
new_board[28] = 0;
|
||||
new_board[29] = 1;
|
||||
}
|
||||
|
||||
return new_board;
|
||||
}
|
||||
|
||||
/* Meta definitions */
|
||||
int extract_board(int *board, PyObject* board_tuple_obj) {
|
||||
long numValuesBoard;
|
||||
|
@ -244,8 +282,6 @@ quack_is_move_valid(PyObject *self, PyObject *args) {
|
|||
int face_value;
|
||||
int move[2];
|
||||
|
||||
int validity;
|
||||
|
||||
PyObject* board_tuple_obj;
|
||||
PyObject* move_tuple_obj;
|
||||
|
||||
|
@ -259,8 +295,8 @@ quack_is_move_valid(PyObject *self, PyObject *args) {
|
|||
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);
|
||||
if (is_move_valid(board, player, face_value, move)) Py_RETURN_TRUE;
|
||||
else Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
|
@ -281,14 +317,17 @@ quack_idxs_with_checkers_of_player(PyObject *self, PyObject *args) {
|
|||
if (extract_board(board, board_tuple_obj)) return NULL;
|
||||
|
||||
idxs = idxs_with_checkers_of_player(board, player);
|
||||
PyObject* idxs_list = PyList_New(0);
|
||||
PyObject* idxs_list = PyList_New(idxs[0]);
|
||||
|
||||
for (int i = 1; i <= idxs[0]; i++) {
|
||||
PyList_Append(idxs_list, Py_BuildValue("i", idxs[i]));
|
||||
for (int i = 0; i < idxs[0]; i++) {
|
||||
PyList_SetItem(idxs_list, i, Py_BuildValue("i", idxs[i+1]));
|
||||
}
|
||||
free(idxs);
|
||||
|
||||
return Py_BuildValue("O", idxs_list);
|
||||
PyObject *result = Py_BuildValue("O", idxs_list);
|
||||
Py_DECREF(idxs_list);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
|
@ -310,10 +349,15 @@ quack_do_move(PyObject *self, PyObject *args) {
|
|||
if (extract_move(move, move_tuple_obj)) return NULL;
|
||||
|
||||
do_move(board, player, move);
|
||||
PyObject* board_tuple = store_board_to_pytuple(board, 26);
|
||||
|
||||
PyObject* board_tuple = store_board_to_pyobject(board);
|
||||
// This is shaky
|
||||
Py_DECREF(board);
|
||||
|
||||
return Py_BuildValue("O", board_tuple);
|
||||
PyObject *result = Py_BuildValue("O", board_tuple);
|
||||
Py_DECREF(board_tuple);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
|
@ -333,16 +377,43 @@ quack_calc_moves(PyObject *self, PyObject *args) {
|
|||
if (extract_board(board, board_tuple_obj)) return NULL;
|
||||
|
||||
board_list boards = calc_moves(board, player, face_value);
|
||||
PyObject* boards_list = PyList_New(0);
|
||||
PyObject* boards_list = PyList_New(boards.size);
|
||||
|
||||
for (int i = 0; i < boards.size; i++) {
|
||||
if (PyList_Append(boards_list, boards.list[i])) {
|
||||
if (PyList_SetItem(boards_list, i, boards.list[i])) {
|
||||
printf("list insertion failed at index %i\n",i);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
return Py_BuildValue("O", boards_list);
|
||||
PyObject *result = Py_BuildValue("O", boards_list);
|
||||
Py_DECREF(boards_list);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
quack_board_features_quack_fat(PyObject *self, PyObject *args) {
|
||||
int board[26];
|
||||
int player;
|
||||
|
||||
PyObject* board_tuple_obj;
|
||||
|
||||
if (! PyArg_ParseTuple(args, "O!i",
|
||||
&PyTuple_Type, &board_tuple_obj,
|
||||
&player))
|
||||
return NULL;
|
||||
|
||||
if (extract_board(board, board_tuple_obj)) return NULL;
|
||||
|
||||
int* new_board = board_features_quack_fat(board, player);
|
||||
PyObject* board_tuple = store_board_to_pytuple(new_board, 30);
|
||||
free(new_board);
|
||||
|
||||
PyObject *result = Py_BuildValue("O", board_tuple);
|
||||
Py_DECREF(board_tuple);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -363,6 +434,10 @@ static PyMethodDef quack_methods[] = {
|
|||
"calc_moves", quack_calc_moves, METH_VARARGS,
|
||||
"Calculates all legal moves from board with specified face value"
|
||||
},
|
||||
{
|
||||
"board_features_quack_fat", quack_board_features_quack_fat, METH_VARARGS,
|
||||
"Transforms a board to the quack-fat board representation"
|
||||
},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user