Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

♟️ ConnectX Bitboard Agent

A brutally fast Connect Four Agent that thinks in bits, not grids.


🧠 What Is This?

This is a high-performance Connect Four agent built for the Kaggle ConnectX competition. Instead of treating the board as a boring 2D array, it encodes the entire game state into a single 64-bit integer — a technique called a bitboard. Every move, every win check, every threat evaluation happens through lightning-fast bitwise operations.

The result? An agent that can search millions of positions per second, often looking 15+ moves ahead within Kaggle's strict 2-second time limit.

The complete decision-making pipeline — from raw board to optimal move.


⚡ Why Bitboards?

A standard Connect Four board is 7 columns × 6 rows = 42 cells. Most implementations store this as a list or 2D array and loop through cells to check for wins. That's slow.

A bitboard packs the entire board into a single integer. Each bit represents one cell. Two integers — one for Player 1, one for Player 2 — capture the full state:

How 42 board cells map to bit positions inside a 64-bit integer.

Column layout (7 columns × 7 bits each, including sentinel row):

Col 0   Col 1   Col 2   Col 3   Col 4   Col 5   Col 6
bit 0   bit 7   bit 14  bit 21  bit 28  bit 35  bit 42
bit 1   bit 8   bit 15  bit 22  bit 29  bit 36  bit 43
bit 2   bit 9   bit 16  bit 23  bit 30  bit 37  bit 44
bit 3   bit 10  bit 17  bit 24  bit 31  bit 38  bit 45
bit 4   bit 11  bit 18  bit 25  bit 32  bit 39  bit 46
bit 5   bit 12  bit 19  bit 26  bit 33  bit 40  bit 47
------  ------  ------  ------  ------  ------  ------
bit 6   bit 13  bit 20  bit 27  bit 34  bit 41  bit 48  ← sentinel (unused)

Win detection in 4 operations:

# Check horizontal 4-in-a-row:
m = pos & (pos >> 7)      # pairs of adjacent pieces
if m & (m >> 14): WIN!    # pairs of pairs = four in a row

That's it. No loops, no boundary checks. Just bit shifts and AND operations. The same trick works for vertical, and both diagonal directions — 12 bitwise operations total to check all four directions.

The bitboard shown below corresponds to a realistic mid-game ConnectX position:

A mid-game position and its corresponding bitboard representation.


🔍 How the Search Works

Alpha-beta pruning in action — grey branches are never explored.

At its core, the agent uses Negamax with Alpha-Beta pruning — the gold standard for two-player zero-sum games. But raw alpha-beta alone isn't enough to beat strong opponents under a 2-second clock. Here's the full stack of techniques layered on top:

1. Iterative Deepening

Instead of guessing how deep to search, the agent starts at depth 1, then depth 2, then depth 3, and so on. Each completed depth gives a valid "best move" — so if time runs out mid-search, we still have the best answer from the previous depth. This also feeds information into the next iteration (see: move ordering).

2. Transposition Table (16M entries)

Many different move sequences lead to the same board position. A hash table with 2²⁴ = 16 million entries caches evaluated positions. Each entry stores:

  • The position's unique key (64-bit hash)
  • The evaluated score
  • The search depth
  • A flag (EXACT, LOWER bound, or UPPER bound)
  • The best move found

The key insight: the position hash is simply pos + (pos | opp) — no Zobrist randomness needed because bitboards are already unique fingerprints.

Mirror symmetry bonus: Every position is also stored for its horizontal mirror. A board with pieces on the left is strategically identical to one mirrored to the right. This effectively doubles the transposition table hit rate for free.

3. Move Ordering

Alpha-beta pruning is only as good as its move ordering. Search the best move first, and you prune almost everything else. The agent uses a layered ordering strategy:

Priority Technique What It Does
1st TT Best Move If this position was seen before, try that move first
2nd Must-Block If the opponent wins next turn, block immediately
3rd Killer Moves 2 moves per ply that recently caused beta cutoffs
4th History Heuristic Moves that have historically been good get priority
5th Center Bias Try center columns before edges (statistically stronger)

4. Aspiration Windows

After depth 4, the agent doesn't search the full score range [-∞, +∞]. Instead, it opens a narrow window of ±150 around the previous depth's score. If the true score falls inside, the search is much faster. If it falls outside (a "fail"), the agent re-searches with the full window. This gamble pays off the vast majority of the time.

5. Principal Variation Search (PVS)

The first move (expected to be the best thanks to move ordering) is searched with a full window. Every subsequent move is searched with a null window [α, α+1] — just to prove it's worse. If it surprisingly isn't, a full re-search kicks in. This reduces the search tree dramatically when move ordering is good.


Search Optimizations Overview

All optimization techniques work together to maximize search depth within Kaggle's strict 2-second move limit.


📊 Evaluation Heuristic

When the search hits its depth limit, the agent needs to estimate who's winning. The evaluation function combines:

Immediate Threats

  • Fork detection: If you have 2+ winning moves, you win regardless (score: +950)
  • Single threat: One winning move available (score: +500)
  • Opponent fork: Emergency — they have a double threat (score: -950)

Positional Scoring

  • Open line analysis: Scans every possible 4-cell window in all 4 directions. Windows with only your pieces score quadratically (3 pieces = 9 points, 2 = 4 points). This makes near-complete lines exponentially more valuable.
  • Center control: Pieces in the center column get a 4× bonus, adjacent columns get . Center control is king in Connect Four.

🚀 Numba JIT Acceleration

The entire search core is compiled to native machine code using Numba's @njit decorator. This eliminates Python's interpreter overhead and delivers near-C performance. The agent gracefully falls back to a pure Python implementation if Numba isn't available.

A warm-up call runs at the start to trigger JIT compilation before the game clock starts ticking.


🏆 Results

Metric Value
Competition Kaggle ConnectX
Search Algorithm Negamax + Alpha-Beta
Time Budget 2 seconds
TT Size 16M entries
Language Python + Numba

📁 Project Structure

connectx-bitboard-agent/
├── src/
│   └── agent.py            # The brain — all search and evaluation logic
├── tests/
│   └── test_agent.py       # Basic tests
├── assets/                  # Screenshots, diagrams, performance plots
├── .github/
│   └── workflows/
│       └── python-app.yml  # CI pipeline (lint + test on push)
├── main.py                  # Local test runner (agent vs random/negamax)
├── requirements.txt         # Python dependencies
├── LICENSE                  # MIT License
├── .gitignore
└── README.md                # You are here

🏁 Getting Started

Prerequisites

  • Python 3.8+
  • numpy
  • numba (optional but highly recommended)
  • kaggle-environments (for local testing)

Install & Run

# Clone the repo
git clone https://github.com/Tarun995/connectX-bitboard-agent.git
cd connectX-bitboard-agent

# Install dependencies
pip install -r requirements.txt

# Run a local game (agent vs random opponent)
python main.py

Submit to Kaggle

Upload src/agent.py directly as your submission file on the ConnectX competition page.


📝 License

This project is licensed under the MIT License — see the LICENSE file for details.


Built with ♟️ bits and ⚡ bitwise magic

About

High-performance ConnectX Agent developed for the Kaggle ConnectX Competition using Bitboards, Negamax Search, Alpha-Beta Pruning, Transposition Tables and Numba JIT.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages