Skip to main content

Overview

Pica y Fija uses a room-based multiplayer system where players create or join rooms to start a game. Each room supports exactly 2 players and can be configured with custom settings like turn timers and visibility.

Creating a Room

Room Configuration

When creating a room, the host can configure three key settings:

Turn Timer

Set the duration (in seconds) each player has to make a guess

Public/Private

Control whether the room appears in public room searches

Approval Required

Require host approval for players joining (future feature)

Client-Side Room Creation

Players create rooms through the lobby interface:
index.html
function crearSala() {
  const tiempoTurno = parseInt(document.getElementById('tiempoTurno').value);
  const publica = document.getElementById('salaPublica').checked;
  const requiereAprobacion = document.getElementById('requiereAprobacion').checked;
  socket.emit('crearSala', { tiempoTurno, publica, requiereAprobacion });
  lobby.style.display = 'none';
  zonaJuego.style.display = 'block';
}

Server-Side Room Creation

The server handles room creation by generating a unique code and initializing the room state:
server.js
socket.on('crearSala', ({ tiempoTurno, publica, requiereAprobacion }) => {
  const code = generateRoomCode();
  rooms[code] = {
    host: socket,
    players: [socket],
    secrets: {},
    turn: 0,
    turnCounts: [1, 1],
    options: { tiempoTurno, publica, requiereAprobacion },
    gameOver: false
  };

  socket.roomCode = code;
  socket.playerId = 0;
  socket.join(code);
  if (publica) publicRooms.push(code);

  socket.emit('salaCreada', { codigo: code });
  socket.emit('info', 'Sala creada. Esperando jugador...');
});
Room codes are 6-character alphanumeric strings generated using Math.random().toString(36).substring(2, 8).toUpperCase()

Joining a Room

Players can join existing rooms in two ways:

Method 1: Join by Room Code

If you have a specific room code, you can join directly:
index.html
function unirseSala() {
  const codigo = document.getElementById('codigoSala').value.trim().toUpperCase();
  if (codigo.length < 4) {
    log.innerText += '❌ Código inválido\n';
    return;
  }
  socket.emit('unirseSala', codigo);
  lobby.style.display = 'none';
  zonaJuego.style.display = 'block';
}
Server-side validation ensures the room exists and has space:
server.js
socket.on('unirseSala', (codigo) => {
  const room = rooms[codigo];
  if (!room) {
    socket.emit('error', 'Sala no encontrada');
    return;
  }

  if (room.players.length >= 2) {
    socket.emit('error', 'La sala ya está llena');
    return;
  }

  joinRoom(socket, codigo);
});

Method 2: Search for Public Rooms

Players can automatically join an available public room:
index.html
function buscarSala() {
  socket.emit('buscarSala');
  lobby.style.display = 'none';
  zonaJuego.style.display = 'block';
}
The server finds the first available public room:
server.js
socket.on('buscarSala', () => {
  const roomCode = publicRooms.find(code => rooms[code].players.length === 1);
  if (roomCode) {
    joinRoom(socket, roomCode);
  } else {
    socket.emit('info', 'No hay salas públicas disponibles');
  }
});
Only rooms with exactly 1 player waiting will appear in the public room search. Full rooms (2 players) are automatically excluded.

Room Lifecycle

Joining Process

When a second player joins, the joinRoom function handles initialization:
server.js
function joinRoom(socket, code) {
  const room = rooms[code];
  socket.join(code);
  room.players.push(socket);
  socket.roomCode = code;
  socket.playerId = 1;

  room.players[0].emit('info', 'Conectado como Jugador 1');
  room.players[1].emit('info', 'Conectado como Jugador 2');

  // Emit event when room is full
  if (room.players.length === 2) {
    room.players.forEach((player, idx) => {
      player.emit('salaLista', {
        jugador: idx + 1,
        sala: code,
        tiempoTurno: room.options.tiempoTurno
      });
    });
  }
}

Room Ready Event

When both players are connected, each receives the salaLista event:
index.html
socket.on('salaLista', data => {
  miJugadorId = data.jugador === 1 ? 0 : 1;
  tiempoTurnoConfigurado = data.tiempoTurno || 60;
  lobby.style.display = 'none';
  zonaJuego.style.display = 'block';
  log.innerText += `✅ Te uniste como Jugador ${data.jugador} a la sala ${data.sala}\n`;
});

Player Disconnection

Rooms are automatically cleaned up when players disconnect:
server.js
socket.on('disconnect', () => {
  const code = socket.roomCode;
  const room = rooms[code];

  if (room) {
    room.players = room.players.filter(p => p !== socket);
    if (room.players.length === 0) {
      delete rooms[code];
      publicRooms = publicRooms.filter(c => c !== code);
    } else {
      room.players[0].emit('info', 'Tu oponente se ha desconectado');
    }
  }
});
Each room object contains:
  • host: Socket reference to the room creator
  • players: Array of socket references (max 2)
  • secrets: Object mapping player IDs to their secret numbers
  • turn: Current player’s turn (0 or 1)
  • turnCounts: Array tracking turn numbers for each player
  • options: Room configuration (tiempoTurno, publica, requiereAprobacion)
  • gameOver: Boolean flag indicating if the game has ended

Socket.IO Events

Client → Server

EventPayloadDescription
crearSala{ tiempoTurno, publica, requiereAprobacion }Creates a new room with settings
buscarSalaNoneSearches for an available public room
unirseSalacodigo (string)Joins a room by code

Server → Client

EventPayloadDescription
salaCreada{ codigo }Confirms room creation with code
salaLista{ jugador, sala, tiempoTurno }Notifies when room is full and ready
infomessage (string)General information messages
errormessage (string)Error messages

Best Practices

Room Code Validation

Always validate room codes on both client and server to prevent invalid join attempts

Capacity Limits

Enforce the 2-player limit strictly to prevent room overflow

Cleanup

Remove empty rooms and update public room lists on disconnection

Player ID Assignment

Host always gets ID 0, joiner gets ID 1 for consistent game logic

Build docs developers (and LLMs) love