Arimaa Forum (http://arimaa.com/arimaa/forum/cgi/YaBB.cgi)
Arimaa >> Bot Development >> Qsearch in Clueless
(Message started by: jdb on Mar 9th, 2009, 3:45pm)

Title: Qsearch in Clueless
Post by jdb on Mar 9th, 2009, 3:45pm
This is the Qsearch for clueless 2009.

It is only called at the start of a turn. In the main search, if there is a capture threat or a goal threat, with less than 4 steps left, the search is extended to complete the turn.


Code:
     private int Quiesce(int ply, int depth, int alpha, int beta, GameState gs) throws AbortSearchException {

           // Always need to have full turn available
           assert (gs.getStepsRemaining() == 4);

           // Check for abort search
           if (abort_search) {
                 throw new AbortSearchException();
           }

           // Get a gamestate to work with
           GameState new_gs = gs_stack[ply];

           // Keep track of how many nodes we have searched
           q_nodes_searched++;

           // Test for a goal on first step
           goal_calls++;
           if (goal.test(gs)) {
                 goal_hits++;
                 return SCORE_MATE - (depth >>> 2);
           }

           // If we do nothing, can opponent goal?
           if (use_qdefend_search) {

                 // There is no point in calling this recursively
                 // The Qsearch will just stand pat
                 if (depth == max_qsearch_depth) {
                       // 8 ply goal search
                       new_gs.playPASS(gs);
                       goal_calls++;
                       if (goal.test(new_gs)) {
                             // SearchTrace(ply, "QS: Goal Threat");

                             // Opponent can goal, OMG, look for a defence
                             if (!QuiesceDefendGoal(ply, gs)) {
                                   // SearchTrace(ply, "QS: No Defence to goal threat");
                                   return -SCORE_MATE + 1 + (depth >> 2);
                             }
                             // SearchTrace(ply, "QS: Defence found");

                       }

                 }
           }

           // Get a stand pat score
           int score = eval.Evaluate(gs, false);

           // Limit depth of q search
           if (depth <= 0) {
                 return score;
           }

           // SearchTrace(ply, "QStand pat score: " + score);

           if (score > alpha) {
                 if (score >= beta) {
                       return score;
                 }
                 alpha = score;
           }

           // Iterate thru all capture moves
           for (long move = qsms[ply].getFirstMove(gs); move != NEW_NO_STEP; move = qsms[ply].getNextMove(gs)) {
                 int steps = new_gs.play(move, gs);

                 if (show_alphabeta_search_trace) {
                       // SearchTrace(ply, -1, alpha, beta, move);
                 }

                 if (new_gs.isGameOver()) {
                       // Note must search rest of possible moves!!!
                       score = new_gs.getGameResult();
                 } else {
                       // Game is NOT over, so we search
                       int new_ply = ply + steps;
                       score = -Quiesce(new_ply, depth - 1, -beta, -alpha, new_gs);
                 }

                 if (score > alpha) {
                       if (score >= beta) {
                             return score;
                       }
                       alpha = score;
                 }
           }

           return alpha;

     }

     /**
      * Opponent has a goal threat, looks for a defence
      *
      * @param ply
      * @param steps_available
      * @param gs
      * @return TRUE iff there is a defence to the goal threat
      */
     public boolean QuiesceDefendGoal(int ply, GameState gs) throws AbortSearchException {
           assert (gs.getStepsRemaining() == 4);

           // Best defence is to goal our own rabbit!
           if (goal.test(gs)) {
                 // QSearchTrace(ply, "QDefend: Defender can goal");
                 return true;
           }

           // Try qdefend killer moves
           GameState new_gs = gs_stack[ply];
           for (long move : qdefend_killers[ply]) {
                 // QSearchTrace(ply, "QDEFKILLER: " + GameState.move_toString(move));
                 if (new_gs.isLegalMove(move, gs)) {
                       new_gs.play(move, gs);

                       // Check if move ends the game
                       if (new_gs.isGameOver()) {
                             int score = new_gs.getGameResult();
                             // We created a win for the enemy, not good
                             if (score == -SCORE_MATE) {
                                   continue;
                             }
                             // We created a win for ourself, great
                             if (score == SCORE_MATE) {
                                   return true;
                             }
                       }

                       assert (new_gs.isFirstStep());
                       if (!goal.test(new_gs)) {
                             // QSearchTrace(ply, "QDefend: Killer move " + GameState.move_toString(move));
                             return true;
                       }
                 }
           }

           // No known defence, so we must search
           // Use iterative deepening, in case there is an easy defence
           for (int def_depth = 1; def_depth <= 4; def_depth++) {
                 // QSearchTrace(ply, "QDefend Starting depth: " + def_depth);
                 if (QuiesceDefendInternal(ply, def_depth, gs, 0)) {
                       // QSearchTrace(ply, "QDefend: Searched Defence found " + GameState.move_toString(qdefend_killers[ply][0]));
                       return true;
                 }
           }

           return false;
     }

     /**
      * Internal quiesce defend
      * Handles the recursive defence search
      *
      * @param ply
      * @param depth
      * @param gs
      * @param partial_move
      * @return
      */
     private boolean QuiesceDefendInternal(int ply, int depth, GameState gs, long partial_move)
                 throws AbortSearchException {

           // Check for abort search
           if (abort_search) {
                 throw new AbortSearchException();
           }

           GameState new_gs = gs_stack[ply];
           long moves[] = qmove_list_stack[ply];
           moves[0] = 0;
           long steps_available = gs.getStepsRemaining();

           // Probe hash table
           long probe_result = probeQHash(gs.getZobristPositionHash(), depth, q_hash_defend_table);
           if (probe_result == QHASH_DEFEND_WIN) {
                 return true;
           }
           if (probe_result == QHASH_DEFEND_LOSS) {
                 return false;
           }

           for (long move = qdms[ply].getFirstMove(gs); move != NEW_NO_STEP; move = qdms[ply].getNextMove(gs)) {

                 // QSearchTrace(ply, depth, move);
                 q_defence_nodes_searched++;

                 int steps = new_gs.play(move, gs);
                 int new_ply = ply + steps;
                 int new_depth = depth - steps;
                 long new_partial_move = partial_move | (move << (16 * (4 - steps_available)));

                 if (new_depth <= 0) {
                       // Complete the player's turn
                       if (new_gs.getStepsRemaining() != 4) {
                             new_partial_move |= (NEW_PASS_MOVE << (16 * (4 - new_gs.getStepsRemaining())));
                             new_gs.playPASS(new_gs);
                       }

                       // Check if move ends the game
                       if (new_gs.isGameOver()) {
                             int score = new_gs.getGameResult();
                             // We created a win for the enemy, not good
                             if (score == -SCORE_MATE) {
                                   continue;
                             }
                             // We created a win for ourself, great
                             if (score == SCORE_MATE) {
                                   record_qdefend_move(ply, new_partial_move);
                                   return true;
                             }
                       }

                       // Check if move prevents an enemy goal
                       if (!goal.test(new_gs)) {
                             record_qdefend_move(ply, new_partial_move);
                             return true;
                       }
                 }

                 // depth remains, so search deeper
                 else {
                       boolean result = QuiesceDefendInternal(new_ply, new_depth, new_gs, new_partial_move);
                       if (result) {
                             return true;
                       }
                 }
           }

           // Store search result in hash table
           storeQHash(gs.getZobristPositionHash(), depth, QHASH_DEFEND_LOSS, q_hash_defend_table);
           return false;
     }

Title: Re: Qsearch in Clueless
Post by 99of9 on Mar 9th, 2009, 3:48pm
Wow, that's very kind of you!



Arimaa Forum » Powered by YaBB 1 Gold - SP 1.3.1!
YaBB © 2000-2003. All Rights Reserved.