Winning strategy for the dice pig game I am writing a computer opponent in java to play the dice game pig. I am trying to code it to be optimized based off of this paper.

    @Override
public boolean decideIfShouldRoll(int turnNumber, int rollNumber,
        int poolSize, int myScore, int opponentsScore) {
    if (myScore &lt; 30 &amp;&amp; opponentsScore &lt; 30) {
        if (poolSize &lt;= 20)
            return true;
        else
            return false;
    }

    // Checks for if the opponent has a greater score
    if (opponentsScore &gt; myScore) {

        // opponent is near winning?
        if (100 - opponentsScore &lt;= 20) {

            // checks if computer is near winning
            if (100 - myScore &lt;= 20) {
                if (poolSize &lt;= 20)
                    return true;
                else
                    return false;
            }

            // if computer not near winning, take a go for broke strategy
            if (100 - myScore &gt; 20) {
                if (poolSize &lt;= 30)
                    return true;
                else
                    return false;
            }

        }
        if (opponentsScore &gt; 20) {
            if (poolSize &lt;= 20)
                return true;
            else
                return false;
        }

        return true;
    }

    if (myScore &gt; opponentsScore) {

        // if near winning and the opponent's score is within 10 try a small
        // wins strategy
        if ((100 - myScore) &lt;= 20 &amp;&amp; (myScore - opponentsScore) &lt;= 10) {
            if (poolSize &lt;= 15)
                return true;
            else
                return false;
        }
        // if 10 points from winning, only build a pool up to 10 points
        if ((100 - myScore) &lt;= 10) {
            if (poolSize &lt;= 10)
                return true;
            else
                return false;
        }
        // if the difference between the computer score and opponent score
        // is &gt; 10, go up to the standard optimal pool size of 20
        if ((myScore - opponentsScore) &gt; 10) {
            if (poolSize &lt;= 20)
                return true;
            else
                return false;
        }

        // if near winning and the opponents score is within 10 points, take
        // a reduced standard pool size
        if ((100 - myScore) &lt;= 20
                &amp;&amp; Math.abs(myScore - opponentsScore) &lt;= 10) {

            if (poolSize &lt;= 15)
                return true;
            else
                return false;
        }

        return true;
    }
    return true;

}
Bugs

The outline of the function is


@Override
public boolean decideIfShouldRoll(int turnNumber, int rollNumber,
        int poolSize, int myScore, int opponentsScore) {
    if (myScore &lt; 30 &amp;&amp; opponentsScore &lt; 30) {
        …
    }
    if (opponentsScore &gt; myScore) {
        …
    }
    if (myScore &gt; opponentsScore) {
        …
    }
    return true;
}



The return true at the end is problematic.  You're saying that, except in the opening moves, anytime the score is tied, you want to roll forever, essentially forfeiting your turn.



If we have 95 points and a pool of 5, we should stop rolling.  Your code tries to amass a pool of 15 points or 10 points.

Redundancy

The opponentScore &gt; 20 test should always be true, since the opponent is in the lead, and the leader has at least 30 points.


@Override
public boolean decideIfShouldRoll(int turnNumber, int rollNumber,
        int poolSize, int myScore, int opponentsScore) {
    if (myScore &lt; 30 &amp;&amp; opponentsScore &lt; 30) {
        …
    }
    if (opponentsScore &gt; myScore) {
        …
        if (opponentsScore &gt; 20) {
            …
        }
        return false;
    }
    if (myScore &gt; opponentsScore) {
        …
    }
    return true;
}





Math.abs() is superfluous here, since we have already established that we are in the lead:


if (myScore &gt; opponentsScore) {
    if ((100 - myScore) &lt;= 20 &amp;&amp; (myScore - opponentsScore) &lt;= 10) {
        …
    }
    …
    if ((myScore - opponentsScore) &gt; 10) {
        …
    }
    if ((100 - myScore) &lt;= 20
            &amp;&amp; Math.abs(myScore - opponentsScore) &lt;= 10) {
        …
    }
    return true;



In fact, if you eliminate the Math.abs(), then you are redundantly restating the (100 - myScore) &lt;= 20 &amp;&amp; (myScore - opponentsScore) &lt;= 10 case exactly.

Verbosity

Anytime you have if (condition) return true; else return false; you should just write return condition;.

I'm not a fan of needless arithmetic like if (100 - opponentsScore &lt;= 20).  It would be shorter to write if (opponentScore &gt;= 80), and just as clear.

Interface

The function name could be simplified to shouldRoll.

Assuming a fair die, there is no logical strategy in which the turnNumber or the rollNumber could be a factor in the decision.  It doesn't matter how you arrived at the current score and pool, because past performance is no indicator of future expectations.  Anything else would be a gambler's fallacy.  Therefore, I suggest eliminating turnNumber and rollNumber from the method signature.

I suggest renaming opponentsScore to theirScore, both to save a few characters and to mirror myScore.

Rewrite

There is too much code altogether!  You are really just trying to express a simple idea: in the face of an imminent loss, go for a pool of 30 points; if you have a comfortable lead, aim for just 15; otherwise, try to gather 20.

@Override
public boolean shouldRoll(int poolSize, int myScore, int theirScore) {
    if (myScore + poolSize &gt;= 100) {
        return false;
    }
    int myLead = myScore - theirScore;
    int wantPool = (myScore &lt; 80 &amp;&amp; theirScore &gt;= 80) ? 30              // Imminent loss, be aggressive.
                 : (myScore &gt;= 80 &amp;&amp; (0 &lt; myLead &amp;&amp; myLead &lt;= 10)) ? 15 // Comfortable lead
                 : 20;                                                  // General case
    return poolSize &lt; wantPool;
}