Skip to main content

How to Create a Tic-Tac-Toe Game in Batch Script

Building a fully functional grid-based game like Tic-Tac-Toe in the Windows Command Prompt is a great way to practice handling state, working with pseudo-arrays, and checking win conditions. Since Batch doesn’t support true two-dimensional arrays, the 3×3 board has to be represented using nine separate variables, with logic that evaluates different combinations to detect a winner.

In this guide, we’ll create a complete interactive Tic-Tac-Toe game for two players using a Batch script.

The Strategy: The 9-Cell Array

  1. Initialize 9 variables representing the board grid (cell1 through cell9), filled initially with numbers 1-9 to act as input guides.
  2. Establish a "Current Player" toggle variable (alternating between X and O).
  3. Draw the board utilizing the echo command and the cell variables.
  4. Capture the human input (1-9).
  5. Validate the move (ensure the target cell isn't already X or O).
  6. Update the cell variable with the Current Player's mark.
  7. Check all 8 possible victory conditions.
  8. Check for a Draw condition.
  9. Loop back to step 3.

Implementation Script

@echo off
setlocal EnableDelayedExpansion
title Batch Tic-Tac-Toe
color 0E

:: Initialize Game State
:Init
for /l %%I in (1,1,9) do set "cell%%I=%%I"
set "player=X"
set "turnCount=0"

:: 1. Draw the Board
:DrawBoard
cls
echo ======================
echo TIC-TAC-TOE : !player!'s turn
echo ======================
echo.
echo ^| ^|
echo !cell1! ^| !cell2! ^| !cell3!
echo _____^|_____^|_____
echo ^| ^|
echo !cell4! ^| !cell5! ^| !cell6!
echo _____^|_____^|_____
echo ^| ^|
echo !cell7! ^| !cell8! ^| !cell9!
echo ^| ^|
echo.

:: 2. Accept User Input
set "choice="
set /p "choice=Player !player!, choose a cell (1-9): "

:: 3. Validate Input
:: First confirm the input is a number 1-9
set "validInput=0"
for /l %%V in (1,1,9) do (
if "!choice!"=="%%V" set "validInput=1"
)

if "!validInput!"=="0" (
echo [^^!] Invalid selection. Enter a number from 1 to 9.
pause >nul
goto DrawBoard
)

:: Check if the cell is already taken (contains X or O)
if "!cell%choice%!"=="X" (
echo [^^!] Cell !choice! is already taken. Choose another.
pause >nul
goto DrawBoard
)
if "!cell%choice%!"=="O" (
echo [^^!] Cell !choice! is already taken. Choose another.
pause >nul
goto DrawBoard
)

:: 4. Process Valid Move
set "cell!choice!=!player!"
set /a "turnCount+=1"

:: 5. Check for Win after placing the mark
:: Horizontal
if "!cell1!"=="!cell2!" if "!cell2!"=="!cell3!" goto Victory
if "!cell4!"=="!cell5!" if "!cell5!"=="!cell6!" goto Victory
if "!cell7!"=="!cell8!" if "!cell8!"=="!cell9!" goto Victory
:: Vertical
if "!cell1!"=="!cell4!" if "!cell4!"=="!cell7!" goto Victory
if "!cell2!"=="!cell5!" if "!cell5!"=="!cell8!" goto Victory
if "!cell3!"=="!cell6!" if "!cell6!"=="!cell9!" goto Victory
:: Diagonal
if "!cell1!"=="!cell5!" if "!cell5!"=="!cell9!" goto Victory
if "!cell3!"=="!cell5!" if "!cell5!"=="!cell7!" goto Victory

:: 6. Check Draw (all 9 cells filled with no winner)
if !turnCount! equ 9 goto Draw

:: 7. Toggle Player
if "!player!"=="X" (
set "player=O"
) else (
set "player=X"
)
goto DrawBoard

:: 8. End States
:Victory
cls
echo ======================
echo TIC-TAC-TOE : FINAL
echo ======================
echo.
echo ^| ^|
echo !cell1! ^| !cell2! ^| !cell3!
echo _____^|_____^|_____
echo ^| ^|
echo !cell4! ^| !cell5! ^| !cell6!
echo _____^|_____^|_____
echo ^| ^|
echo !cell7! ^| !cell8! ^| !cell9!
echo ^| ^|
echo.
echo ======================
echo PLAYER !player! WINS^^!
echo ======================
goto Replay

:Draw
cls
echo ======================
echo TIC-TAC-TOE : FINAL
echo ======================
echo.
echo ^| ^|
echo !cell1! ^| !cell2! ^| !cell3!
echo _____^|_____^|_____
echo ^| ^|
echo !cell4! ^| !cell5! ^| !cell6!
echo _____^|_____^|_____
echo ^| ^|
echo !cell7! ^| !cell8! ^| !cell9!
echo ^| ^|
echo.
echo ======================
echo IT'S A DRAW^^!
echo ======================
goto Replay

:Replay
echo.
set "playAgain="
set /p "playAgain=Play Again? (Y/N): "
if /i "!playAgain!"=="Y" goto Init
echo Thanks for playing^^!
pause
exit /b

How It Works

  1. Virtual Arrays: Batch doesn't have arrays, but set "cell!choice!=!player!" simulates one perfectly. If choice is 5, the variable cell5 is dynamically updated to X.
  2. Delayed Expansion: EnableDelayedExpansion is strictly required here. Without the ! variable syntax, the board wouldn't redraw showing the updated cells on each loop iteration.
  3. Indirect Variable Referencing: The expression !cell%choice%! allows us to evaluate the value of a dynamically named variable. Since choice is set before the current code block is parsed, %choice% expands at parse time to form the variable name (e.g., cell5), and the outer !...! then retrieves that variable's current value at execution time.
  4. Victory Conditions: Tic-Tac-Toe has exactly 8 win configurations. The script stacks horizontal, vertical, and diagonal if statements. If a line consists entirely of identically matched variables (e.g., cell1 == cell2 and cell2 == cell3), a win is triggered. Because unplayed cells contain unique numbers (1–9), three unplayed cells in a row can never produce a false match.

Why Build Tic-Tac-Toe?

  1. Grid Simulation: Understanding how to map a 2D layout (X/Y coordinates) into a flat list of 9 linear variables is a crucial data-structure lesson.
  2. Game Loops and Recursion: Managing a central :DrawBoard game loop that gracefully handles successful logic, failure states (invalid inputs), and interrupt states (wins/draws).
  3. Variable Masking: Displaying variables that continuously change type (from numeric 1-9 guides to string X/O values) in exactly the same grid layout.

Conclusion

Building a fully-featured Tic-Tac-Toe game proves the logical depth available natively inside the Windows Command Prompt. By intelligently leveraging dynamic variable manipulation and comprehensive state-checking conditionals, a purely administrative scripting language transforms flawlessly into a visual, interactive gaming engine.