How to generate a list of random numbers without duplicates in pure batch scripting?

前端 未结 5 1953
青春惊慌失措
青春惊慌失措 2020-12-07 03:51

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%

5条回答
  •  被撕碎了的回忆
    2020-12-07 04:08

    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]!
    

提交回复
热议问题