Batch Games

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
misol101
Posts: 475
Joined: 02 May 2016 18:20

Re: Batch Games

#16 Post by misol101 » 25 Sep 2020 16:20

Lowsun wrote:
25 Sep 2020 15:17
I have also made lots of pure Batch games like platformers, rogue-likes, and other stuff. They're are all here

https://lowsun.itch.io/
These are nice. Maybe not so much for the gameplay, but because you create an atmosphere with the story+music.

Lowsun
Posts: 29
Joined: 14 Apr 2019 17:22

Re: Batch Games

#17 Post by Lowsun » 25 Sep 2020 16:54

@misol101

Thanks. I had a hard time adding stuff to make gameplay better, since the performance would drop really low, or it would be unwieldy in batch. But yeah, I tried to compensate with some extra effort into story.

T3RRY
Posts: 249
Joined: 06 May 2020 10:14

Re: Batch Games

#18 Post by T3RRY » 01 Oct 2020 23:05

Untitled: 16595 bytes
Cat wrote:
25 Apr 2012 19:15
Coded this a LONG time ago. Horrible coding, but it's too big for me to really redo.

Code: Select all

@ECho off
:s
set a1=_&set a2=_&set a3=_&set a4=_&set b1=_&set b2=_&set b3=_&set b4=_&set c1=_&set c2=_&set c3=_&set c4=_
set d3=_&set d4=_&set e1=_&set e2=_&set e3=_&set e4=_&set f1=_&set f2=_&set f3=_&set f4=_&set d1=_&set d2=_
set moves=0&set AC=1&set BC=1&set CC=1&set DC=1&set FC=1&set EC=1
cls&call :board
:start
call :player
call :winlist
GOTO :computer
:AFTER
set /a moves= %moves% + 1
if %moves%==12 goto tie
GOTO START
:player
call :board&set /p P1="ENTER A LETTER:"
if /i %p1%%AC%==A1 set A1=X&Set /a AC= %AC%+1&EXIT /B
if /i %p1%%AC%==A2 set A2=X&Set /a AC= %AC%+1&EXIT /B
if /i %p1%%AC%==A3 set A3=X&Set /a AC= %AC%+1&EXIT /B
if /i %p1%%AC%==A4 set A4=X&Set /a AC= %AC%+1&EXIT /B
if /i %p1%%BC%==B1 set B1=X&set /a BC= %BC%+1&EXIT /B
if /i %p1%%BC%==B2 set B2=X&set /a BC= %BC%+1&EXIT /B
if /i %p1%%BC%==B3 set B3=X&set /a BC= %BC%+1&EXIT /B
if /i %p1%%BC%==B4 set B4=X&set /a BC= %BC%+1&EXIT /B
if /i %p1%%CC%==C1 set C1=X&set /a CC= %CC%+1&EXIT /B
if /i %p1%%CC%==C2 set C2=X&set /a CC= %CC%+1&EXIT /B
if /i %p1%%CC%==C3 set C3=X&set /a CC= %CC%+1&EXIT /B
if /i %p1%%CC%==C4 set C4=X&set /a CC= %CC%+1&EXIT /B
if /i %p1%%DC%==D1 set D1=X&set /a DC= %DC%+1&EXIT /B
if /i %p1%%DC%==D2 set D2=X&set /a DC= %DC%+1&EXIT /B
if /i %p1%%DC%==D3 set D3=X&set /a DC= %DC%+1&EXIT /B
if /i %p1%%DC%==D4 set D4=X&set /a DC= %DC%+1&EXIT /B
if /i %p1%%EC%==E1 set E1=X&set /a EC= %EC%+1&EXIT /B
if /i %p1%%EC%==E2 set E2=X&set /a EC= %EC%+1&EXIT /B
if /i %p1%%EC%==E3 set E3=X&set /a EC= %EC%+1&EXIT /B
if /i %p1%%EC%==E4 set E4=X&set /a EC= %EC%+1&EXIT /B
if /i %p1%%FC%==F1 set F1=X&set /a FC= %FC%+1&EXIT /B
if /i %p1%%FC%==F2 set F2=X&set /a FC= %FC%+1&EXIT /B
if /i %p1%%FC%==F3 set F3=X&set /a FC= %FC%+1&EXIT /B
if /i %p1%%FC%==F4 set F4=X&set /a FC= %FC%+1&EXIT /B
ECHO Invalid&timeout /t 1 /nobreak>nul&GOTO START
:COMPUTER
CALL :ATTACKER
CALL :DEFENDER
:RANDOMERROR
set /a N=%random% %% 6 
IF %N%%AC%==05 GOTO RANDOMERROR
IF %N%%BC%==15 GOTO RANDOMERROR
IF %N%%CC%==25 GOTO RANDOMERROR
IF %N%%DC%==35 GOTO RANDOMERROR
IF %N%%EC%==45 GOTO RANDOMERROR
IF %N%%FC%==55 GOTO RANDOMERROR
IF %N%==0 SET A%AC%=O&SET /A AC= %AC%+1
IF %N%==1 SET B%BC%=O&SET /A BC= %BC%+1
IF %N%==2 SET C%CC%=O&SET /A CC= %CC%+1
IF %N%==3 SET D%DC%=O&SET /A DC= %DC%+1
IF %N%==4 SET E%EC%=O&SET /A EC= %EC%+1
IF %N%==5 SET F%FC%=O&SET /A FC= %FC%+1
call :board&GOTO AFTER
:lose 
call :board&ECho Computer wins&ECho.&ECho Press any key to restart&pause>nul&goto s
:tie
call :board&ECho Tie&ECho.&ECho Press any key to restart&pause>nul&goto s
:win
call :board&EChO You Win&ECho.&ECho Press any key to restart&pause>nul&goto s
:board
cls&ECho.&ECho  _ _ _ _ _ _&ECho ^|%A4%^|%B4%^|%C4%^|%D4%^|%E4%^|%F4%^|
ECho ^|%A3%^|%B3%^|%C3%^|%D3%^|%E3%^|%F3%^|&ECho ^|%A2%^|%B2%^|%C2%^|%D2%^|%E2%^|%F2%^|
ECho ^|%A1%^|%B1%^|%C1%^|%D1%^|%E1%^|%F1%^|&ECho  A B C D E F&ECho.&exit /b
:defender
if %A1%%A2%%A3%%A4%==XXX_ set A4=O&set /a AC= %AC%+1& GOTO AFTER
if %A1%%A2%%A3%%A4%==XX_X set A3=O&set /a AC= %AC%+1& GOTO AFTER
if %A1%%A2%%A3%%A4%==X_XX set A2=O&set /a AC= %AC%+1& GOTO AFTER
if %A1%%A2%%A3%%A4%==_XXX set A1=O&set /a AC= %AC%+1& GOTO AFTER
if %B1%%B2%%B3%%B4%==XXX_ set B4=O&set /a BC= %BC%+1& GOTO AFTER
if %B1%%B2%%B3%%B4%==XX_X set B3=O&set /a BC= %BC%+1& GOTO AFTER
if %B1%%B2%%B3%%B4%==X_XX set B2=O&set /a BC= %BC%+1& GOTO AFTER
if %B1%%B2%%B3%%B4%==_XXX set B1=O&set /a BC= %BC%+1& GOTO AFTER
if %C1%%C2%%C3%%C4%==XXX_ set C4=O&set /a CC= %CC%+1& GOTO AFTER
if %C1%%C2%%C3%%C4%==XX_X set C3=O&set /a CC= %CC%+1& GOTO AFTER
if %C1%%C2%%C3%%C4%==X_XX set C2=O&set /a CC= %CC%+1& GOTO AFTER
if %C1%%C2%%C3%%C4%==_XXX set C1=O&set /a CC= %CC%+1& GOTO AFTER
if %D1%%D2%%D3%%D4%==XXX_ set D4=O&set /a DC= %DC%+1& GOTO AFTER
if %D1%%D2%%D3%%D4%==XX_X set D3=O&set /a DC= %DC%+1& GOTO AFTER
if %D1%%D2%%D3%%D4%==X_XX set D2=O&set /a DC= %DC%+1& GOTO AFTER
if %D1%%D2%%D3%%D4%==_XXX set D1=O&set /a DC= %DC%+1& GOTO AFTER
if %E1%%E2%%E3%%E4%==XXX_ set E4=O&set /a EC= %EC%+1& GOTO AFTER
if %E1%%E2%%E3%%E4%==XX_X set E3=O&set /a EC= %EC%+1& GOTO AFTER
if %E1%%E2%%E3%%E4%==X_XX set E2=O&set /a EC= %EC%+1& GOTO AFTER
if %E1%%E2%%E3%%E4%==_XXX set E1=O&set /a EC= %EC%+1& GOTO AFTER
if %F1%%F2%%F3%%F4%==XXX_ set F4=O&set /a FC= %FC%+1& GOTO AFTER
if %F1%%F2%%F3%%F4%==XX_X set F3=O&set /a FC= %FC%+1& GOTO AFTER
if %F1%%F2%%F3%%F4%==X_XX set F2=O&set /a FC= %FC%+1& GOTO AFTER
if %F1%%F2%%F3%%F4%==_XXX set F1=O&set /a FC= %FC%+1& GOTO AFTER
if %A4%%b4%%c4%%d4%==XXX_ if NOT %d3%==_ set d4=O&Set /a DC= %DC%+1& GOTO AFTER
if %A4%%b4%%c4%%d4%==XX_X if NOT %d3%==_ set c4=O&set /a CC= %CC%+1& GOTO AFTER
if %A4%%b4%%c4%%d4%==X_XX if NOT %d3%==_ set b4=O&set /a BC= %BC%+1& GOTO AFTER
if %A4%%b4%%c4%%d4%==_XXX if NOT %d3%==_ set A4=O&set /a AC= %AC%+1& GOTO AFTER
if %A3%%b3%%c3%%d3%==XXX_ if NOT %d2%==_ set d3=O&set /a DC= %DC%+1& GOTO AFTER
if %A3%%b3%%c3%%d3%==XX_X if NOT %c2%==_ set c3=O&set /a CC= %CC%+1& GOTO AFTER
if %A3%%b3%%c3%%d3%==X_XX if NOT %b2%==_ set b3=O&set /a BC= %BC%+1& GOTO AFTER
if %A3%%b3%%c3%%d3%==_XXX if NOT %a2%==_ set A3=O&set /a AC= %AC%+1& GOTO AFTER
if %A2%%b2%%c2%%d2%==XXX_ if NOT %d1%==_ set d2=O&set /a DC= %DC%+1& GOTO AFTER
if %A2%%b2%%c2%%d2%==XX_X if NOT %c1%==_ set c2=O&set /a CC= %CC%+1& GOTO AFTER
if %A2%%b2%%c2%%d2%==X_XX if NOT %b1%==_ set b2=O&set /a BC= %BC%+1& GOTO AFTER
if %A2%%b2%%c2%%d2%==_XXX if NOT %a1%==_ set A2=O&set /a AC= %AC%+1& GOTO AFTER
if %A1%%b1%%c1%%d1%==XXX_ set d1=O&set /a DC= %DC%+1& GOTO AFTER
if %A1%%b1%%c1%%d1%==XX_X set c1=O&set /a CC= %CC%+1& GOTO AFTER
if %A1%%b1%%c1%%d1%==X_XX set b1=O&set /a BC= %BC%+1& GOTO AFTER
if %A1%%b1%%c1%%d1%==_XXX set A1=O&set /a AC= %AC%+1& GOTO AFTER
if %b4%%c4%%d4%%e4%==XXX_ if NOT %e3%==_ set e3=O&set /a EC= %EC%+1& GOTO AFTER
if %b4%%c4%%d4%%e4%==XX_X if NOT %d3%==_ set d3=O&set /a DC= %DC%+1& GOTO AFTER
if %b4%%c4%%d4%%e4%==X_XX if NOT %c3%==_ set c3=O&set /a CC= %CC%+1& GOTO AFTER
if %b4%%c4%%d4%%e4%==_XXX if NOT %b3%==_ set b3=O&set /a BC= %BC%+1& GOTO AFTER
if %b3%%c3%%d3%%e3%==XXX_ if NOT %e2%==_ set e2=O&set /a EC= %EC%+1& GOTO AFTER
if %b3%%c3%%d3%%e3%==XX_X if NOT %d2%==_ set d2=O&set /a DC= %DC%+1& GOTO AFTER
if %b3%%c3%%d3%%e3%==X_XX if NOT %c2%==_ set c3=O&set /a CC= %CC%+1& GOTO AFTER
if %b3%%c3%%d3%%e3%==_XXX if NOT %b2%==_ set b3=O&set /a BC= %BC%+1& GOTO AFTER
if %b2%%c2%%d2%%e2%==XXX_ if NOT %e1%==_ set e2=O&set /a EC= %EC%+1& GOTO AFTER
if %b2%%c2%%d2%%e2%==XX_X if NOT %d1%==_ set d2=O&set /a DC= %DC%+1& GOTO AFTER
if %b2%%c2%%d2%%e2%==X_XX if NOT %c1%==_ set c2=O&set /a CC= %CC%+1& GOTO AFTER
if %b2%%c2%%d2%%e2%==_XXX if NOT %b1%==_ set b2=O&set /a BC= %BC%+1& GOTO AFTER
if %b1%%c1%%d1%%e1%==XXX_ set e1=O&set /a EC= %EC%+1& GOTO AFTER
if %b1%%c1%%d1%%e1%==XX_X set d1=O&set /a DC= %DC%+1& GOTO AFTER
if %b1%%c1%%d1%%e1%==X_XX set c1=O&set /a CC= %CC%+1& GOTO AFTER
if %b1%%c1%%d1%%e1%==_XXX set b1=O&set /a BC= %BC%+1& GOTO AFTER
if %c4%%d4%%e4%%f4%==XXX_ if NOT %f3%==_ set F4=O&set /a FC= %FC%+1& GOTO AFTER
if %c4%%d4%%e4%%f4%==XX_X if NOT %e3%==_ set E4=O&set /a EC= %EC%+1& GOTO AFTER
if %c4%%d4%%e4%%f4%==X_XX if NOT %d3%==_ set D4=O&set /a DC= %DC%+1& GOTO AFTER
if %c4%%d4%%e4%%f4%==_XXX if NOT %c3%==_ set C4=O&set /a CC= %CC%+1& GOTO AFTER
if %c3%%d3%%e3%%f3%==XXX_ if NOT %f2%==_ set F3=O&set /a FC= %FC%+1& GOTO AFTER
if %c3%%d3%%e3%%f3%==XX_X if NOT %e2%==_ set E3=O&set /a EC= %EC%+1& GOTO AFTER
if %c3%%d3%%e3%%f3%==X_XX if NOT %d2%==_ set D3=O&set /a DC= %DC%+1& GOTO AFTER
if %c3%%d3%%e3%%f3%==_XXX if NOT %c2%==_ set C3=O&set /a CC= %CC%+1& GOTO AFTER
if %c2%%d2%%e2%%f2%==XXX_ if NOT %f1%==_ set F2=O&set /a FC= %FC%+1& GOTO AFTER
if %c2%%d2%%e2%%f2%==XX_X if NOT %e1%==_ set E2=O&set /a EC= %EC%+1& GOTO AFTER
if %c2%%d2%%e2%%f2%==X_XX if NOT %d1%==_ set D2=O&set /a DC= %DC%+1& GOTO AFTER
if %c2%%d2%%e2%%f2%==_XXX if NOT %c1%==_ set C2=O&set /a CC= %CC%+1& GOTO AFTER
if %c1%%d1%%e1%%f1%==XXX_ set F1=O&set /a FC= %FC%+1& GOTO AFTER
if %c1%%d1%%e1%%f1%==XX_X set E1=O&set /a EC= %EC%+1& GOTO AFTER
if %c1%%d1%%e1%%f1%==X_XX set D1=O&set /a DC= %DC%+1& GOTO AFTER
if %c1%%d1%%e1%%f1%==_XXX set C1=O&set /a CC= %CC%+1& GOTO AFTER
if %a1%%b2%%c3%%d4%==XXX_ if NOT %d4%==_ set d4=O&set /a DC= %DC%+ 1& GOTO AFTER
if %a1%%b2%%c3%%d4%==XX_X if NOT %c3%==_ set C3=O&set /a CC= %CC%+ 1& GOTO AFTER
if %a1%%b2%%c3%%d4%==X_XX if NOT %b2%==_ set B2=O&set /a BC= %BC%+ 1& GOTO AFTER
if %a1%%b2%%c3%%d4%==_XXX set A1=O&set /a AC= %AC%+1& GOTO AFTER
if %a4%%b3%%c2%%d1%==XXX_ set D1=O&set /a DC= %DC%+1& GOTO AFTER
if %a4%%b3%%c2%%d1%==XX_X if NOT %c1%==_ set C2=O&set /a CC= %CC%+1& GOTO AFTER
if %a4%%b3%%c2%%d1%==X_XX if NOT %b2%==_ set B3=O&set /a BC= %BC%+1& GOTO AFTER
if %a4%%b3%%c2%%d1%==_XXX if NOT %a3%==_ set A4=O&set /a AC= %AC%+1& GOTO AFTER
if %b1%%C2%%D3%%E4%==XXX_ if NOT %e3%==_ set E4=O&set /a EC= %EC%+1& GOTO AFTER
if %b1%%C2%%D3%%E4%==XX_X if NOT %d2%==_ set D3=O&set /a DC= %DC%+1& GOTO AFTER
if %b1%%C2%%D3%%E4%==X_XX if NOT %c1%==_ set C2=O&set /a CC= %CC%+1& GOTO AFTER
if %b1%%C2%%D3%%E4%==_XXX set B1=O&set /a BC= %BC%+1& GOTO AFTER
if %b4%%C3%%D2%%E1%==XXX_ set E1=O&set /a EC= %EC%+1& GOTO AFTER
if %b4%%C3%%D2%%E1%==XX_X if NOT %d1%==_ set D2=O&set /a DC= %DC%+1& GOTO AFTER
if %b4%%C3%%D2%%E1%==X_XX if NOT %c2%==_ set C3=O&set /a CC= %CC%+1& GOTO AFTER
if %b4%%C3%%D2%%E1%==_XXX if NOT %b3%==_ set B4=O&set /a BC= %BC%+1& GOTO AFTER
if %c1%%d2%%e3%%f4%==XXX_ if NOT %f3%==_ set F4=O&set /a FC= %FC%+1& GOTO AFTER
if %c1%%d2%%e3%%f4%==XX_X if NOT %e2%==_ set E3=O&set /a EC= %EC%+1& GOTO AFTER
if %c1%%d2%%e3%%f4%==X_XX if NOT %d1%==_ set D2=O&set /a DC= %DC%+1& GOTO AFTER
if %c1%%d2%%e3%%f4%==_XXX set C1=O&set /a CC= %CC%+1& GOTO AFTER
if %c4%%d3%%e2%%f1%==XXX_ set F1=O&set /a FC= %FC%+1& GOTO AFTER
if %c4%%d3%%e2%%f1%==XX_X if NOT %e1%==_ set E2=O&set /a EC= %EC%+1& GOTO AFTER
if %c4%%d3%%e2%%f1%==X_XX if NOT %d2%==_ set D3=O&set /a DC= %DC%+1& GOTO AFTER
if %c4%%d3%%e2%%f1%==_XXX if NOT %c3%==_ set C4=O&set /a CC= %CC%+1& GOTO AFTER
exit /b
:attACker
if %A1%%A2%%A3%%A4%==OOO_ if NOT %A3%==_ set A4=O& goto lose
if %A1%%A2%%A3%%A4%==OO_O if NOT %A2%==_ set A3=O& goto lose
if %A1%%A2%%A3%%A4%==O_OO if NOT %A1%==_ set A2=O& goto lose
if %A1%%A2%%A3%%A4%==_OOO set A1=O& goto lose
if %B1%%B2%%B3%%B4%==OOO_ if NOT %B3%==_ set B4=O& goto lose
if %B1%%B2%%B3%%B4%==OO_O if NOT %B2%==_ set B3=O& goto lose
if %B1%%B2%%B3%%B4%==O_OO if NOT %B1%==_ set B2=O& goto lose
if %B1%%B2%%B3%%B4%==_OOO set B1=O& goto lose
if %C1%%C2%%C3%%C4%==OOO_ if NOT %c3%==_ set C4=O& goto lose
if %C1%%C2%%C3%%C4%==OO_O if NOT %c2%==_ set C3=O& goto lose
if %C1%%C2%%C3%%C4%==O_OO if NOT %c1%==_ set C2=O& goto lose
if %C1%%C2%%C3%%C4%==_OOO set C1=O& goto lose
if %D1%%D2%%D3%%D4%==OOO_ if NOT %d3%==_ set D4=O& goto lose
if %D1%%D2%%D3%%D4%==OO_O if NOT %d2%==_ set D3=O& goto lose
if %D1%%D2%%D3%%D4%==O_OO if NOT %d1%==_ set D2=O& goto lose
if %D1%%D2%%D3%%D4%==_OOO set D1=O& goto lose
if %E1%%E2%%E3%%E4%==OOO_ if NOT %e3%==_ set E4=O& goto lose
if %E1%%E2%%E3%%E4%==OO_O if NOT %e2%==_ set E3=O& goto lose
if %E1%%E2%%E3%%E4%==O_OO if NOT %d1%==_ set E2=O& goto lose
if %E1%%E2%%E3%%E4%==_OOO  set E1=O& goto lose
if %F1%%F2%%F3%%F4%==OOO_ if NOT %f3%==_ set F4=O& goto lose
if %F1%%F2%%F3%%F4%==OO_O if NOT %f2%==_ set F3=O& goto lose
if %F1%%F2%%F3%%F4%==O_OO if NOT %f1%==_ set F2=O& goto lose
if %F1%%F2%%F3%%F4%==_OOO set F1=O& goto lose
if %A4%%b4%%c4%%d4%==OOO_ if NOT %d3%==_ set d4=O& goto lose
if %A4%%b4%%c4%%d4%==OO_O if NOT %c3%==_ set c4=O& goto lose
if %A4%%b4%%c4%%d4%==O_OO if NOT %b3%==_ set b4=O& goto lose
if %A4%%b4%%c4%%d4%==_OOO if NOT %a3%==_ set A4=O& goto lose
if %A3%%b3%%c3%%d3%==OOO_ if NOT %d2%==_ set d3=O& goto lose
if %A3%%b3%%c3%%d3%==OO_O if NOT %c2%==_ set c3=O& goto lose
if %A3%%b3%%c3%%d3%==O_OO if NOT %b2%==_ set b3=O& goto lose
if %A3%%b3%%c3%%d3%==_OOO if NOT %a2%==_ set A3=O& goto lose
if %A2%%b2%%c2%%d2%==OOO_ if NOT %d1%==_ set d2=O& goto lose
if %A2%%b2%%c2%%d2%==OO_O if NOT %c1%==_ set c2=O& goto lose
if %A2%%b2%%c2%%d2%==O_OO if NOT %b1%==_ set b2=O& goto lose
if %A2%%b2%%c2%%d2%==_OOO if NOT %a1%==_ set A2=O& goto lose
if %A1%%b1%%c1%%d1%==OOO_ set d1=O& goto lose
if %A1%%b1%%c1%%d1%==OO_O set c1=O& goto lose
if %A1%%b1%%c1%%d1%==O_OO set b1=O& goto lose
if %A1%%b1%%c1%%d1%==_OOO set A1=O& goto lose
if %b4%%c4%%d4%%e4%==OOO_ if NOT %e3%==_ set e4=O& goto lose
if %b4%%c4%%d4%%e4%==OO_O if NOT %d3%==_ set d4=O& goto lose
if %b4%%c4%%d4%%e4%==O_OO if NOT %c3%==_ set c4=O& goto lose
if %b4%%c4%%d4%%e4%==_OOO if NOT %b3%==_ set b4=O& goto lose
if %b3%%c3%%d3%%e3%==OOO_ if NOT %e2%==_ set e3=O& goto lose
if %b3%%c3%%d3%%e3%==OO_O if NOT %d2%==_ set d3=O& goto lose
if %b3%%c3%%d3%%e3%==O_OO if NOT %c2%==_ set c3=O& goto lose
if %b3%%c3%%d3%%e3%==_OOO if NOT %b2%==_ set b3=O& goto lose
if %b2%%c2%%d2%%e2%==OOO_ if NOT %e1%==_ set e2=O& goto lose
if %b2%%c2%%d2%%e2%==OO_O if NOT %d1%==_ set d2=O& goto lose
if %b2%%c2%%d2%%e2%==O_OO if NOT %c1%==_ set c2=O& goto lose
if %b2%%c2%%d2%%e2%==_OOO if NOT %b1%==_ set b2=O& goto lose
if %b1%%c1%%d1%%e1%==OOO_ set e1=O& goto lose
if %b1%%c1%%d1%%e1%==OO_O set d1=O& goto lose
if %b1%%c1%%d1%%e1%==O_OO set c1=O& goto lose
if %b1%%c1%%d1%%e1%==_OOO set b1=O& goto lose
if %c4%%d4%%e4%%f4%==OOO_ if NOT %f3%==_ set F4=O& goto lose
if %c4%%d4%%e4%%f4%==OO_O if NOT %e3%==_ set E4=O& goto lose
if %c4%%d4%%e4%%f4%==O_OO if NOT %d3%==_ set D4=O& goto lose
if %c4%%d4%%e4%%f4%==_OOO if NOT %c3%==_ set C4=O& goto lose
if %c3%%d3%%e3%%f3%==OOO_ if NOT %f2%==_ set F3=O& goto lose
if %c3%%d3%%e3%%f3%==OO_O if NOT %e2%==_ set E3=O& goto lose
if %c3%%d3%%e3%%f3%==O_OO if NOT %d2%==_ set D3=O& goto lose
if %c3%%d3%%e3%%f3%==_OOO if NOT %c2%==_ set C3=O& goto lose
if %c2%%d2%%e2%%f2%==OOO_ if NOT %f1%==_ set F2=O& goto lose
if %c2%%d2%%e2%%f2%==OO_O if NOT %e1%==_ set E2=O& goto lose
if %c2%%d2%%e2%%f2%==O_OO if NOT %d1%==_ set D2=O& goto lose
if %c2%%d2%%e2%%f2%==_OOO if NOT %c1%==_ set C2=O& goto lose
if %c1%%d1%%e1%%f1%==OOO_ set F1=O& goto lose
if %c1%%d1%%e1%%f1%==OO_O set E1=O& goto lose
if %c1%%d1%%e1%%f1%==O_OO set D1=O& goto lose
if %c1%%d1%%e1%%f1%==_OOO set C1=O& goto lose
if %a1%%b2%%c3%%d4%==OOO_ if NOT %d3%==_ set d4=O& goto lose
if %a1%%b2%%c3%%d4%==OO_O if NOT %c2%==_ set C3=O& goto lose
if %a1%%b2%%c3%%d4%==O_OO if NOT %b1%==_ set B2=O& goto lose
if %a1%%b2%%c3%%d4%==_OOO set A1=O& goto lose
if %a4%%b3%%c2%%d1%==OOO_ set D1=O& goto lose
if %a4%%b3%%c2%%d1%==OO_O if NOT %c1%==_ set C2=O& goto lose
if %a4%%b3%%c2%%d1%==O_OO if NOT %b2%==_ set B3=O& goto lose
if %a4%%b3%%c2%%d1%==_OOO if NOT %a3%==_ set A4=O& goto lose
if %b1%%C2%%D3%%E4%==OOO_ if NOT %e3%==_ set E4=O& goto lose
if %b1%%C2%%D3%%E4%==OO_O if NOT %d2%==_ set D3=O& goto lose
if %b1%%C2%%D3%%E4%==O_OO if NOT %c1%==_ set C2=O& goto lose
if %b1%%C2%%D3%%E4%==_OOO set B1=O& goto lose
if %b4%%C3%%D2%%E1%==OOO_ set E1=O& goto lose
if %b4%%C3%%D2%%E1%==OO_O if NOT %d1%==_ set D2=O& goto lose
if %b4%%C3%%D2%%E1%==O_OO if NOT %c2%==_ set C3=O& goto lose
if %b4%%C3%%D2%%E1%==_OOO if NOT %b3%==_ set B4=O& goto lose
if %c1%%d2%%e3%%f4%==OOO_ if NOT %f3%==_ set F4=O& goto lose
if %c1%%d2%%e3%%f4%==OO_O if NOT %e3%==_ set E3=O& goto lose
if %c1%%d2%%e3%%f4%==O_OO if NOT %d1%==_ set D2=O& goto lose
if %c1%%d2%%e3%%f4%==_OOO set C1=O& goto lose
if %c4%%d3%%e2%%f1%==OOO_ set F1=O& goto lose
if %c4%%d3%%e2%%f1%==OO_O if NOT %e1%==_ set E2=O& goto lose
if %c4%%d3%%e2%%f1%==O_OO if NOT %d2%==_ set D3=O& goto lose
if %c4%%d3%%e2%%f1%==_OOO if NOT %c3%==_ set C4=O& goto lose
exit /b
:winlist
call :board
if %A1%%A2%%A3%%A4%==XXXX GOTO WIN
if %B1%%B2%%B3%%B4%==XXXX GOTO WIN
if %C1%%C2%%C3%%C4%==XXXX GOTO WIN
if %D1%%D2%%D3%%D4%==XXXX GOTO WIN
if %E1%%E2%%E3%%E4%==XXXX GOTO WIN
if %F1%%F2%%F3%%F4%==XXXX GOTO WIN
if %A4%%B4%%C4%%D4%==XXXX GOTO WIN
if %A3%%B3%%C3%%D3%==XXXX GOTO WIN
if %A2%%B2%%C2%%D2%==XXXX GOTO WIN
if %A1%%B1%%C1%%D1%==XXXX GOTO WIN
if %B4%%C4%%D4%%E4%==XXXX GOTO WIN
if %B3%%C3%%D3%%E3%==XXXX GOTO WIN
if %B2%%C2%%D2%%E2%==XXXX GOTO WIN
if %B1%%C1%%D1%%E1%==XXXX GOTO WIN
if %C4%%D4%%E4%%F4%==XXXX GOTO WIN
if %C3%%D3%%E3%%F3%==XXXX GOTO WIN
if %C2%%D2%%E2%%F2%==XXXX GOTO WIN
if %C1%%D1%%F1%%E1%==XXXX GOTO WIN
if %A1%%B2%%C3%%D4%==XXXX GOTO WIN
if %A4%%B3%%C2%%D1%==XXXX GOTO WIN
if %B1%%C2%%D3%%E4%==XXXX GOTO WIN
if %B4%%C3%%D2%%E1%==XXXX GOTO WIN
if %C1%%D2%%E3%%F4%==XXXX GOTO WIN
if %C4%%D3%%E2%%F1%==XXXX GOTO WIN
EXIT /B
I like the idea. Had a go at reducing it down a bit, simplified the testing and output. Only thing left to do is make the AI 'smart'

Connect 4: 6884 bytes

Code: Select all

@Echo off & Rem /* Inspired by: https://www.dostips.com/forum/viewtopic.php?f=3&t=3259#p15721 */
:Start rem /* game returns here after win loss or draw */
 CHCP 65001 > nul & Rem Used for BG display
 Pushd "%userprofile%" & (For /F "Delims=" %%C in ('dir BG*.exe /B /S') Do (%%C Cursor 0)) 2> Nul && POPD & Rem /* hides cursor if bg.exe is installed in userprofile */
 CLS & Endlocal & Setlocal DISABLEdelayedexpansion & rem /* Ensure correct environment for macro definition */
::: Win position table. Hor Vert Diag :::\
 Set "W[0]=[1;1][1;2][1;3][1;4]"&rem  :::H
 Set "W[1]=[1;2][1;3][1;4][1;5]"&rem  :::H
 Set "W[2]=[1;3][1;4][1;5][1;6]"&rem  :::H
 Set "W[3]=[2;1][2;2][2;3][2;4]"&rem  :::H
 Set "W[4]=[2;2][2;3][2;4][2;5]"&rem  :::H
 Set "W[5]=[2;3][2;4][2;5][2;6]"&rem  :::H
 Set "W[6]=[3;1][3;2][3;3][3;4]"&rem  :::H
 Set "W[7]=[3;2][3;3][3;4][3;5]"&rem  :::H
 Set "W[8]=[3;3][3;4][3;5][3;6]"&rem  :::H
 Set "W[9]=[4;1][4;2][4;3][4;4]"&rem  :::H
 Set "W[10]=[4;2][4;3][4;4][4;5]"&rem :::H
 Set "W[11]=[4;3][4;4][4;5][4;6]"&rem :::H
 Set "W[12]=[1;1][2;1][3;1][4;1]"&rem :::V
 Set "W[13]=[1;2][2;2][3;2][4;2]"&rem :::V
 Set "W[14]=[1;3][2;3][3;3][4;3]"&rem :::V
 Set "W[15]=[1;4][2;4][3;4][4;4]"&rem :::V
 Set "W[16]=[1;5][2;5][3;5][4;5]"&rem :::V
 Set "W[17]=[1;6][2;6][3;6][4;6]"&rem :::V
 Set "W[18]=[4;1][3;2][2;3][1;4]"&rem :::D
 Set "W[19]=[4;2][3;3][2;4][1;5]"&rem :::D
 Set "W[20]=[4;3][3;4][2;5][1;6]"&rem :::D
 Set "W[21]=[4;6][3;5][2;4][1;3]"&rem :::D
 Set "W[22]=[4;5][3;4][2;3][1;2]"&rem :::D
 Set "W[23]=[1;1][2;2][3;3][4;4]"&rem :::D
::::::::::::::::::::::: Do not modify :::/
(For /F %%a in ('echo prompt $E ^| cmd')do (Set "/E=%%a")
%= Ascii Escape Character. Do Not Modify. =%)
 Set "?Won=(For /F "Tokens=1,2 Delims==" %%G in  ('Set W[ 2^> Nul') Do (For /F "Tokens=1,2,3,4 Delims=[]" %%w in ("%%H")Do (If "!%%w!!%%x!!%%y!!%%z!"=="$$$$" (<Nul Set /P "=%/E%[5;1H%/E%[90m123456%/E%[0m%/E%[%%wH!$:7=4!%/E%[%%xH!$:7=4!%/E%[%%yH!$:7=4!%/E%[%%zH!$:7=4!"&Echo/%/E%[7;1H%/E%[K!$! Won& (If Not "!Mode!"=="A" (Pause > Nul )Else ( Timeout 4 1> Nul ))&Endlocal&Goto :Start)))) & (IF "!AvMoves!"=="" (Echo/%/E%[7;1H%/E%[K%/E%[90mDraw.%/E%[90m& Timeout 5 > Nul &Endlocal &Goto :Start))"
 Set "Move=(Echo/%/E%[7;1H%/E%[K!$! Move&For /F "Delims=" %%G in ('Choice /N /C:123456EN')Do If "%%G" == "N" (Endlocal & Goto :Start)Else if /I "%%G" == "E" (Endlocal & Exit /B 0)Else Call :Test %%G & For %%e in (!Errorlevel!)Do If "%%e" == "0" (Goto :$Move)Else (<Nul Set /P "=%/E%[%%e;%%GH!$!"&Set "%%e;%%G=$"&Set AvMoves=!AvMoves:"%%e;%%G" =!))"
 Set "AiMove=Call :Brains $" & Rem /* Substring modification is used to replace '$' with the active player */
 Set "Menu=(<Nul Set /P"=%/E%[5;1H%/E%[90m123456%/E%[0m%/E%[1;20H%/E%[K%/E%[COLmSelect mode%/E%[0m:%/E%[2;20H%/E%[K[%/E%[COLm1%/E%[0m] Player%/E%[3;20H%/E%[K[%/E%[COLm2%/E%[0m] Player%/E%[4;20H%/E%[K[%/E%[COLmA%/E%[0m] AI battle%/E%[5;20H%/E%[K[%/E%[36mN%/E%[0m] New%/E%[6;20H%/E%[K[%/E%[36mE%/E%[0m] Exit%/E%[0m%/E%[7;20H%/E%[K[%/E%[COLmV%/E%[0m] View Source code%/E%[7;1H%/E%[36m?%/E%[0m")"
 Set "X=%/E%[32;7mx%/E%[0m"&Set "O=%/E%[31;7mo%/E%[0m"&Set "iX=O"&Set "iO=X"
 Set AvMoves="4;1" "4;2" "4;3" "4;4" "4;5" "4;6" "3;1" "3;2" "3;3" "3;4" "3;5" "3;6" "2;1" "2;2" "2;3" "2;4" "2;5" "2;6" "1;1" "1;2" "1;3" "1;4" "1;5" "1;6" &Rem Trailing space required
 Set "ForPlayer=For /F "Tokens=1,2 Delims==" %%G in  ('Set W[ 2^> Nul') Do (For /F "Tokens=1,2,3,4 Delims=[]" %%w in ("%%H")Do (If "!%%w!!%%x!!%%y!!%%z!"=="@" ("
 Set "ONfind=Set "AvMoves=!AvMoves:"%%#;%%d" =!" & Exit /B 0"
 Set "?test=If "!%%$V!"=="" (For /F "Tokens=2 Delims=;" %%d in ("%%$V")Do For /L %%# in (4 -1 1)Do (For /F "Delims=" %%i in ('Set /A "i=%%#+1"')Do if not "%%~i"=="5" (If not "!%%i;%%d!"=="" If "!%%#;%%d!"=="" (<Nul Set /P "=%/E%[%%#;%%dH!e$!"&Set "%%#;%%d=!$!" & %OnFind%))Else (If "!%%#;%%d!"=="" (<Nul Set /P "=%/E%[%%#;%%dH!e$!"&Set "%%#;%%d=!$!" & %OnFind%))))"
 Set "OnFind="
 Setlocal EnableDelayedExpansion & rem /* Establish environment for macro expansion */
 (For %%G in (!AvMoves!)Do <Nul Set /P"=%/E%[%%~GH%/E%[34m◘%/E%[0m")
 %Menu:COL=36% & rem /* display active game menu options */
 Title Connect 4
 (For /F "Delims=" %%G in ('Choice /T 10 /D A /N /C:NA21VE')Do If /I "%%G"=="N" (Endlocal & Goto :Start)Else If /I "%%G"=="E" (Endlocal & Exit /B 0)Else Set "Mode=%%G")
 If "%Mode%"=="V" (Mode 1000 & TYPE "%~F0" & Timeout 10 /NoBreak > Nul & Endlocal & Echo/&Echo/Continue & Pause > Nul & Goto :Start)
 %Menu:COL=90% & rem /* display which game menu options become inactive */
:XMove rem /* [X][O]Move Labels used as turn loop and to control scriptflow for invalid moves. with the aid of substring modification */
 (If "%Mode%" == "A" (TITLE AI Battle & <Nul Set /P "=%/E%[5;20H%/E%[K[%/E%[90mN%/E%[0m] New%/E%[5;1H%/E%[90m123456%/E%[0m%/E%[6;20H%/E%[K[%/E%[90mE%/E%[0m] Exit"& %AIMove:$=X%)Else (<Nul Set /P "=%/E%[5;1H%/E%[32m123456%/E%[0m" & %Move:$=X%)) & %?won:$=X%
:OMove rem /* AI was dumb-ish. lookup table for 'smart' comparison of open moves vs player occupied coordinates has been implemented */
 (If "%Mode%" == "2" (If Not "%Mode%" == "A" <Nul Set /P "=%/E%[5;1H%/E%[31m123456%/E%[0m" & %Move:$=O%) Else %AIMove:$=O%) & %?won:$=O%
Goto :XMove
:Test rem /* returns first avialable Y coordinate for the attempted X coordinate via Errorlevel or 0 for no valid coordinate */
 For /L %%# in (4,-1,1)Do (Echo/"!AvMoves!"| %__AppDir__%findstr.exe /LIC:"%%#;%~1" > Nul 2> Nul && Exit /B %%#)
Exit /B 0
:Brains rem /* AI Calls for loop conditional test block to find an appropriate block / advance coordinate */
 Set "$=%1"& Set "e$=!%1!"& Set "$o=!i%1!"
 Call :ForeThought
 If "%Errorlevel%"=="0" (Exit /B 0)
:FindAIM rem /* test for and fill first valid Y position found at random x axis. repeats until position found */
 (Echo/%/E%[7;1H%/E%[K!%1! Move& For /F "Delims=" %%G in ('Set /A "i=!Random! %%6 + 1"')Do (Call :Test %%G & For %%e in (!Errorlevel!)Do If "%%e" == "0" (Goto :FindAIM)Else (<Nul Set /P "=%/E%[%%e;%%GH!%1!"&Set "%%e;%%G=%1"&Set "AvMoves=!AvMoves:"%%e;%%G" =!"&Exit /B 0)))
 Exit /B 0
:ForeThought rem /* Iterate over W[ win pos array, test for a single empty position in a winning 4 point line and attempt to fill first one found - prioritising Ai's own winning sequence.
rem - cont. - On finding valid 4 coordinate return to move loops. If none, test for 2 unoccupied positions in an AI occupied position set. to advance AI */
%ForPlayer:@=!$!!$!!$!%
   %?test:$V=w% Else %?test:$V=x% Else %?test:$V=y% Else %?test:$V=z%
)))
%ForPlayer:@=!$o!!$o!!$o!%
   %?test:$V=w% Else %?test:$V=x% Else %?test:$V=y% Else %?test:$V=z%
)))
%ForPlayer:@=!$o!!$o!%
   %?test:$V=w% Else %?test:$V=x% Else %?test:$V=y% Else %?test:$V=z%
)))
%ForPlayer:@=!$!!$!%
   %?test:$V=w% Else %?test:$V=x% Else %?test:$V=y% Else %?test:$V=z%
)))
Exit /B 1
Supports 1 or 2 players or watch an 'AI' battle

*Edit: ?Macro's adjusted to invert the color of a connected line on win.
I like the idea. Had a go at reducing it down a bit, simplified the testing and output. Only thing left to do is make the AI 'smart'
- AI has been given a brain. Code updated
AI has been given a brain
- Ai's brain was malformed. surgery complete
Now tests if the square beneath an intended block move is empty prior to making the block.
AI move priority is:
1) Complete any available 4 point line as a winning move
2) Block the first encountered 4 point line to prevent a players winning move
3) attempt to Block the first encountered potential 3 point line to inhibit player board development
4) take the first available move to make a 3 point line of it's own and develop own position
forethought testing function exits with errorlevel 0 when a valid move is found which is used to exit the AI brain function.
Errorlevel 1 is returned if if no move found in which case:
5) take first available random move

- Available Move positions are tracked using the AvMoves variable, with the coordinates of a succesful move removed from AvMoves using substring modification
- Player and random moves are checked against AvMoves in the :Test subroutine, which uses findstr to determine if there is Y;X coordinate available for an attempted X move.
- Y Coordinate is returned via errorlevel, and if no Y available for the given X, errorlevel 0 is returned - which rejects the x coordinate move.
- AvMoves is also used at the start of each game to display the 'board'
- Each occupied y;x coordinate is defined with 'X' for player or 'O' for opponent when a move is taken for use in the :Brains Array tests, with endlocal / setlocal being used to undefine them at the end of each round
- macro's are used throughout the script, predominately out of laziness. Allows reuse of repetitive code in a concise manner, supplying the relevent value the macro iterates over using substring modifiication.

Golfed version with more robust, if slower AI (5557 bytes):

Code: Select all

@Echo off
:Start
 CHCP 65001 > nul & CLS & Mode 40,8
 Pushd "%userprofile%" &(For /F "Delims=" %%C in ('dir BG*.exe /B /S') Do (%%C Cursor 0)) 2> Nul && POPD
 CLS &Endlocal &Setlocal DISABLEdelayedexpansion
 For /F %%a in ('echo prompt $E ^| cmd')do (Set "/E=%%a[")
 Set "?Won=(For /F "Tokens=1,2 Delims==" %%G in  ('Set W[ 2^> Nul') Do (For /F "Tokens=1,2,3,4 Delims=[]" %%w in ("%%H")Do (If "!%%w!!%%x!!%%y!!%%z!"=="$$$$" (<Nul Set /P "=%/E%5;1H%/E%90m123456%/E%0m%/E%%%wH!$:7=4!%/E%%%xH!$:7=4!%/E%%%yH!$:7=4!%/E%%%zH!$:7=4!"&Echo/%/E%7;1H%/E%K!$! Won& (If Not "!Mode!"=="A" (Pause > Nul )Else ( Timeout 4 1> Nul ))&Endlocal&Goto :Start)))) & (IF "!AvMoves!"=="" (Echo/%/E%7;1H%/E%K%/E%90mDraw.%/E%90m& Timeout 5 > Nul &Endlocal &Goto :Start))"
 Set "Move=(Echo/%/E%7;1H%/E%K!$! Move&For /F "Delims=" %%G in ('Choice /N /C:123456EN')Do If "%%G"=="N" (Endlocal & Goto :Start)Else if /I "%%G"=="E" (Endlocal & Exit /B 0)Else Call :Test %%G & For %%e in (!Errorlevel!)Do If "%%e"=="0" (Goto :$Move)Else (<Nul Set /P "=%/E%%%e;%%GH!$!"&Set "%%e;%%G=$"&Set AvMoves=!AvMoves:"%%e;%%G" =!))"
 Set "AiMove=Call :Brains $"
 Set "Menu=(<Nul Set /P"=%/E%5;1H%/E%90m123456%/E%0m%/E%1;20H%/E%K%/E%COLmSelect mode%/E%0m:%/E%2;20H%/E%K[%/E%COLm1%/E%0m] Player%/E%3;20H%/E%K[%/E%COLm2%/E%0m] Player%/E%4;20H%/E%K[%/E%COLmA%/E%0m] AI battle%/E%5;20H%/E%K[%/E%36mN%/E%0m] New%/E%6;20H%/E%K[%/E%36mE%/E%0m] Exit%/E%0m%/E%7;20H%/E%K[%/E%COLmV%/E%0m] View Source code%/E%7;1H%/E%36m?%/E%0m")"
 Set "X=%/E%32;7mx%/E%0m"&Set "O=%/E%31;7mo%/E%0m"&Set "iX=O"&Set "iO=X"
 Set AvMoves="4;1" "4;2" "4;3" "4;4" "4;5" "4;6" "3;1" "3;2" "3;3" "3;4" "3;5" "3;6" "2;1" "2;2" "2;3" "2;4" "2;5" "2;6" "1;1" "1;2" "1;3" "1;4" "1;5" "1;6" &Rem Trailing space required
 Set "IfLine=For /F "Tokens=1,2 Delims==" %%G in  ('Set W[ 2^> Nul') Do (For /F "Tokens=1,2,3,4 Delims=[]" %%w in ("%%H")Do (If "!%%w!!%%x!!%%y!!%%z!"=="@" ("
 Set "ONfind=Set "AvMoves=!AvMoves:"%%#;%%d" =!" & Exit /B 0"
 Set "?Next= (Set /A "_y=%%~#-1,_x=%%~d"&For /L %%n in (0 1 23)Do For /F "Delims=" %%X in (' Echo/"!W[%%n]!" ^| Findstr 2^> Nul /LIC:"!_y!;!_x!" ')Do For /F "Tokens=1,2,3,4 Delims=[]" %%1 in ("!W[%%n]!")Do If "!%%~1!!%%~2!!%%~3!!%%~4!" == "!$o!!$o!!$o!" (Exit /B 1))"
 Set "?AIw=If "!%%$V!"=="" (For /F "Tokens=2 Delims=;" %%d in ("%%$V")Do For /L %%# in (4 -1 1)Do (For /F "Delims=" %%i in ('Set /A "i=%%#+1"')Do if not "%%~i"=="5" (If not "!%%i;%%d!"=="" If "!%%#;%%d!"=="" (<Nul Set /P "=%/E%%%#;%%dH!e$!"&Set "%%#;%%d=!$!" & %OnFind%))Else (If "!%%#;%%d!"=="" (<Nul Set /P "=%/E%%%#;%%dH!e$!"&Set "%%#;%%d=!$!" & %OnFind%))))"
 Set "?is=If "!%%$V!"=="" (For /F "Tokens=2 Delims=;" %%d in ("%%$V")Do For /L %%# in (4 -1 1)Do (For /F "Delims=" %%i in ('Set /A "i=%%#+1"')Do if not "%%~i"=="5" (If not "!%%i;%%d!"=="" If "!%%#;%%d!"=="" (%?Next%&<Nul Set /P "=%/E%%%#;%%dH!e$!"&Set "%%#;%%d=!$!" & %OnFind%))Else (If "!%%#;%%d!"=="" (%?Next%&<Nul Set /P "=%/E%%%#;%%dH!e$!"&Set "%%#;%%d=!$!" & %OnFind%))))"
 Set "List_DEF=Set "#$L=0"&Set "$$L="&For %%n in (1 2)Do if %%n==2 (For %%G in (!$L!)Do (Set "%%~G" > Nul &Set /A "#$L+=1"))Else Set $L="
 Setlocal EnableDelayedExpansion
 %List_DEF:$L=WinLines% "W[0]=[1;1][1;2][1;3][1;4]" "W[1]=[1;2][1;3][1;4][1;5]" "W[2]=[1;3][1;4][1;5][1;6]" "W[3]=[2;1][2;2][2;3][2;4]" "W[4]=[2;2][2;3][2;4][2;5]" "W[5]=[2;3][2;4][2;5][2;6]" "W[6]=[3;1][3;2][3;3][3;4]" "W[7]=[3;2][3;3][3;4][3;5]" "W[8]=[3;3][3;4][3;5][3;6]" "W[9]=[4;1][4;2][4;3][4;4]" "W[10]=[4;2][4;3][4;4][4;5]" "W[11]=[4;3][4;4][4;5][4;6]" "W[12]=[1;1][2;1][3;1][4;1]" "W[13]=[1;2][2;2][3;2][4;2]" "W[14]=[1;3][2;3][3;3][4;3]" "W[15]=[1;4][2;4][3;4][4;4]" "W[16]=[1;5][2;5][3;5][4;5]" "W[17]=[1;6][2;6][3;6][4;6]" "W[18]=[4;1][3;2][2;3][1;4]" "W[19]=[4;2][3;3][2;4][1;5]" "W[20]=[4;3][3;4][2;5][1;6]" "W[21]=[4;6][3;5][2;4][1;3]" "W[22]=[4;5][3;4][2;3][1;2]" "W[23]=[1;1][2;2][3;3][4;4]"
 (For %%G in (!AvMoves!)Do <Nul Set /P"=%/E%%%~GH%/E%34m◘%/E%0m")
 %Menu:COL=36%& Title Connect 4
 (For /F "Delims=" %%G in ('Choice /T 10 /D A /N /C:NA21VE')Do If /I "%%G"=="N" (Endlocal & Goto :Start)Else If /I "%%G"=="E" (Endlocal & Exit /B 0)Else Set "Mode=%%G")
 If "%Mode%"=="V" (notepad.exe "%~F0" & Endlocal & Echo/&Echo/Continue & Pause > Nul & Goto :Start)
 %Menu:COL=90%
:XMove
 (If "%Mode%"=="A" (TITLE AI Battle & <Nul Set /P "=%/E%5;20H%/E%K[%/E%90mN%/E%0m] New%/E%5;1H%/E%90m123456%/E%0m%/E%6;20H%/E%K[%/E%90mE%/E%0m] Exit"& %AIMove:$=X%)Else (<Nul Set /P "=%/E%5;1H%/E%32m123456%/E%0m" & %Move:$=X%)) & %?won:$=X%
:OMove
 (If "%Mode%"=="2" (If Not "%Mode%"=="A" <Nul Set /P "=%/E%5;1H%/E%31m123456%/E%0m" & %Move:$=O%) Else %AIMove:$=O%) & %?won:$=O%
Goto :XMove
:Test
 For /L %%# in (4,-1,1)Do (Echo/"!AvMoves!"| %__AppDir__%findstr.exe /LIC:"%%#;%~1" > Nul 2> Nul && Exit /B %%#)
Exit /B 0
:Brains
 Set "$=%1"& Set "e$=!%1!"& Set "$o=!i%1!"
 Call :ForMove & If "!Errorlevel!"=="0" (Exit /B 0)
:FindAIM
 (Echo/%/E%7;1H%/E%K!%1! Move& For /F "Delims=" %%G in ('Set /A "i=!Random! %%6 + 1"')Do (Call :Test %%G & For %%e in (!Errorlevel!)Do If "%%e" == "0" (Goto :FindAIM)Else (<Nul Set /P "=%/E%%%e;%%GH!%1!"&Set "%%e;%%G=%1"&Set "AvMoves=!AvMoves:"%%e;%%G" =!"&Exit /B 0)))
 Exit /B 0
:ForMove
%IfLine:@=!$!!$!!$!% %?AIw:$V=w% Else %?AIw:$V=x% Else %?AIw:$V=y% Else %?AIw:$V=z%)))
%IfLine:@=!$o!!$o!!$o!% %?is:$V=w% Else %?is:$V=x% Else %?is:$V=y% Else %?is:$V=z% )))
%IfLine:@=!$o!!$o!%     %?is:$V=w% Else %?is:$V=x% Else %?is:$V=y% Else %?is:$V=z% )))
%IfLine:@=!$!!$!%       %?is:$V=w% Else %?is:$V=x% Else %?is:$V=y% Else %?is:$V=z% )))
Exit /B 1

T3RRY
Posts: 249
Joined: 06 May 2020 10:14

Re: Batch Games

#19 Post by T3RRY » 01 Nov 2020 09:31

Decided to try my hand at a pure batch Tetris [ no powershell or external exe's at this point ].
Game uses Vt Escape control character - so unfortunately windows 10 only

I was somewhat lazy with the piece rotation routine- I adapted some routines for flipping / mirroring 'images' from one of my previous projects in order to simulate 90 Degree rotation. I'm sure it could be done more efficiently though.

Display elements [border, control legend and pieces] are defined to their respective coordinates with a prefix of } and output to a file to be displayed via the type command - enabling smooth, flicker-free animation

Collision detection is achieved by detemining if all new y;x coordinates for an attempted move are undefined - If true, the move is allowed.
Once a piece is Set in place - triggered by a downward move encountering a non empty coordinate during an attempted move, each cell coordinate for the current piece is defined with the display value for the piece. When a line is matched, for each line above the matched line, values from each cell are shifted down by one until the matched line is reached. A tempory variable is used to prevent the cells being iterated over from having their values overriden before the iteration is complete.

Code: Select all

@Echo off
 Setlocal EnableExtensions DISABLEdelayedexpansion
 wmic OS get OSArchitecture,caption | FIND "10" >nul || (ECHO/Windows 10 required for ascii escape codes & Endlocal & Exit /B)
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
 Title Tetris by T3RRY & rem commenced 30/10/2020
rem ::: 30/10/2020 Piece creation, basic collision detection, piece movement implemented.
rem ::: 31/10/2020 New piece and Game over trigger tests added.
rem ::: 31/10/2020 Color, Piece rotation added
rem ::: 01/11/2020 Function to test for a completed line added.
rem ::: 01/11/2020  Scoring system added
:::::::: [ TO BE ACTIONED ] :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
rem ::: Getkeys controller version with variable delay for speed increase based on score
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
rem ---------------------------------------------------- /* ASCII escape code definition */
 for /F "delims=#" %%a in ('"prompt #$E# & for %%a in (1) do rem"') do set "\E=%%a"
rem ------------------------------------------------ /* ensure } reference var undefined */
 (For /F "Tokens=1,2 Delims==" %%G in ('Set "}"')Do Set "%%G=") 2> nul
rem ------------------------------------------------------------------ /* define macro's */
 Set "nPiece[1]=Set /A "x1=6,y1=1,x2=6,y2=2,x3=6,y3=3,x4=6,y4=4""
 Set "nPiece[2]=Set /A "x1=6,y1=1,x2=7,y2=1,x3=6,y3=2,x4=7,y4=2""
 Set "nPiece[3]=Set /A "x1=6,y1=1,x2=7,y2=1,x3=7,y3=2,x4=7,y4=3""
 Set "nPiece[4]=Set /A "x1=6,y1=1,x2=6,y2=2,x3=6,y3=3,x4=7,y4=1""
 Set "nPiece[5]=Set /A "x1=6,y1=1,x2=6,y2=2,x3=7,y3=2,x4=7,y4=3""
 Set "nPiece[6]=Set /A "x1=7,y1=1,x2=7,y2=2,x3=6,y3=2,x4=6,y4=3""
 Set "nPiece[7]=Set /A "x1=6,y1=1,x2=6,y2=2,x3=7,y3=2,x4=6,y4=3""
 Set "MoveLeft=Set "valid=0"&Set /A "_x1=!x1!-1,_x2=!x2!-1,_x3=!x3!-1,_x4=!x4!-1" & (For %%v in ("!y1!;!_x1!" "!y2!;!_x2!" "!y3!;!_x3!" "!y4!;!_x4!")Do (IF "!}%%~v!" == "" (Set /A "Valid=!Valid! + 1"))) & If "!Valid!" == "4" (Set /A "x1-=1,x2-=1,x3-=1,x4-=1")"
 Set "MoveRight=Set "valid=0"&Set /A "_x1=!x1!+1,_x2=!x2!+1,_x3=!x3!+1,_x4=!x4!+1" & (For %%v in ("!y1!;!_x1!" "!y2!;!_x2!" "!y3!;!_x3!" "!y4!;!_x4!")Do (IF "!}%%~v!" == "" (Set /A "Valid=!Valid! + 1"))) & If "!Valid!" == "4" (Set /A "x1+=1,x2+=1,x3+=1,x4+=1")"
 Set "MoveDown=Set "valid=0"&Set /A "_y1=!y1!+1,_y2=!y2!+1,_y3=!y3!+1,_y4=!y4!+1" & (For %%v in ("!_y1!;!x1!" "!_y2!;!x2!" "!_y3!;!x3!" "!_y4!;!x4!")Do (IF "!}%%~v!" == "" (Set /A "Valid=!Valid! + 1"))) & (If "!Valid!" == "4" (Set /A "y1+=1,y2+=1,y3+=1,y4+=1")Else (Set /A "Score+=10"&Set "}!y1!;!x1!=%\E%[!y1!;!x1!H%\E%[3!pce!mX%\E%[0m"& Set "}!y2!;!x2!=%\E%[!y2!;!x2!H%\E%[3!pce!mX%\E%[0m"& Set "}!y3!;!x3!=%\E%[!y3!;!x3!H%\E%[3!pce!mX%\E%[0m"& Set "}!y4!;!x4!=%\E%[!y4!;!x4!H%\E%[3!pce!mX%\E%[0m"& >"%TEMP%\tetris.~tmp" (For /F "Tokens=2* Delims==" %%G in ('Set }')Do Echo/%%G) & If "!y1!" == "1" (Goto :Gameover)Else ( Call :isMatch & Goto :newpiece )))"
 Set "ShowPiece=<Nul Set /P "=%\E%[3!pce!m%\E%[!y1!;!x1!HX%\E%[!y2!;!x2!HX%\E%[!y3!;!x3!HX%\E%[!y4!;!x4!HX%\E%[0m""
 Set "HideLast=<Nul Set /P "=%\E%[!ly1!;!lx1!H %\E%[!ly2!;!lx2!H %\E%[!ly3!;!lx3!H %\E%[!ly4!;!lx4!H %\E%[0m""
rem ---------------------------------------------------------- /* Define Control Display */
 Set "}1;20=%\E%[1;20H%\E%[90mScore: !Score!"
 Set "}3;20=%\E%[3;20H%\E%[33mControls:"
 Set "}4;20=%\E%[4;20HA - move Left"
 Set "}5;20=%\E%[5;20HS - move Down"
 Set "}6;20=%\E%[6;20HD - move Right"
 Set "}7;20=%\E%[7;20HR - Rotate"
 Set "}8;20=%\E%[8;20HV - Drop Piece"
 Set "}9;20=%\E%[9;20H%\E%[32mE - Exit%\E%[0m"
rem -------------------- /* Establish environment for macro usage and code block actions */
 Setlocal EnableDelayedExpansion
 mode 60,42
rem ----------------------------------------------------------------- /* hide the cursor */
 <nul Set /P "=%\E%[?25l"
rem --------------------------------------------------------------- /* define the border */
 For %%s in (1 12)Do For /L %%n in (1 1 41) Do (
  Set "}%%n;%%s=%\E%[%%n;%%sH%\E%[90m.%\E%[0m"
  If %%n==41 For /L %%b in (2 1 11)Do (
   Set "}%%n;%%b=%\E%[%%n;%%bH%\E%[90m.%\E%[0m"
  )
 )
 >"%TEMP%\tetris.~tmp" (For /F "Tokens=2* Delims==" %%G in ('Set "}"')Do Echo/%%G)
:newpiece
 CLS
 Type "%TEMP%\tetris.~tmp"
 Set /A pce=%random% %%7 + 1
 !nPiece[%pce%]!
 %ShowPiece%
:loop
rem ----------------------------- /* get pieces last y;x vals to blank out with hidelast */
 For %%c in (y x)Do For %%i in (1 2 3 4)Do Set "l%%c%%i=!%%c%%i!"
rem ----------------------------------------------------------------------- /* game pace */
 Set /A tick+=1
 If "!tick!" == "4" (
  Set "tick=0"
  %movedown%
 )
rem ----------------------------------------------------------------- /* game controller */
 For /F "delims=" %%G in ('choice /N /T 1 /C:prevasd /D S') Do (
  If "%%G" == "E" (TITLE Quit Y\N?&For /F "Delims=" %%C in ('Choice /N /C:YN')Do if %%C==Y (Title & Goto :quit)Else (Title Tetris by T3RRY))
  If "%%G" == "A" %Moveleft%
  If "%%G" == "S" %Movedown%
  If "%%G" == "D" %Moveright%
  If "%%G" == "P" ( Title Paused & Pause > nul & Title Tetris by T3RRY )
  If "%%G" == "V" (For /L %%s in (1 1 39)Do %MoveDown%)
rem ------------------------------------------------------------ /* start rotation logic */
rem --- [ Horizontal flip followed by mirror to simulate 90 degree rotation. ]
  If "%%G" == "R" (
rem ----------------------------------------------------------------- /* flip horizontal */
   Set /A midX=500,midY=500
   For %%A in ("!y1!;!x1!" "!y2!;!x2!" "!y3!;!x3!" "!y4!;!x4!") Do (
    For /F "Tokens=1,2 Delims=;" %%X in ("%%~A") Do (
     Set /A "oY=%%~X"
     Set /A "oX=%%~Y"
    )
    If !oY! LSS !midY! Set /A "midY=!oY!"
    If !oX! LSS !midX! Set /A "midX=!oX!"
   )
   Set "pixel=0"
   For %%B in ("!y1!;!x1!" "!y2!;!x2!" "!y3!;!x3!" "!y4!;!x4!") Do (
    Set /A pixel+=1
    For /F "Tokens=1,2 Delims=;" %%r in ("%%~B") Do (
     Set /A "ny!pixel!=(%%~s-midX)+!midY!,nx!pixel!=(%%~r-!midY!)+!midX!"
   ))
rem -------------------------------------------------------------------------- /* mirror */
  Set "pixel=0"
  Set /A lmidX=500,umidX=0
  For %%C in (!nx1! !nx2! !nx3! !nx4!) Do (
   If %%C LSS !lmidX! (Set /A "lmidX=%%C")
   If %%C GTR !umidX! (Set /A "umidX=%%C")
  )
  Set /A "Mid.X=( !lmidX! + !umidX! ) / 2"
  For %%X in (!nx1! !nx2! !nx3! !nx4!) Do (
   Set /A "pixel=!pixel! + 1"
   Set /A "nx!pixel!=%%X + 1"
   IF %%X LSS !Mid.X! (Set /A "nx!pixel!= %%X + ((!Mid.X!-%%X) * 2) + 1")
   IF %%X GTR !Mid.X! (Set /A "nx!pixel!= %%X - ((%%X-!Mid.X!) * 2) + 1")
  )
rem ------------------------------------------- /* collision detection for rotated coords */
   Set "valid=0"
   For /L %%i in (1 1 4)Do (
    for %%c in ("!ny%%i!;!nx%%i!")Do If "!}%%~c!" == "" (
     Set /A "valid=!valid!+1"
  ))
   If "!valid!" == "4" (
    For %%v in (x y)Do For /L %%i in (1 1 4)Do (
      Set "%%v%%i=!n%%v%%i!"
 )))
rem --------------------------------------------------------------- /* end rotation logic */
rem ------------------------------------------------------------ /* display current state */
  TYPE "%TEMP%\tetris.~tmp"
  %HideLast%
  %ShowPiece%
)
Goto :loop
rem ----------------------------- /* test for completed line when a piece is set in place */
:isMatch
 Set "match=0"
 Set "ymin=42"
 Set "ymax=0"
 For %%n in (!y1! !y2! !y3! !y4!)Do (
  if %%n gtr !ymax! Set "ymax=%%n"
  if %%n lss !ymin! Set "ymin=%%n"
 )
rem ------------- /* test completion of line for each y coord for last piece set in place */
 For /L %%i in (!ymin! 1 !ymax!)Do (
  Set "#of10=0"
  For /L %%c in (2 1 11)Do If Not "!}%%i;%%c!" == "" Set /A "#of10=!#of10!+1"
  If "!#of10!" == "10" (
   Set /A "match=!match!+1"
   Set /A "Score+=(150 * !match!)"
   Set /A "lineabove=%%i-1"
   For /L %%n in (0 1 !lineabove!) Do (
    Set /A "offset=%%n+1"
rem -------------------------- /* transfer updated coord values after iteration complete */
    For %%o in (!offset!)Do For /L %%x in (2 1 11) Do If not "!}%%n;%%x!" == "" (
     Set "n}%%o;%%x=!}%%n;%%x:[%%n;=[%%o;!"
    ) Else (
     Set "n}%%o;%%x="
   ))
   For /L %%Y in (1 1 %%i) Do For /L %%X in (2 1 11) Do Set "}%%Y;%%X=!n}%%Y;%%X!"
   CLS
 ))
rem ----------------------------- /* Update display values for each cell to display file */
 >"%TEMP%\tetris.~tmp" (For /F "Tokens=2* Delims==" %%G in ('Set "}"')Do Echo/%%G)
Exit /B 0
:gameover
 Echo/| CHOICE /N 2> nul & rem BEL
 Echo/%\E%[2;20H%\E%[31mGame Over.%\E%[31m
 Pause > Nul
:quit
rem -------------------------------------- /* restore the cursor ; End of script cleanup */
 <nul Set /P "=%\E%[?25h"
 Del /Q	"%TEMP%\tetris.~tmp" 2> nul
 Endlocal
 Endlocal
 cls
 Title
Goto :Eof
Edit:
Getkeys.exe version now available for download - Uses Aacini's {Antonio's} Getkey.exe to enable use of extended keys
https://drive.google.com/file/d/18M21So ... sp=sharing
Watch:
https://www.youtube.com/watch?v=Vwo00t7HH2o

Controls for getkey version:
arrow keys for left right down
space = rotate
escape = quit
enter = pause
PageDown = Drop Piece
Attachments
Tetris.txt
(8.62 KiB) Downloaded 512 times
Last edited by T3RRY on 07 Dec 2020 03:57, edited 1 time in total.

Aacini
Expert
Posts: 1910
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Batch Games

#20 Post by Aacini » 08 Nov 2020 09:48

Perhaps you could be interested in my Tetris game in a pure Batch file that uses no additional or auxiliary programs. There is also a version of Tetris in color that uses a PowerShell engine to Read arrow keys and show color text in an efficient way.

Antonio

Image

T3RRY
Posts: 249
Joined: 06 May 2020 10:14

Re: Batch Games

#21 Post by T3RRY » 08 Nov 2020 16:29

Aacini wrote:
08 Nov 2020 09:48
Perhaps you could be interested in my Tetris game in a pure Batch file that uses no additional or auxiliary programs. There is also a version of Tetris in color that uses a PowerShell engine to Read arrow keys and show color text in an efficient way.

Antonio

Hi Antonio, had already seen your versions - the idea of a more efficient pure batch controller is tempting. The PowerShell engine is definitely worth trying out or offering as an alternative.

Making Tetris was a thought experiment for me in how I might approach it using VT codes. As such the methodology I've used is somewhat different to other versions of Tetris I've seen out there.

ShadowThief
Expert
Posts: 1166
Joined: 06 Sep 2013 21:28
Location: Virginia, United States

Re: Batch Games

#22 Post by ShadowThief » 08 Nov 2020 16:45

Once upon a time, I took a bunch of games written in BASIC and ported them to batch: https://github.com/sintrode/batch_minigames

Treasure.bat is there because there was a topic on there about code for calculating square roots that I wanted to try out.

T3RRY
Posts: 249
Joined: 06 May 2020 10:14

Re: Batch Games

#23 Post by T3RRY » 06 Dec 2020 10:12

What started out from a request for a tutorial became yet another batch game, A version of Snake for windows 10

Game requires getkey.exe to be in a folder or childfolder the game is stored in; If downloaded from the link in the games header, Both snake.bat and getkey.exe are included

Code: Select all

@Echo off
==================================================
::: Snake by T3RRY Version 1.2 07/12/2020
::: To play, Download from https://drive.google.com/file/d/1_ivtZsSzxEiig3bdCurNFg7SqGES4T53/view?usp=sharing
::: Download contains:
::::::::::::::::::::::::::::::::::::::::::::::::::
::: Getkey.Exe by Antonio {https://stackoverflow.com/users/778560/aacini} for Extended key controls.
::: Snake.bat by T3RRY {https://stackoverflow.com/users/12343998/t3rr0r}
==================================================
rem /* test environment supports macro definition */
 If "!![" == "[" (Echo/Delayed expansion Must not be enabled prior to starting %~n0.bat & Pause & Exit /B 0)
rem /* Enable Codepage for unicode characters */
CHCP 65001 > nul
(Set \n=^^^

%= Macro Newline Do not Modify this code block =%)
(Set COMMENT=rem {i} ^^^

%= Macro Comment line. Do not modify this code block =%)
rem /* use wmic output with find to test if system is windows 10. Exit if not */
 wmic OS get OSArchitecture,caption | FIND "10" > nul || (ECHO/Windows 10 required for ascii escape codes & Exit /B)
rem /* Define Escape character */
 for /F "delims=#" %%a in ('"prompt #$E# & for %%a in (1) do rem"') do set "\E=%%a"
rem ------/* Getkeys controller. allows use of extended keys */
 For /F "Delims=" %%C in ('dir "%~dp0*GetKey.exe" /B /S') Do If not defined GetKey Set "GetKey="%%C" /n"
 Echo/%GetKey%|findstr.exe /LIC:"GetKey.exe" > nul || (Echo/GetKey.Exe not found in Directory. Game cannot be played without GetKey.exe &Pause &Exit /B 0)
rem /* Ensure array used to display screen elements is undefined. */
 (For /F "Tokens=1,2 Delims==" %%G in ('Set "}" 2^> Nul ')Do Set "%%~G=") 2> nul
rem /* game background data file */
If not exist "%TEMP%" (Set "Save.Dir=%~dp0")Else Set "Save.Dir=%TEMP%\"
 Set Background="%Save.Dir%%~n0_background.~tmp"
 Set Foreground="%Save.Dir%%~n0_foreground.~tmp"
 Set Score.Save="%Save.Dir%%~n0_highscore.~sav"
rem /* Console dimensions */
 Set /A ConWidth=80,ConHieght=26
 mode %ConWidth%,%ConHieght%
=============================================================================================
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Macros to define Playfield Border and display
rem /* output defined }!y!;!x! coordinates to file to be typed for display; Hide cmd Cursor */
 Set "UPDATE.Background=Set /A ".End=!.Ymax! + 1" & ((For /F "Tokens=2* Delims==" %%G in ('Set "}"')Do (< nul Set /P "=%%~G") & < nul Set /P "=%\E%[!.END!;1H%\E%[0m%\E%[?25l")) >%Background% & Type %Background%"
::: Border cells are defined to }Ypos;Xpos for use in collision detection.
rem /* Usage: %Background.Border%{VTcolor}{.Xmin}{.Xmax}{.Ymin}{.Ymax}{.Char} */
 Set Background.Border=Set "Border=" ^& For %%n in (1 2)Do If %%n==2 (%\n%
  %COMMENT:{i}= reset arg Border and capture new value \n%
  For /F "Tokens=1,2,3,4,5,6 Delims={}" %%G in ("!Border!")Do If not "%%L" == "" (%\n%
  %COMMENT:{i}= if 6 args present store in return vars \n%
   Set ".Xmin=%%H"^&Set ".Xmax=%%I"^&Set ".Ymin=%%J"^&Set ".Ymax=%%K"^&Set ".Char=%%L"%\n%
  %COMMENT:{i}= Sides - for .Xmin .Xmax do for each in .Ymin to .Ymax Define border cell \n%
   For %%w in (%%H %%I)Do for /L %%h in (%%J,1,%%K)Do (%\n%
    Set "}%%h;%%w=%\E%[%%h;%%wH%\E%[%%~Gm%%~L"%\n%
  %COMMENT:{i}= Top + Base - for each in .Xmin to .Xmax do IF .Ymin or .Ymax Define border cell \n%
    For %%i in (%%J %%K)Do If %%h Equ %%i (%\n%
     For /L %%W in (%%H 1 %%I)Do (%\n%
      Set "}%%h;%%W=%\E%[%%h;%%WH%\E%[%%~Gm%%~L"%\n%
     )%\n%
    )%\n%
   )%\n%
  )Else (Echo/Missing Args for %%Background.Border%%^& Pause ^> nul)%\n%
 )Else Set Border=
::: Stores return values in Vars: .Xmin .Xmax .Ymin .Ymax .Char
=============================================================================================
:::::: SNAKE display macro. Show / Hide
 Set show.snake=For %%n in (1 2)Do if %%n==2 ( %\n%
  %COMMENT:{i}= Capture Args for {snake.head} and {snake.tail} \n%
  (For /F "Tokens=1,2 Delims={}" %%A in ("!Chars!")Do ( %\n%
  %COMMENT:{i}= Substitute hash value in head variable for {snake.head} and output \n%
   For %%h in ("!head:#=%%~A!")Do ( %\n%
    ^<nul Set /P "=%%~h%\E%[!.End!H" %\n%
   ) %\n%
   For %%t in (!tail!)Do ( %\n%
  %COMMENT:{i}= for each coordinate in tail list output {snake.tail} \n%
    ^<nul Set /P "=%\E%[%%~tH%\E%[!Tail.Color!m%%B%\E%[!.End!H%\E%[0m" %\n%
   ) %\n%
  %COMMENT:{i}= redirect all output to file and type once complete \n%
  ))^>%Foreground% ^& Type %foreground% %\n%
 )Else Set Chars=
=============================================================================================
::: Getkey key errorlevel returns:
:::::: Movement Macros with Collision detection.
 Set "Left={x}{-}"
 Set "Right={x}{+}"
 Set "Up={y}{-}"
 Set "Down={y}{+}"
 Set Move.Snake=For %%n in (1 2) Do if %%n==2 ( %\n%
  %COMMENT:{i}= Capture args for {axis.y.x}{vector+-}{snake.tail}{Pi.Char}\n%
  %COMMENT:{i}= Assume move vaild until proven false \n%
  Set "valid=1" %\n%
  For /F "Tokens=1,2,3,4 Delims={}" %%G in ("!Move.Dir!")Do If not "%%~J" == "" ( %\n%
   %COMMENT:{i}= define offset coords for evaluation of valid move \n%
   If /I "%%G" == "x" (Set /A "lx0=!x0!,ly0=!y0!,nx0= !x0! %%H 1")Else (Set /A "nx0=!x0!") %\n%
   If /I "%%G" == "y" (Set /A "lx0=!x0!,ly0=!y0!,ny0= !y0! %%H 1")Else (Set /A "ny0=!y0!") %\n%
   %COMMENT:{i}= test Cell definition \n%
   For /F "Delims=" %%p in ("!ny0!;!nx0!")Do If not "!{%%p!" == "" ( %\n%
    Set "valid=0" %\n%
    For /F "Delims=" %%v in ("!{%%p!")Do ( %\n%
     Set "Cell=%%v" %\n%
     %COMMENT:{i}= if true cell is tail gameover \n%
     Set "?tail=!Cell:%%I=!" %\n%
     If Not "!?Tail!" == "!Cell!" (Goto :Gameover) %\n%
    ) %\n%
    %COMMENT:{i}= If true cell is Pi makePi \n%
    Set "?tail=!Cell:%%J=!" %\n%
    If Not "!?Tail!" == "!Cell!" ( %\n%
     Set "{!fy!;!fx!="^& Set "fy="^& Set "fx=" %\n%
     Set "Valid=1" %\n%
     Set /A "Score+=50" %\n%
     If "!Delay!" == "0" Set /A "Score+=75" %\n%
     Call :makePi %\n%
     Set /A "tail.len+=1" %\n%
     Set "Tail="!y0!;!x0!",!Tail!" %\n%
     Set "{!ny0!;!nx0!=!Snake.Head!" %\n%
    ) %\n%
   ) %\n%
   %COMMENT:{i}= If cell not tail test next \n%
   If "!valid!" == "1" ( %\n%
    %COMMENT:{i}= If cell is border gameover \n%
    If !n%%G0! LEQ !.%%Gmin! (Goto :Gameover)else If !n%%G0! GEQ !.%%Gmax! (Goto :Gameover)Else ( %\n%
     %COMMENT:{i}= Erases last Head Pos \n%
     If "!Tail.len!" == "0" ( %\n%
      Set "{!y0!;!x0!=" %\n%
      ^<nul Set /P "=%\E%[!y0!;!x0!!H " %\n%
     )Else ( %\n%
      %COMMENT:{i}= Grow Tail \n%
      Set "Tail="!y0!;!x0!",!Tail!" %\n%
      Set "Tail.{i}=0" %\n%
      %COMMENT:{i}= Remove last Cell of tail ; define current tail cells \n%
      For %%r in (!Tail!)Do ( %\n%
       If !Tail.{i}! EQU !Tail.Len! ( %\n%
        Set "Tail=!Tail:,"%%~r"=,!" ^& Set "{%%~r="^&^<nul Set /P "=%\E%[%%~r!H " %\n%
       )Else ( %\n%
        Set "{%%~r=!Snake.Tail!" %\n%
        Set /A "Tail.{i}+=1" %\n%
       ) %\n%
      ) %\n%
     ) %\n%
     %COMMENT:{i}= Define new Head Pos \n%
     Set "{!ny0!;!nx0!=!Snake.Head!" %\n%
     Set /A "%%G0=!n%%G0!" %\n%
    ) %\n%
   ) %\n%
  ) %\n%
 )Else Set Move.Dir=
Set "Info=<nul Set /P "=%\E%[10;55HScore: !Score!%\E%[11;55HHigh Score:!HighScore!%\E%[12;55HPi Eaten:!Tail.Len!%\E%[15;55HDelay:%\E%[K + !Delay! -""
=============================================================================================
::::::::::::::::: End macro definition's 
=============================================================================================
:start
Title Snake by T3RRY & CLS
=============================================================================================
rem /*       Initialise Game variables */
 Set /A "Delay=20,x0=24,y0=12,tail.len=0,Score=0,HighScore=0" & REM snake head start position
 Set "head.color=35"&Set "tail.color=36" & Set "Tail="& REM snake properties
 Set "Snake.Head=@"&Set "Snake.Tail=#"
 Set "head=%\E%[!y0!;!x0!H%\E%[!head.color!m#%\E%[0m"
 Set "Pi.char=%\E%(0{%\E%(B" & set "Pi.color=32"
 Set "}2;55=%\E%[2;55H%\E%[33mControls:"
 Set "}3;55=%\E%[3;55H  ▲    - Up"
 Set "}4;55=%\E%[4;55H  ◄    - Left"
 Set "}5;55=%\E%[5;55H  ▼    - Down"
 Set "}6;55=%\E%[6;55H  ►    - Right"
 Set "}7;55=%\E%[7;55HSpace  - Pause"
 Set "}8;55=%\E%[8;55HEscape - Quit"
rem /* Reference variables for keypress errorlevel { translate errorcode from getkey } */
 Set "k-72=Up"&Set "k-80=Down"&Set "k-75=Left"&Set "k-77=Right"&Set "k32=space"&Set "k43=plus"&Set "k45=minus"&Set "k27=ESC"
rem /* Reference variables to get opposing momentum { prevent tail collision by direction change } */
 Set ".Left=Right"&Set ".Right=Left"&Set ".Up=Down"&Set ".Down=Up"
rem /* Space as pause key; Start game Paused */
 Set "Dir=Space"
==================================
rem /*           Enable Macro's */
 Setlocal EnableExtensions EnableDelayedExpansion
=============================================================================================
rem /* Generate border with desired {Color}{.Xmin}{.Xmax}{.Ymin}{.Ymax}{Character}*/
 %Background.Border%{48;2;150;100;70}{1}{50}{1}{25}{▒}
 %UPDATE.Background%
 Call :makePi
 If exist %Score.Save% (
  <%Score.Save% (Set /P "HighScore=")
 )Else >%Score.Save% Echo/!Score!
=============================================================================================
:gameloop
=========
rem /* Resume momentum possessed prior to Pause  { prevent tail collision by direction change } */
 If Defined Last.Dir If /I Not "!Dir!" == "Space" (
  Set "Dir=!Last.Dir!"
  Set "Last.Dir="
 )
 If !Score! GTR !HighScore! (
  Set "Highscore=!Score!"
  >%Score.Save% Echo/!Score!
 )
rem /* Expand macro displaying Controls ; Score info */
 %INFO%
=============================================================================================
rem /* Test move Doesn't oppose current momentum ; Expand Move.Snake macro with Direction Vector 
rem /* and variables containing Collision test Characters. { If not Paused } */
 If /I not "!Dir!" == "Space" For %%D in (!%Dir%!)Do %Move.Snake%%%D{%Snake.Tail%}{%Pi.char%}
=============================================================================================
 %Show.Snake%{!Snake.Head!}{!Snake.Tail!}
 %getKey%
 For %%e in (!Errorlevel!)Do If not "!k%%e!" == "" For %%v in (!Dir!)Do if not "!k%%e!" == "!.%%v!" (
  Set "Key=!k%%e!"
  If not defined Last.dir If /I "!Key!" == "Space" If /I not "!Dir!" == "!Space!" Set "Last.Dir=!Dir!"
  If /I "!Key!" == "plus" (If !Delay! LSS 150 (Set /A "Delay+=5")&Goto :gameloop)
  If /I "!Key!" == "minus" (If !Delay! GEQ 5 (Set /A "Delay-=5")&Goto :gameloop)
  If /I not "!Key!" == "minus" If /I not "!key!" == "plus" Set "Dir=!k%%e!"
  Set "Dir=!k%%e!"
 )
 If "!Key!" == "" (goto :gameloop)
 If /I "!Key!" == "ESC" (goto :End)
rem /* Enact User Adjustable Delay { + - during gameplay } */
 If %Delay% GTR 0 ( For /L %%d in (1 1 !Delay!)Do Call :Delay 2> nul )Else Call :Delay 2> nul
Goto :gameloop
::: { END gameloop }
=============================================================================================
:Gameover
rem /* update screen elements to highlight death ; End the current session ; restart */
 Title Game over
 Set "Tail.Color=90"
 %Show.Snake%{%\E%[31m!Snake.Head!}{!Snake.Tail!}
 %Background.Border%{48;2;75;75;165}{1}{50}{1}{25}{X}
 %UPDATE.Background%
 Echo/|Choice.exe /N /C:n 2> nul
 Timeout /T 2 /NoBreak > nul
 Pause > Nul
 Del "%Save.Dir%%~n0*.~tmp"
 CLS
 Endlocal
Goto :Start
:End
rem /* restore cmd cursor */
 <nul Set /P "=%\E%[?25h"
 Endlocal
 Del "%Save.Dir%%~n0*.~tmp"
 Goto :Eof
=============================================================================================
:makePi function
Setlocal enableDelayedExpansion
:confirmpos
 If not "!fy!" == "" If not "!fx!" == "" (
  <nul Set /P "=%\E%[!fy!;!fx!H %\E%[0m"
 )
 Set "fValid=1"
 Set /a fy=!random! %% (!.Ymax! - 2) + 2,fx=!random! %% (!.Xmax! - 2) + 2
 For /F "delims=" %%g in ("{!fy!;!fx!")Do If Not "!%%g!" == "" (Set "fValid=0")
 For /F "delims=" %%h in ("}!fy!;!fx!")Do If Not "!%%h!" == "" (Set "fValid=0")
 If "!fValid!" == "1" (
  <nul Set /P "=%\E%[!fy!;!fx!H%\E%[%Pi.color%m!Pi.char!%\E%[0m"
  Endlocal & Set "fy=%fy%" & Set "fy=%fx%" & Set "{%fy%;%fx%=%Pi.char%"
  Exit /B 0
 )
Goto :confirmpos
Last edited by T3RRY on 07 Dec 2020 11:05, edited 3 times in total.

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

Re: Batch Games

#24 Post by dbenham » 06 Dec 2020 20:32

Your snake game does not work for me on Win 10. It partially prints the initial screen, and then just hangs.

I do hope you have seen my pure batch implementation of snake.bat - It has extremely smooth graphics, yet does not require any 3rd party exe file as long as you are on Win 10. If pre Win 10 then adding Aacini's CursorPos.exe to the directory provides smooth graphics. But even without it, the game is still very playable - there just may be some annoying screen flicker.

Also there is my faithful batch implementation of the original Crowther and Woods Colossal Cave Adventure - the original interactive fiction text based computer game. My adventure.bat is again pure batch, with all of the descriptive text messages and rules embedded within the file. The cool thing there is I have obfuscated (primitive cipher) all text, variable names, and comments so it is safe to look at the source code without spoiling the fun. The game automatically encodes input and decodes screen output as needed.


Dave Benham

T3RRY
Posts: 249
Joined: 06 May 2020 10:14

Re: Batch Games

#25 Post by T3RRY » 06 Dec 2020 23:24

dbenham wrote:
06 Dec 2020 20:32
Your snake game does not work for me on Win 10. It partially prints the initial screen, and then just hangs.

Dave Benham
I have indeed previously seen your snake game, and it's very nice indeed, however I failed In my past efforts to isolate and replicate the input handling in a stable manner.

Follow up question regarding the issue with my version not working for you - did you download the zip from the Google drive link or place the above batch in a folder that contains getkey.exe ?

The main reason I'd expect it to hang would be that Getkey.exe is not found by the dir command when defining the path for it. When I'm done with work I'll update the script to notify the user if that occurs.

If you do have the download version or getkey.exe I'll have to see if I can replicate the failure. I have two windows 10 systems running different versions and tested the download with both after uploading without error.

The main reason I'd expect it to hang would be that Getkey.exe is not found by the dir command when defining the path for it. When I'm done with work I'll update the script to notify the user if that occurs.
Scrub that. I missed the point about it hanging while typing the ~tmp file.
I'm stumped as to why that may be occuring. Any idea's?

As for smoothness of gameplay, there's no issue here. Game speed is user adjustable during gameplay; and as you'll see, there's no flicker evident.
https://www.youtube.com/watch?v=q1MWWL5eEd0

Lowsun
Posts: 29
Joined: 14 Apr 2019 17:22

Re: Batch Games

#26 Post by Lowsun » 07 Dec 2020 13:10

Hey that's a pretty cool snake! Here's my super basic version using VT100 sequences in pure Batch, inspired by dbenham's

Code: Select all

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
IF not "%1" == "" (
    GOTO :%1
)
TITLE Snake
FOR /F %%A in ('ECHO prompt $E^| cmd') DO SET "ESC=%%A"
(CHCP 65001)>NUL

SET "mov[W]=y]-=1"
SET "mov[A]=x]-=1"
SET "mov[S]=y]+=1"
SET "mov[D]=x]+=1"
SET "snake[bou]=.0;0."
SET every="1/(((~(0-(frames %% #))>>31)&1)&((~((frames %% #)-0)>>31)&1))"
SET /A "map[width]=30", "map[height]=15", "char[0][x]=d[x]=3","char[0][y]=d[y]=3", "snake[mass]=1", "pel[x]=0"
SET "exit=ECHO %ESC%[%map[height]%;1H%ESC%[3BOuch...Press W to Continue&(COPY NUL "%~dpn0.quit")>NUL&EXIT"
SET "snake[disp]=%ESC%[%char[0][y]%;%char[0][x]%H▓"

CALL :MAKEMAP %map[width]% %map[height]%
DEL "%~dpn0.quit" 2>NUL
ECHO %ESC%[?25l

:START
SETLOCAL
"%~F0" CONTROL >"%temp%\%~n0_signal.txt" | "%~F0" GAME <"%temp%\%~n0_signal.txt"
ENDLOCAL
GOTO :START

:GAME
FOR /L %%# in () DO (
    SET /P "input="
    SET /A "frames+=1"
    IF !pel[x]! EQU 0 (
        SET /A "pel[x]=!RANDOM! * ((%map[width]% - 1) - 2 + 1) / 32768 + 2", "pel[y]=!RANDOM! * ((%map[height]% - 1) - 2 + 1) / 32768 + 2"
        SET "pel[disp]=%ESC%[!pel[y]!;!pel[x]!Ho"
    )
    2>NUL SET /A !every:#=13! && (
        IF defined input (
            FOR %%A in (!input!) DO (
                SET /A "d[x]=char[0][x]","d[y]=char[0][y]","d[!mov[%%A]!"
                IF !d[x]! LSS %map[width]% ( IF !d[x]! GTR 1 (
                    IF !d[y]! LSS %map[height]% ( IF !d[y]! GTR 1 (
                        SET "snake[disp]="
                        SET /A "d[shift][x]=char[0][x]=d[x]","d[shift][y]=char[0][y]=d[y]"
                        IF "!pel[x]!;!pel[y]!" == "!d[x]!;!d[y]!" (
                            SET /A "pel[x]=0","snake[mass]+=1"
                        )
                        IF !snake[mass]! NEQ 1 (
                            FOR %%Q in (".!d[x]!;!d[y]!.") DO (
                                IF not "!snake[bou]!" == "!snake[bou]:%%~Q=!" (
                                    %exit%
                                )
                            )
                        )
                        SET "snake[bou]="
                        FOR /L %%M in (1, 1, !snake[mass]!) DO (
                            SET "snake[bou]=!snake[bou]!.!char[%%M][x]!;!char[%%M][y]!"
                            SET /A "d[save][x]=char[%%M][x]","d[save][y]=char[%%M][y]", "char[%%M][x]=d[shift][x]","char[%%M][y]=d[shift][y]", "d[shift][x]=d[save][x]","d[shift][y]=d[save][y]","d[disp]=%%M %% 2"
                            IF !d[disp]! EQU 0 (
                                SET "snake[disp]=!snake[disp]!%ESC%[!char[%%M][y]!;!char[%%M][x]!H▒"
                            ) else (
                                SET "snake[disp]=!snake[disp]!%ESC%[!char[%%M][y]!;!char[%%M][x]!H▓"
                            )
                        )
                        SET "snake[bou]=!snake[bou]!."
                    ) else (%exit%)) else (%exit%)
                ) else (%exit%)) else (%exit%)
            )
        )
    )
    ECHO %ESC%[2J%ESC%[1;1H%disp[map]%!pel[disp]!!snake[disp]!%ESC%[%map[height]%;1H%ESC%[BScore : !snake[mass]!%ESC%[1G%ESC%[BUse WASD to move
)

:MAKEMAP <width> <height>
SETLOCAL
SET "disp[border]="
FOR /L %%W in (1, 1, %1) DO (
    SET "disp[border]=!disp[border]!█"
)
SET /A  "width[adj]=%1 - 2","height[adj]=%2 - 1"
SET "disp[map]=%disp[border]%#%ESC%[B%ESC%[%1D%disp[border]%"
FOR /L %%H in (2, 1, %height[adj]%) DO (
    SET "disp[map]=!disp[map]:#=%ESC%[B%ESC%[%1D█%ESC%[%width[adj]%C█#!"
)
ENDLOCAL&SET "disp[map]=%disp[map]:#=%"
GOTO :EOF

:CONTROL
FOR /L %%C in () do (
    FOR /F "tokens=*" %%A in ('CHOICE /C:WASD /N') DO (
        IF exist "%~dpn0.quit" (
            DEL "%~dpn0.quit"
            EXIT
        )
        <NUL SET /P ".=%%A"
    )
)
GOTO :EOF

T3RRY
Posts: 249
Joined: 06 May 2020 10:14

Re: Batch Games

#27 Post by T3RRY » 07 Dec 2020 20:35

Lowsun wrote:
07 Dec 2020 13:10
Hey that's a pretty cool snake! Here's my super basic version using VT100 sequences in pure Batch, inspired by dbenham's
I like how you've managed to keep it pure batch, however I found your controller to not be as reliable as I'd like
Also is it by intent the player can collide with their tail by making a move that opposes their current momentum?
I found this to be particularly problematic if making a U turn and the keypress for the right angle direction change is not picked up by your controller.

There's some similarities in how my script deal with repetative actions
rather than a function for generating the border, I made a macro that also takes arguments for color and character

expanded as:

Code: Select all

 %Background.Border%{48;2;150;100;70}{1}{50}{1}{25}{▒}
Vector changes are also handled in a similar manner, translating keypresses to values used in the move.snake macro

Code: Select all

 Set "Left={x}{-}"&Set "Right={x}{+}"&Set "Up={y}{-}"&Set "Down={y}{+}"
 :::
 If /I not "!Dir!" == "Space" For %%D in (!%Dir%!)Do %Move.Snake%%%D{%Snake.Tail%}{%Pi.char%}

Lowsun
Posts: 29
Joined: 14 Apr 2019 17:22

Re: Batch Games

#28 Post by Lowsun » 07 Dec 2020 21:17

T3RRY wrote:
07 Dec 2020 20:35
Lowsun wrote:
07 Dec 2020 13:10
Hey that's a pretty cool snake! Here's my super basic version using VT100 sequences in pure Batch, inspired by dbenham's
I like how you've managed to keep it pure batch, however I found your controller to not be as reliable as I'd like
Also is it by intent the player can collide with their tail by making a move that opposes their current momentum?
I found this to be particularly problematic if making a U turn and the keypress for the right angle direction change is not picked up by your controller.

There's some similarities in how my script deal with repetative actions
rather than a function for generating the border, I made a macro that also takes arguments for color and character

expanded as:

Code: Select all

 %Background.Border%{48;2;150;100;70}{1}{50}{1}{25}{▒}
Vector changes are also handled in a similar manner, translating keypresses to values used in the move.snake macro

Code: Select all

 Set "Left={x}{-}"&Set "Right={x}{+}"&Set "Up={y}{-}"&Set "Down={y}{+}"
 :::
 If /I not "!Dir!" == "Space" For %%D in (!%Dir%!)Do %Move.Snake%%%D{%Snake.Tail%}{%Pi.char%}
Yeah the controller isn't too reliable, but part of it is because I only check for movement every 13 "frames", so some keypresses are missed sometimes. I could have taken that out, but then the speed would be waayyyy too fast. And yeah, it is by intent that moving opposite to direction results in a collision. It's true I could've make a macro, but I feel like it's a little overkill, especially with something like background border that's only generated once. To be honest, in those situations I feel like a simple function is easier to look at / debug. I'm not too big of a fan of huge macros, when most of the time you could just use string substitution to make more simple macros.

Your version of snake is pretty damn good. The only problem I had was some flicker, and on my old laptop it ran pretty slow.

T3RRY
Posts: 249
Joined: 06 May 2020 10:14

Re: Batch Games

#29 Post by T3RRY » 07 Dec 2020 21:41

Your version of snake is pretty damn good. The only problem I had was some flicker, and on my old laptop it ran pretty slow.
Unfortunately I've not found a means to standardise delays that isn't impacted by the specs of a PC

I have two PC's I've tested this on. A gaming rig and an old student laptop - and it's significantly slower on the laptop. Hence why I included the ability to modify the delay rate during gameplay using + - keys.

It's only my slower pc at the fastest gameplay setting {0 delay} that I see any flicker, and once the tail is two characters or longer this disappears. This happens because the only cells I clear are the cell previously occupied by the head and the last tail cell position. On the slow pc at tail lengths < 2 it results in noticible flicker.

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

Re: Batch Games

#30 Post by dbenham » 08 Dec 2020 08:00

T3RRY wrote:
07 Dec 2020 21:41
Unfortunately I've not found a means to standardise delays that isn't impacted by the specs of a PC
That is actually fairly simple. Treat your game as a movie, consisting of a series of static frames with incremental changes displayed sequentially to simulate motion. You want the frame rate to be constant, regardless of the speed of the PC.

Each time you draw a frame, store the current time in a variable as an integral value. The %TIME% pseudo variable has centisecond resolution (two decimal places). Parse the time into each of its components and do the simple math to convert the time into an integral centisecond value. Treat each centisecond as a clock tick. You want a constant number of ticks between each frame. A large tick value equates to a slow game, a small tick value a fast game.

Between the display of each frame you need to gather player input and compute all the game action (player and other entity movements, collisions, random events, etc., and finally draw everything (or just the changes) into a frame buffer. I simply use strings within environment variables as the frame buffer. Then when it is time to draw the next frame, simply print the frame buffer strings to the screen.

Your game will be in an "endless" loop, gathering input, computing actions, and drawing frames. Once you have successfully completed all actions necessary for the next frame, you enter a tight loop where you are just waiting for the correct time to display the frame. Compute the current integral clock time and subtract from the value of the previous frame display. If it is >= the target number of clicks, then display your next frame. If not, then continue waiting in your tight loop. If the time difference is negative, then you crossed the midnight threshold and you must add 8,640,000 clicks (24 x 60 x 60 x 100) to your difference to get the correct positive value.

In my snake game, the number of computations per frame is more or less constant, so I simplify things a bit by doing all frame computations after the requisite frame ticks have expired and then immediately display the result.

Either way, as long as all computations fit within the window of your specified frame tick rate, then you have smooth animation.

That is a lot of words, but it is actually very little code. My snake game is well commented, so you should be able to look at the code and recognize how I accomplish all of this.


Dave Benham

Post Reply