#include static PyObject* QuackError; /* 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)) ; } /* Meta definitions */ static PyObject* quack_is_move_valid(PyObject *self, PyObject *args) { int board[26]; int player; int face_value; int move[2]; int validity; PyObject* board_tuple_obj; PyObject* move_tuple_obj; if (! PyArg_ParseTuple(args, "O!iiO!", &PyTuple_Type, &board_tuple_obj, &player, &face_value, &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