Hello everyone! 👋
A few weeks ago, I launched NodeClash – a real-time multiplayer platform where developers can battle each other in Data Structures and Algorithms (DSA).
Getting the initial idea was easy. But making sure that both players see each other's keystrokes, test case results, and AI constraints in real-time without the server crashing? That was the real challenge.
Today, I want to share how I structured the WebSocket matchmaking logic using Node.js and Socket.io.
🏗️ The Matchmaking Problem
When a user clicks "Start Battle", the server needs to:
- Check if there's an existing player waiting in the queue.
- If yes, pair them up, generate a unique Room ID, and send both players to the same battle arena.
- If no, put the player in a waiting state.
💻 The Socket.io Approach
Instead of complex polling, I relied heavily on Socket.io's rooms feature. Here is a simplified version of my backend matchmaking logic:
javascript
// A simple queue to hold waiting players
let waitingPlayers = [];
io.on('connection', (socket) => {
console.log(`User connected: ${socket.id}`);
socket.on('join_queue', (userData) => {
if (waitingPlayers.length > 0) {
// Opponent found!
const opponent = waitingPlayers.pop();
const roomId = `battle_${opponent.id}_${socket.id}`;
// Put both players in the same isolated room
socket.join(roomId);
io.sockets.sockets.get(opponent.id).join(roomId);
// Broadcast to both players that the match is starting
io.to(roomId).emit('match_found', { roomId, problem: generateRandomDSA() });
} else {
// No one waiting, join the queue
waitingPlayers.push({ id: socket.id, user: userData });
}
});
});
Top comments (0)