#include static PyObject* QuackError; typedef struct board_list board_list; struct board_list { int size; PyObject* list[16]; }; /* Utility functions */ int sign(int x) { return (x > 0) - (x < 0); } int abs(int x) { if (x >= 0) return x; else return -x; } /* end utility functions */ /* Helper functions */ int *idxs_with_checkers_of_player(int board[], int player) { int idxs_tmp[26]; int ctr = 0; for (int i = 0; i < 26; i++) { if (board[i] * player >= 1) { idxs_tmp[ctr] = i; ctr++; } } int *idxs = malloc((1 + ctr) * sizeof(int)); if (idxs == NULL) { fprintf(stderr, "malloc failed\n"); abort(); } idxs[0] = ctr; for (int i = 0; i < ctr; i++) { idxs[i+1] = idxs_tmp[i]; } return idxs; } int is_forward_move(int direction, int player) { return direction == player; } int face_value_match_move_length(int delta, int face_value) { return abs(delta) == face_value; } int bear_in_if_checker_on_bar(int board[], int player, int from_idx) { int bar; if (player == 1) bar = 0; else bar = 25; if (board[bar] != 0) return from_idx == bar; else return 1; } int checkers_at_from_idx(int from_state, int player) { return sign(from_state) == player; } int no_block_at_to_idx(int to_state, int player) { if (-sign(to_state) == player) return abs(to_state) == 1; else return 1; } int can_bear_off(int board[], int player, int from_idx) { int* checker_idxs = idxs_with_checkers_of_player(board, player); if (player == 1) { for (int i = 1; i <= checker_idxs[0]; i++) { if ( !((checker_idxs[i] >= from_idx) && (checker_idxs[i] >= 19)) ) return 0; } } else { for (int i = 1; i <= checker_idxs[0]; i++) { if ( !((checker_idxs[i] <= from_idx) && (checker_idxs[i] <= 6)) ) return 0; } } return 1; } /* end helper functions */ int is_move_valid(int board[], int player, int face_value, int move[]) { int from_idx = move[0]; int to_idx = move[1]; int to_state; int from_state = board[from_idx]; int delta = to_idx - from_idx; int direction = sign(delta); int bearing_off; if (to_idx >= 1 && to_idx <= 24) { to_state = board[to_idx]; bearing_off = 0; } else { to_state = 0; bearing_off = 1; } return is_forward_move(direction, player) && face_value_match_move_length(delta, face_value) && bear_in_if_checker_on_bar(board, player, from_idx) && checkers_at_from_idx(from_state, player) && no_block_at_to_idx(to_state, player) && (!bearing_off || can_bear_off(board, player, from_idx)) ; } void 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; /* 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; } 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"); abort(); } for (int i = 0; i < 26; i++) { new_board[i] = board[i]; } do_move(new_board, player, move); return new_board; } PyObject* store_board_to_pyobject(int board[]) { PyObject* board_tuple = PyTuple_New(26); for (int i = 0; i < 26; i++) { PyTuple_SetItem(board_tuple, i, Py_BuildValue("i", board[i])); } return board_tuple; } 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 }; if (checker_idxs[0] == 0) { boards.size = 1; PyObject* board_tuple = store_board_to_pyobject(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); 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); // segfault maybe :'( free(new_board); boards.list[ctr] = board_tuple; ctr++; } } boards.size = ctr; 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