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

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

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

import com.barrybecker4.common.geometry.ByteLocation;
import com.barrybecker4.common.geometry.Location;
import com.barrybecker4.game.common.board.BoardPosition;

/**
 * Representation of the candidate next moves on a GoMoku Game Board.
 * Immutable after construction.
 * @author Barry Becker
 */
public class CandidateMoves {

    /** 8 footprint offsets around a single position. */
    private static ByteLocation[] SPLAT = {
            new ByteLocation(-1, -1),
            new ByteLocation(-1, 0),
            new ByteLocation(-1, 1),
            new ByteLocation(0, -1),
            new ByteLocation(0, 1),
            new ByteLocation(1, -1),
            new ByteLocation(1, 0),
            new ByteLocation(1, 1),
    };

    private int numRows, numCols;

    /** this is an auxiliary structure to help determine candidate moves. should extract to sep class. */
    private boolean[][] candidateMoves_;

    /**
     * Constructor
     * @param board the gomoku board to determine candidate moves for
     */
    public CandidateMoves(GoMokuBoard board) {
        this.numRows = board.getNumRows();
        this.numCols = board.getNumCols();
        this.candidateMoves_ = new boolean[numRows + 2][numCols + 2];
        determineCandidateMoves(board);
    }

    /** For internal use only */
    protected CandidateMoves() {}

    /**
     * We consider only those spaces bordering on non-empty spaces.
     * In theory all empties should be considered, but in practice only
     * those bordering existing moves are likely to be favorable.
     *
     * @return true if this position is a possible next move
     */
    public boolean isCandidateMove( int row, int col )  {
        return candidateMoves_[row][col];
    }

    public void setCandidate(BoardPosition pos) {

        if ( pos != null && !pos.isOccupied())  {
            candidateMoves_[pos.getRow()][pos.getCol()] = true;
        }
    }

    /**
     * This method splats a footprint of trues around the current moves.
     * later we look for empty spots that are true for candidate moves.
     */
    protected void determineCandidateMoves(GoMokuBoard board)  {

        int i,j;
        boolean hasCandidates = false;
        for ( i = 1; i <= numRows; i++ ) {
            for ( j = 1; j <= numCols; j++ ) {
                if ( board.getPosition(i, j).isOccupied() ) {
                    Location location = new ByteLocation(i, j);
                    // set the surrounding footprint
                    for (Location offset : SPLAT) {
                        BoardPosition pos =
                                board.getPosition(location.incrementOnCopy(offset));
                        setCandidate(pos);
                    }
                    hasCandidates = true;
                }
            }
        }
        // edge case when no moves on the board - just use the center
        Location center = new ByteLocation(numRows / 2 + 1, numCols / 2 + 1);
        BoardPosition pos = board.getPosition(center);
        if (!hasCandidates) {
            setCandidate(pos);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy