SNAKE.BAT 4.1 - An arcade style game using pure batch
Moderator: DosItHelp
Re: SNAKE.BAT - An arcade style game using pure batch
Well actually the /L option is not necessary since XCOPY doesn't copy the same file onto itself. It was just my thinking to tell XCOPY that it should only do a simulation of the copy action instead of trying to really copy the file. A double safeguarding so to speak
I'm not quite certain what the /X option has to do with it though Where did you see it?
Regards
aGerman
I'm not quite certain what the /X option has to do with it though Where did you see it?
Regards
aGerman
Re: SNAKE.BAT - An arcade style game using pure batch
Using XCOPY to replace CHOICE is brilliant Thanks jeb, aGerman, and Carlos (and any one else that may have worked on it)
I've reworked SNAKE.BAT to use XCOPY instead of CHOICE. There are lots of benefits:
- A pure batch solution is now compatible with XP
- No more nasty beep when pressing an invalid key
- No more need to check for the version of CHOICE
- No more key translation
The implementation I used for my controller does not read ! properly due to delayed expansion being enabled. But that does not matter since the game does not need that key.
The code works great on my Win 7 machine. I don't detect any delay between key press and character turning.
The code also "works" running on a virtual XP machine hosted by my Win 7 machine. But now there is a significant delay from when I press a key to when the game detects the key press. So it is hard to get the turn timing down. The old version that used CHOICE did not suffer from this problem on my virtual XP machine.
Can someone out there test on a real XP machine and tell me how this new version performs? If it works well, then I will abandon the CHOICE version altogether.
Code: Select all
@echo off
if "%~1" == "startGame" goto :game
if "%~1" == "startController" goto :controller
::---------------------------------------------------------------------
:: setup some global variables used by both the game and the controller
set "keyFile=key.txt"
set "cmdFile=cmd.txt"
::------------------------------------------
:: launch the game and the controller
copy nul "%keyFile%" >nul
start "" /b "%~f0" startController 9^>^>%keyFile% 2^>nul ^>nul
cmd /c "%~f0" startGame 9^<%keyFile% ^<nul
echo(
::--------------------------------------------------------------------------------
:: Upon exit, wait for the controller to close before deleting the temp input file
:close
2>nul (>>"%keyFile%" call )||goto :close
del "%keyFile%"
exit /b
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:game
setlocal disableDelayedExpansion
title %~nx0
cls
::----------------------------
:: user configurable options
set "up=W"
set "down=S"
set "left=A"
set "right=D"
set "width=40" max=99
set "height=25" max=99
:: max playing field: (width-2)*(height-2) <= 1365
::----------------------------
:: resize the console window
set /a cols=width+1, lines=height+10, area=(width-2)*(height-2)
if %area% gtr 1365 (
echo ERROR: Playfield area too large
>"%cmdFile%" (echo quit)
exit
)
if %lines% lss 14 set lines=14
if %cols% lss 46 set cols=46
mode con: cols=%cols% lines=%lines%
::----------------------------
:: define variables
set "spinner1=-"
set "spinner2=\"
set "spinner3=|"
set "spinner4=/"
set "spinner= spinner1 spinner2 spinner3 spinner4 "
set "space= "
set "bound=#"
set "food=+"
set "head=@"
set "body=O"
set "death=X"
set "playerSpace=%space%%food%"
set "xDiff%up%=+0"
set "xDiff%down%=+0"
set "xDiff%left%=-1"
set "xDiff%right%=+1"
set "yDiff%up%=-1"
set "yDiff%down%=+1"
set "yDiff%left%=+0"
set "yDiff%right%=+0"
set "%up%Axis=Y"
set "%down%Axis=Y"
set "%left%Axis=X"
set "%right%Axis=X"
set "delay1=20"
set "delay2=15"
set "delay3=10"
set "delay4=7"
set "delay5=5"
set "delay6=3"
set "delay0=0"
set "desc1=Sluggard"
set "desc2=Crawl"
set "desc3=Slow"
set "desc4=Normal"
set "desc5=Fast"
set "desc6=Insane"
set "desc0=Unplayable"
set "spinnerDelay=3"
set /a "width-=1, height-=1"
::---------------------------
:: define macros
::define a Line Feed (newline) string (normally only used as !LF!)
set LF=^
::Above 2 blank lines are required - do not remove
::define a newline with line continuation
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
:: setErr
::: Sets the ERRORLEVEL to 1
set "setErr=(call)"
:: clrErr
::: Sets the ERRORLEVEL to 0
set "clrErr=(call )"
:: getKey ValidKeys
::: Check for keypress. Only accept keys listed in ValidKeys
::: Accept any key if ValidKeys is empty.
::: Return result in Key variable. Key is undefined if no valid keypress.
set getKey=%\n%
for %%# in (1 2) do if %%#==2 (for /f "eol= delims= " %%1 in ("!args!") do (%\n%
set "validKeys=%%1"%\n%
set "key="%\n%
^<^&9 set /p "key="%\n%
if defined validKeys for %%K in (!key!) do if "!validKeys:%%K=!" equ "!validKeys!" set "key="%\n%
)) else set args=
:: draw
::: draws the board
set draw=%\n%
cls%\n%
for /l %%Y in (0,1,%height%) do echo(!line%%Y!%\n%
echo Speed=!Difficulty!%\n%
echo Score=!score!
:: test X Y ValueListVar
::: tests if value at coordinates X,Y is within contents of ValueListVar
set test=%\n%
for %%# in (1 2) do if %%#==2 (for /f "tokens=1-3" %%1 in ("!args!") do (%\n%
for %%A in ("!line%%2:~%%1,1!") do if "!%%3:%%~A=!" neq "!%%3!" %clrErr% else %setErr%%\n%
)) else set args=
:: plot X Y ValueVar
::: places contents of ValueVar at coordinates X,Y
set plot=%\n%
for %%# in (1 2) do if %%#==2 (for /f "tokens=1-3" %%1 in ("!args!") do (%\n%
set "part2=!line%%2:~%%1!"%\n%
set "line%%2=!line%%2:~0,%%1!!%%3!!part2:~1!"%\n%
)) else set args=
::--------------------------------------
:: start the game
setlocal enableDelayedExpansion
call :initialize
::--------------------------------------
:: main loop (infinite loop)
for /l %%. in (1 0 1) do (
%=== compute time since last move ===%
for /f "tokens=1-4 delims=:.," %%a in ("!time: =0!") do set /a "t2=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100, tDiff=t2-t1"
if !tDiff! lss 0 set /a tDiff+=24*60*60*100
if !tDiff! geq !delay! (
%=== delay has expired, so time for movement ===%
%=== establish direction ===%
%getKey% ASDW
for %%K in (!key!) do if "!%%KAxis!" neq "!axis!" (
set /a "xDiff=xDiff%%K, yDiff=yDiff%%K"
set "axis=!%%KAxis!"
)
%=== erase the tail ===%
set "TX=!snakeX:~-2!"
set "TY=!snakeY:~-2!"
set "snakeX=!snakeX:~0,-2!"
set "snakeY=!snakeY:~0,-2!"
%plot% !TX! !TY! space
%=== compute new head location and attempt to move ===%
set /a "X=PX+xDiff, Y=PY+yDiff"
set "X= !X!"
set "Y= !Y!"
set "X=!X:~-2!"
set "Y=!Y:~-2!"
(%test% !X! !Y! playerSpace) && (
%=== move successful ===%
%=== remove the new head location from the empty list ===%
for %%X in ("!X!") do for %%Y in ("!Y!") do set "empty=!empty:#%%~X %%~Y=!"
(%test% !X! !Y! food) && (
%=== moving to food - eat it ===%
%=== restore the tail ===%
%plot% !TX! !TY! body
set "snakeX=!snakeX!!TX!"
set "snakeY=!snakeY!!TY!"
%=== increment score and locate and draw new food ===%
set /a "score+=1, F=(!random!%%(emptyCnt-=1))*6+1"
for %%F in (!F!) do (%plot% !empty:~%%F,5! food)
) || (
%=== moving to empty space ===%
%=== add the former tail position to the empty list ===%
set "empty=!empty!#!TX! !TY!"
)
%=== draw the new head ===%
if defined snakeX (%plot% !PX! !PY! body)
%plot% !X! !Y! head
%=== Add the new head position to the snake strings ===%
set "snakeX=!X!!snakeX!"
set "snakeY=!Y!!snakeY!"
set "PX=!X!"
set "PY=!Y!"
%draw%
) || (
%=== failed move - game over ===%
%plot% !TX! !TY! body
call :spinner !PX! !PY! death
%draw%
echo(
call :ask "Would you like to play again? (Y/N)" YN
if /i "!key!" equ "N" (
>"%cmdFile%" (echo quit)
exit
) else (
call :initialize
)
)
set /a t1=t2
)
)
:ask Prompt ValidKeys
:: Prompt for a keypress. ValidKeys is a list of acceptable keys
:: Wait until a valid key is pressed and return result in Key variable
>"%cmdFile%" (echo prompt)
<nul set /p "=%~1 "
:purge
(%getKey% {purged})
if !key! neq {purged} goto :purge
:getResponse
(%getKey% %2)
if not defined key (
>"%cmdFile%" (echo one)
goto :getResponse
)
exit /b
:spinner X Y ValueVar
set /a d1=-1000000
for /l %%N in (1 1 5) do for %%C in (%spinner%) do (
call :spinnerDelay
%plot% %1 %2 %%C
%draw%
)
call :spinnerDelay
(%plot% %1 %2 %3)
exit /b
:spinnerDelay
for /f "tokens=1-4 delims=:.," %%a in ("!time: =0!") do set /a "d2=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100, dDiff=d2-d1"
if %dDiff% lss 0 set /a dDiff+=24*60*60*100
if %dDiff% lss %spinnerDelay% goto :spinnerDelay
set /a d1=d2
exit /b
::-------------------------------------
:initialize
cls
echo Speed Options:
echo delay
echo # Description (seconds)
echo --- ----------- ---------
echo 1 Sluggard 0.20
echo 2 Crawl 0.15
echo 3 Slow 0.10
echo 4 Normal 0.07
echo 5 Fast 0.05
echo 6 Insane 0.03
echo 0 Unplayable none
echo(
call :ask "Pick a speed (1-6, 0):" 1234560
set "difficulty=!desc%key%!"
set "delay=!delay%key%!"
echo %key% - %difficulty%
echo(
<nul set /p "=Initializing."
set "axis=X"
set "xDiff=+1"
set "yDiff=+0"
set "empty="
set /a "PX=1, PY=height/2, FX=width/2+1, FY=PY, score=0, emptyCnt=0, t1=-1000000"
set "snakeX= %PX%"
set "snakeY= %PY%"
set "snakeX=%snakeX:~-2%"
set "snakeY=%snakeY:~-2%"
for /l %%Y in (0 1 %height%) do (
<nul set /p "=."
set "line%%Y="
for /l %%X in (0,1,%width%) do (
set "cell="
if %%Y equ 0 set "cell=%bound%"
if %%Y equ %height% set "cell=%bound%"
if %%X equ 0 set "cell=%bound%"
if %%X equ %width% set "cell=%bound%"
if %%X equ %PX% if %%Y equ %PY% set "cell=%head%"
if not defined cell (
set "cell=%space%"
set "eX= %%X"
set "eY= %%Y"
set "empty=!empty!#!eX:~-2! !eY:~-2!"
set /a emptyCnt+=1
)
if %%X equ %FX% if %%Y equ %FY% set "cell=%food%"
set "line%%Y=!line%%Y!!cell!"
)
)
(%draw%)
echo(
echo Movement keys: %up%=up %down%=down %left%=left %right%=right
echo Avoid running into yourself (%body%%body%%head%) or wall (%bound%)
echo Eat food (%food%) to grow.
echo(
call :ask "Press a key to start..."
>"%cmdFile%" (echo go)
exit /b
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:controller
:: As written, this routine incorrectly reports ! as )
:: But that doesn't matter since we don't need the ! key.
setlocal enableDelayedExpansion
set "cmd=hold"
set "key="
for /l %%. in (1 0 1) do (
if "!cmd!" neq "hold" (
for /f "delims=" %%A in ('xcopy /w "%~f0" "%~f0" 2^>nul') do (
if not defined key set "key=%%A"
)
set "key=!key:~-1!"
)
if exist "%cmdFile%" (
<"%cmdFile%" set /p "cmd="
del "%cmdFile%"
)
if "!cmd!" equ "quit" exit
if defined key (
if "!cmd!" equ "prompt" >&9 (echo {purged})
>&9 (echo !key!)
if "!cmd!" neq "go" set "cmd=hold"
set "key="
)
)
Dave Benham
Re: SNAKE.BAT - An arcade style game using pure batch
Snake using xcopy works fine on crawl speed on my XP SP3 laptop 1.7GHz core two duo, with an SSD. No delay in turns.
Re: SNAKE.BAT - An arcade style game using pure batch
foxidrive wrote:Snake using xcopy works fine on crawl speed on my XP SP3 laptop 1.7GHz core two duo, with an SSD. No delay in turns.
Very cool Have you tried a faster speed
Re: SNAKE.BAT - An arcade style game using pure batch
I have now. speeds 4,5,6 also respond immediately as far as I can tell. speed 0 was too quick for me.
Maybe the SSD helps with loading xcopy but it should be cached anyway you'd think.
One item that could possibly be enhanced - have a choice between the arrow keys or w,a,s,d or maybe i,j,k,l and select with w, i or up arrow.
Maybe the SSD helps with loading xcopy but it should be cached anyway you'd think.
One item that could possibly be enhanced - have a choice between the arrow keys or w,a,s,d or maybe i,j,k,l and select with w, i or up arrow.
Re: SNAKE.BAT - An arcade style game using pure batch
foxidrive wrote:I have now. speeds 4,5,6 also respond immediately as far as I can tell. speed 0 was too quick for me.
Maybe the SSD helps with loading xcopy but it should be cached anyway you'd think.
That is great news it works for you, but I would love to hear from an XP user that does not have a solid state drive. Anyone out there
foxidrive wrote:One item that could possibly be enhanced - have a choice between the arrow keys or w,a,s,d or maybe i,j,k,l and select with w, i or up arrow.
The key mappings are easily changed in the source code. Simply change the definitions that appear under the comment: ":: user configurable options". XCOPY can detect keys (or key combinations) that map to single byte code characters. This includes things like <Enter>, <Tab>, <Backspace> and control characters accessed via combinations like <Ctrl><A> for 0x01. But arrow keys, function keys, etc. cannot be detected.
XCOPY is a major improvement over CHOICE in that CHOICE can only accept alpha-numeric keys.
Note - when mapping keys, do not use the * ~ or = keys
Dave Benham
Re: SNAKE.BAT - An arcade style game using pure batch
Hi Dave,
nice implenatation, especially I like the real life example of macros
In my host Win7 system it works good.
In my vmWare XP-System it works quite good, it's flickering a bit too much.
The flickering is mostly just after I press any key.
jeb
nice implenatation, especially I like the real life example of macros
dbenham wrote:That is great news it works for you, but I would love to hear from an XP user that does not have a solid state drive. Anyone out there
In my host Win7 system it works good.
In my vmWare XP-System it works quite good, it's flickering a bit too much.
The flickering is mostly just after I press any key.
jeb
Re: SNAKE.BAT - An arcade style game using pure batch
Thanks jeb
Given that it works OK for you in VM-Ware, I think I will retire the CHOICE version. If it works on VM-Ware, I've got to believe it works on native XP.
The flicker has very little to do with the user input, since input and display are two entirely different processes. But I suppose there is limited bandwidth for all processes in VM-Ware. The CHOICE version flickers badly on my VM-Ware XP as well. But the XCOPY version has turning delay for me on VM-Ware. I'm glad turning works well for you.
Dave Benham
Given that it works OK for you in VM-Ware, I think I will retire the CHOICE version. If it works on VM-Ware, I've got to believe it works on native XP.
The flicker has very little to do with the user input, since input and display are two entirely different processes. But I suppose there is limited bandwidth for all processes in VM-Ware. The CHOICE version flickers badly on my VM-Ware XP as well. But the XCOPY version has turning delay for me on VM-Ware. I'm glad turning works well for you.
Dave Benham
Re: SNAKE.BAT - An arcade style game using pure batch
Dave,
thanks for making this.
slight flicker using winxp sp3. AMD athlon 1.53Ghz with Western Digital HDD 20GB. 6 and 0 are unplayable - too fast.
Did not notice any delay on turning. Just as responsive on keypress.
thanks.
thanks for making this.
slight flicker using winxp sp3. AMD athlon 1.53Ghz with Western Digital HDD 20GB. 6 and 0 are unplayable - too fast.
Did not notice any delay on turning. Just as responsive on keypress.
thanks.
Re: SNAKE.BAT - An arcade style game using pure batch
That is great news Brinda. Thanks.
Speeds 6 and 0 are intended to be unplayable. Thery are only there to demonstrate the potential speed of batch animation.
Dave Benham
Speeds 6 and 0 are intended to be unplayable. Thery are only there to demonstrate the potential speed of batch animation.
Dave Benham
Re: SNAKE.BAT - An arcade style game using pure batch
I've posted a new and improved version at the top of the original post in this thread.
The prior version still had inter-process communication issues that could lead to the game hanging - refusing to accept input. It was mostly due to sequencing issues.
I've completely reworked the inter-process communication such that the game should be much more stable now. I'm hoping this will solve the problems Squashman was seeing. I know it solved problems that I was seeing.
Foxidrive had requested the ability to redefine the movement keys. I told him that he just needed to change the values in some variable assignments. Well I discovered that was I lie. There was still a critical place where I had the movement keys hard coded. This version fixes the parameterization of the key definitions.
The location of the temporary files is now controlled by the TEMP (or TMP) environment variable, which should always point to a high speed device. Now it should not matter where SNAKE.BAT is run from.
Finally, I establish a unique session ID and lock for each instance of a running SNAKE game. The session ID is incorporated into the names of the temp files, so multiple instances should be able to share the same temp folder without interference. The session ID is derived from the current time to 1/100th second. I doubt there will ever be a collision. But if there is a collision, the game lock for one of the instances will fail and it will automatically loop back and try a new session ID.
Dave Benham
The prior version still had inter-process communication issues that could lead to the game hanging - refusing to accept input. It was mostly due to sequencing issues.
I've completely reworked the inter-process communication such that the game should be much more stable now. I'm hoping this will solve the problems Squashman was seeing. I know it solved problems that I was seeing.
Foxidrive had requested the ability to redefine the movement keys. I told him that he just needed to change the values in some variable assignments. Well I discovered that was I lie. There was still a critical place where I had the movement keys hard coded. This version fixes the parameterization of the key definitions.
The location of the temporary files is now controlled by the TEMP (or TMP) environment variable, which should always point to a high speed device. Now it should not matter where SNAKE.BAT is run from.
Finally, I establish a unique session ID and lock for each instance of a running SNAKE game. The session ID is incorporated into the names of the temp files, so multiple instances should be able to share the same temp folder without interference. The session ID is derived from the current time to 1/100th second. I doubt there will ever be a collision. But if there is a collision, the game lock for one of the instances will fail and it will automatically loop back and try a new session ID.
Dave Benham
Re: SNAKE.BAT - An arcade style game using pure batch
tis working here in Win8. No delays.
Re: SNAKE.BAT - An arcade style game using pure batch
Updated the code in the first post. No functional changes. Mostly just improved comments/documentation
Dave Benham
Dave Benham
-
- Expert
- Posts: 961
- Joined: 15 Jun 2012 13:16
- Location: Italy, Rome
Re: SNAKE.BAT - An arcade style game using pure batch
hi dave,
great work!
On my machine the cpu is always at 100%!!!
you could add an option to speed it consumes less cpu?
For those PCs that have the serial you could insert a delay in this way:
echo(>Com3:
On my pc has a delay of about 230ms this command, whith 10-15% cpu usage.
I tried it on snake on my PC and it actually reduces cpu usage up to about 20%.
great work!
On my machine the cpu is always at 100%!!!
you could add an option to speed it consumes less cpu?
For those PCs that have the serial you could insert a delay in this way:
echo(>Com3:
On my pc has a delay of about 230ms this command, whith 10-15% cpu usage.
I tried it on snake on my PC and it actually reduces cpu usage up to about 20%.
-
- Posts: 3
- Joined: 23 Sep 2013 09:03