This seems to work nicely:
Random random = new Random();
public int[] fourRandoms(int limit) {
int[] randoms = new int[4];
int[] three = new int[3];
for (int i = 0; i < 3; i++) {
three[i] = random.nextInt(limit);
}
int min = Math.min(three[0], Math.min(three[1], three[2]));
int max = Math.max(three[0], Math.max(three[1], three[2]));
int mid = three[0] + three[1] + three[2] - max - min;
randoms[0] = min - 0;
randoms[1] = mid - min;
randoms[2] = max - mid;
randoms[3] = limit - max;
return randoms;
}
public void test() {
for (int i = 1; i < 10; i++) {
int[] randoms = fourRandoms(100);
int sum = Arrays.stream(randoms).sum();
System.out.println(Arrays.toString(randoms) + " = " + sum);
}
}
It's an implementation of @SpaceTrucker's idea.
Alternatively - using Java 8 Streams.
public int[] nRandomsThatSumToLimit(int n, int limit) {
return IntStream
.concat(
// Stream n-1 random ints and sort them.
random.ints(n - 1, 0, limit).sorted(),
// Plus the final limit value.
IntStream.of(limit))
// Convert into a stream of differences.
.map(new IntUnaryOperator() {
// Maintain the previous.
int p = 0;
@Override
public int applyAsInt(int n) {
// Difference.
int d = n - p;
// Persist.
p = n;
return d;
}
}).toArray();
}