I'm trying to code a tictactoe game in batch. But I ran into several problems I can't solve.
After the third move of player 1, the game has to check if player 1 has won. I tried to do that by making 8 variables of all possible 8 winlines. And then the game checks if any of the winlines equals to XXX or OOO. The Problem is that the field variables (_f1, _f2, etc.) don't change to X or O. I set them at the beginning of the script by their numbers, but I dont understand why they dont change once a player put a X or O in that field/variable.
The code is very ugly and unnecessarily long. I'm aware of the
for
command and i can do basic loops, but I cant wrap my head around the syntax if the command gets too complicated. How can I put all the repititions in for loops?@echo off setlocal enabledelayedexpansion title .:TIC TAC TOE:. mode con: cols=40 lines=20 color 02 cls goto :main :check if !_win1!==XXX ( echo END OF GAME pause ) if !_win2!==XXX ( echo END OF GAME pause ) if !_win3!==XXX ( echo END OF GAME pause ) if !_win4!==XXX ( echo END OF GAME pause ) if !_win5!==XXX ( echo END OF GAME pause ) if !_win6!==XXX ( echo END OF GAME pause ) if !_win7!==XXX ( echo END OF GAME pause ) if !_win8!==XXX ( echo END OF GAME pause ) goto :eof :player2turn choice /c 123456789 /n /m "!_player2!, it's your turn!" if !errorlevel!==1 ( if !_f1!==1 ( set _f1=!_player2symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==2 ( if !_f2!==2 ( set _f2=!_player2symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==3 ( if !_f3!==3 ( set _f3=!_player2symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==4 ( if !_f4!==4 ( set _f4=!_player2symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==5 ( if !_f5!==5 ( set _f5=!_player2symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==6 ( if !_f6!==6 ( set _f6=!_player2symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==7 ( if !_f7!==7 ( set _f7=!_player2symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==8 ( if !_f8!==8 ( set _f8=!_player2symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==9 ( if !_f9!==9 ( set _f9=!_player2symbol! goto :eof ) else ( goto :player1turn ) ) goto :eof :player1turn choice /c 123456789 /n /m "!_player1!, it's your turn!" if !errorlevel!==1 ( if !_f1!==1 ( set _f1=!_player1symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==2 ( if !_f2!==2 ( set _f2=!_player1symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==3 ( if !_f3!==3 ( set _f3=!_player1symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==4 ( if !_f4!==4 ( set _f4=!_player1symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==5 ( if !_f5!==5 ( set _f5=!_player1symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==6 ( if !_f6!==6 ( set _f6=!_player1symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==7 ( if !_f7!==7 ( set _f7=!_player1symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==8 ( if !_f8!==8 ( set _f8=!_player1symbol! goto :eof ) else ( goto :player1turn ) ) if !errorlevel!==9 ( if !_f9!==9 ( set _f9=!_player1symbol! echo !_win1! echo !_player1symbol! pause goto :eof ) else ( goto :player1turn ) ) goto :eof ::displaying the map :map echo. echo. echo. echo !_f7! ^| !_f8! ^| !_f9! echo --------- echo !_f4! ^| !_f5! ^| !_f6! echo --------- echo !_f1! ^| !_f2! ^| !_f3! echo. echo. echo. goto :eof ::setting variables :setvar set _f1=1 set _f2=2 set _f3=3 set _f4=4 set _f5=5 set _f6=6 set _f7=7 set _f8=8 set _f9=9 set _win1=!_f7!!_f8!!_f9! set /a _win2=!_f4! !_f5! !_f6! set /a _win3=!_f1! !_f2! !_f3! set /a _win4=!_f7! !_f4! !_f1! set /a _win5=!_f8! !_f5! !_f2! set /a _win6=!_f9! !_f6! !_f3! set /a _win7=!_f7! !_f5! !_f3! set /a _win8=!_f9! !_f5! !_f1! goto :eof ::player settings :setup echo. set /p _player1=Enter name for Player 1: echo. choice /c xo /n /m "!_player1! do you want to play as X or O?" if !errorlevel!==1 ( set _player1symbol=X set _player2symbol=O ) else ( set _player1symbol=O set _player2symbol=X ) echo. echo. set /p _player2=Enter name for Player 2: echo. cls echo. echo. echo. echo !_player1!(!_player1symbol!) vs. !_player2!(!_player2symbol!) pause>nul goto :eof :main setlocal call :setup cls call :setvar call :map call :player1turn cls call :map call :player2turn cls call :map call :player1turn cls call :map call :player2turn cls call :map call :player1turn call :check endlocal goto :eof
CodePudding user response:
You should research and define your coding approach before write a single line of program. Also, you should learn the language features in order to make good use of its facilities. This applies to any programming language.
This is the way I would do it:
@echo off
setlocal EnableDelayedExpansion
rem Test for win: Horizontal rows
set "win[1]=%%pos[1]%%%%pos[2]%%%%pos[3]%%"
set "win[2]=%%pos[4]%%%%pos[5]%%%%pos[6]%%"
set "win[3]=%%pos[7]%%%%pos[8]%%%%pos[9]%%"
rem Test for win: Vertical cols
set "win[4]=%%pos[1]%%%%pos[4]%%%%pos[7]%%"
set "win[5]=%%pos[2]%%%%pos[5]%%%%pos[8]%%"
set "win[6]=%%pos[3]%%%%pos[6]%%%%pos[9]%%"
rem Test for win: Diagonals
set "win[7]=%%pos[1]%%%%pos[5]%%%%pos[9]%%"
set "win[8]=%%pos[7]%%%%pos[5]%%%%pos[3]%%"
for /L %%i in (1,1,9) do set "pos[%%i]=%%i"
set "taken=_"
cls
set /P "player[X]=Enter player 1 (X) name: "
set /P "player[O]=Enter player 2 (O) name: "
call :showBoard
set "players=XO"
for /L %%n in (1,1,9) do (
call :playerTurn !players:~0,1!
if !result! equ 1 echo You win^^^! & goto :EOF
set "players=!players:~1,1!!players:~0,1!"
)
echo Game was a draw...
goto :EOF
:playerTurn wichOne
choice /C 123456789 /N /M "!player[%1]!, it's your turn: "
set "choice=%errorlevel%"
if "!taken:%choice%=!" neq "%taken%" echo Bad position & goto playerTurn
set "taken=%taken%%choice%"
set "pos[%choice%]=%1"
call :showBoard
rem Test if win
set "result=0"
for /L %%i in (1,1,8) do if !result! equ 0 (
call set "line=!win[%%i]!
if "!line!" equ "%1%1%1" set "result=1"
)
exit /B
:showBoard
echo/
echo/
echo %pos[1]% ^| %pos[2]% ^| %pos[3]%
echo ---------
echo %pos[4]% ^| %pos[5]% ^| %pos[6]%
echo ---------
echo %pos[7]% ^| %pos[8]% ^| %pos[9]%
echo/
echo/
exit /B
CodePudding user response:
@Aacini posted a great answer, so I decided to post my own as well. As they say, there are many ways to skin a cat.
@echo off & Title Tic-Tac-Toe
setlocal enabledelayedexpansion & mode con: cols=40 lines=20 & color 02
for /F %%i in ('echo prompt $E ^| cmd') do set "n=%%iE"
:menu
cls & set /p "playerX=enter name Player 1 (X): " & set /p "playerO=enter name Player 2 (O): "
set gone=.
for /l %%i in (1,1,9) do set a%%i=%%i
for /L %%i in (1,1,4) do for %%a in (X O) do (
for %%x in (!a1!!a2!!a3! !a4!!a5!!a6! !a7!!a8!!a9! !a1!!a4!!a7! !a2!!a5!!a8! !a3!!a6!!a9! !a1!!a5!!a9! !a3!!a5!!a7!) do (
if "%%x" == "!_h!!_h!!_h!" echo !pl! wins & timeout /t 4 /NOBREAK >nul & goto :menu
)
set pl=!player%%a! & set _h=%%a
call :play
set "a!ch!=%%a"
if %%i geq 4 echo No winners & timeout /t 4 /NOBREAK >nul & goto :menu
)
:play
cls & echo(
echo !a1! ^| !a2! ^| !a3!%n% ----------%n% !a4! ^| !a5! ^| !a6!%n% ----------%n% !a7! ^| !a8! ^| !a9!%n%
choice /c 123456789 /m "!pl!'s turn"
set ch=!errorlevel!
if !ch! equ 0 exit /b
if "!gone:%ch%=!" neq "%gone%" echo That spot has been taken, try again & timeout /t 3 /NOBREAK >nul & goto :play
set "gone=%gone%!ch!"
goto :eof
And a version for older windows that does not support VT100:
@echo off & Title Tic-Tac-Toe
setlocal enabledelayedexpansion & mode con: cols=40 lines=20 & color 02
:menu
cls & set /p "playerX=enter name Player 1 (X): " & set /p "playerO=enter name Player 2 (O): "
set gone=.
for /l %%i in (1,1,9) do set a%%i=%%i
for /L %%i in (1,1,4) do for %%a in (X O) do (
for %%x in (!a1!!a2!!a3! !a4!!a5!!a6! !a7!!a8!!a9! !a1!!a4!!a7! !a2!!a5!!a8! !a3!!a6!!a9! !a1!!a5!!a9! !a3!!a5!!a7!) do (
if "%%x" == "!_h!!_h!!_h!" echo !pl! wins & timeout /t 4 /NOBREAK >nul & goto :menu
)
set pl=!player%%a! & set _h=%%a
call :play
set "a!ch!=%%a"
if %%i geq 4 echo No winners & timeout /t 4 /NOBREAK >nul & goto :menu
)
:play
cls & echo(
echo !a1! ^| !a2! ^| !a3!
echo ----------
echo !a4! ^| !a5! ^| !a6!
echo ----------
echo !a7! ^| !a8! ^| !a9!
echo(
choice /c 123456789 /m "!pl!'s turn"
set ch=!errorlevel!
if !ch! equ 0 exit /b
if "!gone:%ch%=!" neq "%gone%" echo That spot has been taken, try again & timeout /t 3 /NOBREAK >nul & goto :play
set "gone=%gone%!ch!"
goto :eof