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

com.barrybecker4.game.twoplayer.gomoku.GoMokuMoveGenerator Maven / Gradle / Ivy

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

import com.barrybecker4.common.geometry.Location;
import com.barrybecker4.game.common.MoveList;
import com.barrybecker4.game.common.board.GamePiece;
import com.barrybecker4.game.twoplayer.common.BestMoveFinder;
import com.barrybecker4.game.twoplayer.common.TwoPlayerMove;
import com.barrybecker4.optimization.parameter.ParameterArray;

import static com.barrybecker4.game.twoplayer.common.search.strategy.SearchStrategy.WINNING_VALUE;

/**
 * Responsible for determining a set of reasonable next moves.
 *
 * @author Barry Becker
 */
final class GoMokuMoveGenerator {

    /**
     * Constructor.
     */
    public GoMokuMoveGenerator() {
    }

    /**
     * @return all reasonably good next moves.
     */
    public final MoveList generateMoves(GoMokuSearchable searchable,
                                                       TwoPlayerMove lastMove, ParameterArray weights) {
        MoveList moveList = new MoveList<>();

        GoMokuBoard pb = searchable.getBoard();
        CandidateMoves candMoves = pb.getCandidateMoves();

        boolean player1 = (lastMove == null) || !lastMove.isPlayer1();

        int ncols = pb.getNumCols();
        int nrows = pb.getNumRows();

        for (int i = 1; i <= nrows; i++ ) {
             for (int j = 1; j <= ncols; j++ ) {
                if ( candMoves.isCandidateMove( i, j )) {
                    int lastValue = lastMove == null ? 0 : lastMove.getValue();
                    TwoPlayerMove move = TwoPlayerMove.createMove( i, j, lastValue, new GamePiece(player1));

                    searchable.makeInternalMove( move );
                    move.setValue(searchable.worth(move, weights));
                    // now revert the board
                    searchable.undoInternalMove( move );
                    moveList.add( move );
                }
            }
        }
        BestMoveFinder finder =
                new BestMoveFinder<>(searchable.getSearchOptions().getBestMovesSearchOptions());
        return finder.getBestMoves(moveList);
    }

    /**
     * @return a list of urgent moves (i.e positions that can result in a win for either player.
     */
    public MoveList generateUrgentMoves(
            GoMokuSearchable searchable, TwoPlayerMove lastMove, ParameterArray weights) {
        // no urgent moves at start of game.
        if (lastMove == null)  {
            return new MoveList<>();
        }
        MoveList allMoves = findMovesForBothPlayers(searchable, lastMove, weights);

        // now keep only those that result in a win or loss.
        MoveList urgentMoves = new MoveList<>();
        boolean currentPlayer = !lastMove.isPlayer1();

        for (TwoPlayerMove move : allMoves) {
            // if its not a winning move or we already have it, then skip
            if ( Math.abs(move.getValue()) >= WINNING_VALUE  && !contains(move, urgentMoves)) {
                move.setUrgent(true);
                move.setPlayer1(currentPlayer);
                move.setPiece(new GamePiece(currentPlayer));
                urgentMoves.add(move);
            }
        }
        return urgentMoves;
    }

    /**
     * Consider both our moves and opponent moves.
     * @return Set of all next moves.
     */
    private MoveList findMovesForBothPlayers(
            GoMokuSearchable searchable, TwoPlayerMove lastMove, ParameterArray weights) {
        MoveList allMoves = new MoveList<>();

        MoveList moves = generateMoves(searchable, lastMove, weights);
        allMoves.addAll(moves);

        // unlike go, I don't know if we need this
        TwoPlayerMove oppLastMove = lastMove.copy();
        oppLastMove.setPlayer1(!lastMove.isPlayer1());
        MoveList opponentMoves =
                generateMoves(searchable, oppLastMove, weights);
        for (TwoPlayerMove m : opponentMoves){
            allMoves.add(m);
        }

        return allMoves;
    }

    /**
     * This version of contains does not consider the player when determining containment.
     * @return true of the {@link MoveList} contains the specified move.
     */
    private boolean contains(TwoPlayerMove move, MoveList moves) {
        for (TwoPlayerMove m : moves) {
            Location moveLocation = m.getToLocation();
            if (moveLocation.equals(move.getToLocation())) {
                return true;
            }
        }
        return false;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy