in a larger program that I am attempting to create in batch format it is important that I learn how to set a variables value to that of an arrays value as determined by the number of another variable if it is possible in a simple .bat file. my current code for the testing file reads as
set a[1]=1
set a[0]=10000
set c=0
set b=%a[%%c]%
echo %b%
all this returns is: ECHO is off I need it to return: 10000 so I can then use similar code
@echo off
setlocal enabledelayedexpansion
set Goblin[0]=5
set Goblin[1]=20
set Goblin[2]=7
set Goblin[3]=Goblin
set Zombie[0]=7
set Zombie[1]=15
set Zombie[2]=3
set Zombie[3]=Zombie
set Skeleton[0]=3
set Skeleton[1]=11
set Skeleton[2]=10
set Skeleton[3]=Skeleton
set Orc[0]=7
set Orc[1]=25
set Orc[2]=0
set Orc[3]=Orc
set Acrobat[0]=4
set Acrobat[1]=15
set Acrobat[2]=80
set Acrobat[3]=Acrobat
set PossibleEnemies[0]=!Goblin!
set PossibleEnemies[1]=!Zombie!
set PossibleEnemies[2]=!Skeleton!
set PossibleEnemies[3]=!Orc!
set PossibleEnemies[4]=!Acrobat!
set /a Enemy1=%random% %%5
set /a Enemy2=%random% %%5
set /a Enemy1.MaximumHealth=%PossibleEnemies[Enemy1[1]]%
set /a Enemy2.MaximumHealth=%PossibleEnemies[Enemy2[1]]%
set /a Enemy1.Damage=%PossibleEnemies[Enemy1[0]]%
set /a Enemy2.Damage=%PossibleEnemies[Enemy2[0]]%
set /a Enemy1.Dodge=%PossibleEnemies[Enemy1[2]]%
set /a Enemy2.Dodge=%PossibleEnemies[Enemy2[2]]%
set Enemy1.Name=%PossibleEnemies[Enemy1[3]]%
set Enemy2.Name=%PossibleEnemies[Enemy2[3]]%
to randomize which enemy you are fighting(you fight two at once). I have also tried
set a[1]=1
set a[0]=10000
set c=0
set b=%a[%c%]%
echo %b%
and
set a[1]=1
set a[0]=10000
set c=0
set b=%a[!c!]%
echo %b%
as well as
set a[1]=1
set a[0]=10000
set c=0
set b=%a[c]%
echo %b%
to no avail
CodePudding user response:
I believe there are other tricks that can do this, but basic method would be this:
@ECHO OFF
SETLOCAL EnableDelayedExpansion
set a[1]=1
set a[0]=10000
set c=0
set b=!a[%c%]!
echo %b%
EDIT:
Stephan's comment had a link that included the trick I couldn't remember, but I knew it used CALL
(NOTE: Call cost time and can slow a script down.):
@ECHO OFF
set a[1]=1
set a[0]=10000
set c=0
CALL SET b=%%a[%c%]%%
echo %b%
CodePudding user response:
There are no arrays in cmd/batch
. The one and only variable type is STRING (although Lists and Arrays can be simulated to a certain degree). I therefore would change from arrays (independent variables for each element) to lists (one variable containing all elements) and put all "array/list stuff handling" into a subroutine, making it easy in the main code to get a certain element:
@echo off
setlocal enabledelayedexpansion
REM define readable names for indexes (for more readable code later)
set "MaxHealth=2"
set "Damage=1"
set "Dodge=3"
set "Name=4"
set "Goblin=1"
set "Zombie=2"
set "Skeleton=3"
set "Orc=4"
set "Acrobat=5"
REM define a list of properties for each creature
set "_Goblin=5,20,7,little Goblin"
set "_Zombie=7,15,3,angry Zombie"
set "_Skeleton=3,11,10,bony Skeleton"
set "_Orc=7,25,0,furious Orc"
set "_Acrobat=4,15,80,fast Acrobat"
REM define a list of all creatures
set "PossibleEnemies=Goblin,Zombie,Skeleton,Orc,Acrobat"
set /a Enemy1=%random% %%5
set /a Enemy2=%random% %%5
REM get properties
call :GetProperty %Enemy1% Name Enemy1
call :GetProperty %Enemy2% Name Enemy2
call :GetProperty %Enemy1% MaxHealth Enemy1
call :GetProperty %Enemy2% MaxHealth Enemy2
call :GetProperty %Enemy1% Damage Enemy1
call :GetProperty %Enemy2% Damage Enemy2
call :GetProperty %Enemy1% Dodge Enemy1
call :GetProperty %Enemy2% Dodge Enemy2
echo You fight against:
set Enemy
goto :eof
:GetProperty Type Property VarName ; resulting variable = [VarName].[Property]
echo DBG: EnemyType=%1
echo DBG: Property=%2
for /f "tokens=%1 delims=," %%a in ("%PossibleEnemies%") do set "Type=%%a"
echo DBG: Type=%Type%
echo DBG: ReturnVar=%3.%2
set "opt=tokens=!%2! delims=," & REM not possible to use delayed expansion in for /f "[options]"
for /f "%opt%" %%a in ("!_%Type%!") do set "%3.%2=%%a"
echo DBG: Returnval=!%3.%2!
echo DBG: -----
goto :of
Example output (without the DBG
lines):
You fight against:
Enemy1=3
Enemy1.Damage=3
Enemy1.Dodge=10
Enemy1.MaxHealth=11
Enemy1.Name=bony Skeleton
Enemy2=1
Enemy2.Damage=5
Enemy2.Dodge=7
Enemy2.MaxHealth=20
Enemy2.Name=little Goblin
If you want, you can put the REM get properties
(all those call ...
lines) into another subroutine for even more readable main code.
To answer your actual question: you need one layer of expansion per depth-layer. You have a variable containing a variable containing a variable, so you need three layers of parsing (the original layer plus two more. One more layer is usually achieved by delayed expansion; three layers are a bit more complicated: use call
for an additional layer. The innermost variable is used "as usual" %c%
for the next layer you have to double each %
, as one %
gets consumed by the additional layer of parsing (the second call
), the same is true for the outermost (third) layer (the first call
), resulting in four %
, because each layer of parsing halves them:
@echo off
setlocal
set a[2]=1000
set b[1]=2
set c=1
call call set d=%%%%a[%%b[%c%]%%]%%%%
echo %d%
result: 1000