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
