void upgradePieces_ButtonClick(control* input) { char piece = ResolveLetterFromButtonName(input->name); chosenMove->new_disc = piece; if (is_move_in_move_list(chosenMove, curMovesList) == true){ make_move(board, chosenMove); SwitchButtonHighlight(gameSelectedSquare_control); gameSelectedSquare_control = NULL; curSettings->next_turn = get_opposite_color(curSettings->next_turn); free_move_list(curMovesList); curMovesList = NULL; free_move_list(posMovesFromCurPos); posMovesFromCurPos = NULL; free(chosenMove); chosenMove = NULL; Game(); } // DrawTree if (-1 == FlipTree(&error_global)) { guiQuit = -1; return; } }
int ComputerTurn(char** error) { if (gameOver == false && tie == false){ struct move_list* best_move_list = NULL; int number_of_boards_evaluated = 0; int current_move_grade = get_best_moves(curSettings->minimax_depth, board, get_opposite_color(curSettings->user_color), curMovesList, &best_move_list, &number_of_boards_evaluated); // Check for errors if (FAILED_ERROR == current_move_grade) { free_move_list(curMovesList); curMovesList = NULL; free_move_list(best_move_list); best_move_list = NULL; *error = "ERROR: Failed getting best moves."; return -1; } // Make the move make_move(board, &best_move_list->mov); curSettings->next_turn = get_opposite_color(curSettings->next_turn); free_move_list(curMovesList); curMovesList = NULL; free_move_list(posMovesFromCurPos); posMovesFromCurPos = NULL; free(chosenMove); chosenMove = NULL; free_move_list(best_move_list); Game(); } return 0; }
void GameBoardMainMenu_ButtonClick(control* input) { free_move_list(curMovesList); curMovesList = NULL; free_move_list(posMovesFromCurPos); posMovesFromCurPos = NULL; free(chosenMove); chosenMove = NULL; free(curSettings); MainMenu(); }
void GameBoardSave_ButtonClick(control* input) { isSaveMode = true; free_move_list(curMovesList); curMovesList = NULL; free_move_list(posMovesFromCurPos); posMovesFromCurPos = NULL; free(chosenMove); chosenMove = NULL; SaveLoadMenu(); }
static int negamax_algo(struct chessboard *c, int color, int depth, int alpha, int beta) { struct move_list *l; struct raw_move m; int n; int val, best_val = INT_MIN; if (!depth) return !color ? calculate_board_heuristic(c) : -calculate_board_heuristic(c); l = allocate_move_list(); for (int i = 0; i < 16; i++) { n = enumerate_moves(c, (color << 4) | i, l); expanded_moves += n; for (int j = 0; j < n; j++) { get_move(l, j, &m.sx, &m.sy, &m.dx, &m.dy); execute_raw_move(c, &m); evaluated_moves++; val = -negamax_algo(c, !color, depth - 1, -beta, -alpha); unwind_raw_move(c, &m); best_val = max(best_val, val); alpha = max(alpha, val); if (alpha >= beta) break; } } free_move_list(l); return best_val; }
static void ParseOptGameList(SourceFileType file_type) { Move *move_list = NULL; while(ParseGame(&move_list) && !finished_processing()) { if(file_type == NORMALFILE) { DealWithGame(move_list); } else if(file_type == CHECKFILE) { DealWithGame(move_list); } else if(file_type == ECOFILE) { if(move_list != NULL) { DealWithEcoLine(move_list); } else { fprintf(GlobalState.logfile,"ECO line with zero moves.\n"); report_details(GlobalState.logfile); } } else { /* Unknown type. */ free_tags(); free_move_list(move_list); } move_list = NULL; setup_for_new_game(); } }
/* Break up a single line of moves into a list of moves * comprising a positional variation. * In doing so, set GlobalState.depth_of_positional_search * if this variation is longer than the default. */ static Move * compose_positional_variation(char *line) { char *move; /* Build a linked list of the moves of the variation. */ Move *head = NULL, *tail = NULL; Boolean Ok = TRUE; /* Keep track of the depth. */ unsigned depth = 0; move = strtok(line," "); while(Ok && (move != NULL) && (*move != '*')){ if((move = strip_move_number(move)) == NULL){ /* Only a move number. */ } else{ Move *next = decode_move((unsigned char *) move); if(next == NULL){ fprintf(GlobalState.logfile,"Failed to identify %s\n",move); Ok = FALSE; } else{ /* Chain it on to the list. */ if(tail == NULL){ head = next; tail = next; } else{ tail->next = next; tail = next; } next->next = NULL; } depth++; } /* Pick up the next likely move. */ move = strtok(NULL," "); } if(Ok){ /* Determine whether the depth of this variation exceeds * the current default. * Depth is counted in move pairs. * Add some extras, in order to be surer of catching transpositions. */ depth = ((depth+1) / 2) + 4; if(depth > GlobalState.depth_of_positional_search){ GlobalState.depth_of_positional_search = depth; } } else{ if(head != NULL){ free_move_list(head); } head = NULL; } return head; }
void add_positional_variation_from_line(char *line) { if(non_blank_line(line)){ Move *next_variation = compose_positional_variation(line); if(next_variation != NULL){ /* We need a NULL fen string, because this is from * the initial position. */ store_hash_value(next_variation,(const char *)NULL); free_move_list(next_variation); /* We need to know globally that positional variations * are of interest. */ GlobalState.positional_variations = TRUE; } } }
/* Returns sx|sy|dx|dy in an integer byte-by-byte from least to most * significant, indicating which move should be made next. * * We seperate the initial iteration of negamax out like this to track the * actual move associated with the best score. Doing so during the * deeper iterations is a waste of time. */ unsigned int calculate_move(struct chessboard *c, int color, int depth) { struct move_list *l; int n, fbsx = -1, fbsy = -1, fbdx = -1, fbdy = -1; int val, best_val = INT_MIN, alpha = INT_MIN, beta = INT_MAX; struct raw_move m; struct timespec *t; expanded_moves = 0; evaluated_moves = 0; t = start_timer(); l = allocate_move_list(); for (int i = 0; i < 16; i++) { n = enumerate_moves(c, (color << 4) | i, l); expanded_moves += n; for (int j = 0; j < n; j++) { get_move(l, j, &m.sx, &m.sy, &m.dx, &m.dy); execute_raw_move(c, &m); evaluated_moves++; val = -negamax_algo(c, !color, depth - 1, -beta, -alpha); alpha = max(alpha, val); if (val > best_val) { best_val = val; fbsx = m.sx; fbsy = m.sy; fbdx = m.dx; fbdy = m.dy; } debug("Move %d/%d for piece %d (%d,%d) => (%d,%d) has heuristic value %d\n", j + 1, n, (color << 4) | i, m.sx, m.sy, m.dx, m.dy, val); unwind_raw_move(c, &m); } } free_move_list(l); expanded_moves += n; debug("Evaluated %luM/%luM expanded moves in %lu seconds\n", evaluated_moves / 1000000, expanded_moves / 1000000, get_timer_and_free(t) / 1000); return (fbsx) | (fbsy << 8) | (fbdx << 16) | (fbdy << 24); }
void GameBoardSquare_ButtonClick(control* input) { if ((curSettings->next_turn == curSettings->user_color || curSettings->game_mode == TWO_PLAYERS_GAME_MODE || isUpgrade) && gameOver == false){ if (input == gameSelectedSquare_control) { switchOffAllButtons(); gameSelectedSquare_control = NULL; free_move_list(posMovesFromCurPos); posMovesFromCurPos = NULL; } else if (gameSelectedSquare_control == NULL) { position chosenPos = GetPosOfSquare(input); if (is_piece_of_color(get_piece(board, chosenPos), curSettings->next_turn) == true){ SwitchButtonHighlight(input); gameSelectedSquare_control = input; get_moves_from_pos(curMovesList, chosenPos, &posMovesFromCurPos); HightlightPosMoves(posMovesFromCurPos); } } else if (gameSelectedSquare_control != NULL) { position startPos = GetPosOfSquare(gameSelectedSquare_control); position endPos = GetPosOfSquare(input); chosenMove = (move*)(calloc(1, sizeof(move))); if (chosenMove == NULL) { guiQuit = -1; return; } chosenMove->start_pos = startPos; chosenMove->end_pos = endPos; chosenMove->new_disc = EMPTY; if (is_move_in_move_list(chosenMove, curMovesList) == true){ if (isPawnUpgradePossible(chosenMove, board[(int)startPos.col][(int)startPos.row]) == true){ if (-1 == DrawPiecesOnSidePanelFilterColor(tree->children[0], &upgradePieces_ButtonClick, curSettings->next_turn, &error_global)) { free(chosenMove); chosenMove = NULL; guiQuit = -1; } isUpgrade = true; } else { make_move(board, chosenMove); SwitchButtonHighlight(gameSelectedSquare_control); gameSelectedSquare_control = NULL; curSettings->next_turn = get_opposite_color(curSettings->next_turn); free_move_list(curMovesList); curMovesList = NULL; free_move_list(posMovesFromCurPos); posMovesFromCurPos = NULL; free(chosenMove); chosenMove = NULL; Game(); return; } } } // DrawTree if (-1 == FlipTree(&error_global)) { guiQuit = -1; return; } } }
int HighlightBestMove(int blinknum, char** error) { struct move_list* best_move_list = NULL; int number_of_boards_evaluated = 0; // Get the best next move int current_move_grade = get_best_moves(curSettings->minimax_depth, board, curSettings->next_turn, curMovesList, &best_move_list, &number_of_boards_evaluated); // Check for errors if (FAILED_ERROR == current_move_grade) { free_move_list(best_move_list); return -1; } move bestMove = best_move_list->mov; position startPos = bestMove.start_pos; position endPos = bestMove.end_pos; control* startSquare = buttonsBoard[(int)startPos.col][7 - (int)startPos.row]; control* endSquare = buttonsBoard[(int)endPos.col][7 - (int)endPos.row]; bool startHiglighted = startSquare->ishighlighted; bool endHiglighted = endSquare->ishighlighted; startSquare->ishighlighted = 1; endSquare->ishighlighted = 1; for (int i = 0; i < blinknum; i++){ SwitchButtonHighlight(startSquare); SwitchButtonHighlight(endSquare); if (isPawnUpgradePossible(&bestMove, get_piece(board, startPos))) { char* fileName = ResolveFileNameFromLetter(bestMove.new_disc); char* name = ResolveNameFromLetter(bestMove.new_disc); if (fileName != NULL){ control* chessPiece_control; if (-1 == Create_panel_from_bmp( fileName, name, (Sint16)(GAMEBOARDBACKGROUND_W - BUTTON_W - MARGIN), (Sint16)(0.5*BOARD_H - SQUARE_H - 0.5), (Uint16)SQUARE_W, (Uint16)SQUARE_H, &chessPiece_control, error)) { return -1; } UINode* chessPiece_node; if (-1 == CreateAndAddNodeToTree(chessPiece_control, tree->children[0], &chessPiece_node, error)) { FreeControl(chessPiece_control); return -1; } } } // DrawTree if (-1 == FlipTree(error)) { return -1; } SDL_Delay(250); } startSquare->ishighlighted = startHiglighted; endSquare->ishighlighted = endHiglighted; free_move_list(best_move_list); return 0; }
int calculate_score_for_board_alpha(Disc board [BOARD_SIZE][BOARD_SIZE],int depth, int current_player, int alpha, int beta) { int is_max=0, temp = 0, current_depth = depth; Disc copy [BOARD_SIZE][BOARD_SIZE]; int temp_score =0; Move* curr_suggested_move =NULL; MoveList* moves_for_all_discs_this_turn = NULL, *curr =NULL; is_max = (current_player == global_current_player) ? 1 :-1; if (depth >=curret_max_depth || (global_max_depth ==5 && count > max_board_count)) { temp = get_discs_board_score_for_player(board, global_current_player); return temp; } update_all_legal_moves_for_player(board, current_player); moves_for_all_discs_this_turn = collect_all_moves_for_player(board, current_player); if (moves_for_all_discs_this_turn==NULL || moves_for_all_discs_this_turn->m ==NULL) { free_all_optional_moves_for_player(board, current_player); free_move_list(moves_for_all_discs_this_turn); moves_for_all_discs_this_turn = NULL; return (-600)*(is_max); } if (is_max ==1) { curr = moves_for_all_discs_this_turn; while (curr !=NULL) { if (global_max_depth ==5 && count > max_board_count) { free_all_optional_moves_for_player(board, current_player); free_move_list(moves_for_all_discs_this_turn); moves_for_all_discs_this_turn = NULL; return alpha; } count++; copy_board_from_copy(board, copy); curr_suggested_move = curr->m; make_turn_for_player(copy,curr_suggested_move,current_player); temp_score = calculate_score_for_board_alpha(copy, current_depth+1, (current_player)*(-1), alpha, beta); if (temp_score >= beta) { free_all_optional_moves_for_player(board, current_player); free_move_list(moves_for_all_discs_this_turn); moves_for_all_discs_this_turn = NULL; return beta; } if (temp_score > alpha) { alpha = temp_score; } curr = curr->next; } free_all_optional_moves_for_player(board, current_player); free_move_list(moves_for_all_discs_this_turn); moves_for_all_discs_this_turn = NULL; return alpha; } else { curr = moves_for_all_discs_this_turn; while (curr !=NULL) { if (global_max_depth ==5 && count > max_board_count) { free_all_optional_moves_for_player(board, current_player); free_move_list(moves_for_all_discs_this_turn); moves_for_all_discs_this_turn = NULL; return beta; } count++; copy_board_from_copy(board, copy); curr_suggested_move = curr->m; make_turn_for_player(copy,curr_suggested_move,current_player); temp_score = calculate_score_for_board_alpha(copy, current_depth+1, (current_player)*(-1), alpha, beta); if (temp_score <= alpha) { free_all_optional_moves_for_player(board, current_player); free_move_list(moves_for_all_discs_this_turn); moves_for_all_discs_this_turn = NULL; return alpha; } if (temp_score< beta) { beta = temp_score; } curr = curr->next; } free_all_optional_moves_for_player(board, current_player); free_move_list(moves_for_all_discs_this_turn); moves_for_all_discs_this_turn = NULL; return beta; } return 5000; }
Move* MaxMove (Disc board [BOARD_SIZE][BOARD_SIZE],int current_player) { Disc copy [BOARD_SIZE][BOARD_SIZE]; int temp_score =0, alpha =-1000; Move* best_move =NULL; Move* curr_suggested_move =NULL; MoveList* moves_for_all_discs_this_turn = NULL, *curr =NULL; count =0; update_all_legal_moves_for_player(board, current_player); moves_for_all_discs_this_turn = collect_all_moves_for_player(board, current_player); if (global_max_depth == 5) { curret_max_depth = calculate_current_best_max_depth(board); } else { curret_max_depth = global_max_depth; } curr = moves_for_all_discs_this_turn; while (curr !=NULL && curr->m !=NULL) { copy_board_from_copy(board, copy); curr_suggested_move = curr->m; make_turn_for_player(copy,curr_suggested_move,current_player); if (global_max_depth ==5 && count > max_board_count) { free_all_optional_moves_for_player(copy,current_player); free_move_list(moves_for_all_discs_this_turn); moves_for_all_discs_this_turn = NULL; printf ("%lu\n",count); return best_move; } count++; temp_score = calculate_score_for_board_alpha(copy, 0, current_player*-1, -1000, 1000); if (temp_score >= alpha) { if (best_move !=NULL) { free_move(&best_move); best_move = NULL; } best_move= init_move_from_int_arrs(curr_suggested_move->from, curr_suggested_move->to); alpha =temp_score; } curr = curr->next; } free_all_optional_moves_for_player(copy,current_player); free_move_list(moves_for_all_discs_this_turn); moves_for_all_discs_this_turn = NULL; curr= NULL; printf ("%lu\n",count); return best_move; }
int get_move_score_using_minimax( int max_depth, char board[BOARD_SIZE][BOARD_SIZE], COLOR current_color, COLOR run_for_color, int current_depth, struct move_list* move_list, int alpha, int beta, int* number_of_boards_evaluated) { bool maximizingPlayer = current_depth % 2 == 0 ? true : false; int grade = 4000; if (maximizingPlayer) { grade *= -1; } struct move_list* current_move_node = move_list; do { // Temp board for current move char minimax_board[BOARD_SIZE][BOARD_SIZE]; (*number_of_boards_evaluated)++; // Copies the board to a temp board copy_boards(board, minimax_board); // Make the move we want to check make_move(minimax_board, ¤t_move_node->mov); int score = get_board_score_for_color(minimax_board, run_for_color); int current_move_grade = FAILED_ERROR; // Stop condition - if we got to the max depth or there is a winner if (max_depth == current_depth + 1 || WIN_SCORE == score || LOSE_SCORE == score) { current_move_grade = score; } else { // Get the color of the next turn COLOR next_color = get_opposite_color(current_color); // Get the move list for the next turn struct move_list* minimax_move_list = NULL; if (-1 == get_moves_for_color(minimax_board, next_color, &minimax_move_list)) { // get_moves_for_color failed return FAILED_ERROR; } // Checks if there is no moves for the next turn if (NULL == minimax_move_list) { current_move_grade = score; } else { // Run minimax again with the new board and position current_move_grade = get_move_score_using_minimax(max_depth, minimax_board, next_color, run_for_color, current_depth + 1, minimax_move_list, alpha, beta, number_of_boards_evaluated); free_move_list(minimax_move_list); // If return value is FAILED_ERROR there was an error with a standard function if (FAILED_ERROR == current_move_grade) { return FAILED_ERROR; } } } if (maximizingPlayer) { grade = grade > current_move_grade ? grade : current_move_grade; alpha = alpha > grade ? alpha : grade; } else { grade = grade < current_move_grade ? grade : current_move_grade; beta = beta < grade ? beta : grade; } if (beta <= alpha) { break; } } while (NULL != (current_move_node = current_move_node->next)); return grade; }
int get_best_moves( int max_depth, char board[BOARD_SIZE][BOARD_SIZE], COLOR run_for_color, struct move_list* move_list, struct move_list** best_move_list, int* number_of_boards_evaluated) { int grade = -4000; int current_depth = 0; struct move_list* current_move_node = move_list; do { // Temp board for current move char minimax_board[BOARD_SIZE][BOARD_SIZE]; (*number_of_boards_evaluated)++; // Copies the board to a temp board copy_boards(board, minimax_board); // Make the move we want to check make_move(minimax_board, ¤t_move_node->mov); int score = get_board_score_for_color(minimax_board, run_for_color); int current_move_grade = FAILED_ERROR; // Stop condition - if we got to the max depth or there is a winner if (max_depth == current_depth + 1 || WIN_SCORE == score || LOSE_SCORE == score) { current_move_grade = score; } else { // Get the color of the next turn COLOR next_color = get_opposite_color(run_for_color); // Get the move list for the next turn struct move_list* minimax_move_list = NULL; if (-1 == get_moves_for_color(minimax_board, next_color, &minimax_move_list)) { // get_moves_for_color failed return FAILED_ERROR; } // Checks if there is no moves for the next turn if (NULL == minimax_move_list) { current_move_grade = score; } else { // Run minimax again with the new board and position current_move_grade = get_move_score_using_minimax(max_depth, minimax_board, next_color, run_for_color, current_depth + 1, minimax_move_list, ALPHA_INIT, BETA_INIT, number_of_boards_evaluated); free_move_list(minimax_move_list); // If return value is FAILED_ERROR there was an error with a standard function if (FAILED_ERROR == current_move_grade) { return FAILED_ERROR; } } } // Update the grade if it the first move or take the max grade or the min grade according to the depth if (current_move_grade >= grade) { if (current_move_grade > grade) { free_move_list(*best_move_list); *best_move_list = NULL; } struct move_list* temp = add_new_move_node(*best_move_list, current_move_node->mov.start_pos, current_move_node->mov.end_pos, current_move_node->mov.new_disc); if (NULL == temp) { return FAILED_ERROR; } *best_move_list = temp; grade = current_move_grade; } } while (NULL != (current_move_node = current_move_node->next)); return grade; }