Digitalise Agency

tic-tac-toe-gui

Tic Tac Toe

Noughts and crosses on a computer: two players take turns clicking a 3x3 grid, and the program spots the win, highlights the winning line, and keeps score. This small learning exercise began as an earlier version with a real flaw: it only ever checked whether X had won, so O could complete a line and play carried on regardless. The rewrite checks all eight lines for both players.

Solo

Solo work by our founder, Salman Adnan.

Endless Openings: noughts and crosses playing itself, game after game. Someone completes a line, the line is marked, and the board clears for the next round. Live and interactive: drag it to orbit, scroll or pinch to zoom. Open full screen
The real Tic Tac Toe GUI.
Live screenshot of the actual Tkinter app.
8win lines checked (rows, columns, diagonals)
2files: game.py logic + main.py GUI
3tracked stats: X wins, O wins, draws

Overview

A two-player Tic Tac Toe game with a real graphical interface built in tkinter. It started as a console script with a real bug (the win check only ever tested for X), and this rewrite fixes that properly, detects wins across all eight lines for both players, and tracks score across rounds without closing the window.

This began as a "Day 83" console-only practice script that just printed a numbered board and read input(), and it had a real bug: the win check only ever tested for player X, so O could complete a full line and the game would keep running as if nothing happened. This rewrite keeps the original goal, representing a 3x3 board and detecting a win across all eight lines without a library, but fixes the bug properly and replaces the terminal loop with an actual tkinter window.

Key features

  • Two-player hot-seat play on a clickable 3x3 grid of buttons.
  • Win detection across all 8 lines (3 rows, 3 columns, 2 diagonals) for both X and O, plus draw detection when the board fills with no winner.
  • The winning line is highlighted in place on the board when a game ends.
  • A status label shows whose turn it is, and the result when a round ends.
  • A "Play again" button resets the board without closing the window.
  • A running score tracker (X wins / O wins / draws) that persists across rounds in the same session.

Verification

game.py holds the win/draw logic with no tkinter or I/O dependency, which means it was unit tested directly. check_winner compares both marks against all 8 win lines and returns the winner and the winning line, and main.py holds only display state (colors, labels, the running score dict) without duplicating any of that logic. Running python3 main.py opens the window and plays a full game, confirming the highlighted winning line and score tracker update as designed.

Tech stack

  • Python 3.6+
  • tkinter

A challenge worth noting

The console version hardcoded 8 or-chained comparisons, all checked only against X, which is exactly how the O-detection bug slipped in. Rather than duplicating that shape 8 more times for O, check_winner loops over a list of the 8 index triples (WIN_LINES) and checks whether all three cells match a non-empty mark, handling both players with one code path. A smaller fix worth noting: tkinter's default disabled state grays out button text, which would make X and O look the same shade of gray once placed, so disabledforeground is set explicitly to keep each mark's real color after the cell is disabled.

Book a call

Let's talk about what you're building.

Pick a slot below. No forms, no back-and-forth emails.