Package com.barrybecker4.game.twoplayer.go.board.analysis.group

Source Code of com.barrybecker4.game.twoplayer.go.board.analysis.group.AbsoluteHealthCalculator

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

import com.barrybecker4.game.common.GameContext;
import com.barrybecker4.game.twoplayer.go.board.GoBoard;
import com.barrybecker4.game.twoplayer.go.board.GoProfiler;
import com.barrybecker4.game.twoplayer.go.board.analysis.group.eye.EyeHealthEvaluator;
import com.barrybecker4.game.twoplayer.go.board.analysis.group.eye.GroupEyeCache;
import com.barrybecker4.game.twoplayer.go.board.elements.eye.GoEyeSet;
import com.barrybecker4.game.twoplayer.go.board.elements.group.IGoGroup;
import com.barrybecker4.game.twoplayer.go.board.elements.string.IGoString;

/**
* Determine the absolute health of a group independent of the health of neighboring groups.
* @author Barry Becker
*/
@SuppressWarnings("HardCodedStringLiteral")
class AbsoluteHealthCalculator {

    /** The group of go stones that we are analyzing. */
    private IGoGroup group_;

    /**
     * This is a number between -1 and 1 that indicates how likely the group is to live
     * independent of the health of the stones around it.
     * all kinds of factors can contribute to the health of a group.
     * Local search should be used to make this as accurate as possible.
     * If the health is 1.0 then the group has at least 2 eyes and is unconditionally alive.
     * If the health is -1.0 then there is no way to save the group even if you could
     * play 2 times in a row.
     * Unconditional life means the group cannot be killed no matter how many times the opponent plays.
     * A score of near 0 indicates it is very uncertain whether the group will live or die.
     */
    private float absoluteHealth_ = 0;

    /** Number of stones in the group. */
    private int cachedNumStonesInGroup_;

    /** Maintains cache of this groups eyes. */
    private GroupEyeCache eyeCache_;

    private GroupAnalyzerMap analyzerMap_;

    /**
     * Constructor
     * @param group the group to analyze
     */
    public AbsoluteHealthCalculator(IGoGroup group, GroupAnalyzerMap analyzerMap) {
        group_ = group;
        analyzerMap_ = analyzerMap;
        eyeCache_ = new GroupEyeCache(group, analyzerMap_);
    }

    /**
     * @return false if the group has changed (structurally) in any way.
     */
    public boolean isValid() {
        return eyeCache_.isValid();
    }

    /** for st the eyeCache to be cleared. */
    public void invalidate() {
        eyeCache_.invalidate();
    }

    /**
     * used only for test.
     * @return eye potential
     */
    public float getEyePotential() {
        return eyeCache_.getEyePotential();
    }

    /**
     * Calculate the absolute health of a group.
     * All the stones in the group have the same health rating because the
     * group lives or dies as a unit.
     * (not entirely true - strings live or die as unit, but there is a relationship).
     * Good health of a black group is positive; white, negative.
     * The health is a function of the number of eyes (their type and status), liberties, and
     * the health of surrounding groups. If the health of an opponent bordering group
     * is in worse shape than our own then we get a boost since we can probably
     * kill that group first. See RelativeHealthCalculator.calculateRelativeHealth.
     * A perfect 1 (or -1) indicates unconditional life (or death).
     * This means that the group cannot be killed (or given life) no matter
     * how many times the opponent plays (see Dave Benson 1977).
     *  http://senseis.xmp.net/?BensonsAlgorithm
     *
     * @return the overall health of the group independent of nbr groups.
     */
    public float calculateAbsoluteHealth(GoBoard board) {

        if (eyeCache_.isValid()) {
            GameContext.log(1, "cache valid. Returning health=" + absoluteHealth_);
            return absoluteHealth_;
        }

        int numLiberties = group_.getNumLiberties(board);

        // we multiply by a +/- sign depending on the side
        float side = group_.isOwnedByPlayer1() ? 1.0f : -1.0f;

        // first come up with some approximation for the health so update eyes can be done more accurately.
        float numEyes = eyeCache_.calcNumEyes();
        int numStones = group_.getNumStones();
        LifeAnalyzer lifeAnalyzer = new LifeAnalyzer(group_, board, analyzerMap_);
        EyeHealthEvaluator eyeEvaluator = new EyeHealthEvaluator(lifeAnalyzer);

        absoluteHealth_ = eyeEvaluator.determineHealth(side, numEyes, numLiberties, numStones);

        GoProfiler.getInstance().startUpdateEyes();
        eyeCache_.updateEyes(board)// expensive
        GoProfiler.getInstance().stopUpdateEyes();

        float eyePotential = eyeCache_.getEyePotential();
        float revisedNumEyes = eyeCache_.calcNumEyes();
        numEyes = Math.max(eyePotential, revisedNumEyes);

        // health based on eye shape - the most significant factor
        float health = eyeEvaluator.determineHealth(side, numEyes, numLiberties, numStones);

        // No bonus at all for false eyes
        absoluteHealth_ = health;
        if (Math.abs(absoluteHealth_) > 1.0) {
            GameContext.log(0"Warning: health exceeded 1.0: " +" health="+health+" numEyes="+numEyes);
            absoluteHealth_ = side;
        }

        return absoluteHealth_;
    }

    /**
     * @return set of eyes currently identified for this group.
     */
    public GoEyeSet getEyes(GoBoard board) {
        if (!eyeCache_.isValid())  {
            calculateAbsoluteHealth(board);
        }
        return eyeCache_.getEyes(board);
    }

    /**
     * Calculate the number of stones in the group.
     * @return number of stones in the group.
     */
    public int getNumStones() {
        if (eyeCache_.isValid()) {
            return cachedNumStonesInGroup_;
        }
        int numStones = 0;
        for (IGoString str : group_.getMembers()) {
            numStones += str.size();
        }
        cachedNumStonesInGroup_ = numStones;
        return numStones;
    }
}
TOP

Related Classes of com.barrybecker4.game.twoplayer.go.board.analysis.group.AbsoluteHealthCalculator

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.