SNAKE.BAT 4.1 - An arcade style game using pure batch

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
aGerman
Expert
Posts: 4654
Joined: 22 Jan 2010 18:01
Location: Germany

Re: SNAKE.BAT - An arcade style game using pure batch

#31 Post by aGerman » 17 Jul 2013 13:35

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 :wink:
I'm not quite certain what the /X option has to do with it though :? Where did you see it?

Regards
aGerman

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: SNAKE.BAT - An arcade style game using pure batch

#32 Post by dbenham » 17 Jul 2013 19:51

:shock: :D
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

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: SNAKE.BAT - An arcade style game using pure batch

#33 Post by foxidrive » 17 Jul 2013 20:46

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.

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: SNAKE.BAT - An arcade style game using pure batch

#34 Post by dbenham » 17 Jul 2013 20:51

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 8) Have you tried a faster speed :?:

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: SNAKE.BAT - An arcade style game using pure batch

#35 Post by foxidrive » 18 Jul 2013 00:57

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.

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: SNAKE.BAT - An arcade style game using pure batch

#36 Post by dbenham » 18 Jul 2013 05:36

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

jeb
Expert
Posts: 1041
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: SNAKE.BAT - An arcade style game using pure batch

#37 Post by jeb » 18 Jul 2013 06:06

Hi Dave,

nice implenatation, especially I like the real life example of macros :D

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

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: SNAKE.BAT - An arcade style game using pure batch

#38 Post by dbenham » 18 Jul 2013 07:51

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

brinda
Posts: 78
Joined: 25 Apr 2012 23:51

Re: SNAKE.BAT - An arcade style game using pure batch

#39 Post by brinda » 18 Jul 2013 08:12

Dave,

thanks for making this. :D
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.

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: SNAKE.BAT - An arcade style game using pure batch

#40 Post by dbenham » 18 Jul 2013 09:11

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

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: SNAKE.BAT - An arcade style game using pure batch

#41 Post by dbenham » 20 Jul 2013 17:20

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

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: SNAKE.BAT - An arcade style game using pure batch

#42 Post by foxidrive » 20 Jul 2013 20:11

tis working here in Win8. No delays.

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: SNAKE.BAT - An arcade style game using pure batch

#43 Post by dbenham » 06 Aug 2013 20:49

Updated the code in the first post. No functional changes. Mostly just improved comments/documentation


Dave Benham

einstein1969
Expert
Posts: 941
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: SNAKE.BAT - An arcade style game using pure batch

#44 Post by einstein1969 » 02 Sep 2013 07:10

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%.

Delmar Grande
Posts: 3
Joined: 23 Sep 2013 09:03

Re: SNAKE.BAT - An arcade style game using pure batch

#45 Post by Delmar Grande » 05 Oct 2013 16:26

Very good!
I posted your code here http://dbatchscript.forumeiros.com/
:D

Post Reply