Home > OS >  How do you set the value of a variable to the value of an arrays slot defined by another variable(se
How do you set the value of a variable to the value of an arrays slot defined by another variable(se

Time:05-15

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

  • Related