-3

(Because someone asked, I have Windows 10, if anyone was wondering.

I have recently been working on a desktop PAI (Partial Artificial Intelligence) that will be able to perform some basic tasks for me while I am not at my computer.

However, I want it to choose and say 1 of 9 different possible messages. For example, I have 9 different ways to say "How can I help you?", and I want it to choose and echo one of those 9 ways.

To do this, I want to use the variable %RANDOM%. The problem is that %RANDOM% generates a random number in between 0 and 32767, and I only want it to generate a random number in between 1 and 9.

I have seen multiple people across the internet say to use the piece of code:

 SET /a rand=(%RANDOM%*9/32768)+1 

However, this does not work. Or maybe it does for some people, but certainly not for me. Whenever I implement this into a batch file, it either just closes the window because it doesn't know how to run the code, or it just chooses the same number over and over again, no matter what.

I have also already tried it with and without Delayed Expansion, and if I try to run the code in the regular command prompt (CMD.EXE), it just says "Missing operator."

It's hard for me because I don't really know much about arithmetic in batch. Any help on fixing this is greatly appreciated!

  • 2
    [Edit your question](https://stackoverflow.com/posts/50237550/edit) to show us a little bit more of your script, _(the relevant lines just before/after the single line you've provided)_, so that we can put answers/comments into context. – Compo May 08 '18 at 15:49
  • your statement looks totally correct to me. And if I copy and paste it, both at the command prompt and on a bat file, it works perfectly well. What version of windows you are running? – PA. May 08 '18 at 16:05
  • 1
    Possible duplicate of [How to generat a random number between 1 and 100 using batch](https://stackoverflow.com/questions/22107406/how-to-generat-a-random-number-between-1-and-100-using-batch) – phuclv May 08 '18 at 16:38
  • Your "question" describes multiple problems that I'm pretty sure are all unrelated. When asking a question about dysfunctional code, you need to focus on one problem and provide a minimal set of code that others can run and get the same result. You should describe exactly what you expect vs what you observe. – dbenham May 08 '18 at 18:07

2 Answers2

3

What happens if you use set /a rnd=(%RANDOM%%%9)+1 instead?

Example:

@Echo Off

Set "msg[1]=G'day!"
Set "msg[2]=Hello!"
Set "msg[3]=Hey!"
Set "msg[4]=Hi!"
Set "msg[5]=Hiya!"
Set "msg[6]=Howdy?"
Set "msg[7]=Sup?"
Set "msg[8]=Whazzup?"
Set "msg[9]=Yo!"

Set /A rnd=(%RANDOM% %% 9) + 1

Call Echo %%msg[%rnd%]%%

Pause
Compo
  • 36,585
  • 5
  • 27
  • 39
  • Surprisingly, it worked. I saw other people say to use statements likes that as well, but even those ones didn't work. But for some odd reason, this one out of the hundreds of other ones I've seen decided to work. Thanks a lot! –  May 09 '18 at 19:58
2

When you state that you constantly get the same value when you run your script, I suspect you are launching your script by double clicking the script within Windows Explorer, or else on your desktop.

The source of that problem is the random seed value that each cmd.exe session establishes upon startup. The seed changes by 3 or 4 only once every second, (10 every 3 seconds).

Each time you launch your script by double clicking, you start a new cmd.exe session. All sessions that launch within the same second will be given the exact same random seed, and thus the same sequence.

Your problem is compounded by the formula you use to generate a "random" number from 1 to 9: SET /a "rand=(%RANDOM%*9/32768)+1" With that formula the initial result will change only once every ~18 minutes.

A simpler formula of set /a "rand=%random% %% 9 + 1" will change the initial value once every second.

Here is a demonstration of what I mean.

test.bat

@echo off
set "t=%time%
set /a r=%random%, n1=r*9/32768+1, n2=r%%9+1
echo t=%t%, r=%r%, n1=%n1%, n2=%n2%

Here is what happens when I use a loop to run the script 25 times in different cmd.exe sessions:

C:\test>for /l %n in (1 1 25) do @cmd /c test.bat
t=14:22:05.00, r=29206, n1=9, n2=2
t=14:22:05.13, r=29206, n1=9, n2=2
t=14:22:05.24, r=29206, n1=9, n2=2
t=14:22:05.35, r=29206, n1=9, n2=2
t=14:22:05.47, r=29206, n1=9, n2=2
t=14:22:05.58, r=29206, n1=9, n2=2
t=14:22:05.71, r=29206, n1=9, n2=2
t=14:22:05.83, r=29206, n1=9, n2=2
t=14:22:05.96, r=29206, n1=9, n2=2
t=14:22:06.08, r=29209, n1=9, n2=5
t=14:22:06.19, r=29209, n1=9, n2=5
t=14:22:06.32, r=29209, n1=9, n2=5
t=14:22:06.44, r=29209, n1=9, n2=5
t=14:22:06.55, r=29209, n1=9, n2=5
t=14:22:06.66, r=29209, n1=9, n2=5
t=14:22:06.79, r=29209, n1=9, n2=5
t=14:22:06.90, r=29209, n1=9, n2=5
t=14:22:07.02, r=29212, n1=9, n2=8
t=14:22:07.15, r=29212, n1=9, n2=8
t=14:22:07.27, r=29212, n1=9, n2=8
t=14:22:07.38, r=29212, n1=9, n2=8
t=14:22:07.50, r=29212, n1=9, n2=8
t=14:22:07.63, r=29212, n1=9, n2=8
t=14:22:07.74, r=29212, n1=9, n2=8
t=14:22:07.86, r=29212, n1=9, n2=8

t is the time, r is the raw random seed value, n1 is the value computed by your original formula, and n2 is the value with the simpler formula. You can see that your original formula result never changes, even though the seed value changed 3 times.

If I repeat the experiment, but this time run each command within the same cmd.exe session, then you see that the random number sequence is reasonable.

C:\test>for /l %n in (1 1 25) do @test.bat
t=14:26:12.83, r=24169, n1=7, n2=5
t=14:26:12.83, r=7515, n1=3, n2=1
t=14:26:12.84, r=8502, n1=3, n2=7
t=14:26:12.84, r=11715, n1=4, n2=7
t=14:26:12.86, r=28979, n1=8, n2=9
t=14:26:12.86, r=5966, n1=2, n2=9
t=14:26:12.86, r=4269, n1=2, n2=4
t=14:26:12.87, r=27310, n1=8, n2=5
t=14:26:12.87, r=11966, n1=4, n2=6
t=14:26:12.89, r=16129, n1=5, n2=2
t=14:26:12.89, r=16597, n1=5, n2=2
t=14:26:12.89, r=2994, n1=1, n2=7
t=14:26:12.90, r=16762, n1=5, n2=5
t=14:26:12.90, r=1718, n1=1, n2=9
t=14:26:12.92, r=17976, n1=5, n2=4
t=14:26:12.92, r=20805, n1=6, n2=7
t=14:26:12.94, r=11730, n1=4, n2=4
t=14:26:12.94, r=20414, n1=6, n2=3
t=14:26:12.94, r=28978, n1=8, n2=8
t=14:26:12.95, r=11615, n1=4, n2=6
t=14:26:12.95, r=13486, n1=4, n2=5
t=14:26:12.97, r=21228, n1=6, n2=7
t=14:26:12.97, r=25754, n1=8, n2=6
t=14:26:12.97, r=3979, n1=2, n2=2
t=14:26:12.98, r=16189, n1=5, n2=8

There really isn't a good pure batch solution for randomly generating numbers across different cmd.exe sessions. But you can use hybrid scripting to get a decent solution. Below is a demonstration JScript/batch solution that works well. However it is slow because the :random function must initialize a new CSCRIPT session each time it is called.

test2.bat

@if (@X)==(@Y) @end /* harmless hybrid line that begins a JScrpt comment
:::::::::::: batch portion ::::::::::::::
@echo off
call :random 1 9 rand
echo %rand%
exit /b

:random  min  max  rtnVar
for /f %%A in (
  'cscript //E:JScript //nologo "%~f0" "Math.floor(Math.random()*(%2-%1+1))+%1"'
) do set "%3=%%A"
exit /b


:: The following JScript code evaluates a JScript expression
:: and writes the result to stdout
************ JScript portion *********************/
WScript.StdOut.WriteLine(eval(WScript.Arguments.Unnamed(0)));

Here are results of rapidly running the above in 25 different cmd.exe sessions - exactly the result you want.

C:\test>for /l %n in (1 1 25) do @cmd /c test2.bat
9
8
7
5
9
8
5
1
5
6
5
8
7
8
7
1
2
6
6
5
6
4
8
4
9
dbenham
  • 127,446
  • 28
  • 251
  • 390