This is a submission for the Redis AI Challenge: Beyond the Cache.
What I Built
I developed a Plants vs. Zombies-inspired tower defense game that redefines what’s possible with Redis. This project uses Redis as the entire backend infrastructure. All game logic, state management, and real-time features are handled without a traditional SQL or NoSQL database.
Core Game Features
- Tower Defense: Engage in real-time battles against waves of zombies.
- Live Leaderboards: Compete for the top spot with five different real-time leaderboards.
- Persistent Game State: Players can reconnect and resume their games exactly where they left off. -** Dynamic Player Stats:** Track comprehensive, live statistics and player progress.
- Smart Username Suggestions: Get creative, plant-themed username ideas automatically.
How Redis Powers the Backend
- Redis is the engine behind the game. I utilized its diverse data structures to build a highly performant and scalable backend.
- Real-time Communication: Redis Pub/Sub handles all real-time events for multiplayer gameplay.
- Leaderboards: Redis sorted sets manage and update the live leaderboards, making it easy to rank players.
- Player Data: Game state and player statistics are stored using Redis hashes and other data structures for efficient access and updates.
- Analytics: Redis data structures track game metrics and analytics on the fly.
- Persistence: Redis's persistence features ensure that all game data is saved across sessions.
Demo
Here is the full Github Code you can test for yourself Github Code
How I Used Redis 8
This project demonstrates Redis using different Redis data structures to replace traditional database architectures:
1. Primary Database (Hashes)
Redis completely replaces SQL databases
Redis stores all persistent data including complex nested game states, player profiles, and session information.
// Store complete game states as JSON
await redis.hset(`game:${gameId}:state`, 'data', JSON.stringify({
players: {...},
plants: [...],
zombies: [...],
currentWave: 5,
gameStatus: 'playing'
}));
// Player profiles with statistics and achievements
await redis.hset(`player:${playerId}:data`, {
score: 15420,
zombiesKilled: 89,
plantsPlanted: 156,
gamesWon: 12,
achievements: JSON.stringify(['first_win', 'zombie_slayer'])
});
2. Real-Time Pub/Sub
Live multiplayer without polling
All real-time updates use Redis Pub/Sub for sub-millisecond message delivery to unlimited concurrent players.
// Broadcast plant placements to all players instantly
await redis.publish(`game:${gameId}:updates`, JSON.stringify({
type: 'plant_placed',
plant: {type: 'sunflower', row: 2, col: 3},
playerId: 'GardenMaster',
timestamp: Date.now()
}));
// Wave completion notifications
await redis.publish(`game:${gameId}:events`, JSON.stringify({
type: 'wave_completed',
wave: 5,
nextWaveIn: 30000,
message: 'Wave 5 completed! Prepare for boss wave!'
}));
3. Event Sourcing (Streams)
Complete game replay and analytics pipeline
Provides complete event sourcing capabilities - every game action is recorded for replay, analytics, and debugging without external event streaming systems
// Record every game action for complete audit trail
await redis.xadd(`game:${gameId}:events`, '*', {
action: 'plant_placed',
playerId: 'ZombieSlayer',
plantType: 'peashooter',
position: JSON.stringify({row: 1, col: 4}),
cost: 100,
timestamp: Date.now()
});
// Analytics pipeline processes all events
const gameEvents = await redis.xrange(`game:${gameId}:events`, '-', '+');
// Can reconstruct any game state from event history
4. Leaderboards (Sorted Sets)
Real-time competitive rankings
Automatic ranking system with O(log N) performance - no manual sorting or separate ranking calculations needed.
// Update multiple leaderboards simultaneously during gameplay
await redis.zadd('leaderboard:high_scores', player.score, playerId);
await redis.zadd('leaderboard:zombies_killed', player.zombiesKilled, playerId);
await redis.zadd('leaderboard:plants_planted', player.plantsPlanted, playerId);
// Get top 10 players with scores instantly
const topPlayers = await redis.zrevrange('leaderboard:high_scores', 0, 9, 'WITHSCORES');
// Returns: [['EpicSunflower', '25840'], ['GardenMaster', '23150'], ...]
5. Lane Management (Lists)
FIFO zombie queues for game mechanics
Perfect queue management for game mechanics - zombies spawn and move in correct order with atomic operations.
// Each game lane has its own zombie queue
await redis.lpush(`game:${gameId}:lane:0:zombies`, JSON.stringify({
type: 'basic_zombie',
health: 100,
speed: 1.0,
spawnTime: Date.now()
}));
// Process zombies in spawn order (FIFO)
const nextZombie = await redis.rpop(`game:${gameId}:lane:0:zombies`);
👥 6. Session Management (Sets)
Active games and player tracking
Efficient session management with set operations - instant membership checks and lobby management without complex queries.
// Track all active games
await redis.sadd('active_games', gameId);
// Track players in each game
await redis.sadd(`game:${gameId}:players`, playerId);
// Efficient membership checks
const isPlayerInGame = await redis.sismember(`game:${gameId}:players`, playerId);
const activeGameCount = await redis.scard('active_games');
7. Analytics & Metrics (HyperLogLog + Counters)
Memory-efficient statistics
Memory-efficient unique counting, global statistics, and rate limiting without external analytics systems.
// HyperLogLog for unique player counting (uses only ~12KB for millions of players)
await redis.pfadd('hll:unique_players', playerId);
const uniquePlayerCount = await redis.pfcount('hll:unique_players');
// Global game statistics
await redis.incr('counter:total_games');
await redis.incrby('counter:zombies_killed', zombiesKilledThisGame);
await redis.incrby('counter:plants_planted', plantsPlantedThisGame);
// Rate limiting with expiring counters
await redis.incr(`rate_limit:${playerId}:${currentHour}`);
await redis.expire(`rate_limit:${playerId}:${currentHour}`, 3600);
Traditional Redis Usage
// What most applications do - Redis as cache layer
const cachedUser = await redis.get(`cache:user:${userId}`);
if (!cachedUser) {
const user = await database.query('SELECT * FROM users WHERE id = ?', userId);
await redis.setex(`cache:user:${userId}`, 3600, JSON.stringify(user));
return user;
}
return JSON.parse(cachedUser);
Redis as Complete Platform
// What this project demonstrates - Redis as the entire backend
class GameEngine {
constructor(redis) {
this.redis = redis; // Redis IS the database, not a cache
}
async placePlant(gameId, playerId, plantType, row, col) {
// 1. Primary Database: Update game state
const gameState = await this.redis.hget(`game:${gameId}:state`, 'data');
// ... modify game state ...
await this.redis.hset(`game:${gameId}:state`, 'data', JSON.stringify(gameState));
// 2. Real-time: Notify all players instantly
await this.redis.publish(`game:${gameId}:updates`, JSON.stringify({
type: 'plant_placed', plant: newPlant, playerId
}));
// 3. Event Sourcing: Record for replay/analytics
await this.redis.xadd(`game:${gameId}:events`, '*', {
action: 'plant_placed', playerId, plantType, row, col
});
// 4. Leaderboards: Update rankings
await this.redis.zadd('leaderboard:plants_planted', ++player.plantsPlanted, playerId);
// 5. Analytics: Update global statistics
await this.redis.incr('counter:plants_planted');
await this.redis.pfadd('hll:unique_players', playerId);
// 6 different Redis capabilities in one operation!
}
}
Key Technical Achievements
Architecture Innovation
- Zero SQL databases - Redis handles all data persistence
- No cache invalidation - No cache layer because Redis IS the primary database
- Event-driven design - Pub/Sub eliminates all polling
- Complete audit trails - Streams provide event sourcing out of the box ### Performance Benefits
- Sub-millisecond operations - All data operations in memory
- Zero cache misses - No cache layer means no cache invalidation complexity
- Horizontal scalability - Architecture ready for Redis Cluster deployment
- Memory efficiency - HyperLogLog and optimized data structures
roduction Game Features
- Persistent progression - Player statistics and achievements survive server restarts
- Live competitive rankings - 5 different leaderboard categories updating in real-time
- Smart user experience - Auto-generated usernames, responsive design, health monitoring
** Deployment Ready**
- Docker support - Single container and multi-container configurations
- Production logging - Structured logging with multiple log levels
- Health monitoring - Comprehensive health checks and metrics endpoints
- Complete documentation - Deployment guides, API documentation, development workflows
Conclusion
This Plants vs Zombies game demonstrates Redis as a complete, powerful, multi-model platform that can:
Replace entire database stacks - No PostgreSQL, MongoDB, or MySQL needed
Provide real-time capabilities - Built-in Pub/Sub eliminates message queues
Handle complex analytics - HyperLogLog, counters, and sorted sets for insights
Scale to millions of users - Ready for Redis Cluster horizontal scaling
Deliver consistent sub-millisecond performance - All operations in memory
The game is fully functional, production-ready, and demonstrates Redis as the complete backend infrastructure for modern real-time applications.
Top comments (0)