I want to generate a list of random numbers with a predefined number of items %RND_TOTAL% in the given range from %RND_MIN% to %RND_MAX%
Aacini's original solution is efficient, however, it can only support a maximum of 31 possible values because FOR /F cannot read more than 31 tokens. EDIT - His 2nd solution eliminated the limitation.
Below is a similar concept that uses a constant width for the numbers in the list. This enables me to easily use substring operations to both extract the randomly selected values, and to remove each value from the list.
As written, this solution supports values from 0 to 9999, with a maximum number of possible values <= 1354.
I used a very similar strategy for managing random food placement in my SNAKE.BAT game. I had to keep track of all empty locations within the playing field, and randomly select a new food location from that list.
@echo off
setlocal enableDelayedExpansion
:: This script has the following limitations:
:: RND_MIN >= 0
:: RND_MAX <= 9999
:: ((RND_MAX - RND_MIN + 1) / RND_INTER) <= 1354
::
set "RND_MIN=1"
set "RND_MAX=10"
set "RND_INTER=1"
set "RND_TOTAL=8"
set /a cnt=(RND_MAX - RND_MIN + 1) / RND_INTER
:: Define a string containing a space delimited list of all possible values,
:: with each value having 10000 added
set "pool="
set /a "beg=RND_MIN+10000, end=RND_MAX+10000, cnt=(RND_MAX-RND_MIN+1)/RND_INTER"
for /l %%N in (%beg% %RND_INTER% %end%) do set "pool=!pool!%%N "
:: Build the randomly sequenced array of numbers
for /l %%N in (1 1 %RND_TOTAL%) do (
%= Randomly select a value from the pool of all possible values =%
%= and compute the index within the string, as well as the index =%
%= of the next value =%
set /a "loc=(!random!%%cnt)*6, next=loc+6"
%= Transfer the index values to FOR variables =%
for %%A in (!loc!) do for %%B in (!next!) do (
%= Assign the selected value to the output array =%
set /a "RND_NUM[%%N]=!pool:~%%A,5!-10000"
%= Remove the value from the pool =%
set "pool=!pool:~0,%%A!!pool:~%%B!"
set /a cnt-=1
)
)
:: Display the results
for /l %%N in (1 1 %RND_TOTAL%) do echo !RND_NUM[%%N]!