Package com.barrybecker4.game.twoplayer.common.search.strategy

Source Code of com.barrybecker4.game.twoplayer.common.search.strategy.NegaMaxMemoryStrategy

/** Copyright by Barry G. Becker, 2000-2011. Licensed under MIT License: http://www.opensource.org/licenses/MIT  */
package com.barrybecker4.game.twoplayer.common.search.strategy;

import com.barrybecker4.game.common.MoveList;
import com.barrybecker4.game.twoplayer.common.TwoPlayerMove;
import com.barrybecker4.game.twoplayer.common.search.SearchWindow;
import com.barrybecker4.game.twoplayer.common.search.Searchable;
import com.barrybecker4.game.twoplayer.common.search.transposition.Entry;
import com.barrybecker4.game.twoplayer.common.search.transposition.HashKey;
import com.barrybecker4.game.twoplayer.common.search.transposition.TranspositionTable;
import com.barrybecker4.game.twoplayer.common.search.tree.SearchTreeNode;
import com.barrybecker4.optimization.parameter.ParameterArray;

/**
*  This strategy class defines the NegaMax with memory search algorithm.
*  This version stores the values of moves that have already been searched.
*  Based on pseudo code from Artificial Intelligence for Games by Millington and Funge.
*
@author Barry Becker
*/
public final class NegaMaxMemoryStrategy extends NegaMaxStrategy
                                         implements MemorySearchStrategy {

    /** Stores positions that have already been evaluated, so we do not need to repeat work. */
    private TranspositionTable lookupTable;

    /**
     * Constructor.
     */
    public NegaMaxMemoryStrategy( Searchable controller, ParameterArray weights ) {
        super( controller, weights );
        lookupTable = new TranspositionTable();
    }

    @Override
    public TranspositionTable getTranspositionTable() {
        return lookupTable;
    }

    @Override
    public TwoPlayerMove search( TwoPlayerMove lastMove, SearchTreeNode parent ) {
        // need to negate alpha and beta on initial call.
        SearchWindow window = getOptions().getBruteSearchOptions().getInitialSearchWindow();
        int g = window.getMidPoint();
        return searchInternal( lastMove, lookAhead_, new SearchWindow(g, g), parent );
    }

    @Override
    protected TwoPlayerMove searchInternal( TwoPlayerMove lastMove,
                                           int depth,
                                           SearchWindow window, SearchTreeNode parent ) {
        HashKey key = searchable.getHashKey();
        Entry entry = lookupTable.get(key);
        if (lookupTable.entryExists(entry, lastMove, depth, window)) {
            if (entry.lowerValue > window.alpha) {
                entry.bestMove.setInheritedValue(entry.lowerValue);
                return entry.bestMove;
            }
            else if (entry.upperValue < window.beta) {
                entry.bestMove.setInheritedValue(entry.upperValue);
                return entry.bestMove;
            }
        }

        entry = new Entry(lastMove, depth, new SearchWindow(-INFINITY, INFINITY));

        boolean done = searchable.done( lastMove, false);
        if ( depth <= 0 || done ) {
            if (doQuiescentSearch(depth, done, lastMove))  {
                TwoPlayerMove qMove = quiescentSearch(lastMove, depth, window, parent);
                if (qMove != null)  {
                    entry = new Entry(qMove, qMove.getInheritedValue());
                    lookupTable.put(key, entry);
                    return qMove;
                }
            }
            int sign = fromPlayer1sPerspective(lastMove) ? 1 : -1;
            int value = sign * lastMove.getValue();
            lastMove.setInheritedValue(value);
            entry.lowerValue = value;
            entry.upperValue = value;
            lookupTable.put(key, entry);
            return lastMove;
        }

        MoveList list = searchable.generateMoves(lastMove, weights_);

        if (depth == lookAhead_)
            numTopLevelMoves_ = list.size();

        if ( emptyMoveList( list, lastMove) )   return null;

        return findBestMove(lastMove, depth, list, window, parent);
    }


    /**
     * @inheritDoc
     */
    @Override
    protected TwoPlayerMove findBestMove(TwoPlayerMove lastMove, int depth, MoveList list,
                                         SearchWindow window, SearchTreeNode parent) {
        int i = 0;
        int bestInheritedValue = -INFINITY;
        TwoPlayerMove selectedMove;

        TwoPlayerMove bestMove = (TwoPlayerMove)list.get(0);
        Entry entry = new Entry(bestMove, depth, window);

        while ( !list.isEmpty() ) {
            TwoPlayerMove theMove = getNextMove(list);
            if (pauseInterrupted())
                return lastMove;
            updatePercentDone(depth, list);

            searchable.makeInternalMove( theMove );
            SearchTreeNode child = addNodeToTree(parent, theMove, window); i++;

            selectedMove = searchInternal( theMove, depth-1, window.negateAndSwap(), child );

            searchable.undoInternalMove( theMove );

            if (selectedMove != null) {

                int selectedValue = -selectedMove.getInheritedValue();
                theMove.setInheritedValue( selectedValue );

                if ( selectedValue > bestInheritedValue ) {
                    bestMove = theMove;
                    entry.bestMove = theMove;
                    bestInheritedValue = selectedValue;
                    if ( alphaBeta_ && bestInheritedValue >= window.beta) {
                        showPrunedNodesInTree(list, parent, i, selectedValue, window);
                        break;
                    }
                }
            }
        }
        storeBestMove(window.alpha, entry, bestMove.getInheritedValue());
        bestMove.setSelected(true);
        lastMove.setInheritedValue(-bestMove.getInheritedValue());
        return bestMove;
    }

    /**
     * Store off the best move so we do not need to analyze it again.
     */
    private void storeBestMove(int alpha, Entry entry, int bestValue) {
        if (bestValue <= alpha) {
            entry.upperValue = bestValue;
        }
        else  {
            entry.lowerValue = bestValue;
        }
        lookupTable.put(searchable.getHashKey(), entry);
    }
}
TOP

Related Classes of com.barrybecker4.game.twoplayer.common.search.strategy.NegaMaxMemoryStrategy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.