Sankalp Rai Gambhir· Fullstack Software & AI Engineer
HomeProjectsInsightsSkillsBlogContactResume
Back to Projects

Tic-Tac-Toe Multiplayer Game

A production-grade, real-time multiplayer Tic-Tac-Toe platform with unbeatable AI, live WebSocket gameplay, and persistent game history.

ReactTypeScriptViteTailwind CSSFramer MotionZustandDexie.js (IndexedDB)GoNode.jsRedisMongoDBDocker
GitHubLive Demo
Tic-Tac-Toe Multiplayer Game
5000+ (per instance)
Concurrent Players
3
AI Difficulty Levels
Single & Multiplayer
Game Modes
80%+
Test Coverage
Overview

A full-stack Tic-Tac-Toe application demonstrating advanced frontend engineering and distributed backend architecture. The backend combines a Go WebSocket server for real-time play and a Node.js REST API for player management and persistence, using Redis and MongoDB. The frontend is a modern React SPA with Minimax AI (with teaching mode), multiplayer via WebSockets, IndexedDB game history, and a mobile-first, accessible UI.

Timeline: 2 months
Role: Fullstack Software Engineer
Implementation Overview
  • ✓Unbeatable Minimax AI with alpha-beta pruning (teaching & hint modes)
  • ✓Real-time multiplayer with Go WebSocket server (auto-reconnect, join by code)
  • ✓Persistent game history and replays (IndexedDB)
  • ✓Responsive, accessible UI with dark mode and keyboard navigation
  • ✓Atomic move validation and rate limiting via Redis Lua scripts
  • ✓Player authentication and JWT token management
  • ✓Production-ready Docker deployment and zero-cost cloud hosting

Technical Deep Dive

1
Problem

Ensuring atomic move validation and preventing race conditions in multiplayer

✓

Solution

Used Redis Lua scripts for atomic move validation and pub/sub for event broadcasting

</>

Implementation

Minimax AI with Alpha-Beta Pruning

function minimax(board, depth, alpha, beta, maximizing) {
  if (isTerminal(board) || depth === 0) return evaluate(board);
  if (maximizing) {
    let maxEval = -Infinity;
    for (const move of getMoves(board)) {
      const eval = minimax(applyMove(board, move), depth - 1, alpha, beta, false);
      maxEval = Math.max(maxEval, eval);
      alpha = Math.max(alpha, eval);
      if (beta <= alpha) break;
    }
    return maxEval;
  } else {
    let minEval = Infinity;
    for (const move of getMoves(board)) {
      const eval = minimax(applyMove(board, move), depth - 1, alpha, beta, true);
      minEval = Math.min(minEval, eval);
      beta = Math.min(beta, eval);
      if (beta <= alpha) break;
    }
    return minEval;
  }
}
Key Insight: The Minimax algorithm with alpha-beta pruning powers the unbeatable AI, efficiently searching the game tree for optimal moves.
2
Problem

Scaling WebSocket connections for thousands of concurrent players

✓

Solution

Stateless Go WebSocket server with Redis connection pooling for horizontal scaling

</>

Implementation

Atomic Move Validation with Redis Lua

// Lua script for atomic move validation
EVAL "if redis.call('HEXISTS', KEYS[1], ARGV[1]) == 0 then redis.call('HSET', KEYS[1], ARGV[1], ARGV[2]); return 1 else return 0 end" 1 game:1234 moveX 'X'
Key Insight: Atomic move validation in multiplayer is enforced using Redis Lua scripts, preventing race conditions and double moves.
3
Problem

Providing a non-blocking, explainable AI experience in the browser

✓

Solution

Web Worker offloading for AI calculations and teaching mode explanations

</>

Implementation

Web Worker AI Offloading

// Offload AI to a Web Worker
const worker = new Worker('minimax.worker.js');
worker.postMessage({ board, difficulty });
worker.onmessage = (e) => setBestMove(e.data.move);
Key Insight: AI calculations are offloaded to a Web Worker, ensuring the UI remains responsive even for complex computations.
View Full Repository