I see a number of problems in that code:
set /a chance= %random% %%30+1
if %chance% gtr 10 && lss 30 (
set /a %nails%+1
echo You got nails! %chance%
)
Going through them:
The if
statement is not valid, &&
is the "execute next command if previous command worked" conjunction, not a general "and" operator. To do what you want would be:
if %chance% gtr 10 if %chance% lss 30
.
See here for a way to do and
and or
in cmd
language.
The command set /a %nails%+1
does not actually change nails
in any way, it just evaluates an expression and throws it away. You need an assignment to assign a value, and you don't need the variable markers in this case:
set /a "nails += 1"
.
If you're using delayedexpansion
to print out nails
(and you should be), you need a !
both before and after the variable name:
echo You got !nails! %chance%
.
As an aside, you'll probably notice I have a penchant for quoting my set /a
expressions and spacing them nicely - I find this aids readability.
That will fix some specific problems but, to be honest, you're probably better off making a generic function that can give you a yes/no answer for some probability of an event happening. That way, you can reuse it anywhere you need it.
You can use a function like chance
, shown below in a complete program, to decide whether something should happen based on a percentage:
@echo off
goto :main
:chance
setlocal enableextensions enabledelayedexpansion
set retcode=1==0
set /a "value = %random% %% 100"
rem echo %value% rem uncomment for debugging
if %value% lss %2 set retcode=1==1
endlocal && set %1=%retcode%
goto :eof
:main
call :chance result 50
echo %result%
It should be called with both a variable name to put the result into, and the percentage level you want to use. For example, if you wanted to set a variable hasdied
based on a 5% chance, you would call it with:
call :chance hasdied 5
if %hasdied% goto :handlebeingdead
The function contains a number of features which probably bear explanation:
The setlocal
command ensures that no variables escape the scope of this function (but see below), useful for proper encapsulation.
The value
variable is set to some random value between 0
and 99
inclusive. It's not perfectly distributed since %random%
will give you a value up to 32767
so will be slightly skewed toward numbers less than 68
. Said skew is probably not enough to concern yourself with.
This value is then compared with the threshold you provided (the second argument) to decide the return value true or false.
The return value is rather sneaky in that it gives you an expression that you can put into an if
statement without having to do an explicit comparison like:
if %hasdied%==1
By returning such an equality comparison directly, you can just use the return value as if it was boolean.
The endlocal
then cleans up any variable changes that have been made in this function, including the return code. However, the fact that the substitutions on this line take place before any of it is executed means that the set
part of it will already have the correct value of retcode
substituted before the endlocal
cleans it up. This is a way to have specific variables "escape" the scope bounded by setlocal/endlocal
. The retcode
value is therefor placed in the parameter whose name you provided as the first argument.
The set %1=
part of that command is a way to allow you to specify what variable should receive the value in the call itself, akin to myvar = function()
. That stops you from having to allocate a hard-coded variable name to each function and then assign it to another variable after the call.
And, of course, the goto :eof
is simply a return
instruction.