/* * Main function for getting all of the moves currently possible for a player. * * @params: (player) - the player whose moves are to be put in the list * @return: a list of all moves currently possible for the player, or NULL if any allocation errors occurred */ struct LinkedList* Board_getPossibleMoves(char** board, int player){ struct LinkedList* possibleJumpMoves = getPossibleJumps(board, player); if (possibleJumpMoves == NULL){ // allocation failed return NULL; } if (LinkedList_length(possibleJumpMoves) != 0){ /* if jumps are possible, they are the only type of move legally possible */ struct LinkedList* trimmedJumpMoves = trimJumpMovesList(possibleJumpMoves); if(trimmedJumpMoves == NULL){ // allocation failed LinkedList_free(possibleJumpMoves); return NULL; } return trimmedJumpMoves; } LinkedList_free(possibleJumpMoves); struct LinkedList* singleMoves = getPossibleSingleMoves(board, player); if (singleMoves == NULL){ // allocation failed return NULL; } return singleMoves; }
unsigned int RenderBatch_getDrawableCount(RenderBatch* batch) { return LinkedList_length(batch->drawables); }
/* * The minimax AI algorithm. */ int alphabeta(PossibleMove* possibleMove, int depth, int player, int alpha, int beta){ int (*evaluationFunction)(Board*, int, int) = (maxRecursionDepth == BEST)? &Board_getBetterScore: &Board_getScore; int thisBoardScore = evaluationFunction(possibleMove->board, turn, player); // maximum depth reached or game is over or allocation error occurred in Board_getScore if (depth == 1 || thisBoardScore == 10000 || thisBoardScore == -10000 || thisBoardScore == -10001){ return thisBoardScore; } Board* board = possibleMove->board; LinkedList* possibleMoves = Board_getPossibleMoves(board, player); if (!possibleMoves){ return -10001; } //terminal node if (LinkedList_length(possibleMoves) == 0){ LinkedList_free(possibleMoves); return thisBoardScore; } //single child node if (LinkedList_length(possibleMoves) == 1){ PossibleMove* onlyMove = PossibleMoveList_first(possibleMoves); int score = evaluationFunction(onlyMove->board, turn, player); LinkedList_free(possibleMoves); return score; } int extremum = (player == turn)? INT_MIN : INT_MAX; Iterator iterator; Iterator_init(&iterator, possibleMoves); while (Iterator_hasNext(&iterator)) { PossibleMove* currentPossibleMove = (PossibleMove*)Iterator_next(&iterator); int score = alphabeta(currentPossibleMove, depth-1, !player, alpha, beta); if (score == -10001){ //allocation error occured extremum = score; break; } if ( (player != turn && score < extremum) || (player == turn && score > extremum) || (rand()%2 && score == extremum) ){ extremum = score; } //game over - no need to evaluate further moves // if (extremum == 10000 || extremum == -10000){ // break; // } //alpha-beta pruning if (turn == player){ alpha = (score > alpha)? score: alpha; if (alpha >= beta){ break; } } else{ beta = (score < beta)? score: beta; if (beta <= alpha){ break; } } } LinkedList_free(possibleMoves); return extremum; }