You need deterministic algorithm
First redefine your requirements:
- Every column should have at least 1 number, so no column should be completely blank
- First column should have numbers from 1..10, second 11..20, third 21..30 and so on to the ninth column having from 81..90
- only 15 numbers needed to fill the ticket
- Additional requirement: Every row should have 5 numbers
This is how I'd do it:
- First select 9 randoms (to satisfy first requirement)
- 1..10 - one random number from this range
- 11..20 - one random number from this range
- ...
- 81..90 - one random number from this range
- Prepare an array (
selectNums
) of numbers 1..90 and remove all selected in step 1
- Loop
- get a random number from the
selectNums
array
- add it to your ticket and remove it from the
selectNums
aray
- if selected number fills a column of three then remove all numbers from that range from the
selectNums
array.
- Go back to step 1 in the loop
This algorithm will take you exactly 9 steps + 6 steps in the loop so it's deterministic which is better for the processor utilization. And it also fills your ticket with up to three numbers per column and not less than 1 (if I understood your requirements due too poor english in the question).
Yo when you select random numbers you always select a number between 0 and selectNums
array length which will give you position in array where you have to take a number from.
Additonal functionality to create the actual ticket
Above steps will get you to a point where you will get exactly 15 numbers with at most 3 from the same ten numbers range. Fine. All you have to do now is to create your ticket.
- define 3 variables:
row1Count
, row2Count
and row3Count
and set them all to 0.
- Fill the ticket by starting from the fully filled columns (all three numbers):
- Get the first full column and fill it up in the ticket while also incrementing all three variables by one.
- Remove these numbers from the
selectNums
array.
- Go back to step 2.1.
- Fill the ticket with columns with two numbers:
- Get the first two numbers column. Fill them in the ticket by using three possible permutations of filling them in (1&2, 2&3, 1&3). Fill the first pair using the first permutation, second one with the second and so on. Don't forget to increment corresponding row counter variables.
- remove those two numbers from
selectNums
array
- Go back to step 3.1.
- Fill the ticket with single number columns (those that have just one number):
- Get the first number from
selectNums
array and put it in the row with the smallest count and put in on the ticket in that particular row. When there are at least two rows with the same count, you can select whichever you prefer by either selecting one randomly or taking the first one (quickest).
- Remove the number from
selectNums
array
- Go back to 4.1.
This part should get you to fully filled ticket with all columns having at least one number and all rows containing exactly 5 numbers in total.
If smaller numbers are not allowed to be under larger ones, you can always add an additional step to this process and reorder numbers in those columns that have more than just one number in it.
One final observation
This solution has been simplified by using arrays and counters. You could of course create a complete object model that would be functionally rich and would provide you all the info you need. You could for instance have a Ticket and TicketColumn classes:
public class TicketColumn
{
public int Count { get; }
public int? FirstRowValue { get; set; }
public int? SecondRowValue { get; set; }
public int? ThirdRowValue { get; set; }
...
public void Reorder() { ... }
}
public class Ticket
{
public TicketColumn[] Columns
public int FirstRowCount { get; private set; }
public int SecondRowCount { get; private set; }
public int ThirdRowCount { get; private set; }
...
}
Or something similar. This is just an idea that this whole program would be better off in object oriented manner.