Connect Four vs Computer — Free HTML CSS JS Snippet
Connect Four vs Computer · Games · Plain HTML, CSS & JS · Live preview
For supporters
Source Code
Want the source code?
Play the game for free. Become a WebDevPuneet supporter to unlock the complete HTML, CSS and JavaScript source code, the exports (HTML, React, Vue, Angular, Tailwind) and Fork.
Extend with AI
Take This Snippet Further With AI
The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.
What's included
Features
About this UI Snippet
Connect Four vs Computer — Grid Gravity Drop, 4-Direction Win Detection & Heuristic AI Opponent

Connect Four is a two-player strategy game built on a deceptively simple mechanic: discs fall under gravity into one of seven columns, stacking on top of whatever is already there, and the first player to line up four discs of their own colour horizontally, vertically, or diagonally wins. This snippet implements the full game as a genuine playable board — not a static mockup — complete with real gravity simulation, four-direction win checking, and a heuristic computer opponent that plays a credible game rather than moving randomly.
The gravity model: a 2D array, not pixel maths
The board is represented as a 7-column array of 6-row arrays, board[col][row], where row 0 is the bottom of the column. Instead of placing a disc exactly where the user clicked, lowestEmptyRow(col) scans the column from the bottom upward and returns the first null slot — that index is where the disc actually lands. This is the real mechanic behind Connect Four's gravity: clicking anywhere in a column always drops into the lowest available cell, and the CSS reinforces it visually by laying each column out with flex-direction: column-reverse so cell index 0 renders at the bottom. The falling animation itself is pure CSS — a .c4-disc starts at transform: scale(0) translateY(-140%) and animates to scale(1) translateY(0) with a bouncy cubic-bezier(0.34, 1.56, 0.64, 1) easing curve that gives the drop a satisfying overshoot.
Four-direction win detection
After every move, checkWin(col, row, player) walks outward from the just-placed disc along four axis pairs: horizontal [1, 0], vertical [0, 1], and both diagonals [1, 1] and [1, -1]. For each direction it counts matching discs going forward and then counts again going backward along the same axis, because a winning line can extend on either side of the disc that completed it. If the combined run reaches four or more, the coordinates of that line are returned and each winning cell gets a .win-cell class that adds a glowing green ring and a slow pulsing brightness animation, making the winning line immediately obvious.
The heuristic AI: three priorities, no brute force
The computer opponent does not use minimax or a deep search tree — it applies three ordered heuristics that are exactly how a competent human casual player thinks about the game. First, wouldWin(col, COMPUTER) temporarily drops a yellow disc into every legal column and re-runs checkWin to see whether that move produces an immediate four-in-a-row; if any column does, the computer takes it and wins on the spot. Second, if no winning move exists, the same check runs with HUMAN as the hypothetical player — if the human could win next turn by dropping into some column, the computer occupies that column itself to block it. Third, if neither an immediate win nor a necessary block exists, the computer falls back to positional strategy: it prefers columns in centerOrder = [3, 2, 4, 1, 5, 0, 6], trying the centre column first and working outward. This reflects real Connect Four theory — the centre column participates in more possible four-in-a-row lines (horizontal, vertical, and both diagonals) than any edge column, so occupying it early creates more future winning threats.
Session scoring and disc rendering
A running tally of wins, losses, and draws persists across rounds in a scores object and renders in three coloured score pills above the board. Each disc is a separate absolutely-positioned <div> layered on top of an empty circular cell rather than a background-colour change, which is what makes the drop-in scale animation possible — the disc element itself animates in, rather than a colour simply appearing.
Step by step
How to Use
- 1Drop a discClick anywhere in a column to drop a red disc into the lowest empty cell of that column. The disc animates in with a bouncy fall — you cannot click a specific row, only a column, exactly like the physical game.
- 2Watch the computer respondAfter your move, the status line reads "Computer is thinking..." for a short 450ms delay before computerMove() runs. This pause exists purely for pacing — the AI itself resolves instantly via the three-tier heuristic in wouldWin() and centerOrder.
- 3Read the win highlightWhen four discs connect in any of the four directions, checkWin() returns the exact winning coordinates and each of those four discs gets the .win-cell class, adding a glowing green ring and pulsing brightness so the winning line is unmistakable.
- 4Track the session tallyThe three score pills above the board (You / Draws / Computer) increment automatically via updateScoreboard() at the end of every round and persist in memory across "New Game" clicks within the same page load.
- 5Start a fresh boardClick "New Game" to call createBoard(), which resets the board array to a 7x6 grid of nulls, clears all disc elements, and re-enables column clicks without touching the session score tally.
- 6Customise the AI difficultyTo make the computer weaker, remove the wouldWin(c, HUMAN) blocking check so it only takes immediate wins. To make it stronger, extend wouldWin() to look two moves ahead, or add a check for moves that create a double-threat (two simultaneous three-in-a-rows).
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
No — the AI always follows the same three-tier priority: take an immediate winning move if one exists, otherwise block the human's immediate winning move if one exists, otherwise pick the most central available column. It never makes a deliberately weak or random move, so it plays a consistent, fair, moderately challenging game every round.
checkWin() iterates over four direction vectors: [1,0] for horizontal, [0,1] for vertical, [1,1] for the rising diagonal, and [1,-1] for the falling diagonal. For each vector it counts matching discs both forward and backward from the placed disc along that same axis, so a diagonal line that extends on either side of the new disc is still correctly detected as connected.
Yes. The current wouldWin() helper only simulates one move ahead. To add lookahead, extend it into a minimax function that recursively simulates the human's best response to each computer move and scores the resulting position, then picks the column with the best worst-case outcome. A depth of 4-6 plies is typically enough to make Connect Four very difficult to beat for a casual player.
Column-first indexing matches how the player actually interacts with the game — clicking a column and letting gravity decide the row. lowestEmptyRow(col) can then simply scan board[col] from index 0 upward without needing to transpose coordinates, which keeps both the drop logic and the CSS column-reverse layout consistent with the same mental model.
Not out of the box, but it is a small change: remove the setTimeout(computerMove) call inside handleColumnClick and instead track whose turn it is with a currentPlayer variable that toggles between red and yellow after every successful drop, calling placeDisc and checkWin identically for both players.