char getBestMove(char subBoard[], char superBoard[], char superBoardSpot, char opPlayer, char levels) { long best = -9999999999; char move; char start, end; char j = 0; char lastSuperBoardState; if (superBoardSpot == -1) { //search all spots on the board start = 0; end = SUB_BOARD_SIZE; } else { start = superBoardSpot * 9; end = start + 9; } threadpool thpool = thpool_init(THREADS); //search within the superboard for (char i = start; i < end; i++) { if (isOpenSpot(subBoard, superBoard, i)) { //Take the winning move is available lastSuperBoardState = superBoard[(i - (i % 9)) / 9]; char newSuperBoardSpot = doMove(subBoard, superBoard, opPlayer, i); if (superBoardWon(superBoard) == opPlayer) { undoMove(subBoard, superBoard, i, lastSuperBoardState); return i; } undoMove(subBoard, superBoard, i, lastSuperBoardState); ThreadData data; data.subBoard = copyBoard(subBoard, SUB_BOARD_SIZE); data.superBoard = copyBoard(superBoard, SUPER_BOARD_SIZE); data.opPlayer = opPlayer; data.levels = levels; data.move = i; tData[j] = data; thpool_add_work(thpool, (void*)threadStarter, j++); } } numThreads = j; thpool_wait(thpool); for (char i = 0; i < numThreads; i++) { if (trData[i].score > best) { best = trData[i].score; move = trData[i].move; } } return move; }
bool isLegalMove(Board_t self, int move) { makeMove(self, move); bool isLegal = wasLegalMove(self); undoMove(self); return isLegal; }
Move getBestMove(board Game, Piece piece, Point point) { Move possibleMoves[26]; int possibleMovesNumber = getPossibleMoves(Game, piece, possibleMoves, point); Move result = NULL; int bestValue = -INFINITY; for (int i = 0; i < possibleMovesNumber; i++) { doMove(Game, possibleMoves[i]); int moveValue = evaluatePosition(Game, aiPlayerNumber, possibleMoves[i]); if (moveValue > bestValue) { result = possibleMoves[i]; bestValue = moveValue; } undoMove(Game, possibleMoves[i]); } for (int i=0; i<possibleMovesNumber; i++) { if (result != possibleMoves[i]) { cleanMoveData(possibleMoves[i]); } } return result; }
int Game::minMove(int depth, int alpha, int beta) { std::vector<int> allMoves = getAvailableMoves(); int winner = checkWinner(); if ((allMoves.size() <= 0 || winner > 0) || depth <= 0) { return evaluateState(2, winner); } int* bestMove = NULL; int bestScore = INT_MAX; for (std::vector<int>::const_iterator it = allMoves.begin(); it != allMoves.end(); it++) { setCell(*it, 1); int score = maxMove(depth - 1, alpha, beta); undoMove(*it); if (score < bestScore) { bestScore = score; beta = score; } if (beta < alpha) { return bestScore; } } return bestScore; }
PositionStatus AbstractGame::getPositionStatus() { if(!POSITION_DEFINED()) { if(m_bricksOnBoard <= 1) { DEFINE_POSITION(m_bricksOnBoard == 0, m_bricksOnBoard); } else { bool winnerMoveFound = false; int pliesToWin = 30; int pliesToLoose = 0; for(Move m = firstMove(); m && !winnerMoveFound; m = nextMove(m)) { doMove(m); const PositionStatus status = getPositionStatus(); if(IS_LOOSERSTATUS(status)) { winnerMoveFound = true; if(PLIESTOEND(status) < pliesToWin) { pliesToWin = PLIESTOEND(status); } } else if(!winnerMoveFound) { if(PLIESTOEND(status) > pliesToLoose) { pliesToLoose = PLIESTOEND(status); } } undoMove(m); } if(winnerMoveFound) { DEFINE_POSITION(true , pliesToWin + 1); } else { DEFINE_POSITION(false, pliesToLoose + 1); } } } return m_statusTable[m_board]; }
Move AbstractGame::findBestMove(MoveResultArray &moveArray, PlayLevel level) { moveArray.clear(); for(Move m = firstMove(); m; m = nextMove(m)) { doMove(m); const PositionStatus status = getPositionStatus(); moveArray.add(MoveWithResult(m, MAKE_STATUS(IS_LOOSERSTATUS(status),PLIESTOEND(status)+1))); undoMove(m); } moveArray.sort(); return moveArray.selectBestMove(level, m_bricksOnBoard); }
void Ship::go() { if (tempSpeed > 0) { properties.posX += cos(properties.shipDirection); properties.posX += sin(properties.shipDirection); if (isOnTheScreen()) { --tempSpeed; --turnData.move; } else undoMove(); } }
long long moveTest(Board_t self, int depth) { if (depth <= 0) return 1; long long total = 0; int moveList[maxMoves]; int nrMoves = generateMoves(self, moveList); for (int i=0; i<nrMoves; i++) { makeMove(self, moveList[i]); if (wasLegalMove(self)) total += moveTest(self, depth - 1); undoMove(self); } return total; }
void test_undo_move(){ //if I am able to insert 7th entry in a column //after undoing the 8th entry then my test succeeds int i = 0; for(i=0; i < rows; ++i){ assert_true(validMove(g_board,4)==1); makeMove(g_board, 4); } assert_true(validMove(g_board,4)==0); undoMove(g_board); assert_true(validMove(g_board,4)==1); }
void Move::performUndo(Player& p, Player& q, std::vector<Vertex>& v) { switch (p.getMove().state) { case PlayState::State::PLACE: undoPlace(p, v[p.getMove().fInt - 1]); break; case PlayState::State::SLIDE: case PlayState::State::HOP: undoMove(p, v[p.getMove().fInt - 1], v[p.getMove().tInt - 1]); break; case PlayState::State::REMOVE: undoRemove(p, q, v[p.getMove().fInt - 1]); break; default: break; } }
int Game::minMax() { std::vector<int> allMoves = getAvailableMoves(); int bestMove = NULL; int bestScore = INT_MIN; for (std::vector<int>::const_iterator it = allMoves.begin(); it != allMoves.end(); it++) { setCell(*it, 1); int val = maxMove(100, INT_MIN + 1, INT_MAX); undoMove(*it); if (val > bestScore) { bestScore = val; bestMove = *it; } } return bestMove; }
int abMax(int** board, int alpha, int beta, list<Move>& actions, Move move, int depth) { switch(terminalState(board, move)) { case Draw: return 0; break; case Win: return -INFINITE_SCORE; break; } //Depth handling if(depth==0) return staticEvaluation(board); if(depth != -1) depth--; list<Move>* children = legalMoves(board); int v = -INFINITE_SCORE; int w; for(list<Move>::iterator it = children->begin(); it != children->end(); ++it) { list<Move> &tmp = list<Move>(); int i = it->x; int j = it->y; doMove(board, *it, PLAYER_COLOR); display(board); w = abMin(board, alpha, beta, tmp, *it,depth); undoMove(board, *it); if(w > v) { v = w; actions = tmp; actions.push_front(*it); } if(v >= beta) return v; alpha = max(alpha, v); } return v; }
MOVESTATUS BOARD::doUserMove ( POSITION start, POSITION end ) { PIECE *p = whatPiece(start.row, start.col); POSITIONLIST moves; BOARDMETRIC metric; BESTMOVES bestMoves; MOVEUNDODATA undoData; int m; if (!p) return(MOVESTATUS(ILLEGALMOVE)); p->legalMoves(start, *this, moves); for (m = 0; m < moves.nMoves; m++) { if ((moves.end[m].row == end.row) && (moves.end[m].col == end.col)) break; } if (m == moves.nMoves) return(MOVESTATUS(ILLEGALMOVE)); doMove(start, end, undoData); findBestMoves(1, OtherColor(p->whatColor()), metric, &bestMoves); if (metric.kingSituation[p->whatColor()] == KINGLOST) { undoMove(end, start, undoData); return(MOVESTATUS(WOULDLOSEKING, bestMoves.move[0].start)); } if (undoData.capturedPiece) delete undoData.capturedPiece; if (undoData.enPassantEffect == ENPASSANTCAPTURE) return(MOVESTATUS(MOVEENPASSANT)); else return(MOVESTATUS(MOVEDONE)); }
/* Make sure that makeMove, validMovesLeft and undoMove work correctly in a * 'normal' situation. */ void test_moves_properly() { board_type *board = createBoard(X, Y); int i, j; for(i = 0; i < X; i++) { for(j = 0; j < Y; j++) { makeMove(board, i); } } CU_ASSERT_FALSE(validMovesLeft(board)); CU_ASSERT_EQUAL(board->lm, (X * Y) + LM_INIT); for(i = 0; i < X; i++) { for(j = 0; j < Y; j++) { undoMove(board); } } CU_ASSERT_EQUAL(board->lm, LM_INIT); CU_ASSERT_TRUE(validMovesLeft(board)); free(board); }
int main(int argc, char *argv[]) { { int i; if((argc - 1) % 2) goto help; for(i = 1; i < argc - 1; i += 2) if(!editing && (!strcmp(argv[i], "-e") || !strcmp(argv[i], "--edit"))) editing = argv[i+1]; else if(!layout_title[0] && (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--title"))) { bzero(layout_title, 55); strncpy(layout_title, argv[i+1], 54); } else { help: printf("usage: mahjong [--edit <layout> [--title <layout title>]]\n"); return 0; } } srand(time(NULL)); allegro_init(); { int x, y, z; for(x = 16; x--;) for(y = 9; y--;) for(z = 3; z--;) pieceInit(board[x][y][z], x, y, z); } set_color_depth(SCREEN_DEPTH); if(set_gfx_mode(GFX_AUTODETECT_WINDOWED, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH*2, SCREEN_HEIGHT) < 0) { fprintf(stderr, "fatal: %s\n", allegro_error); exit(1); } #ifdef ALLEGRO_WINDOWS set_display_switch_callback(SWITCH_IN, update); #endif left_view = create_sub_bitmap(screen, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); right_view = create_sub_bitmap(screen, SCREEN_WIDTH, 0, SCREEN_WIDTH, SCREEN_HEIGHT); // init colors BACKGROUND_COLOR = makecol32(0x2F, 0x5F, 0x2F); // soft green SELECTED_COLOR = makecol32(0x00, 0xDF, 0x00); // green OLD_SELECTED_COLOR = makecol32(0x00, 0xBF, 0xBF); // cyan // load data { DATAFILE *data = load_datafile("#"); new_game = data[NEW_GAME_BMP].dat; undo = data[UNDO_BMP].dat; help = data[HELP_BMP].dat; quit = data[QUIT_BMP].dat; tile = data[TILE_BMP].dat; number[ 0] = data[BLACK1_BMP].dat; number[ 2] = data[BLACK2_BMP].dat; number[ 4] = data[BLACK3_BMP].dat; number[ 6] = data[BLACK4_BMP].dat; number[ 8] = data[BLACK5_BMP].dat; number[10] = data[BLACK6_BMP].dat; number[12] = data[BLACK7_BMP].dat; number[14] = data[BLACK8_BMP].dat; number[16] = data[BLACK9_BMP].dat; number[ 1] = data[RED1_BMP].dat; number[ 3] = data[RED2_BMP].dat; number[ 5] = data[RED3_BMP].dat; number[ 7] = data[RED4_BMP].dat; number[ 9] = data[RED5_BMP].dat; number[11] = data[RED6_BMP].dat; number[13] = data[RED7_BMP].dat; number[15] = data[RED8_BMP].dat; number[17] = data[RED9_BMP].dat; suit[0] = data[SPADE_BMP].dat; suit[1] = data[CLUB_BMP].dat; suit[2] = data[DIAMOND_BMP].dat; suit[3] = data[HEART_BMP].dat; layouts[0] = data[BLOCK_LYT].dat; layouts[1] = data[FLAT_LYT].dat; layouts[2] = data[FROGGER_LYT].dat; layouts[3] = data[PRECIOUS_LYT].dat; layouts[4] = data[PTRAD_LYT].dat; layouts[5] = data[PYRAMID_LYT].dat; layouts[6] = data[STEPS_LYT].dat; layouts[7] = data[THETA_LYT].dat; } scroll_screen(SCREEN_WIDTH, 0); current_view = right_view; install_timer(); install_mouse(); install_keyboard(); show_mouse(current_view); text_mode(BACKGROUND_COLOR); if(!editing) { defaultLayout(); if(alert("Our Own Version of Mahjong Solitaire, v0.1.4", NULL, "Copyright (c) 2001 Eric Mulvaney, Michelle Bondy", "Play", "Edit", 0, 0) == 2 && file_select_ex("Please select layout file to edit:", path, "lyt", PATH_LENGTH-1, OLD_FILESEL_WIDTH, OLD_FILESEL_HEIGHT)) { int x, y, z; editing = path; for(x = 16; x--;) for(y = 9; y--;) for(z = 3; z--;) board[x][y][z].value = EMPTY; } } mouse_callback = editing ? mouse_handler_for_editing : mouse_handler; if(editing) { Layout data; FILE *file = fopen(editing, "r"); if(file) { if(fread(&data, sizeof(Layout), 1, file)) { int x, y, z; if(!layout_title[0]) memcpy(layout_title, data.title, 55); for(x = 16; x--;) for(y = 9; y--;) for(z = (data.board[x][y] > 3) ? 3 : data.board[x][y]; z--;) { board[x][y][z].value = BLANK; if(!--n_pieces_left) goto skip; } } skip: fclose(file); } update(); } click_ready = 0; while(1) // game loop { if(click_ready) { int x = click_x - (BOARD_XOFF - 2 * EDGE_WIDTH ); int y = click_y - (BOARD_YOFF - 2 * EDGE_HEIGHT); int z; for(z = 3; x > 0 && y > 0 && z--; x -= EDGE_WIDTH, y -= EDGE_HEIGHT) { int i = x / FACE_WIDTH; int j = y / FACE_HEIGHT; if(i >= 16 || j >= 9) continue; if(editing) { if(click_ready == 1 && board[i][j][z].value == EMPTY) { if((z == 0 || board[i][j][z-1].value != EMPTY) && n_pieces_left) { n_pieces_left--; board[i][j][z].value = BLANK; updatePiece(&board[i][j][z]); goto event_handled; } } else if(click_ready == 2 && board[i][j][z].value != EMPTY) { if(z == 2 || board[i][j][z+1].value == EMPTY) { board[i][j][z].value = EMPTY; n_pieces_left++; updatePiece(&board[i][j][z]); goto event_handled; } } } else if(selectPiece(&board[i][j][z])) { if(!n_pairs_remaining) { if(current_view != left_view) update(); if(alert("Congratulations! You won!", "Play another?", NULL, "Yes", "No", 0, 0) == 1) newGame(); else return 0; } goto event_handled; } } if(click_y < BUTTON_YOFF + BUTTON_HEIGHT && click_y > BUTTON_YOFF) { if(editing) { if(click_x > NEW_GAME_BUTTON_X1 && click_x < NEW_GAME_BUTTON_X2) { if(n_pieces_left == 144) goto event_handled; if(current_view != left_view) update(); if(alert("Are you sure you want to clear the current Layout?", NULL, NULL, "Yes", "No", 0, 0) == 1) { int x, y, z; for(x = 16; x--;) for(y = 9; y--;) for(z = 3; z--;) board[x][y][z].value = EMPTY; n_pieces_left = 144; update(); } } else if(click_x > QUIT_BUTTON_X1 && click_x < QUIT_BUTTON_X2) { int ync; if(current_view != left_view) update(); if(n_pieces_left) ync = alert3("WARNING: Layout is incomplete.", NULL, "Do you wish to save before exiting?", "Yes", "No", "Cancel", 0, 0, 0); else ync = alert3("Do you wish to save before exiting?", NULL, NULL, "Yes", "No", "Cancel", 0, 0, 0); if(ync == 2) return 0; else if(ync == 1) { Layout data; FILE *file; memcpy(data.title, layout_title, 55); data.complete = (n_pieces_left) ? 0 : 1; if((file = fopen(editing, "w"))) { for(x = 16; x--;) for(y = 9; y--;) { if (board[x][y][2].value == BLANK) data.board[x][y] = 3; else if(board[x][y][1].value == BLANK) data.board[x][y] = 2; else if(board[x][y][0].value == BLANK) data.board[x][y] = 1; else data.board[x][y] = 0; } if(fwrite(&data, sizeof(Layout), 1, file)) { fclose(file); return 0; } else fclose(file); } if(alert("WARNING: Save failed!", NULL, "Do you still wish to exit?", "Yes", "No", 0, 0) == 1) return 0; } } } else if(click_x > NEW_GAME_BUTTON_X1 && click_x < NEW_GAME_BUTTON_X2) newGame(); else if(click_x > UNDO_BUTTON_X1 && click_x < UNDO_BUTTON_X2) undoMove(); else if(click_x > HELP_BUTTON_X1 && click_x < HELP_BUTTON_X2) giveHelp(1); else if(click_x > QUIT_BUTTON_X1 && click_x < QUIT_BUTTON_X2) { if(current_view != left_view) update(); if(alert("Are you sure you want to quit?", NULL, NULL, "Yes", "No", 0, 0) == 1) return 0; } } event_handled: click_ready = 0; } else rest(100); } return 0; }
int alphaBeta(int depth, int alpha, int beta, bool whiteToPlay) { int val, i; EVALUATE_INFO_t eval = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint32_t legalMoves = 0; PIECE_t pieceBackup; PIECE_e piece; #if ENABLE_TRANSPOSITION_TABLE int hashFlag = ALPHA_HASH_RESULT; if (val = probeHash(depth, alpha, beta) != UNKNOWN_HASH_RESULT) { cacheHits++; return val; } else { cacheMisses++; } #endif // ENABLE_TRANSPOSITION_TABLE // calculate all of the moves MOVE_t moves[MOVE_LIST_SIZE]; legalMoves += AddAllLegalMovesToMoveList(moves, &eval, whiteToPlay); if (!legalMoves && depth == currentDepth) { printf("pass"); exit(0); } if (depth == 0) { numberEvaluations++; AddAllLegalMovesToMoveList(&moves[legalMoves-1], &eval, !whiteToPlay); val = evaluateBoard(&eval); #if ENABLE_TRANSPOSITION_TABLE recordHash(depth, val, EXACT_HASH_RESULT); #endif //ENABLE_TRANSPOSITION_TABLE if (!whiteToPlay) val = val * -1; return val; } numberNodes++; // for each move for (i = 0; i < legalMoves; i++) { // backup piece so we can undo the move later piece = (moves[i].move & PIECE_MASK) >> PIECE_SHIFT; pieceBackup.piece = pieces[piece].piece; // play the move playMove(moves, i); // Check to see if this position is a win val = isWin(); if (!whiteToPlay) { val = val*-1; } if (val > DRAW_SCORE) { val = val + depth; } else if (val < 0) { val = val - depth; } else if (val == DRAW_SCORE) { val = 0; } else { // not a win or draw; search deeper //val = alphaBeta(depth - 1, alpha, beta, !whiteToPlay); val = -alphaBeta(depth - 1, -beta, -alpha, !whiteToPlay); } // undo move undoMove(pieceBackup, piece); // alpha beta pruning: if (val >= beta) { #if ENABLE_TRANSPOSITION_TABLE recordHash(depth, beta, BETA_HASH_RESULT); #endif //ENABLE_TRANSPOSITION_TABLE return beta; } if (val > alpha) { alpha = val; if (depth == currentDepth) { currMove.move = moves[i].move; currentScore = val; } #if ENABLE_TRANSPOSITION_TABLE hashFlag = EXACT_HASH_RESULT; #endif //ENABLE_TRANSPOSITION_TABLE } } #if ENABLE_TRANSPOSITION_TABLE recordHash(depth, alpha, hashFlag); #endif //ENABLE_TRANSPOSITION_TABLE return alpha; }
//Minimax with alpha beta pruning long minimax(char subBoard[], char superBoard[], char superBoardSpot, char goal, char opPlayer, char level, long alpha, long beta) { char gameOver = superBoardWon(superBoard); char start, end; char player; long v; struct timeval testTime; double elapsedTime; char lastSuperBoardState; //Time ran out gettimeofday(&testTime, NULL); elapsedTime = (testTime.tv_sec - t1.tv_sec); if (elapsedTime >= MAX_TURN_TIME) { return heuristic(subBoard, superBoard, opPlayer); } if (level == 0) { return heuristic(subBoard, superBoard, opPlayer); } if (gameOver > -1) { return heuristic(subBoard, superBoard, opPlayer); } //We need to go deeper if (superBoardSpot == -1) { //search all spots on the board start = 0; end = SUB_BOARD_SIZE; } else { start = superBoardSpot * 9; end = start + 9; } //setup the minimizer/maximizer if (goal == MAXIMIZE) { v = -9999999999; //Choose the player based on whether we are maximizing or minimizing if (opPlayer == X) { player = X; } else { player = O; } for (int i=start; i < end; i++) { if (isOpenSpot(subBoard, superBoard, i)) { char newSuperBoardSpot; long result; //Time ran out gettimeofday(&testTime, NULL); elapsedTime = (testTime.tv_sec - t1.tv_sec); if (elapsedTime >= MAX_TURN_TIME) { return v; } lastSuperBoardState = superBoard[(i - (i % 9)) / 9]; newSuperBoardSpot = doMove(subBoard, superBoard, player, i); result = minimax(subBoard, superBoard, newSuperBoardSpot, MINIMIZE, opPlayer, level - 1, alpha, beta); undoMove(subBoard, superBoard, i, lastSuperBoardState); if (result > v) { v = result; } if (v > alpha) { alpha = v; } if (beta <= alpha) { break; } } } } else { v = 9999999999; //Choose the player based on whether we are maximizing or minimizing if (opPlayer == X) { player = O; } else { player = X; } for (int i=start; i < end; i++) { if (isOpenSpot(subBoard, superBoard, i)) { char newSuperBoardSpot; long result; //Time ran out gettimeofday(&testTime, NULL); elapsedTime = (testTime.tv_sec - t1.tv_sec); if (elapsedTime >= MAX_TURN_TIME) { return v; } lastSuperBoardState = superBoard[(i - (i % 9)) / 9]; newSuperBoardSpot = doMove(subBoard, superBoard, player, i); result = minimax(subBoard, superBoard, newSuperBoardSpot, MAXIMIZE, opPlayer, level - 1, alpha, beta); undoMove(subBoard, superBoard, i, lastSuperBoardState); if (result < v) { v = result; } if (v < beta) { alpha = v; } if (beta <= alpha) { break; } } } } return v; }
void BOARD::helpFindBestMoves ( int lookAhead, PIECECOLOR moveColor, BOARDMETRIC &metric, BESTMOVES *bestMoves ) { POSITION where; POSITIONLIST moves; BOARDMETRIC testMetric; BOOL metricSet = FALSE; MOVEUNDODATA undoData; int m, compareResult; int origMaterialDiff = metric.materialDiff; MOVETYPE castleType; testMetric.kingSituation[WHITE] = KINGOK; testMetric.kingSituation[BLACK] = KINGOK; // try all possible moves for the given color for (where.row = 0; where.row < NUMROWS; where.row++) for (where.col = 0; where.col < NUMCOLS; where.col++) { if (whatPiece(where)) if (whatPiece(where)->whatColor() == moveColor) { whatPiece(where)->legalMoves(where, *this, moves); for (m = 0; m < moves.nMoves; m++) { testMetric.materialDiff = origMaterialDiff; doMove ( where, moves.end[m], undoData ); if (undoData.capturedPiece) { if (undoData.capturedPiece->whatType() == TYPEKING) { undoMove ( moves.end[m], where, undoData ); metric.kingSituation[OtherColor(moveColor)] = KINGLOST; if (bestMoves) { bestMoves->nMoves = 0; bestMoves->move[0] = PIECEMOVE ( NORMALMOVE, where, moves.end[m] ); } return; } testMetric.materialDiff -= undoData.capturedPiece->signedValue(); } if (canPromote(moves.end[m])) { testMetric.materialDiff -= whatPiece(moves.end[m])->signedValue(); promote(moves.end[m], TYPEQUEEN); testMetric.materialDiff += whatPiece(moves.end[m])->signedValue(); if (lookAhead > 1) helpFindBestMoves ( lookAhead - 1, OtherColor(moveColor), testMetric, (BESTMOVES *) 0 ); compareResult = compareMetric ( testMetric, metric, metricSet, moveColor ); if (compareResult >= 0) { if (compareResult > 0) { metric = testMetric; metricSet = TRUE; if (bestMoves) bestMoves->nMoves = 0; } if (bestMoves) bestMoves->move[bestMoves->nMoves++] = PIECEMOVE ( NORMALMOVE, where, moves.end[m], TYPEQUEEN ); } testMetric.materialDiff -= whatPiece(moves.end[m])->signedValue(); restorePawn(moves.end[m]); promote(moves.end[m], TYPEKNIGHT); testMetric.materialDiff += whatPiece(moves.end[m])->signedValue(); if (lookAhead > 1) helpFindBestMoves ( lookAhead - 1, OtherColor(moveColor), testMetric, (BESTMOVES *) 0 ); compareResult = compareMetric ( testMetric, metric, metricSet, moveColor ); if (compareResult >= 0) { if (compareResult > 0) { metric = testMetric; metricSet = TRUE; if (bestMoves) bestMoves->nMoves = 0; } if (bestMoves) bestMoves->move[bestMoves->nMoves++] = PIECEMOVE ( NORMALMOVE, where, moves.end[m], TYPEKNIGHT ); } restorePawn(moves.end[m]); } else // no promotion { if (lookAhead > 1) helpFindBestMoves ( lookAhead - 1, OtherColor(moveColor), testMetric, (BESTMOVES *) 0 ); compareResult = compareMetric ( testMetric, metric, metricSet, moveColor ); if (compareResult >= 0) { if (compareResult > 0) { metric = testMetric; metricSet = TRUE; if (bestMoves) bestMoves->nMoves = 0; } if (bestMoves) bestMoves->move[bestMoves->nMoves++] = PIECEMOVE ( NORMALMOVE, where, moves.end[m] ); } } undoMove ( moves.end[m], where, undoData ); } // end of for loop over each legal move for piece } } // end of double for loop over each board position // only try castling moves if look ahead move than one, since // nothing can be captured by doing a castling move if (lookAhead > 1) { castleType = QUEENSIDECASTLE; for ( ; ; ) { if (canCastle(castleType, moveColor)) { testMetric.materialDiff = origMaterialDiff; castle(castleType, moveColor, undoData); helpFindBestMoves ( lookAhead - 1, OtherColor(moveColor), testMetric, (BESTMOVES *) 0 ); compareResult = compareMetric ( testMetric, metric, metricSet, moveColor ); if (compareResult >= 0) { if (compareResult > 0) { metric = testMetric; metricSet = TRUE; if (bestMoves) bestMoves->nMoves = 0; } if (bestMoves) bestMoves->move[bestMoves->nMoves++] = PIECEMOVE(castleType); } undoCastle(castleType, moveColor, undoData); } if (castleType == KINGSIDECASTLE) break; castleType = KINGSIDECASTLE; } // see if the loss of the king is the result of a stalemate // instead of check mate if (metric.kingSituation[moveColor] == KINGLOST) { helpFindBestMoves ( 1, OtherColor(moveColor), testMetric, (BESTMOVES *) 0 ); if (testMetric.kingSituation[moveColor] != KINGLOST) // king will be lost on next move, but is not in check metric.kingSituation[moveColor] = STALEMATE; } } return; }
ReturnValue alphaBeta(Configuration v, int alpha, int beta, int depth){ // int counter=0; if (DEBUG_STACK){ printstack(); printf("alphabeta a=%d b=%d d=%d\n", alpha, beta, depth); // printBoardNonBlock(v); } ++stackcount; HashRetVal s; s=retrieve(v); ReturnValue ret; ReturnValue temp; ret.alpha=alpha; ret.beta=beta; if (s!=NULL) { switch (s->type){ case EXACT: if (s->lowerbound>=beta) { ret.value=s->lowerbound; ret.move=s->mv; --stackcount; if (DEBUG_STACK){ printstack(); printf("hit exact 1\n"); } return ret; } if (s->upperbound<=alpha) { ret.value=s->upperbound; ret.move=s->mv; --stackcount; if (DEBUG_STACK){ printstack(); printf("hit exact 2\n"); } return ret; } ret.alpha=max(alpha, s->lowerbound); ret.beta=min(beta, s->upperbound); ret.move=s->mv; break; case FAIL_LOW: if (s->upperbound<=alpha) { ret.value=s->upperbound; ret.move=s->mv; --stackcount; if (DEBUG_STACK){ printstack(); printf("hit fail low\n"); } return ret; } break; case FAIL_HIGH: if (s->lowerbound>=beta) { ret.value=s->lowerbound; ret.move=s->mv; --stackcount; if (DEBUG_STACK){ printstack(); printf("hit fail high\n"); } return ret; } break; default: break; } free(s); } if (depth==0) { ChildIterator itr=getExpansion(v); ret.value=getCurrentValue(itr); ret.move=getCurrent(itr); releaseChildIterator(itr); if (getType(v)==MAXNODE) updateMoveHeuristic(v, ret.move.x, ret.move.y, ret.value); else updateMoveHeuristic(v, ret.move.x, ret.move.y, -ret.value); if (DEBUG_STACK){ printBoardNonBlock(v); printstack(); printf("eval %d\n", ret.value); printstack(); printf("(%d, %d)\n", ret.move.x, ret.move.y); } } else if (getType(v)==MAXNODE) { // printf("*\n"); ChildIterator itr=getExpansion(v); // printf("e: %d %d %d\n", getCurrent(itr).x, getCurrent(itr).y, depth); int a=alpha; ret.value=-FIVE_SCORE; ret.move=getCurrent(itr); if (getCurrentValue(itr)>=FIVE_SCORE){ ret.value=FIVE_SCORE; } else { while (itr!=NULL && ret.value<beta) { // printf("depth=%d, move=%d %d\n", // depth, getCurrent(itr).x, // getCurrent(itr).y); if (tickTimer()==0) break; applyMove(v, getCurrent(itr)); // printBoardNonBlock(v); if (DEBUG_STACK){ printstack(); printf("black trying %d %d\n", getCurrent(itr).x, getCurrent(itr).y); } switch (getChildrenCount(itr)){ // case 1: /* ++quadcount; temp=alphaBeta(v, a, beta, depth-((doublecount & 3)==0));*/ case 1: // case 2: ++doublecount; temp=alphaBeta(v, a, beta, depth-1); --doublecount; break; default: temp=alphaBeta(v, a, beta, depth-1); break; } updateMoveHeuristic(v, temp.move.x, temp.move.y, temp.value); if (DEBUG_STACK){ printstack(); printf("black try %d %d, result=%d\n", getCurrent(itr).x, getCurrent(itr).y, temp.value); } if (temp.value>ret.value) { ret.value=temp.value; ret.move=getCurrent(itr); // printf("current black move = %d %d\n", ret.move.x, ret.move.y); } undoMove(v, getCurrent(itr)); // printBoard(v); if (a<ret.value){ a=ret.value; } // printf("a=%d ret.value=%d\n", a, ret.value); // TODO to be verified /* if (temp.value<=-INFINITY){ ++counter; } if (counter>2) break;*/ getNext(&itr); // printf("e: %d %d\n", itr->current.x, itr->current.y); } if (DEBUG_STACK){ if (ret.value>=beta){ printstack(); printf("pruned\n"); } } } releaseChildIterator(itr); } else { // printf("-\n"); ChildIterator itr=getExpansion(v); // printf("n: %d %d %d\n", getCurrent(itr).x, getCurrent(itr).y, depth); int b=beta; ret.value=FIVE_SCORE; ret.move=getCurrent(itr); if (getCurrentValue(itr)<=-FIVE_SCORE){ ret.value=-FIVE_SCORE; } else { while (itr!=NULL && ret.value>alpha) { if (tickTimer()==0) break; applyMove(v, getCurrent(itr)); if (DEBUG_STACK){ printstack(); printf("white trying %d %d\n", getCurrent(itr).x, getCurrent(itr).y); } if (getChildrenCount(itr)<=1){ ++doublecount; temp=alphaBeta(v, alpha, b, depth-1); --doublecount; } else { temp=alphaBeta(v, alpha, b, depth-1); } updateMoveHeuristic(v, temp.move.x, temp.move.y, -temp.value); if (DEBUG_STACK){ printstack(); printf("white try %d %d, result=%d\n", getCurrent(itr).x, getCurrent(itr).y, temp.value); printf("retval=%d\n", ret.value); } if (temp.value<ret.value){ ret.value=temp.value; ret.move=getCurrent(itr); // printf("current white move = %d %d\n", ret.move.x, ret.move.y); } undoMove(v, getCurrent(itr)); if (b>ret.value){ b=ret.value; } // printf("a=%d ret.value=%d\n", b, ret.value); /* if (ret.value<=-INFINITY-10) break;*/ // TODO to be verified /* if (temp.value>=INFINITY){ ++counter; } if (counter>2) break;*/ getNext(&itr); } if (DEBUG_STACK){ if (ret.value<=alpha){ printstack(); printf("pruned\n"); } } } releaseChildIterator(itr); } if (ret.value<=alpha && getType(v)==MINNODE) { /* fail low */ v->upperbound=ret.value; if (depth>0) store(v, ret.move, FAIL_LOW); /* Fail low result implies an upper bound */ } else if (ret.value>alpha && ret.value<beta) { /* accurate window */ v->upperbound=v->lowerbound=ret.value; if (depth>0) store(v, ret.move, EXACT); } else if (getType(v)==MINNODE && ret.value>=MAXNODE){ /* fail high */ v->lowerbound=ret.value; if (depth>0) store(v, ret.move, FAIL_HIGH); } /* printstack(); printf("ab return %d (%d,%d))\n", ret.value, ret.move.x, ret.move.y);*/ // getchar(); --stackcount; return ret; }
int minMax(int depth, char color, int alpha, int beta, int total, int totalThreats) { color = (color == 'b') ? 'r' : 'b'; int lastRow = findLastRow(board); int lastMoveValue = calculateAdjacentStep('b', board->lastColumn, lastRow); int threatLevel = findGoodSquares(board->lastColumn, lastRow); totalThreats += threatLevel; //fprintf(stderr, "Value: %d\n", totalThreats); if (color == 'r') { total -= (lastMoveValue); // if (threatLevel > 0 && totalThreats < 2) // { total -= threatLevel * 25 - depth; // } // else if (threatLevel < 0 && totalThreats > -2) // { // total -= threatLevel * 50; // } //if (totalThreats > -1) //{ //total -= threatLevel * 50; //} } else { total += (lastMoveValue); //if (threatLevel > 0 && totalThreats < 1) //{ total += threatLevel * 25 + depth; //} //else if (threatLevel < 0 && totalThreats > -1) //{ // total += threatLevel * 50; // } //if (totalThreats < 1) //{ //total += threatLevel * 50; ///} } if (depth <= 0) { return calculatePosition(color, total); } Move* legalMoves = getLegalMoves(board, color); if (legalMoves[0].colour == 'x') { return 0; } int currentValue; int i; for (i = 0; legalMoves[i].colour != 'x'; i++) { // if (difftime(time(NULL), startTime) > 170.0) // { // return -1000; // } if (legalMoves[i].colour == 'w') { if (legalMoves[i].column >= 0) { alpha = 1000 * legalMoves[i].column + depth; } else { alpha = 1000 * legalMoves[i].column - depth; } break; } makeMove(legalMoves[i]); currentValue = -minMax(depth - 1, color, -beta, -alpha, -total, totalThreats); undoMove(); if (currentValue >= beta) { return beta; } alpha = MAX(currentValue, alpha); } free(legalMoves); return alpha; }
pWidget::pWidget() #ifndef Q_OS_SYMBIAN : KXmlGuiWindow(0), #else : QMainWindow(0), #endif dill(0), m_dealer(0), m_bubbles(0) { setObjectName( "pwidget" ); current_pwidget = this; // KCrash::setEmergencySaveFunction(::saveGame); // Game // TODO actions #if 0 KStandardGameAction::gameNew(this, SLOT(newGame()), actionCollection()); KStandardGameAction::restart(this, SLOT(restart()), actionCollection()); KStandardGameAction::load(this, SLOT(openGame()), actionCollection()); recent = KStandardGameAction::loadRecent(this, SLOT(openGame(const KUrl&)), actionCollection()); recent->loadEntries(KGlobal::config()->group( QString() )); KStandardGameAction::save(this, SLOT(saveGame()), actionCollection()); KStandardGameAction::quit(this, SLOT(close()), actionCollection()); // Move undo = KStandardGameAction::undo(this, SLOT(undoMove()), actionCollection()); redo = KStandardGameAction::redo(this, SLOT(redoMove()), actionCollection()); KAction *a; a = actionCollection()->addAction("choose_game"); a->setText(i18n("&Choose Game...")); connect( a, SIGNAL( triggered( bool ) ), SLOT( chooseGame() ) ); a = actionCollection()->addAction("change_game_type"); a->setText(i18n("Change Game Type...")); connect( a, SIGNAL( triggered( bool ) ), SLOT( slotShowGameSelectionScreen() ) ); a = actionCollection()->addAction("random_set"); a->setText(i18n("Random Cards")); connect( a, SIGNAL( triggered( bool ) ), SLOT( slotPickRandom() ) ); a->setShortcuts( KShortcut( Qt::Key_F9 ) ); if (!qgetenv("KDE_DEBUG").isEmpty()) // developer shortcut { a = actionCollection()->addAction("snapshot"); a->setText(i18n("Take Game Preview Snapshots")); connect( a, SIGNAL( triggered( bool ) ), SLOT( slotSnapshot() ) ); a->setShortcuts( KShortcut( Qt::Key_F8 ) ); } a = actionCollection()->addAction("select_deck"); a->setText(i18n("Select Deck...")); connect( a, SIGNAL( triggered( bool ) ), SLOT( slotSelectDeck() ) ); a->setShortcuts( KShortcut( Qt::Key_F10 ) ); a = actionCollection()->addAction("game_stats"); a->setText(i18n("Statistics")); connect( a, SIGNAL( triggered( bool ) ), SLOT(showStats()) ); gamehelpaction = actionCollection()->addAction("help_game"); connect( gamehelpaction, SIGNAL( triggered( bool ) ), SLOT(helpGame())); gamehelpaction->setShortcuts( KShortcut( Qt::Key_F2 ) ); // Game type dependent actions hintaction = KStandardGameAction::hint( 0, 0, actionCollection() ); demoaction = KStandardGameAction::demo( 0, 0, actionCollection() ); drawaction = actionCollection()->addAction("move_draw"); drawaction->setText( i18nc("Take one or more cards from the deck, flip them, and place them in play", "Dra&w") ); drawaction->setIcon( KIcon("kpat") ); drawaction->setShortcut( Qt::Key_Space ); dealaction = actionCollection()->addAction("move_deal"); dealaction->setText( i18nc("Deal a new row of cards from the deck", "Dea&l") ); dealaction->setIcon( KIcon("kpat") ); dealaction->setShortcut( Qt::Key_Enter ); redealaction = actionCollection()->addAction("move_redeal"); redealaction->setText( i18nc("Collect the cards in play, shuffle them and redeal them", "&Redeal") ); redealaction->setIcon( KIcon("roll") ); redealaction->setShortcut( Qt::Key_R ); dropaction = actionCollection()->addAction("move_drop"); dropaction->setText( i18nc("Automatically move cards to the foundation piles", "Dro&p") ); dropaction->setIcon( KIcon("legalmoves") ); dropaction->setShortcut( Qt::Key_P ); // Configuration actions KConfigGroup cg(KGlobal::config(), settings_group ); autodropaction = new KToggleAction(i18n("&Enable Autodrop"), this); actionCollection()->addAction("enable_autodrop", autodropaction); connect( autodropaction, SIGNAL( triggered( bool ) ), SLOT(enableAutoDrop()) ); autodropaction->setChecked( cg.readEntry("Autodrop", true) ); solveraction = new KToggleAction(i18n("E&nable Solver"), this); actionCollection()->addAction("enable_solver", solveraction); connect( solveraction, SIGNAL( triggered( bool ) ), SLOT( enableSolver() ) ); solveraction->setChecked( cg.readEntry("Solver", true) ); rememberstateaction = new KToggleAction(i18n("&Remember State on Exit"), this); actionCollection()->addAction("remember_state", rememberstateaction); connect( rememberstateaction, SIGNAL( triggered( bool ) ), SLOT( enableRememberState() ) ); rememberstateaction->setChecked( cg.readEntry("RememberStateOnExit", false) ); #endif foreach( const DealerInfo * di, DealerInfoList::self()->games() ) { foreach( int id, di->ids ) m_dealer_map.insert( id, di ); if ( QString(di->name).toLower() == "freecell" ) m_freeCellId = di->ids.first(); }
Move getNextMove(Board* inputBoard) { srand(time(NULL)); startTime = time(NULL); board = inputBoard; int spaceCount = 0; int x, y; int totalThreats = 0; for (x = 0; x < board->width; x++) { for (y = 0; y < board->height; y++) { if (board->boardMatrix[x][y] == 's') { totalThreats += findGoodSquares(x, y); spaceCount++; } } } //fprintf(stderr, "%d\n", totalThreats); if (spaceCount % 2 != 0) { realColor = 'r'; } printSillyRPGStartText(); int additionalDepth = board->width - emptyColumns(board); currentDepth = STARTING_DEPTH + MAX(0, additionalDepth); // if we're taking too much time, turn the depth down so we don't go over if (board->totalGameTime > 900000) { currentDepth--; } if (board->totalGameTime > 1000000) { currentDepth--; } firstColumn = board->lastColumn; Move moveToMake = { -1, 'r' }; int i; int alpha = SMALLNUM; int beta = BIGNUM; Move* legalMoves = getLegalMoves(board, currentTurnChar); int currentValue; for (i = 0; legalMoves[i].colour != 'x'; i++) { // if (difftime(time(NULL), startTime) > 170.0) // { // fprintf(stderr, "KOS-MOS woke up!\n"); // break; // } makeMove(legalMoves[i]); currentValue = -minMax(currentDepth, 'b', -beta, -alpha, 0, totalThreats); if (currentValue == 1000) { currentValue = -1000; } // int difference = 0; // if (currentValue > 3000 && currentDepth > 0) // { // difference = currentDepth - (currentValue % 1000); // currentDepth -= difference; // currentValue -= difference; // alpha -= difference; // currentDepth = MAX(currentDepth, 0); // } // KEEP for debugging purposes fprintf(stderr, "(%d, %c), %d\n", legalMoves[i].column + 1, legalMoves[i].colour, currentValue); undoMove(); if (currentValue >= beta) { moveToMake = legalMoves[i]; break; } if (currentValue > alpha) { moveToMake = legalMoves[i]; alpha = currentValue; } } free(legalMoves); printSillyRPGEndText(moveToMake, alpha); return moveToMake; }
/* winnerIs should accept scores of four in horizontal, vertical and both * diagonal directions. Should return the correct winning player and IFF there * are four points in a row. */ void test_winnerIs() { board_type *board = createBoard(X, Y); int i, j; CU_ASSERT_EQUAL(winnerIs(board), 0); for(i = 0; i < 4; i++) { board->current_player = PLAYER_ONE; makeMove(board, i); } CU_ASSERT_EQUAL(winnerIs(board), PLAYER_ONE); for(i = 0; i < 4; i++) undoMove(board); for(i = 0; i < 4; i++) { board->current_player = PLAYER_TWO; makeMove(board, i); } CU_ASSERT_EQUAL(winnerIs(board), PLAYER_TWO); for(i = 0; i < 4; i++) undoMove(board); /* Bottom left to top right diagonal */ for(i = 2; i < 5; i++) { for(j = i; j < 5; j++) { board->current_player = PLAYER_TWO; makeMove(board, i); } } for(i = 2; i < 6; i++) { board->current_player = PLAYER_ONE; makeMove(board, i); } CU_ASSERT_EQUAL(winnerIs(board), PLAYER_ONE); /* Bottom left to top right diagonal */ for(i = 2; i < 6; i++) { for(j = i; j < 6; j++) undoMove(board); } /* Bottom left to top right diagonal */ for(i = 2; i < 5; i++) { for(j = 5; j > i; j--) { board->current_player = PLAYER_ONE; makeMove(board, i); } } for(i = 2; i < 6; i++) { board->current_player = PLAYER_TWO; makeMove(board, i); } CU_ASSERT_EQUAL(winnerIs(board), PLAYER_TWO); undoMove(board); CU_ASSERT_EQUAL(winnerIs(board), 0); free(board); }
bool Board::move(move_t move) { // add to move history stack Piece captured_piece; if (move.bits & 1) { captured_piece = pieces[move.to]; } else { captured_piece = _; } hist_t hist = {move, captured_piece, side_castle, xside_castle, ep}; move_history.push(hist); // make move color[move.from] = EMPTY; color[move.to] = side; pieces[move.to] = pieces[move.from]; pieces[move.from] = _; // move rook if castling if (move.bits & 2) { if (side == WHITE) { if (move.to == 62) { // kingside color[63] = EMPTY; color[61] = side; pieces[63] = _; pieces[61] = R; } else { // queenside color[56] = EMPTY; color[59] = side; pieces[56] = _; pieces[59] = R; } } else { if (move.to == 57) { // kingside color[56] = EMPTY; color[58] = side; pieces[56] = _; pieces[58] = R; } else { // queenside color[63] = EMPTY; color[60] = side; pieces[63] = _; pieces[60] = R; } } side_castle = 0; } // update castling rights if (pieces[56] != R || color[56] != side) side_castle &= (side ? 2 : 1); if (pieces[63] != R || color[63] != side) side_castle &= (side ? 1 : 2); if (side == WHITE && (pieces[60] != K || color[60] != side)) side_castle = 0; if (side == BLACK && (pieces[59] != K || color[59] != side)) side_castle = 0; if (pieces[0] != R || color[0] != xside) xside_castle &= (side ? 1 : 2); if (pieces[7] != R || color[7] != xside) xside_castle &= (side ? 2 : 1); if (xside == WHITE && (pieces[3] != K || color[3] != xside)) xside_castle = 0; if (xside == BLACK && (pieces[4] != K || color[4] != xside)) xside_castle = 0; // promotion if (move.bits & 4) { pieces[move.to] = move.promote; } // en passant captures the pawn if (move.bits & 8) { color[move.to + 8] = EMPTY; pieces[move.to + 8] = _; } // moving pawn 2 squares forwards sets up en passant if (move.bits & 16) { ep = 63 - (move.from - 8); } else { ep = -1; } Board::rotateBoard(); std::swap(side, xside); std::swap(side_castle, xside_castle); if (isCheck(xside)) { undoMove(); return false; } return true; }