A full-featured Java implementation of Connect Four with a polished Swing GUI, three game modes, a difficulty-selectable AI opponent powered by Minimax with Alpha-Beta pruning, and a packaged macOS application.
A pre-built macOS application is available to download — no Java installation or compilation required.
Because the app isn't signed with an Apple Developer certificate, macOS will block it from opening by default. To remove the quarantine flag, run the following command in your terminal after dragging the app to your Applications folder:
xattr -cr /Applications/connectFour.appThen double-click the app to launch it as normal. You only need to run this command once.
What does this command do?
xattr -crrecursively removes extended attributes (including thecom.apple.quarantineflag macOS adds to downloaded files) from the app bundle. It does not modify the app itself.
- Three game modes — Human vs Human, Human vs AI, AI vs AI
- Three AI difficulty levels — Easy, Medium, Hard
- Minimax AI with Alpha-Beta pruning — searches up to 6 moves ahead on Hard
- Heuristic board evaluation — scores windows, rewards centre control, detects forks
- Win detection in all four directions — horizontal, vertical, diagonal, anti-diagonal
- Polished Swing GUI — custom-painted dialogs, hover indicators, animated piece drops
- Non-blocking AI — AI computation runs on a background thread so the UI never freezes
- Draw detection — recognises a full board with no winner
- Play Again / Quit dialog — shown at the end of every game
src/
├── Main.java # Entry point — launches the Swing application
├── Cell.java # Enum: R, Y, EMPTY — represents board cell states
├── Board.java # Core game logic — grid, move validation, win detection, board cloning
├── BoardPanel.java # Swing JPanel — renders the board, handles mouse input and game loop
├── GameWindow.java # JFrame setup — initialises players and wires everything together
├── Player.java # Interface — getMove(Board) and getColour()
├── HumanPlayer.java # Implements Player — stores pending mouse click move
├── AIPlayer.java # Implements Player — Minimax + Alpha-Beta + heuristic evaluation
├── ModeDialog.java # Swing dialog — Human vs Human / Human vs AI / AI vs AI
├── DifficultyDialog.java# Swing dialog — Easy / Medium / Hard
└── GameOverDialog.java # Swing dialog — Play Again / Quit
Requirements: Java 11 or later
# 1. Clone the repository
git clone https://github.com/n8wn/connectFour.git
cd connectFour/src
# 2. Compile all source files
javac *.java
# 3. Run the application
java Main- On launch, select a game mode: Human vs Human, Human vs AI, or AI vs AI
- If playing against the AI, choose a difficulty: Easy, Medium, or Hard
- Click any column to drop your piece into it — pieces fall to the lowest available row
- Red always goes first
- The first player to connect four pieces in a row (horizontally, vertically, or diagonally) wins
- If the board fills with no winner, the game is a draw
- A dialog will appear at the end — choose to play again or quit
The AI opponent is the core of this project. Here's how it works in detail.
The AI uses the Minimax algorithm to search the game tree, alternating between maximising its own score and minimising the opponent's. At each node it:
- Clones the board (
Board.cloneBoard()) so the real game state is never affected - Simulates every available move (
Board.colsAvailable()) - Recursively evaluates the resulting positions
- Returns the move with the highest score
Alpha-Beta pruning is applied to cut branches that cannot affect the final result. If the current path can never beat an already-found option, the search stops early — significantly reducing the number of positions evaluated at deeper depths.
Depth 2 (Easy) → looks 2 moves ahead
Depth 4 (Medium) → looks 4 moves ahead
Depth 6 (Hard) → looks 6 moves ahead
Win/loss states are scored with a depth bonus so the AI prefers faster wins and longer survival:
if (winner == colour) return 100000 + depth; // faster win = higher score
if (winner == opponentColour) return -100000 - depth; // faster loss = lower scoreWhen the search reaches its depth limit without a terminal state, evaluateBoard() scores the position statically:
- Sliding window scoring — every group of four consecutive cells (horizontal, vertical, diagonal, anti-diagonal) is scored based on how many AI or opponent pieces it contains:
- 3 AI + 1 empty → +5
- 2 AI + 2 empty → +2
- 3 opponent + 1 empty → −4
- Centre column control — occupying the centre column is rewarded (+3 per piece), as it maximises the number of winning lines available
- Fork detection — positions where a player has two simultaneous winning threats (a fork) are detected and scored heavily (+20 for AI fork, −20 for opponent fork)
| Level | Search Depth | Random Move Chance |
|---|---|---|
| Easy | 2 | 55% |
| Medium | 4 | 30% |
| Hard | 6 | 0% |
Easy and Medium modes occasionally make random moves to simulate human-like imperfection.
Minimax is computationally expensive, especially at depth 6. Running it on the Event Dispatch Thread would freeze the UI while the AI thinks. To prevent this, AI computation is offloaded to a SwingWorker background thread:
SwingWorker<Integer, Void> worker = new SwingWorker<>() {
@Override
protected Integer doInBackground() {
return currentPlayer.getMove(board); // runs off the UI thread
}
@Override
protected void done() {
int col = get();
Board.dropCell(board, col, currentPlayer.getColour()); // back on UI thread
repaint();
}
};
worker.execute();This also enables AI vs AI mode, where both players think on background threads and the UI updates cleanly between moves.
Board.java was designed from the start with AI compatibility in mind. Key methods:
| Method | Purpose |
|---|---|
cloneBoard() |
Deep copies the grid so Minimax can simulate moves without mutating real state |
colsAvailable() |
Returns a list of non-full columns for move enumeration |
dropCell() |
Applies gravity — drops a piece to the lowest empty row in a column |
isGameWon() |
Checks all four directions for a four-in-a-row |
isGridFull() |
Detects draw conditions |
The interface is built entirely with Java Swing, with all visual components custom-painted using Graphics2D:
- BoardPanel — renders the 6×7 grid with circular cells, drop shadows, and a subtle shine effect on empty cells. Handles mouse click and hover events
- ModeDialog — modal dialog for selecting game mode, shown on launch
- DifficultyDialog — modal dialog for selecting AI difficulty, shown when Human vs AI is chosen
- GameOverDialog — modal dialog shown at the end of each game with Play Again / Quit options
- All dialogs use a consistent dark navy colour scheme with accent-coloured buttons that highlight on hover
- Language: Java
- GUI: Java Swing (JPanel, JFrame, JDialog, Graphics2D)
- AI: Minimax, Alpha-Beta Pruning, Heuristic Evaluation
- Concurrency: SwingWorker
- Packaging: macOS DMG
- Animated piece drop (smooth fall transition)
- Sound effects on piece placement and win
- Score tracking across multiple rounds
- Iterative deepening for more consistent AI response times
- Windows and Linux packaging