Page 1 of 4
Batch function help?
Posted: 02 Jul 2014 15:30
by JWinslow23
Hello! I am trying to create a function in Batch for my first time, and it's not working so far, for some reason. Maybe it's because I tried to concatenate the strLen routine with another that I made up...I should try a separate call to strLen if I don't find anything else.
Here is the code for my function so far. It is supposed to calculate the Scrabble score of a phrase in a variable, and output the score to another variable.
Code: Select all
@echo off
set "myString=Hello"
call :scrabbleScore myString score
echo Phrase: %myString%
echo Score: %score%
pause >nul
exit /b
:scrabbleScore
setlocal enabledelayedexpansion
set "_=A!%~1!"
set #=0
for /l %%g in (12,-1,0) do (set /a "#|=1<<%%g"
for %%h in (!#!) do if "!_:~%%h,1!"=="" set /a "#&=~1<<%%g")
set "@=%1"
set "$=0"
for /l %%g in (1,1,%#%) do (
for %%h in (A a E e I i L l N n O o R r S s T t U u) do if !%@%:~%%g,1!==%%h set /a $+=1
for %%h in (D d G g) do if !%@%:~%%g,1!==%%h set /a $+=2
for %%h in (B b C c M m P p) do if !%@%:~%%g,1!==%%h set /a $+=3
for %%h in (F f H h V v W w Y y) do if !%@%:~%%g,1!==%%h set /a $+=4
for %%h in (K k) do if !%@%:~%%g,1!==%%h set /a $+=5
for %%h in (J j X x) do if !%@%:~%%g,1!==%%h set /a $+=8
for %%h in (Q q Z z) do if !%@%:~%%g,1!==%%h set /a $+=10
)
endlocal
if "%~2" neq "" set %~2=%$%
exit /b
This test case is supposed to output:
Any help would be greatly appreciated, thanks!
Re: Batch function help?
Posted: 02 Jul 2014 15:40
by ShadowThief
First and foremost, if you're going to use vague, seemingly random single characters for variables, you're gonna have a bad time.
Second, %score% has no value because it only exists inside of delayedexpansion. Put the setlocal enabledelayedexpansion right after the @echo off.
Re: Batch function help?
Posted: 02 Jul 2014 16:08
by Squashman
Haven't figured out why you are getting this error
Code: Select all
1!==%h was unexpected at this time.
But I do see two flaws in your initial logic.
Your @ variable should be set like this
Your FOR /L should start with Zero because when you want to substring with the SET command the first position is 0. It is basically an offset.
Just an example of doing substrings.
Code: Select all
C:\BatchFiles\scrabble>set mystring=hello
C:\BatchFiles\scrabble>set var=%mystring:~0,1%
C:\BatchFiles\scrabble>echo %var%
h
Then you would also need to subtract one from your length so that it only runs your loop the correct amount of times for the string length.
Re: Batch function help?
Posted: 02 Jul 2014 16:20
by einstein1969
There are 3 problem
1) or use double quote surrounding "!%@%:~%%g,1!"=="%%h" or escape
2) The index of string start from 0 to len-1
3) for bypass endlocal barrier the set must be on the same line or using ().
Code: Select all
@echo off
set "myString=Hello"
call :scrabbleScore myString score
echo Phrase: %myString%
echo Score: %score%
pause >nul
exit /b
:scrabbleScore
setlocal enabledelayedexpansion
set "_=A!%~1!"
set #=0
for /l %%g in (12,-1,0) do (set /a "#|=1<<%%g"
for %%h in (!#!) do if "!_:~%%h,1!"=="" set /a "#&=~1<<%%g")
set "@=%1"
set "$=0"
set /a Len=#-1
for /l %%g in (0,1,%Len%) do (
for %%h in (A a E e I i L l N n O o R r S s T t U u) do if "!%@%:~%%g,1!"=="%%h" set /a $+=1
for %%h in (D d G g) do if "!%@%:~%%g,1!"=="%%h" set /a $+=2
for %%h in (B b C c M m P p) do if "!%@%:~%%g,1!"=="%%h" set /a $+=3
for %%h in (F f H h V v W w Y y) do if "!%@%:~%%g,1!"=="%%h" set /a $+=4
for %%h in (K k) do if "!%@%:~%%g,1!"=="%%h" set /a $+=5
for %%h in (J j X x) do if "!%@%:~%%g,1!"=="%%h" set /a $+=8
for %%h in (Q q Z z) do if "!%@%:~%%g,1!"=="%%h" set /a $+=10
)
endlocal & if "%~2" neq "" set %~2=%$%
exit /b
einstein1969
Re: Batch function help?
Posted: 02 Jul 2014 16:56
by JWinslow23
Never mind, I found a solution. It works properly now. Maybe I could add this to the site's functions page...
Code: Select all
@echo off
call :scrabbleScore "This test case should return sixty-six points" score
echo Phrase: This test case should return sixty-six points
echo Score: %score%
echo(
set "myString=This phrase is supposed to be worth exactly one hundred twenty points in Scrabble"
call :scrabbleScoreVar myString score
echo Phrase: %myString%
echo Score: %score%
pause >nul
exit /b
:scrabbleScore phrase score -- Calculates and returns the Scrabble score of a phrase in quotes
:: -- phrase [in]: phrase to calculate score of (must be in quotes)
:: -- score [out]: variable name to store result to
if "%~2" neq "" set ?=%1&call :scrabbleScoreVar ? %~2
exit /b
:scrabbleScoreVar phrasevar score -- Calculates and returns the Scrabble score of a variable
:: -- phrasevar [in]: variable name to calculate score of
:: -- score [out] : variable name to store result to
setlocal enabledelayedexpansion
set _=A!%~1!&set #=0&for /l %%g in (12,-1,0)do (set /a "#|=1<<%%g"
for %%h in (!#!)do if "!_:~%%h,1!"=="" set /a "#&=~1<<%%g")
set/a#-=1,$=0&set @=!%~1!&for /l %%g in (0,1,%#%)do (call set j=%%@:~%%g,1%%
for %%h in (A a E e I i L l N n O o R r S s T t U u)do if !j!==%%h set /a $+=1
for %%h in (D d G g)do if !j!==%%h set /a $+=2
for %%h in (B b C c M m P p)do if !j!==%%h set /a $+=3
for %%h in (F f H h V v W w Y y)do if !j!==%%h set /a $+=4
for %%h in (K k)do if !j!==%%h set /a $+=5
for %%h in (J j X x)do if !j!==%%h set /a $+=8
for %%h in (Q q Z z)do if !j!==%%h set /a $+=10)
endlocal&if "%~2" neq "" set %~2=%$%
exit /b
This includes code to calculate the score of a variable and of quoted text, plus two test cases.
Whaddaya think?
EDIT: Made it much faster and shorter.
Re: Batch function help?
Posted: 02 Jul 2014 18:32
by einstein1969
You're doing great! Keep it up!
einstein1969
Re: Batch function help?
Posted: 02 Jul 2014 18:34
by Squashman
JWinslow23 wrote:Whaddaya think?
As mentioned earlier by Shadowthief most people do not like this coding style.
I try to make my code as readable as possible using indentation and descriptive variables. I don't mind the use of symbols as variables as long as the code is indented and readable. When you start using symbols as variables instead of Alphanumeric names it makes it very hard for someone to come along behind you and understand how to use the code or even fix it in the future or add enhancements to the code if they are not very experienced with the scripting language.
Re: Batch function help?
Posted: 02 Jul 2014 18:38
by JWinslow23
Squashman: Sorry, it's just my style is to make my code tiny. I'll make a more readable version in a while.
EDIT: I believe that this, with a few modifications, could go on the Functions page:
Code: Select all
@echo off
call :scrabbleScore "This test case should return sixty-six points" score
echo Phrase: This test case should return sixty-six points
echo Score: %score%
echo(
set "myString=This phrase is supposed to be worth exactly one hundred twenty points in Scrabble"
call :scrabbleScoreVar myString score
echo Phrase: %myString%
echo Score: %score%
pause >nul
exit /b
:scrabbleScore phrase score -- Calculates and returns the Scrabble score of a phrase in quotes
:: -- phrase [in]: phrase to calculate score of (must be in quotes)
:: -- score [out]: variable name to store result to
if "%~2" neq "" (
set ?=%1
call :scrabbleScoreVar ? %~2
)
exit /b
:scrabbleScoreVar phrasevar score -- Calculates and returns the Scrabble score of a variable
:: -- phrasevar [in]: variable name to calculate score of
:: -- score [out] : variable name to store result to
setlocal enabledelayedexpansion
set "str=A!%~1!"
set "len=0"
for /l %%g in (12,-1,0) do (
set /a "len|=1<<%%g"
for %%h in (!len!) do if "!str:~%%h,1!"=="" set /a "len&=~1<<%%g"
)
set /a len-=1
set #=0
set str=!%~1!
for /l %%g in (0,1,%len%) do (
call set sub=%%str:~%%g,1%%
for %%h in (A a E e I i L l N n O o R r S s T t U u) do if !sub!==%%h set /a #+=1
for %%h in (D d G g) do if !sub!==%%h set /a #+=2
for %%h in (B b C c M m P p) do if !sub!==%%h set /a #+=3
for %%h in (F f H h V v W w Y y) do if !sub!==%%h set /a #+=4
for %%h in (K k) do if !sub!==%%h set /a #+=5
for %%h in (J j X x) do if !sub!==%%h set /a #+=8
for %%h in (Q q Z z) do if !sub!==%%h set /a #+=10
)
endlocal & if "%~2" neq "" set %~2=%#%
exit /b
Re: Batch function help?
Posted: 02 Jul 2014 19:08
by einstein1969
For faster execution read this
CALL me, or better avoid callIn dos batch should always make two versions:
1) A more readable version with variable names understandable.
Even indentation and spacing are important.
2) The second version is the version that instead it goes fast. In this case the spaces, length of variables affect the speed. This version can not be easily readable.
Looks at Ed Dyreen expert's posts. (dubbed "too complex").
example
A special visual effect code: The Matrixor jeb's cat:
Code: Select all
@echo off
setlocal EnableDelayedExpansion
set LF=^
set ^"-=:-)^
^% ;-) %^
% 8-( %^^
%lf:^=!LF!%!LF:^
&"=<&^|>!"
set ^"+=Why?This echo It works^^^^^^^^^^!"
(%-%%+%)
einstein1969
Re: Batch function help?
Posted: 02 Jul 2014 19:54
by Aacini
Code: Select all
@echo off
setlocal EnableDelayedExpansion
rem Define the array of values per letter
for %%a in (A E I L N O R S T U) do set value[%%a]=1
for %%a in (D G) do set value[%%a]=2
for %%a in (B C M P) do set value[%%a]=3
for %%a in (F H V W Y) do set value[%%a]=4
set value[K]=5
for %%a in (J X) do set value[%%a]=8
for %%a in (Q Z) do set value[%%a]=10
call :scrabbleScore "This test case should return sixty-six points" score
echo Phrase: This test case should return sixty-six points
echo Score: %score%
echo/
set "myString=This phrase is supposed to be worth exactly one hundred twenty points in Scrabble"
call :scrabbleScoreVar myString score
echo Phrase: %myString%
echo Score: %score%
pause >nul
exit /b
:scrabbleScore phrase score -- Calculates and returns the Scrabble score of a phrase in quotes
:: -- phrase [in]: phrase to calculate score of (must be in quotes)
:: -- score [out]: variable name to store result to
if "%~2" equ "" exit /B
set "phrase=%1"
goto entryPoint
:scrabbleScoreVar phrasevar score -- Calculates and returns the Scrabble score of a variable
:: -- phrasevar [in]: variable name to calculate score of
:: -- score [out] : variable name to store result to
if "%~2" equ "" exit /B
set "phrase=!%~1!"
:entryPoint
set %2=0
for /F "delims=" %%a in ('cmd /U /C echo %phrase%^| find /V ""') do if "%%a" neq " " set /A "%2+=value[%%a]"
exit /b
Antonio
Re: Batch function help?
Posted: 02 Jul 2014 21:05
by JWinslow23
Bravo there, Aacini, as usual. This seems like a better approach to store the values into an array and call them for each character. However, does this work for uppercase as well as lowercase? If it does, then I am definitely using it.
Re: Batch function help?
Posted: 02 Jul 2014 22:36
by ShadowThief
JWinslow23 wrote:Bravo there, Aacini, as usual. This seems like a better approach to store the values into an array and call them for each character. However, does this work for uppercase as well as lowercase? If it does, then I am definitely using it.
Only as long as you want the uppercase and lowercase values to be identical; batch variables are not case sensitive.
Re: Batch function help?
Posted: 03 Jul 2014 00:46
by foxidrive
The
if command has the
/i case insensitive switch which is useful.
Code: Select all
for %%h in (A E I L N O R S T U) do if /i !j!==%%h set /a $+=1
for %%h in (D G) do if /i !j!==%%h set /a $+=2
for %%h in (B C M P) do if /i !j!==%%h set /a $+=3
for %%h in (F H V W Y) do if /i !j!==%%h set /a $+=4
for %%h in (K) do if /i !j!==%%h set /a $+=5
for %%h in (J X) do if /i !j!==%%h set /a $+=8
for %%h in (Q Z) do if /i !j!==%%h set /a $+=10)
instead of
Code: Select all
for %%h in (A a E e I i L l N n O o R r S s T t U u)do if !j!==%%h set /a $+=1
for %%h in (D d G g)do if !j!==%%h set /a $+=2
for %%h in (B b C c M m P p)do if !j!==%%h set /a $+=3
for %%h in (F f H h V v W w Y y)do if !j!==%%h set /a $+=4
for %%h in (K k)do if !j!==%%h set /a $+=5
for %%h in (J j X x)do if !j!==%%h set /a $+=8
for %%h in (Q q Z z)do if !j!==%%h set /a $+=10)
Re: Batch function help?
Posted: 03 Jul 2014 19:26
by JWinslow23
foxidrive wrote:The
if command has the
/i case insensitive switch which is useful.
Code: Select all
for %%h in (A E I L N O R S T U) do if /i !j!==%%h set /a $+=1
for %%h in (D G) do if /i !j!==%%h set /a $+=2
for %%h in (B C M P) do if /i !j!==%%h set /a $+=3
for %%h in (F H V W Y) do if /i !j!==%%h set /a $+=4
for %%h in (K) do if /i !j!==%%h set /a $+=5
for %%h in (J X) do if /i !j!==%%h set /a $+=8
for %%h in (Q Z) do if /i !j!==%%h set /a $+=10)
instead of
Code: Select all
for %%h in (A a E e I i L l N n O o R r S s T t U u)do if !j!==%%h set /a $+=1
for %%h in (D d G g)do if !j!==%%h set /a $+=2
for %%h in (B b C c M m P p)do if !j!==%%h set /a $+=3
for %%h in (F f H h V v W w Y y)do if !j!==%%h set /a $+=4
for %%h in (K k)do if !j!==%%h set /a $+=5
for %%h in (J j X x)do if !j!==%%h set /a $+=8
for %%h in (Q q Z z)do if !j!==%%h set /a $+=10)
Noted. That could be useful.
Re: Batch function help?
Posted: 04 Jul 2014 08:47
by dbenham
einstein1969 wrote:Squashman wrote:JWinslow23 wrote:Whaddaya think?
As mentioned earlier by Shadowthief most people do not like this coding style.
I try to make my code as readable as possible using indentation and descriptive variables. I don't mind the use of symbols as variables as long as the code is indented and readable. When you start using symbols as variables instead of Alphanumeric names it makes it very hard for someone to come along behind you and understand how to use the code or even fix it in the future or add enhancements to the code if they are not very experienced with the scripting language.
In dos batch should always make two versions:
1) A more readable version with variable names understandable.
Even indentation and spacing are important.
2) The second version is the version that instead it goes fast. In this case the spaces, length of variables affect the speed. This version can not be easily readable.
I find that advice unworkable. It is hard enough to debug and maintain one version. How can you be sure that your second optimized version is functionally identical to the readable version? Each version would need to be independently tested every time any change is made.
I strongly agree with Squashman.
I understand that length of code can impact performance, but that effect is usually minimal compared to other batch bottlenecks. (I'm assuming the script is on a reasonably fast storage medium)
In every script I have worked on, I have always been able to achieve good, perfectly acceptable performance without resorting to short, unintelligible variable names, remark stripping, or indent/space stripping. Could I squeeze out a bit more performance by using those techniques? - Yes. But I've never found it worthwhile. And I hate reading code that does use those techniques.
I've written some significant game scripts that impress people with their performance, yet they all use sensible names, extensive documentation, and good indentation:
SNAKE.BAT 27k -
viewtopic.php?f=3&t=4741 ADVENTURE.BAT 158k -
viewtopic.php?f=3&t=4876Dave Benham