Hi,
Let’s suppose that you have m
rows and n
columns, you have m * n
possible crosses where to put your rectangles.
Each time you pick a cross to draw something, you need to mark it as used. So you need to store one information for each cross, whether it has been used or not.
The sentence “The cross has been used” called a predicate in logic, it’s something that can be true or false. The result of a predicate is a boolean value either true
or false
in Java.
Indeed you are going to store a boolean
value for each cross telling if a cross has been used.
By default, each cross is not used, which means it’s going to hold false
and whenever you choose a cross at location x
and y
, you set the boolean to true. If it was already true, you pick another value.
One thing is that crosses are organized as a grid which means that a cross is identifiable with a row number and a column number. So the best way is to use two dimensional array like images.
You could do it like this :
int m = 10; // Rows
int n = 5; // Columns
// Declare a two dimensional array of boolean
// By default they are false
boolean[][] crossUsed = new boolean[m][n];
//...
// When you choose a random cross
int row = int(random(m));
int col = int(random(n));
// We can use directly the value stored in the array in the if since it's true or false
if (!crossUsed[row][col]) { // If it's not used
// Draw something on the cross
// Set it to true, we used it
crossAvailable[row][col] = true;
} else {
// It's false so we need to pick another cross...
}
This is the basic idea, but what if we go to the else statement? It means that the cross was previously used and we need to pick another cross so we would do again int row = int(random(m));...
to choose a random cross. And what if the cross is used again? We need to do the same… and the same…
So you see that we can’t write code like this by copy and pasting if and else nested. We need a loop. But a special one, a do ... while
:
// Declare variables but not affect them
int row, col;
do {
row = int(random(m));
col = int(random(n));
} while(crossUsed[row][col]);
// If the loop stops, row and col are going to indicate an unused cross
Which is quite self explanatory : “choose a random column and a random row while this random cross is used”
Ok so it works but what happens when there’s for example 5 crosses out of 100 that are free to use.
It means that at each while loop, you have 5 / 100 = 5%
chance to find an unused cross assuming that the random()
function is equiprobabilistic (every number has an equal probability to be picked, this is the definition of true randomness).
So with 5%
of probability, you are going to make plenty of loops before randomly finding the 5 crosses left. It’s even worse if there’s one cross left… It’s not doable if you want to use all the crosses, we need to find another solution.
This is a visualization of the number of retries (do while loop) over the number of crosses that has been used (on a total of 100 crosses) :
(fun fact : this was made using Processing )
You can clearly see that as soon as there’s more and more crosses that are used, the number of retries grows exponentially. To compare, I put one with 100 and another with 1000 crosses to show that more crosses also means more retry because you can randomly pick number in a larger collection.
In your previous code, you have a total of 2090 crosses with a canvas size of (1122, 793)
so it’s going to be really expensive to compute.
Anyway all this to say that there’s another method that is smarter, can you try to solve this?
Hope you like it, don’t mind if you didn’t understand everything, I am also experimenting!