Daniel Campos
HomeAboutThoughtsProjectsContact
Daniel Campos

Fullstack developer building practical software with clear interfaces and solid foundations.

Navigation

HomeProjectsThoughtsAbout

Social

ContactLinks

© 2026 Daniel Campos. All rights reserved.

TT
ProjectTic-Tac-Toe (Java & Prolog)

Tic-Tac-Toe (Java & Prolog)

A desktop tic-tac-toe game that pairs a Swing interface with Prolog-powered minimax so single-player mode plays optimally.

Snapshot

FieldDetails
TypeDesktop game prototype
ContextUniversity project (Artificial Intelligence)
RoleSolo developer
Year
2019
StatusAcademic prototype
Main focusHybrid 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.

minimax2.plprolog
minimax(Pos, BestNextPos, Val) :-
    bagof(NextPos, move(Pos, NextPos), NextPosList),
    best(NextPosList, BestNextPos, Val), !.

minimax(Pos, _, Val) :-
    utility(Pos, Val).

betterOf(Pos0, Val0, _, Val1, Pos0, Val0) :-
    min_to_move(Pos0),
    Val0 > Val1, !.

betterOf(Pos0, Val0, _, Val1, Pos0, Val0) :-
    max_to_move(Pos0),
    Val0 < Val1, !.

betterOf(_, _, Pos1, Val1, Pos1, Val1).

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").

GamePc.javajava
    private void prolog(){
        try{
            String conexion = "consult('minimax2.pl')";
            Query con = new Query(conexion);
            System.out.println(conexion + "" + (con.hasMoreSolutions() ? "ACEPTADO" : "FALLADO"));
        } catch (Exception e){
            e.printStackTrace();
        }
    }

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.
Share:
TT
ProjectTic-Tac-Toe (Java & Prolog)

Summary

A desktop tic-tac-toe game where Java handles the UI and Prolog runs minimax for an unbeatable computer opponent.

Tech Stack

JavaJava SwingSWI PrologAI

Categories

tool

Timeline

Aug 2019 – Aug 2019

← Back to Projects