A desktop tic-tac-toe game that pairs a Swing interface with Prolog-powered minimax so single-player mode plays optimally.
Snapshot
Field
Details
Type
Desktop game prototype
Context
University project (Artificial Intelligence)
Role
Solo developer
Year
2019
Status
Academic prototype
Main focus
Hybrid Java/Prolog architecture and minimax-based CPU play
Overview
I built a classic tic-tac-toe desktop app in Java with a custom Swing interface and wired the game logic to SWI-Prolog through JPL. The project explores how a familiar UI can stay in Java while search, win detection, and optimal moves live in declarative Prolog code.
Single-player mode uses a minimax implementation so the computer does not make casual mistakes. Two-player mode keeps turns in Java but still delegates win and tie checks to Prolog. It is a finished local prototype, not a shipped product, and it stays in my portfolio as an early example of mixing languages for game AI.
The problem
Tic-tac-toe is simple on the surface, but a fair computer opponent needs real lookahead, not random or greedy picks. I wanted to practice that decision-making in Prolog while still delivering a polished desktop experience.
A weak CPU makes single-player mode feel pointless after a few games.
Win and tie rules are easy to get subtly wrong when duplicated across UI code paths.
I wanted hands-on experience bridging a JVM app to an external Prolog runtime, not keeping all logic in one language.
Who it was for
Players who want a quick local game on the desktop
Anyone curious about minimax and logic programming in a small, readable codebase
Me, as a sandbox for Java UI work and Prolog integration
My role
I owned the project end to end: Swing screens (home, rules, about, two-player and vs-PC boards), turn handling, the Java-to-Prolog bridge, Prolog modules for moves and minimax, packaging with NetBeans, and the visual assets. I chose what stayed in Java versus what Prolog should own.
What the project does
The app opens on a home screen where you pick play against the computer or against another person on the same machine. In vs-PC mode you play as X; after each click the board updates and Prolog returns the CPU move as O. In two-player mode the UI alternates X and O with a turn indicator while Prolog answers whether someone won or the board is full.
Loads minimax2.pl or gatoes.pl at startup depending on the game mode
Represents the board as a nine-cell structure shared between Java and Prolog queries
Uses minimax in single-player mode so the CPU plays optimally (wins or draws)
Reuses Prolog win/2 predicates for consistent outcome detection in both modes
Shows dialogs for occupied cells, winners, and ties, then returns to the home screen
Key features
Unbeatable single-player opponent
After the human places X, Java sends the live board to Prolog and applies the returned state. The CPU is modeled as the minimax MIN player and the human as MAX, matching the utility scores in the Prolog layer.
GamePc.javajava
private void cpuMove(){
String move = "start_it([o," + Arrays.toString(tictactoe) + ",_],o,NewBoard).";
Query exec = new Query(move);
if (exec.hasSolution()) {
String x = exec.oneSolution().get("NewBoard").toString();
tictactoe = clean.clean(x);
posicionate();
}
}
I kept the board as a Java string array for rendering but let Prolog choose the move, so the search stays declarative and the UI stays imperative.
Minimax game tree in Prolog
The CPU picks moves by expanding legal positions, scoring terminal states, and comparing branches with MIN/MAX-aware betterOf/6 rules.
Terminal utilities treat an O win as +1, an X win as -1, and a tie as 0, which lines up with the computer playing as minimizer.
Two-player mode with shared rule engine
Local multiplayer runs turn alternation in Java (Game.java) but still consults Prolog for wins and ties, so both modes share the same winning-line definitions instead of duplicating them in Swing handlers.
Custom Swing shell
Screens use undecorated frames, background images, and overlay labels for X and O markers. The home flow links to rules and about views so the app feels like a small product rather than a bare grid demo.
Technical approach
Architecture splits presentation and integration in Java from rules and search in Prolog. On launch, vs-PC mode runs consult('minimax2.pl') and two-player mode loads gatoes.pl. JPL Query objects execute goals such as start_it/3 for moves and win/2 for outcomes.
The Java side maps clicks to board cells, blocks occupied squares, and refreshes piece visibility. CleanArray parses the Prolog solution string back into nine entries because JPL returns structured results as text that must be aligned with the UI model (empty cells as "0", markers as "x" or "o").
The project targets Java 8, bundles through NetBeans, and expects SWI-Prolog 8.2+ with jpl.jar on the classpath. The prototype does not include automated tests or a cross-platform installer; running it assumes Prolog is installed and reachable from the working directory where the .pl files live.
Design decisions
I treated the desktop UI as the main experience: fixed 1024×600 layouts, Spanish copy, and JOptionPane feedback for errors and results. Logic stayed out of the form editor code wherever possible.
Used Swing .form files for layout speed while keeping game flow in hand-written methods
Chose a string-based board in Java for the PC screen because it matched how I built queries from Arrays.toString
Delegated win/tie detection to Prolog even in two-player mode to avoid diverging rule implementations
Applied the Nimbus look-and-feel for slightly more modern defaults on Java 8
Kept separate Prolog entry points (minimax2.pl vs gatoes.pl) so CPU search does not complicate local multiplayer startup
Challenges and tradeoffs
Parsing Prolog answers with fixed substring indexes in CleanArray is brittle if the term format changes.
The bridge depends on a local SWI-Prolog install and a machine-specific jpl.jar path in the NetBeans project, which hurts portability.
Board encoding differs slightly between modes (numbered cells for two-player vs "0"/x/o for vs-PC), which adds mental overhead when debugging.
Every click in vs-PC mode triggers a full minimax search; fine for tic-tac-toe, but the pattern would need caching for larger games.
UI event handlers repeat similar validation blocks per button, which I accepted to ship the prototype quickly.
What I learned
This was one of my first deliberate language-boundary projects. I learned that the hard part is not minimax on a tiny board but keeping a single source of truth for rules while two runtimes exchange state.
Declarative move generation and utility scoring are a strong fit for Prolog; Java is a better home for frames, images, and input.
Thin, well-named Prolog goals (start_it, win, bestMove) make the Java side readable.
Integration glue (consult paths, query strings, parsing solutions) deserves as much care as the algorithm itself.
Even classic games benefit from separating “who won?” from “how do we draw the board?”
Current status
The project is no longer actively maintained and should be read as a completed personal prototype from 2019. I keep it in my portfolio because it shows early full-stack ownership on a small scale: UI, integration, and game AI in one repo. It is not deployed online; it runs as a local JAR with SWI-Prolog available on the machine.
If I revisited this today
Replace string slicing in CleanArray with a structured binding or a small JSON-like interchange format.
Unify board representation across modes and cover win/tie/move goals with a few integration tests.
Extract repeated button handlers into one “play at index” path in Java.
Consider a CLI-only Prolog mode for faster algorithm experiments without launching Swing.
Package Prolog dependencies or document a container image so recruiters can run the demo without manual SWI installs.