quack without leaks

This commit is contained in:
Christoffer Müller Madsen 2018-05-11 21:24:10 +02:00
parent 383dd7aa4b
commit 1aa9cf705f
3 changed files with 110 additions and 42 deletions

View File

@ -42,13 +42,14 @@ class Board:
# quack-fat # quack-fat
@staticmethod @staticmethod
def board_features_quack_fat(board, player): def board_features_quack_fat(board, player):
board = list(board) return np.array(quack.board_features_quack_fat(board,player)).reshape(1,30)
positives = [x if x > 0 else 0 for x in board] # board = list(board)
negatives = [x if x < 0 else 0 for x in board] # positives = [x if x > 0 else 0 for x in board]
board.append( 15 - sum(positives)) # negatives = [x if x < 0 else 0 for x in board]
board.append(-15 - sum(negatives)) # board.append( 15 - sum(positives))
board += ([1, 0] if np.sign(player) > 0 else [0, 1]) # board.append(-15 - sum(negatives))
return np.array(board).reshape(1,30) # board += ([1, 0] if np.sign(player) > 0 else [0, 1])
# return np.array(board).reshape(1,30)
# quack-fatter # quack-fatter

View File

@ -216,10 +216,7 @@ class Network:
:return: A pair of the best state to go to, together with the score of that state :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_moves = list(Board.calculate_legal_states(board, player, roll))
legal_states = np.array([self.board_trans_func(move, player)[0] for move in legal_moves])
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])
scores = self.model.predict_on_batch(legal_states) scores = self.model.predict_on_batch(legal_states)
transformed_scores = [x if np.sign(player) > 0 else 1 - x for x in scores] 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 # find all legal states from the given board and the given roll
init_legal_states = Board.calculate_legal_states(board, player, roll) init_legal_states = Board.calculate_legal_states(board, player, roll)
legal_states = np.array([self.board_trans_func(state, player)[0] for state in init_legal_states])
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])
scores = self.calc_vals(legal_states) scores = self.calc_vals(legal_states)
scores = [score.numpy() for score in scores] scores = [score.numpy() for score in scores]

View File

@ -34,7 +34,7 @@ int *idxs_with_checkers_of_player(int board[], int player) {
int *idxs = malloc((1 + ctr) * sizeof(int)); int *idxs = malloc((1 + ctr) * sizeof(int));
if (idxs == NULL) { if (idxs == NULL) {
fprintf(stderr, "malloc failed\n"); PyErr_NoMemory();
abort(); abort();
} }
@ -79,15 +79,22 @@ int can_bear_off(int board[], int player, int from_idx) {
if (player == 1) { if (player == 1) {
for (int i = 1; i <= checker_idxs[0]; i++) { for (int i = 1; i <= checker_idxs[0]; i++) {
if ( !((checker_idxs[i] >= from_idx) && if ( !((checker_idxs[i] >= from_idx) &&
(checker_idxs[i] >= 19)) ) return 0; (checker_idxs[i] >= 19)) ) {
free(checker_idxs);
return 0;
}
} }
} else { } else {
for (int i = 1; i <= checker_idxs[0]; i++) { for (int i = 1; i <= checker_idxs[0]; i++) {
if ( !((checker_idxs[i] <= from_idx) && 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; 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* do_move_clone(int board[], int player, int move[]) {
int* new_board = malloc(sizeof(int) * 26); int* new_board = malloc(sizeof(int) * 26);
if (new_board == NULL) { if (new_board == NULL) {
fprintf(stderr, "malloc failed\n"); PyErr_NoMemory();
abort(); abort();
} }
@ -161,9 +168,9 @@ int* do_move_clone(int board[], int player, int move[]) {
return new_board; return new_board;
} }
PyObject* store_board_to_pyobject(int board[]) { PyObject* store_board_to_pytuple(int board[], int size) {
PyObject* board_tuple = PyTuple_New(26); PyObject* board_tuple = PyTuple_New(size);
for (int i = 0; i < 26; i++) { for (int i = 0; i < size; i++) {
PyTuple_SetItem(board_tuple, i, Py_BuildValue("i", board[i])); PyTuple_SetItem(board_tuple, i, Py_BuildValue("i", board[i]));
} }
return board_tuple; return board_tuple;
@ -175,8 +182,9 @@ board_list calc_moves(int board[], int player, int face_value) {
if (checker_idxs[0] == 0) { if (checker_idxs[0] == 0) {
boards.size = 1; 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; boards.list[0] = board_tuple;
free(checker_idxs);
return boards; 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)) { if (is_move_valid(board, player, face_value, move)) {
int* new_board = do_move_clone(board, player, 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 :'( // segfault maybe :'(
free(new_board); free(new_board);
@ -198,10 +206,40 @@ board_list calc_moves(int board[], int player, int face_value) {
} }
} }
free(checker_idxs);
boards.size = ctr; boards.size = ctr;
return boards; 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 */ /* Meta definitions */
int extract_board(int *board, PyObject* board_tuple_obj) { int extract_board(int *board, PyObject* board_tuple_obj) {
long numValuesBoard; long numValuesBoard;
@ -233,7 +271,7 @@ int extract_move(int *move, PyObject* move_tuple_obj) {
move_val_obj = PyTuple_GetItem(move_tuple_obj, i); move_val_obj = PyTuple_GetItem(move_tuple_obj, i);
move[i] = PyLong_AsLong(move_val_obj); move[i] = PyLong_AsLong(move_val_obj);
} }
return 0; return 0;
} }
@ -244,8 +282,6 @@ quack_is_move_valid(PyObject *self, PyObject *args) {
int face_value; int face_value;
int move[2]; int move[2];
int validity;
PyObject* board_tuple_obj; PyObject* board_tuple_obj;
PyObject* move_tuple_obj; PyObject* move_tuple_obj;
@ -258,9 +294,9 @@ quack_is_move_valid(PyObject *self, PyObject *args) {
if (extract_board(board, board_tuple_obj)) return NULL; if (extract_board(board, board_tuple_obj)) return NULL;
if (extract_move(move, move_tuple_obj)) return NULL; if (extract_move(move, move_tuple_obj)) return NULL;
validity = is_move_valid(board, player, face_value, move); if (is_move_valid(board, player, face_value, move)) Py_RETURN_TRUE;
return Py_BuildValue("i", validity); else Py_RETURN_FALSE;
} }
static PyObject* 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; if (extract_board(board, board_tuple_obj)) return NULL;
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(idxs[0]);
for (int i = 1; i <= idxs[0]; i++) { for (int i = 0; i < idxs[0]; i++) {
PyList_Append(idxs_list, Py_BuildValue("i", idxs[i])); PyList_SetItem(idxs_list, i, Py_BuildValue("i", idxs[i+1]));
} }
free(idxs); free(idxs);
PyObject *result = Py_BuildValue("O", idxs_list);
Py_DECREF(idxs_list);
return Py_BuildValue("O", idxs_list); return result;
} }
static PyObject* static PyObject*
@ -310,10 +349,15 @@ quack_do_move(PyObject *self, PyObject *args) {
if (extract_move(move, move_tuple_obj)) return NULL; if (extract_move(move, move_tuple_obj)) return NULL;
do_move(board, player, move); 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);
PyObject *result = Py_BuildValue("O", board_tuple);
Py_DECREF(board_tuple);
return Py_BuildValue("O", board_tuple); return result;
} }
static PyObject* static PyObject*
@ -333,16 +377,43 @@ quack_calc_moves(PyObject *self, PyObject *args) {
if (extract_board(board, board_tuple_obj)) return NULL; if (extract_board(board, board_tuple_obj)) return NULL;
board_list boards = calc_moves(board, player, face_value); 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++) { 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); printf("list insertion failed at index %i\n",i);
abort(); 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, "calc_moves", quack_calc_moves, METH_VARARGS,
"Calculates all legal moves from board with specified face value" "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} {NULL, NULL, 0, NULL}
}; };