Batch- generating a random number of random numbers - batch-file

As part of a program I'm making, I want to be able to 'plot' or 'mark' random points on a grid. In doing so I need to generate a random number(x) to determine the number of plots- and then x amount of different random numbers representing coordinates. At the moment I have the following code:
#echo off
:obno
set /a r1=%random%
if %r1% gtr 10 goto obno else (
goto ob
)
:ob
for /L %%R in (1,1,%r1%) do set /a n%%R=%random%*240/32678+1
echo %r1%
echo %n1% %n2% %n3% %n4% %n5% %n6% %n7% %n8% %n9% %n10%
pause
What happens here is I end up with x amount of the same random number instead of different ones
i.e. ouput:
5
108 108 108 108 108
so any help would be greatly appreciated!

In a loop you should be using delayed expansion e.g.
SETLOCAL ENABLEDELAYEDEXPANSION and using !RANDOM! instead of %RANDOM%
And...
%RANDOM% gives you a random number between 0 and 32767.
Using an expression like below you can change the range to anything you like (here the range is [1…100] instead of [0…32767]).
SET /A test=%RANDOM% * 100 / 32768 + 1
And below will produce number between 1~100
set /a num=%random% %%100 +1
To get a random number between 0 and 9 on the command line, use
set /a "rand=%random% % 10"
If used in a batch file then double the modulo operator
set /a "rand=%random% %% 10"

Using your code, you can use a call and double the % to make %%random%%
#echo off
:obno
set /a r1=%random%
if %r1% gtr 10 goto obno else (
goto ob
)
:ob
for /L %%R in (1,1,%r1%) do call set /a n%%R=%%random%%*240/32678+1
echo %r1%
echo %n1% %n2% %n3% %n4% %n5% %n6% %n7% %n8% %n9% %n10%
pause

Here is a simliar post to generate random numbers in a batch file
You need to include the following at the start of your batch file
setlocal EnableDelayedExpansion
Random variable not changing in "for" loop in windows batch file

#ECHO OFF
SETLOCAL
:obno
set /a r1=%RANDOM% %% 10 + 1
:ob
for /L %%R in (1,1,%r1%) do CALL set /a n%%R=%%random%% %%%% 240 + 1
echo %r1%
echo %n1% %n2% %n3% %n4% %n5% %n6% %n7% %n8% %n9% %n10%
GOTO :EOF
Since %random% produces a random number 0..32767, your original code will waste a lot of time waiting for a number between 0 and 10. Also, it may generate 0.
The % operator is used for 'modulus'. Within a batch, you need to double it, so %random% %% 10 produces 0..9
By CALLing a command, you can avoid the need to setlocal enabledelayedexpansion BUT you also need to redouble any % you use, hence the doubling around random and quadrupling for the mod operator.
The setlocal isn't strictly necessary, BUT what it does is back out enviroment changes when the batch ends, so r1,n1..n10 simply no longer exist in the environment once the batch finishes. If you OMIT the setlocal then any variable set in one run will REMAIN set for a subsequent run, so if your first run sets n5 (and also therefore n1..n4) then if the second run sets r1=2, n3..n5 would be displayed with the stale data from the previous run.
Finally, if you allow r1=0 then since none of n1..n10 are set, the echo %n1%... command will be resolved to echo, will will show the echo status (Echo is on/off). This can be overcome by using the syntax echo(%n1%.... The character directly following the O has been found to do some strange things.
echoDot for instance is traditional for a blak newline. The ( may look odd and appear to 'unbalance' the nesting, but works quite happily to produce a newline with empty arguments.

Related

batch script how to create an array with specific continued numbers

I need to create an integer array that stops at a limit number and then goes on after another fixed value. Something like [1 2 3 4 5 10 11 12 13 14 15 16], where 5 is the limit number and 10 where it restarts.
Can you do something like set arr = [1:%lim%, 10:%max%] ?
#ECHO OFF
SETLOCAL
CALL :buildlist mylist 1 5 10 16
ECHO list is %mylist%
PAUSE
GOTO :eof
:: Produce a list of integers
:: %1 is listname
:: %2 is start value
:: %3 is end-value for range
:: %4 is restart-value
:: %5 is end-value
:buildlist
SET "%1="
FOR /L %%v IN (%2,1,%5) DO (
IF %%v leq %3 CALL SET "%1=%%%1%% %%v"
IF %%v geq %4 CALL SET "%1=%%%1%% %%v"
)
CALL SET "%1=%%%1:~1%%"
GOTO :eof
Batch really doesn't have arrays, but can simulate one with a little imagination.
The above routine produces a list of values to the specification, ready for processing by a for statement.
Although it's possible to use delayedexpansion, it's possible to avoid that facility. By CALL ing a set command, the command is parsed before execution so to decode the hieroglyphics, where %1 is the variable name "var"
SET "%1=%%%1%% %%v"
is processed as:
SET "var=%var% %v"
as %% is an escaped-%, and %v will be replaced by the value of the metavariable (loop-control variable) %%v
Similarly,
SET "%1=%%%1:~1%%"
is executed as
SET "var=%var:~1%"
which deletes the first character, which will be a space.
This problem is about several for /L commands really, although it could be described in terms of nested if commands or in other different ways...
There are several different methods to give the values of the for commands, and also to implement they. I think this is the simplest one:
#echo off
setlocal EnableDelayedExpansion
set ranges="1:5" "10:16"
set "list="
for %%a in (%ranges::= 1 %) do for /L %%i in (%%~a) do set "list=!list! %%i"
echo list=%list%
Note that this method also works with several (more than two) ranges of values.
PS - This result is a list, not an array
Batch doesn't have OR operators, so you'll have to make do with two separate if statements - one for the first set of numbers and one for the second set of numbers. You can, however, put both of those in the same for loop:
#echo off
setlocal enabledelayedexpansion
set "lim=5"
set "max=10"
REM Setting counter to -1 because we're going to increment the counter and then
REM use it, and arrays famously start at zero.
set "counter=-1"
for /L %%A in (1,1,16) do (
if %%A LEQ %lim% (
set /a counter+=1
set "array[!counter!]=%%A"
)
if %%A GEQ %max% (
set /a counter+=1
set "array[!counter!]=%%A"
)
)
REM Display the contents of the array just to prove it worked.
REM Alphabetic order is used, so array[10] and array[11] are going to print before array[1]
set array[

Minimum To Maximum in Batch File

I have a question about a piece of code I am writing.
Set /a 4DgtNum= %Random% %%9999
That's what is being used. I need to know how could I make a "Start at this number end in the range of another" code like start at (I.E 1000 and the max you can go to is 9999, but use any number between that ratio).
#ECHO Off
SETLOCAL enabledelayedexpansion
For %%b IN (#) DO FOR /F "delims==" %%a In ('set %%b 2^>Nul') DO SET "%%a="
FOR /L %%x IN (1,1,30000) DO CALL :choosernd&SET /a #!num!+=1
SET #
GOTO :eof
:choosernd
set /a min=1000
set /a max=9999
set /a min=1
set /a max=5
set /a rangesize=max-min+1
SET /a numranges=32767/rangesize
SET /a maxrange=rangesize * numranges-1
:chooseagain
set /a num=%RANDOM%
if %num% gtr %maxrange% GOTO chooseagain
SET /a num=(num %% rangesize) + min
rem ECHO %num%
GOTO :EOF
This question has been asked many times on SO. Here's a generate-and-test routine.
The meat of the matter is the :choosernd routine, where you set your minimum and maximum values.
I overrode your 1000 and 9999 with 1 and 5 for ease of testing.
First, calculate range size. That part should be obvious.
Next - the random-number generator returns %random% in the range 0..32767, so using %random% %% 100 for instance would return 328 numbers in 0..67, but 327 in 68..99. Hence, calculate the number of full ranges (327) available, and the maximum value to obtain an even distribution; (100*327)-1=32699.
Get a random number, but reject any that are greater than the maximum, so reject 32700..32767.
Perform a modulus operation on the chosen, filtered number and add the minimum, giving num
The code before this is simply clearing any variables whose names begin # and then executing the :choosernd routine 30,000 times. Each time, the variable #!num! is incremented, where delayedexpansion (which is explained many. many times on SO - use the search facility) is used to correctly choose a counter.
Then the counter is displayed for verification (the "random" generator is not particularly good)
Note that delayedexpansion is used only in the logging routine - it does not need to be invoked for the :choosernd routine.
Also - note that variablenames may not start with a digit.
When you use the point-click-and-giggle method of executing a batch, the batch window will often close if a syntax-error is found. You should instead open a 'command prompt' and run your batch from there so that the window remains open and any error message will be displayed.

Batch file quitting after doing "call :loop"

I have a bit of (Bad) Code for encrypting text, but to be able to decrypt it needs to have something inbetween the numbers. I want to fit random letters inbetween the numbers so it looks less obvious, this is where i got to:
#echo off
setlocal enableDelayedExpansion
set /p code=Text:
set chars=0123456789abcdefghijklmnopqrstuvwxyz
for /L %%N in (10 1 36) do (
for /F %%C in ("!chars:~%%N,1!") do (
Set _Alphanumeric=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
Set _count=0
set _RNDLen=%random%
Set /A _RNDLen=_RNDLen%%4
If !_count! leq %_RNDLen% call :loop
set "code=!code:%%C=-%%N!"
)
)
echo !code!
echo !_str!
pause
:loop
Set /a _count+=1
set _RND=%random%
Set /A _RND=_RND%%51
SET _str=!_str!!_Alphanumeric:~%_RND%,1!
EXIT /B %ERRORLEVEL%
The problem is that the program just quits before giving any output, even if i remove the exit /b statement. Thanks for help
I've no idea what principle you're using for your algorithm, but fundamentally you need to understand delayed expansion.
When your outer loop, for %%N is parsed, every %var% is replaced by the contents of that variable at that time, hence
set _RNDLen=%random%
If !_count! leq %_RNDLen% call :loop
are replaed by
set _RNDLen=a specific random number
If !_count! leq call :loop
The first line here will set _rndlen to the same number every time (for ny run) and since _rndlen is undefined at the start of the loop, it willl be replaced by nothing, hence the if statement has faulty syntax and hence cmd objects and would display a message.
You can use !random! with delayed expansion invoked to select a rendom number each time, and you need !_rndlen! to access the changed value of _rndlen (changed from its original value of nothing to some random value and then mod-4'd)
Personally, I'd assign _alphanumeric outside of the (outer) loop since its value isn't varied by the loop operation.
And naturally, you know that when you hit Return following the pause, the loop code will be executed before the routine terminates (by flow-through) and you should include a
goto :eof
line after the pause to skip this last operation.

How to echo a variable multiple times by multiplying it with another variable?

I am writing a batch script and I am having trouble echoing a variable, here is the script,
#echo off
set num1=1
set num2=10
set /a "out=%num1%*%num2%"
echo %out%
pause`
The output I receive is 10 which makes sense but I want it to echo 'num1' ten times instead of multiplying 'num1' by 'num2'. So I want the output to be 1111111111.
Also I don't want to loop the command 10 times as I am putting the output into a text file with 'output>> file.txt' otherwise I will end up with this in the text file,
1
1
1
1
1
1
1
1
1
1
I want to end up with 1111111111, thank you.
#ECHO OFF
SETLOCAL
set num1=1
set num2=10
SET "out="&FOR /L %%a IN (1,1,%num2%) DO CALL SET "out=%%out%%%%num1%%"
echo %out%
GOTO :EOF
The SET "out=" and FOR /L %%a IN (1,1,%num2%) DO CALL SET "out=%%out%%%%num1%%" may be on separate lines if desired. Setting out to nothing is simply a safety measure to ensure that if it contains a value, it's cleared first.
The for /L performs the call command num2 times.
The call command executes SET "out=%out%%num1%" in a subprocess because each %% is interpreted as an escaped-% (% is the escape character for %) - "escaping" a character means turning off its special meaning.
The syntax SET "var=value" (where value may be empty) is used to ensure that any stray trailing spaces are NOT included in the value assigned.
Just to show a different method with set /A and a loop:
#echo off
set /A "num1=1,num2=10,out=0"
:loop
set /a "out*=10,out+=num1,num2-=1"
If %num2% gtr 0 goto :loop
echo %out%
pause
This is the simplest way to solve this problem, using Delayed Expansion.
#echo off
setlocal EnableDelayedExpansion
set num1=1
set num2=10
set "out="
for /L %%i in (1,1,%num2%) do set "out=!out!%num1%"
echo %out%
pause
PS - The multiply term is not exact in this case; perhaps "echo a variable the times indicated by another variable" be more clear...
If what you want is to print num1 num2 times in the same line you can do something like:
#echo off
set "num1=1"
set "num2=10"
(for /L %%i in (1,1,%num2%) do set /p "=%num1%" <nul
echo()>file.txt
The command set /p "=%num1%" <nul prints the text %num1% in the current line without the LF character. So num1 gets printed num2 times in the same line.

Batch file randomizer 1-30 then output 5 Numbers

I need a batch file randomizer to randomly select 5 numbers from 1-30 then output them. I have researched and found nothing that is useful to me. I am a Beginner so if you could make the code simple and explain it so i can reproduce it later if i need it again.
batch noob answer is absolutly correct, but can generate duplicated numbers. For an option with no duplicate numbers,
#echo off
setlocal enableextensions
for /F "tokens=2" %%l in ('cmd /v:on /c "#for /L %%n in (1 1 30) do #echo ^!random^! %%n"^|sort^|more +25') do (
echo %%l
)
It spawns a cmd (cmd /v:on /c "....") to generate a list of numbers 1-30 prefixed with a random number, this list is then sorted (sort), using the random number as key. Once sorted, more +25 is used to skip the first 25 numbers in list, and then, a for /F is used to step over the 5 last lines, taking the second token from it (the lines contains the random number and the number from 1-30) and echoing it to console
Use RANDOM -- that's what you are looking for.
RANDOM gives a number between 0 and 32767.
Example:
set /a num=%random%
echo.%num%
This will output a number between 0 and 32767.
But if you want to reduce that number do this:
set /a num=%random% %%5
echo.%num%
This will output a number between 0 and 4.
In your case (range 1 to 30) do this:
set /a num1=%random% %%30 +1
set /a num2=%random% %%30 +1
set /a num3=%random% %%30 +1
set /a num4=%random% %%30 +1
set /a num5=%random% %%30 +1
echo %num1%
echo %num2%
echo %num3%
echo %num4%
echo %num5%
Hope it helps! :D

Resources