/* * Trims the list of possible jump moves, so it only contains moves that result in the maximum amount of captures * * @params: (jumpMovesList) - the list of all possible jump moves * @return: a trimmed list, or NULL if any allocation errors occurred */ static struct LinkedList* trimJumpMovesList (struct LinkedList* jumpMovesList){ int maxCaptures = 0; //finding the maximum number of captures in a currently possible jump move struct Iterator iterator; Iterator_init(&iterator, jumpMovesList); while(Iterator_hasNext(&iterator)){ struct PossibleMove* currMove = (struct PossibleMove*)(Iterator_next(&iterator)); int currNumOfCaptures = PossibleMove_numOfCaptures(currMove); if(currNumOfCaptures > maxCaptures){ maxCaptures = currNumOfCaptures; } } //creating a new list and filling it only with the appropriate moves struct LinkedList* trimmedJumpMoves = LinkedList_new(&PossibleMove_free); if(trimmedJumpMoves == NULL){ // allocation failed return NULL; } struct Iterator secondIterator; Iterator_init(&secondIterator, jumpMovesList); while(Iterator_hasNext(&secondIterator)){ struct PossibleMove* currMove = (struct PossibleMove*)(Iterator_next(&secondIterator)); if(PossibleMove_numOfCaptures(currMove) == maxCaptures){ struct PossibleMove* clonedCurrMove = PossibleMove_clone(currMove); if (clonedCurrMove == NULL){ // allocation failed LinkedList_free(trimmedJumpMoves); return NULL; } LinkedList_add(trimmedJumpMoves, clonedCurrMove); } } LinkedList_free(jumpMovesList); return trimmedJumpMoves; }
int printBestMoves(char* command){ int depth; if (command[15] == 'b'){ depth = computeBestDepth(); } else{ if (sscanf(command, "get_best_moves %d", &depth) != 1){ return -1; } } LinkedList* allPossibleMoves = Board_getPossibleMoves(&board, turn); if (!allPossibleMoves){ return 1; } int bestScore = INT_MIN; Iterator iterator; Iterator_init(&iterator, allPossibleMoves); LinkedList* bestMoves = PossibleMoveList_new(); if (!bestMoves){ PossibleMoveList_free(allPossibleMoves); return 1; } while(Iterator_hasNext(&iterator)){ PossibleMove* currentMove = (PossibleMove*)Iterator_next(&iterator); int score = alphabeta(currentMove, depth, !turn, INT_MIN, INT_MAX); if (score > bestScore) { LinkedList_removeAll(bestMoves); if(LinkedList_add(bestMoves, currentMove)){ LinkedList_removeAll(bestMoves); LinkedList_free(bestMoves); PossibleMoveList_free(allPossibleMoves); return 1; } bestScore = score; } else if (score == bestScore){ if(LinkedList_add(bestMoves, currentMove)){ LinkedList_removeAll(bestMoves); LinkedList_free(bestMoves); PossibleMoveList_free(allPossibleMoves); return 1; } } } PossibleMoveList_print(bestMoves); LinkedList_removeAll(bestMoves); //removes the nodes LinkedList_free(bestMoves); //frees the struct LinkedList_free(allPossibleMoves); //frees the moves return 0; }
/* LinkedList* getRedirectionQueue() Description: Creates a queue that can be iterated through using _next() args: char** args Array of tokens return: LinkedList reverse so that _next() iterates through in order of args. Args are grouped with redirects in the middle of them. Returns NULL if not a proper redirection. */ LinkedList* getRedirectionQueue(char** args){ if(!isProperRedirection(args)){ return NULL; } LinkedList* stack = LinkedList_init(); LinkedList* output = LinkedList_init(); int j = 0; char** buffer = calloc(128, sizeof(*buffer)); for(int i = 0; args[i] != NULL; i++){ if(args[i][0] != '>' && args[i][0] != '<'){ buffer[j] = args[i]; //Start collecting args j++; }else{ //Redirect detected. Queue. LinkedList_queue(stack, buffer); char** redirect = calloc(1,sizeof(*redirect)); //Add the redirect symbol to the queue redirect[0] = args[i]; LinkedList_queue(stack, redirect); j = 0; buffer = calloc(128, sizeof(*buffer)); //Make new args collector } } if(buffer){ LinkedList_queue(stack, buffer); //Edge case. Final queue } output = LinkedList_reverse(stack); //Reverse stack to get queue LinkedList_free(stack); return output; }
LinkedList* getPipeQueue(char** args){ if(!isProperPipe(args)){ return NULL; } LinkedList* stack = LinkedList_init(); LinkedList* output = LinkedList_init(); int j = 0; char** buffer = calloc(128, sizeof(*buffer)); for(int i = 0; args[i] != NULL; i++){ if(args[i][0] != '|'){ buffer[j] = args[i]; //Start collecting args j++; }else{ //Pipe detected. Queue. LinkedList_queue(stack, buffer); char** pipeline = calloc(1,sizeof(*pipeline)); //Add the pipeline symbol to the queue pipeline[0] = args[i]; LinkedList_queue(stack, pipeline); j = 0; buffer = calloc(128, sizeof(*buffer)); //Make new args collector } } if(buffer){ LinkedList_queue(stack, buffer); //Edge case. Final queue } output = LinkedList_reverse(stack); //Reverse stack to get queue LinkedList_free(stack); return output; }
/* * 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; }
/* * Retrieves a list of all jump moves currently possible for a player. * * @params: (player) - the player whose moves are to be put in the list * @return: a LinkedList struct of jump moves currently possible for the player, or NULL if any allocation errors occurred */ static struct LinkedList* getPossibleJumps (char** board, int player){ struct LinkedList* jumpMoves = LinkedList_new(&PossibleMove_free); if(jumpMoves == NULL){ //allocation failed return NULL; } for (int x = 1; x <= Board_SIZE; x++){ for (int y = 1; y <= Board_SIZE; y++){ if (Board_evalPiece(board, x, y, player) <= 0){ continue; } for (int i = -1; i <= 1; i += 2){ for (int j = -1; j <= 1; j += 2){ struct Tile* destTile = NULL; if (!isInRange(x+i,y+j) || !isInRange(x+2*i,y+2*j)){ continue; } int pieceIsKing = Board_evalPiece(board, x, y, player) == 3; if (pieceIsKing){ destTile = canKingCaptureInDirection(board, x, y, i, j); } else{ int enemyNearby = Board_evalPiece(board, x+i, y+j, player) < 0; int enemyIsCapturable = Board_isEmpty(board, x+2*i, y+2*j); if(enemyNearby && enemyIsCapturable){ destTile = Tile_new(x+2*i, y+2*j); if (destTile == NULL){ // allocation failed return NULL; } } } if (!destTile){ continue; } struct LinkedList* jumpSteps = LinkedList_new(&Tile_free); if (jumpSteps == NULL){ // allocation failed Tile_free(destTile); return NULL; } LinkedList_add(jumpSteps, destTile); struct PossibleMove* possibleJumpMove = PossibleMove_new(x, y, jumpSteps, board); if (possibleJumpMove == NULL){ // allocation failed Tile_free(destTile); LinkedList_free(jumpSteps); return NULL; } populateJumpList(jumpMoves, possibleJumpMove); } } } } return jumpMoves; }
int leftMouseButtonUp(SDL_Event e){ convertPixelsToBoardPosition(e, &selectedX, &selectedY); if (movesOfSelectedPiece){ LinkedList_free(movesOfSelectedPiece); movesOfSelectedPiece = NULL; } movesOfSelectedPiece = Board_getPossibleMovesOfPiece(&board, selectedX, selectedY, 0); if (!movesOfSelectedPiece){ return 1; } return 0; }
/* * Gets a list of all single step moves currently possible for a player. * * @params: (player) - the player whose moves are to be put in the list * @return: a list of single step moves currently possible for the player, or NULL if any allocation errors occurred */ static struct LinkedList* getPossibleSingleMoves (char** board, int player){ struct LinkedList* possibleSingleMoves = LinkedList_new(&PossibleMove_free); if (possibleSingleMoves == NULL){ return NULL; } int forward = (player == BLACK) ? -1 : 1; /* for each player's different direction of "forward" */ for (int x = 1; x <= Board_SIZE; x++){ for (int y = 1; y <= Board_SIZE; y++){ if (Board_evalPiece(board, x, y, player) <= 0){ //this tile doesn't contain one of this player's pieces continue; } for (int sideward = -1; sideward <= 1; sideward += 2){ for (int k = -Board_SIZE; k <= Board_SIZE; k++){ if (!isInRange(x+k*sideward, y+k)){ continue; } int pieceIsKing = Board_evalPiece(board, x, y, player) == 3; if (!pieceIsKing && k != forward){ continue; } if(Board_isEmpty(board, x+k*sideward, y+k)){ struct Tile* destTile = Tile_new(x+k*sideward, y+k); if (destTile == NULL){ // allocation failed return NULL; } struct LinkedList* singleSteps = LinkedList_new(&Tile_free); if (singleSteps == NULL){ // allocation failed Tile_free(destTile); return NULL; } LinkedList_add(singleSteps, destTile); struct PossibleMove* possibleSingleMove = PossibleMove_new(x, y, singleSteps, board); if (possibleSingleMove == NULL){ // allocation failed Tile_free(destTile); LinkedList_free(singleSteps); return NULL; } LinkedList_add(possibleSingleMoves, possibleSingleMove); } if (!pieceIsKing && k == forward){ break; } } } } } return possibleSingleMoves; }
int setSelectedMoveToBest(){ if (movesOfSelectedPiece){ LinkedList_free(movesOfSelectedPiece); } movesOfSelectedPiece = LinkedList_new(&PossibleMove_free); if (!movesOfSelectedPiece){ return -1; } PossibleMove* bestMove = getBestMove(); if (!bestMove){ return -1; } selectedX = bestMove->fromX; selectedY = bestMove->fromY; if(LinkedList_add(movesOfSelectedPiece, bestMove)){ return -1; } return 0; }
/* * 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; }