@echo off
:Test
set /a x=%random% %% 296 + 1
for %%? in (%x2%) do if "%x%"=="%%?" goto Test
if "%x2%"=="" (set x2=%x%) else set x2=%x2% %x%
set /a x3+=1
if %x% lss 10 (if %x3% lss 10 (echo. %x% - %x3%) else if %x3% lss
100 (echo. %x% - %x3%) else echo. %x% - %x3%) else if %x% lss 100
(if %x3% lss 10 (echo. %x% - %x3%) else if %x3% lss 100 (echo. %x% -
%x3%) else echo. %x% - %x3%) else if %x3% lss 10 (echo %x% - %x3%)
else if %x3% lss 100 (echo %x% - %x3%) else echo %x% - %x3%
if "%x3%"=="296" (echo.
echo Done.
echo.
pause
goto :eof)
goto Test
Do you have a better way to do this?
How about something like the following?
@echo off
setlocal
set ctr=0
:Test
if %ctr% equ 296 goto :EOF
set /a x=%random% %% 296 + 1
echo/.%x2%. | findstr ".%x%." > nul
if %errorlevel% equ 0 goto :Test
set /a ctr += 1
set x2=%x2% %x%
echo/%x2%
goto :Test
But it will get slower and slower as x2 contains more and more numbers....
--
Phil Robyn
University of California, Berkeley
%RANDOM% comes from a pseudorandom number generator with a period of
32768. As long as OP doesn't need more than 32768 lines, the OP could
use as follows.
@echo off & setlocal enableextensions enabledelayedexpansion
if .%1. == .. goto USAGE
if .%2. == .. goto USAGE
if .%3. == .. ( set m=1 ) else ( set m=%3 )
copy nul "%0.temp" > nul 2>&1
for /L %%k in (%1,%m%,%2) do (
set /a x=!random!+100000
echo !x:~1! %%k >> "%0.temp"
)
for /F "tokens=2 delims= " %%k in ('sort "%0.temp"') do echo %%k
del "%0.temp"
goto :EOF
:USAGE
echo %0 startnum endnum [stepval]
goto :EOF
It'll slow down as the number of records increases, but the sort
command's O(N log(N)) performance should be noticeably faster. For
arguments 1 5000 it runs in 3-4 seconds on my system.
wget -O- http://www.random.org/cgi-bin/randseq?min=1^&max=296 2>null
You can get wget for Windows from
<http://users.ugent.be/~bpuype/wget/>
See <http://www.random.org/> for more information about their true
random number/sequence/byte service. Your task is a random sequence.
--
T.E.D. (tda...@gearbox.maem.umr.edu)
@echo off
if "%~1"=="" goto Help
if "%~2"=="" goto Help
if "%~3"=="" (set step=1) else set step=%~3
for /l %%? in (%~1 %step% %~2) do echo !random!:%%? >>%~nx0.txt
for /f "tokens=2 delims=:" %%? in ('sort %~nx0.txt') do echo %%?
del "%~nx0.txt"
goto :eof
:Help
echo.
echo %~n0 start stop [step]
goto :eof
I could, but either the command
sort /? | more
or going through the Start Menu, Help and Support and searching for the
sort command would give a much more complete explanation that I'd
provide.
>And why you did SET /A X=!RANDOM!+100000 and not just SET /A X=!RANDOM! ?
DOS sort is relatively simplistic. It's purely text sorting, so 5 would
sort after 1, 22, 370, 4567890123 etc. in ascending order because 5
comes after 1, 2, 3 and 4 in character order. The 2 phase process of
setting x to !RANDOM!+100000 then using !x:~1! effectively ensures that
the resulting output records' first field always has 5 decimal digits
possibly with leading zeros. 00005 will sort *before* 00022, 00370 etc.
(4567890123 would be a bit beyond the problem scope I assumed) in
ascending order. When using a sorting tool that lacks numeric
semantics, padding with leading zeros is the next best thing.
set /p low= Input Lowerbound:
set /p upp= Input Upperbound:
call:_random "cscript.exe" "%tmp%\tmp.vbs" "%low%" "%upp%"
echo Random Number is: %r%& pause& goto:eof
:_random
echo>%2 randomize:wscript.echo int^(^(%4-%3+1^)*rnd+%3^)
(for /f %%r in ('%~$path:1 %2')do set r=%%r)& del %2
goto:eof
OR goto:Examples
Benny Pedersen,
PS: the %~$path:1 returns the full path of cscript.exe
:Examples
echo.... 1: %~$path:1
echo.... 2: %~dp$path:1%~1
for %%f in (%~1)do (
echo.... 3: %%~$path:f
echo.... 4: %%~dp$path:f%~1
echo.... 5: %%~dp$path:f%%f
)
OP wants shuffled numbers from 1 to 296, not a single integer from
within that range. If a single integer were all that's desired, the
OP's
set /a x=%random% %% 296 + 1
would probably suffice (though it's not uniform since 32768 isn't
divisible by 296). If it should be uniform, then
:loop
set /a x=%random%
if %x% gtr 32559 goto :loop
set /a x=x %% 296 + 1
If VBScript's Rnd were a high quality pseudorandom number generator,
then there might be some reason to use it. However, for the OP's task
of shuffling integers in a range, CMD's %RANDOM% is more than
sufficient. There are things VBScript can do that CMD and a few bundled
console utilities can't, but this isn't one of them.
Benny,
PS. I like VBS :-)
Harlan Grove skrev:
Have you tried microsoft.public.scripting.vbscript ?
I know something about DOS in Win9X. Hmm, I remenber the step up from
version 6.22, that was hard in the beginning. Now when I do a step
forward from DOS in 9X til NT, it's the same hard.
but after writing about 5 batch files in NT, its now easy. But I probly
got much to learn.
Benny
Harlan Grove skrev:
> I tried to write a batch file that prints random numbers (from 1 to 296
> for example) and I tried to make it so it won't print a number that has
> already been shown, this is what I got:
> Do you have a better way to do this?
That can be called the shuffle problem (as for shuffle a deck of
cards). One algorithm is covered e.g. in
169462 Oct 27 2004 ftp://garbo.uwasa.fi/pc/link/tsfaqp.zip
tsfaqp.zip Common Turbo Pascal Questions and Timo's answers
As for random numbers in scripts
87} How can I create a four-digit random string?
150924 Jan 11 2006 ftp://garbo.uwasa.fi/pc/link/tscmd.zip
tscmd.zip Useful NT/2000/XP script tricks and tips, T.Salmi
All the best, Timo
--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FIN-65101, Finland
Timo's FAQ materials at http://www.uwasa.fi/~ts/http/tsfaq.html
Your problem is the shuffle problem. Getting a random number is part
of the task. It is not overly difficult to get a three digit random
number in a specified range if one starts from how to get a
four-digit one.
> I think Harlan gave me the best way to do my task.
Excellent! (BTW note, the established programming methods for
the shuffle do not have the slowdown phenomenon.)
All the best, Timo
--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FIN-65101, Finland
Useful script files and tricks ftp://garbo.uwasa.fi/pc/link/tscmd.zip
@echo off
setlocal
for /l %%i in (1,1,296) do set rand[%%i]=%%i
for /l %%i in (296,-1,1) do call :sub %%i
goto :eof
:sub
set /a x=%random% %% %1% + 1
call echo %%rand[%x%]%%
call set rand[%%x%%]=%%rand[%1]%%
Usually the second loop ends at 2 since there's no point in swapping
a[1] with itself.
>goto :eof
>
>:sub
>set /a x=%random% %% %1% + 1
>call echo %%rand[%x%]%%
>call set rand[%%x%%]=%%rand[%1]%%
This is the textbook shuffling algorithm, and in languages with
integer-indexed arrays it's most efficient. However, CMD lacks arrays,
so each pseudo array element is a separate variable, and dereferencing
each one involves a linear search through the environment table, which
makes the CMD implementation O(N**2) rather than O(N) when using
indexed arrays. For only 296 entries, no big deal. For, say, 5000
entries, it's much slower than approaches using the sort command, which
is O(N log(N)).
PS. Don't tell me what to do.
To be fair, the code was specific to 1-based pseudo arrays. If you want
to use other bases, e.g., 4, then it's up to you to modify the code. In
this case,
set /a x=%random% %% (%1 - 4 + 1) + 4
or simplify to
set /a x=%random% %% (%1 - 3) + 4
I note that you and I are not seeing eye to eye. I happens. Best to
avoid each other from now on. Oh sorry, I shouldn't be telling you
what to do. So, you'll do whatever you decide, since you don't like
getting advice or answers from me.
Not to worry. I'll do the avoiding from now on.
I don't know what you mean. You wanted random numbers from 1 to 296.
If you want random numbers from 1 to 4, replace 296 by 4. If you want
random numbers starting by min (>=1) till max (>min) use:
@echo off
setlocal
set min=4
set max=5
for /l %%i in (%min%,1,%max%) do set rand[%%i]=%%i
for /l %%i in (%max%,-1,%min%) do call :sub %%i
goto :eof
:sub
set /a x=%1-min+1
set /a x=%random% %% x + min
Then only 295 and not 296 numbers are echoed.
Fair point. So add the statement
echo %rand[1]%
just after the second for loop. You don't need to call the subroutine
to try swapping rand[1] with itself. For that matter, there's probably
little need to call it when the iteration variable is less than 5. That
would require adding a third for loop like
for /L %%i in (5,-1,1) do call echo %%rand[%%i]%%
just before the goto :eof line.
Another take. Using VBS-aided scripting and the shuffle algoritm to
avoid any repeats:
@echo off & setlocal enableextensions enabledelayedexpansion
::
:: Set the number of random numbers to be shuffled
:: Typically 52 would be a deck of cards
set max_=52
::
:: Build a Visual Basic Script
set vbs_=%mytemp%\tmp$$$.vbs
findstr "'%skip%VBS" "%~f0" > %vbs_%
::
:: Run it with Microsoft Windows Script Host Version 5.6
set cmd_=%mytemp%\tmp$$$.cmd
cscript //nologo %vbs_% > %cmd_%
::
:: Call the command line script which the script host built
call %cmd_%
::
:: Display the results
for /l %%i in (1,1,%max_%) do echo rand[%%i] = !rand[%%i]!
::
:: Clean up
for %%f in ("%vbs_%" "%cmd_%") do if exist %%f del %%f
endlocal & goto :EOF
'
'.......................................................
'The Visual Basic Script
'
Dim maxItems, i, j, k, rand(1000) 'VBS
Set WshShell = WScript.CreateObject("WScript.shell") 'VBS
maxItems=WshShell.ExpandEnvironmentStrings("%max_%") 'VBS
Randomize 'VBS
For i = 1 to MaxItems 'VBS
rand(i) = i 'VBS
Next 'VBS
For i = 1 to MaxItems 'VBS
j = 1 + Int(MaxItems*rnd) 'VBS
k = rand(i) 'VBS
rand(i) = rand(j) 'VBS
rand(j) = k 'VBS
Next 'VBS
For i = 1 to MaxItems 'VBS
WScript.Echo "@set rand[" & i & "]=" & rand(i) 'VBS
Next 'VBS
The output would be e.g.
C:\_D\TEST>cmdfaq
rand[1] = 3
rand[2] = 6
:
rand[50] = 36
rand[51] = 26
rand[52] = 40
For brevity and greater efficiency, allow me to suggest the algorithm
posted by Horst Kraemer and quoted at the end of Section 140 of the
invaluable Turbo Pascal FAQ cited in sig line 4 below. ISTM that its
first statement can be removed if the loop is changed to start at 1.
BTW, I suggest changing the Subject of that section to "Shuffling or
dealing a deck of cards".
The destination of the quoted link has moved from pascal.htm#Rand to
pas-rand.htm, and pas-time.htm#Delay in #67 is now pas-wait.htm#Delay.
--
© John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 MIME. ©
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/&c., FAQqy topics & links;
<URL:http://www.merlyn.demon.co.uk/clpb-faq.txt> RAH Prins : c.l.p.b mFAQ;
<URL:ftp://garbo.uwasa.fi/pc/link/tsfaqp.zip> Timo Salmi's Turbo Pascal FAQ.
> Timo Salmi <t...@uwasa.fi> posted :
>> Another take. Using VBS-aided scripting and the shuffle algoritm
>> to avoid any repeats:
> For brevity and greater efficiency, allow me to suggest the
> algorithm posted by Horst Kraemer and quoted at the end of Section
> 140 of the invaluable Turbo Pascal FAQ cited in sig line 4 below.
Thanks John. I have added a link to your posting in the cmd FAQ
random item.
> BTW, I suggest changing the Subject of that section to "Shuffling
> or dealing a deck of cards".
Can't do. The subject lines in the pascal FAQ are limited in length.
> The destination of the quoted link has moved from pascal.htm#Rand
> to pas-rand.htm, and pas-time.htm#Delay in #67 is now
> pas-wait.htm#Delay.
Corrected. Even if it is unlikely that my Turbo Pascal FAQ will have
new versions.
In case anyone wonders what this has to do with scripting. Well, some
of the programming algorithms are easily portable as was the card
shuffling algorithm.
All the best, Timo
--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FIN-65101, Finland
If you had a random integer, r, drawn from 1 to 6, use it to generate a
random even integer between 0 and 10 as (r - 1) * 2.
Where does '%skip% come from in that last line?
Thanks
Matt
> Where does '%skip% come from in that last line?
Ah, you missed the essence of the trick. (It's empty. Of course.)
Thanks
Matt
"Timo Salmi" <t...@uwasa.fi> wrote in message
news:43f24560$0$25333$9b53...@news.fv.fi...
> Could you explain how it works? I found a couple other posts where you use
> the same findstr "'%skip%" trick and in some %skip% is defined as nothing
> and others it's not defined at all, which is the same so that fact is
> insignificant. I still don't know what's going on behind the scenes.
>
> Thanks
>
> Matt
>
>
> "Timo Salmi" <t...@uwasa.fi> wrote in message
> news:43f24560$0$25333$9b53...@news.fv.fi...
>> Matt Williamson wrote:
>>>>"Timo Salmi" <t...@uwasa.fi> wrote in message :: Build a Visual Basic
>>>>Script
>>>> set vbs_=%mytemp%\tmp$$$.vbs
>>>> findstr "'%skip%VBS" "%~f0" > %vbs_%
>>
>>> Where does '%skip% come from in that last line?
>>
>> Ah, you missed the essence of the trick. (It's empty. Of course.)
>>
Not to steal Timo's thunder - it stops findstr from filtering that same
line into the output file, as it is not literally 'VBS.