Adding up dice rolls with constraints I have written the below code which generates 4 random, whole integer values between 1 and 6 and then saves the sum of the 3 largest values. It generates a total of 6 values this way, displays the total along with all 6 values once finished.


The order in which each value was generated must be preserved.
The total of all 6 values must be at least 75 or above.
At least 2 of the values must be 15 or more.


import java.util.Random;
import java.util.Arrays;

public class Test {
    static boolean goodRoll = false;


    public static int genAttribute() {

        Random dice = new Random();
        int[] sumArray = {dice.nextInt(6) + 1, dice.nextInt(6) + 1, dice.nextInt(6) + 1, dice.nextInt(6) + 1};
        for (int num : sumArray) {
            System.out.println(num);
        }


        int first = Integer.MIN_VALUE;
        int firstIndex = -1;
        int second = Integer.MIN_VALUE;
        int secondIndex = -1;
        int third = Integer.MIN_VALUE;


        for (int i = 0; i &lt; sumArray.length; i++) {
            int num = sumArray[i];
            if (num &gt; first) {
                first = num;
                firstIndex = i;
            }
        }

        for (int i = 0; i &lt; sumArray.length; i++) {
            int num = sumArray[i];
            if (num &gt; second &amp;&amp; num &lt;= first &amp;&amp; i != firstIndex) {
                second = num;
                secondIndex = i;
            }
        }

        for (int i = 0; i &lt; sumArray.length; i++) {
            int num = sumArray[i];
            if (num &gt; third &amp;&amp; num &lt;= second &amp;&amp; i != secondIndex &amp;&amp; i != firstIndex) {
                third = num;
            }
        }
        System.out.println(first + " " + second + " " + third);

        return first + second + third;

    }

    public static boolean checkFinalArray(int[] checkArray) {
        int fifteenCount = 0;
        for (int z : checkArray) {
            if (z &gt;= 15) {
                fifteenCount++;
            }
        }

        return (fifteenCount &gt;= 2 &amp;&amp; Arrays.stream(checkArray).sum() &gt;= 75);
    }

    public static void main(String[] args) {

        while (!goodRoll) {
            int[] finalArray;
            finalArray = new int[6];

            for (int i = 0; i &lt; 6; ++i) {
                finalArray[i] = genAttribute();
            }

            if (checkFinalArray(finalArray)) {
                System.out.println("sum: " + Arrays.stream(finalArray).sum());
                // Enhanced for to print each die
                for (int x : finalArray) {
                    System.out.println(x);


                }
                goodRoll = true;
            }
        }
    }

}


Can this be more efficiently written?
Document your code. In the code.  
Be sure you got the specification right.
Very helpful here is giving test serious consideration early on.
• testing order in which each value was generated must be preserved
 looks a nightmare

One way to present the approach coded:
1) generate six sums
2) if this sextuple is not admissible, start over
Alternatives:
2b) while sextuple is not admissible, delete oldest sum and append a new one
  This still results in six sums generated in a row.
2c) while sextuple is not admissible, delete smallest sum and append a new one
  This still preserves the order in which each value was generated
  - but it skews the distribution.
But: What if the real requirement was
Generate six pseudo-random values with a distribution identical to the one from a procedure as sketched, with utmost efficiency
(You'd have to define efficiency.)
Name things for what they can/will be used for. Difficult to guess for (test,) genAttribute(), checkFinalArray()
Parametrise where it does not add effort
What if you next wanted seven values each from five rolls of tetrahedral dice, three over a threshold of eleven and a total of at least 42?
sometimes it pays to take a step back and try to look at the requirements specification from a different angle:
The sum of the three largest values out of four may seem to require identifying those three values.
From a distance, it looks like the total minus the minimum.


I started putting in writing what I think should do:

   /** @param &lt;code&gt;nSums&lt;/code&gt; count of sums to return
    *  @param &lt;code&gt;nDraws&lt;/code&gt; count of summands for each sum
    *  @param &lt;code&gt;from&lt;/code&gt; lower bound for summands
    *  @param &lt;code&gt;to_inclusive&lt;/code&gt; upper bound for summands
    *  @param &lt;code&gt;threshold&lt;/code&gt; for "big enough"
    *  @param &lt;code&gt;requiredCount&lt;/code&gt; count of sums required to be
    *                                                   "big enough"
    *  @param &lt;code&gt;lowestTotal&lt;/code&gt; total to reach
    *
    *  @return &lt;code&gt;nSums&lt;/code&gt; of &lt;code&gt;nDraws&lt;/code&gt; values each
    *   but the smallest among those
    *   - &lt;em&gt;if&lt;/em&gt;&lt;br/&gt;
    *    - at least &lt;code&gt;requiredCount&lt;/code&gt; 
    *               sums reach &lt;code&gt;threshold&lt;/code&gt; &lt;em&gt;and&lt;/em&gt;&lt;br/&gt;
    *    - the total is &lt;code&gt;lowestTotal&lt;/code&gt;, at least */
    public static int[]
    sufficientTopSums(int nSums, int nDraws, int from, int to_inclusive,
        int threshold, int requiredCount, int lowestTotal) {
        // Start with a queue filled with very negative values
        // keep a total and a count of sufficiently high sums

        // check int range suffices
        assert((long)(nDraws - 1) * to_inclusive &lt; Integer.MAX_VALUE / nSums);
        final int veryNegative = Integer.MIN_VALUE/nDraws;
        Queue&lt;Integer&gt; q = new ArrayDeque&lt;&gt;(Collections.nCopies(
            nSums, veryNegative));
        for (int total = veryNegative * nSums, sufficient = 0 ; ; ) {
            int replaced = q.remove();
            // account for value removed
            total -= replaced;
            if (threshold &lt;= replaced)
                sufficient--;
            // generate &amp; keep new sum
            int sum = sumIgnoringMin(nDraws, from, to_inclusive);
            q.add(sum);
            // account for new value
            if (threshold &lt;= sum)
                sufficient++;
            if (lowestTotal &lt;= (total += sum)
                &amp;&amp; requiredCount &lt;= sufficient)
                return q.stream().mapToInt(x-&gt;x).toArray();
        }
    }
    public static void main(String[] args) {
        System.out.println(Arrays.toString(
            sufficientTopSums(6, 4, 1, 6, 15, 2, 75)));
    }

    static final java.util.Random dice = new java.util.Random();
    private static final int[] NO_INTS = {};

   /** @param &lt;code&gt;nDraws&lt;/code&gt; count of values to draw
    *  @param &lt;code&gt;from&lt;/code&gt; lower bound for values
    *  @param &lt;code&gt;to_inclusive&lt;/code&gt; upper bound for values
    *  @return sum of draws, excluding minimal value drawn */
    static int sumIgnoringMin(int nDraws, int from, int to_inclusive) {
        int to = to_inclusive - from + 1;
        int min = Integer.MAX_VALUE,
            sum = from * (nDraws);
        while (0 &lt;= --nDraws) {
            int drawn = dice.nextInt(to);
            if (drawn &lt; min)
                min = drawn;
            sum += drawn;
        }
        return sum - min - from;
    }


and stumbled upon not really knowing what representation to choose for the return value.
Oh, well, int[] and Collection&lt;Integer&gt; can be converted easily enough.
For lack of array rotation support, I went for a Queue&lt;Integer&gt;.