All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.barrybecker4.game.twoplayer.common.TwoPlayerSearchable Maven / Gradle / Ivy

There is a newer version: 1.6
Show newest version
/** Copyright by Barry G. Becker, 2000-2011. Licensed under MIT License: http://www.opensource.org/licenses/MIT  */
package com.barrybecker4.game.twoplayer.common;

import com.barrybecker4.common.geometry.Location;
import com.barrybecker4.game.common.GameContext;
import com.barrybecker4.game.common.player.Player;
import com.barrybecker4.game.common.player.PlayerList;
import com.barrybecker4.game.twoplayer.common.search.options.SearchOptions;
import com.barrybecker4.game.twoplayer.common.search.transposition.HashKey;
import com.barrybecker4.game.twoplayer.common.search.transposition.ZobristHash;
import com.barrybecker4.optimization.parameter.ParameterArray;
import com.barrybecker4.game.twoplayer.common.search.strategy.SearchStrategy;

/**
 * For searching two player games
 *
 * @author Barry Becker
 */
public abstract class TwoPlayerSearchable>
        extends AbstractSearchable {

    protected final B board_;
    protected final PlayerList players_;

    /** helps to find the best moves. */
    protected final BestMoveFinder bestMoveFinder_;

    /** Used to generate hashkeys. */
    protected final ZobristHash hash;


    /**
     * Constructor.
     */
    public TwoPlayerSearchable(final B board,  PlayerList players) {

        super(board.getMoveList());
        board_ = board;
        players_ = players;

        hash = new ZobristHash(board_);
        bestMoveFinder_ = new BestMoveFinder<>(getSearchOptions().getBestMovesSearchOptions());
    }

    /**
     * Copy constructor.
     */
    public TwoPlayerSearchable(TwoPlayerSearchable searchable) {

        this((B)searchable.getBoard().copy(), (PlayerList)searchable.players_.clone());
    }

    public B getBoard() {
        return board_;
    }

    /**
     * Make the specified move.
     * It is actually ok if the same player moves twice in the case where we are looking for urgent moves.
     * @param move the move to play.
     */
    public void makeInternalMove(M move) {

        getBoard().makeMove(move);

        if (move.isPassOrResignation())  {
            hash.applyPassingMove();
        } else {
            Location loc = move.getToLocation();
            hash.applyMove(loc, getBoard().getStateIndex(getBoard().getPosition(loc)));
        }
    }

    /**
     * takes back the most recent move.
     * @param move move to undo
     */
    public void undoInternalMove(M move) {
        TwoPlayerMove lastMove = moveList_.getLastMove();
        assert move.equals(lastMove) : "The move we are trying to undo ("+ move +") in list="
                + moveList_ + " was not equal to the last move (" + lastMove + "). all move=" + getBoard().getMoveList();

        Location loc = move.getToLocation();

        if (!move.isPassingMove()) {
            hash.applyMove(loc, getBoard().getStateIndex(getBoard().getPosition(loc)));
        }

        getBoard().undoMove();
    }

    /**
     * Evaluates from player 1's perspective
     * @return an integer value for the worth of the move.
     *  must be between -SearchStrategy.WINNING_VALUE and SearchStrategy.WINNING_VALUE.
     */
    public abstract int worth(M lastMove, ParameterArray weights);


    @Override
    public SearchOptions getSearchOptions() {
        return ((TwoPlayerPlayerOptions) getCurrentPlayer().getOptions()).getSearchOptions();
    }

    /**
     * Given a move, determine whether the game is over.
     * If recordWin is true, then the variables for player1/2HasWon can get set.
     *  sometimes, like when we are looking, ahead we do not want to set these.
     * @param move the move to check. If null then return true. This is typically the last move played.
     * @param recordWin if true then the controller state will record wins
     */
    public boolean done(M move, boolean recordWin ) {

        // the game can't be over if no moves have been made yet.
        if (moveList_.getNumMoves() == 0) {
            return false;
        }
        if (players_.anyPlayerWon()) {
            GameContext.log(0, "Game over because one of the players has won."); // NON_NLS
            return true;
        }
        if (moveList_.getNumMoves() > 0 && move == null) {
            Player currentPlayer = getCurrentPlayer();
            GameContext.log(0, "Game is over because there are no more moves for player " + currentPlayer); // NON_NLS
            if (recordWin) {
                currentPlayer.setWon(true);
            }
            return true;
        }

        int absValue = Math.abs(move.getValue());
        boolean won = (absValue >= SearchStrategy.WINNING_VALUE);

        if ( won && recordWin ) {
            if ( move.getValue() >= SearchStrategy.WINNING_VALUE )
                players_.getPlayer1().setWon(true);
            else
                players_.getPlayer2().setWon(true);
        }
        boolean maxMovesExceeded = moveList_.getNumMoves() >= getBoard().getMaxNumMoves();

        return (maxMovesExceeded || won);
    }

    /**
     * @return the player who's turn it is to move next.
     */
    private Player getCurrentPlayer()  {
        TwoPlayerMove move = moveList_.getLastMove();
        return (move==null || !move.isPlayer1()) ?  players_.getPlayer1() : players_.getPlayer2();
    }

    /**
     * @return true if the specified move caused one or more opponent pieces to become jeopardized
     */
    public boolean inJeopardy(M move, ParameterArray weights) {
        return false;
    }

    /**
     * @return get a hash key that represents this board state (with negligibly small chance of conflict)
     */
    public HashKey getHashKey() {
        return hash.getKey();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy