Event Overview
Pica y Fija uses Socket.IO for real-time bidirectional communication between clients and server. This page documents all events, their parameters, and usage examples.
Event Types
Client → Server Events emitted by the client to request actions
Server → Client Events emitted by the server to notify clients of state changes
Client → Server Events
These events are emitted by the client and handled by the server.
crearSala
Creates a new game room with specified options.
Turn time limit in seconds. Determines how long each player has to make a guess.
Whether the room should be publicly listed. If true, other players can find it via buscarSala.
Whether the host must approve players joining. Currently not enforced in the implementation.
Client Example
socket . emit ( 'crearSala' , {
tiempoTurno: 60 ,
publica: true ,
requiereAprobacion: false
});
Server Handler
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...' );
});
Response Events
salaCreada - Contains the generated room code
info - Confirmation message
buscarSala
Searches for an available public room and automatically joins it.
This event takes no parameters.
Client Example
socket . emit ( 'buscarSala' );
Server Handler
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' );
}
});
Behavior
Finds the first public room with only 1 player (waiting for opponent)
Automatically calls joinRoom() if found
Emits info event if no rooms available
Response Events
salaLista - If room found and joined successfully
info - Status messages
unirseSala
Joins a specific room by code.
The 6-character room code (e.g., “XK9P2L”)
Client Example
const roomCode = "XK9P2L" ;
socket . emit ( 'unirseSala' , roomCode );
Server Handler
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 );
});
Validation
Room must exist
Room must have fewer than 2 players
Response Events
error - If room not found or full
salaLista - If joined successfully
info - Player assignment confirmation
secret
Submits the player’s secret 4-digit number.
A 4-digit number with all unique digits (e.g., “1234”, “9876”)
Client Example
const mySecret = "1234" ;
socket . emit ( 'secret' , mySecret );
Server Handler
socket . on ( 'secret' , secret => {
const room = rooms [ socket . roomCode ];
if ( ! room ) return ;
if ( ! / ^ \d {4} $ / . test ( secret ) || new Set ( secret ). size !== 4 ) {
socket . emit ( 'error' , 'El número debe tener 4 cifras diferentes' );
return ;
}
room . secrets [ socket . playerId ] = secret ;
socket . emit ( 'info' , 'Número secreto guardado' );
if ( room . secrets [ 0 ] && room . secrets [ 1 ]) {
io . to ( socket . roomCode ). emit ( 'start' );
setTimeout (() => broadcastTurn ( room ), 200 );
}
});
Validation
Must be exactly 4 digits
All digits must be unique (checked via new Set(secret).size !== 4)
Behavior
Stores secret in room.secrets[playerId]
When both players submit secrets, emits start to begin the game
After 200ms delay, broadcasts the first turn
Response Events
error - If validation fails
info - Confirmation message
start - When both secrets are submitted (broadcast to room)
turn - First turn notification
guess
Submits a guess attempt to crack the opponent’s secret number.
A 4-digit guess with all unique digits (e.g., “5678”)
Client Example
const myGuess = "5678" ;
socket . emit ( 'guess' , myGuess );
Server Handler
socket . on ( 'guess' , guess => {
const room = rooms [ socket . roomCode ];
if ( ! room ) return ;
if ( room . turn !== socket . playerId ) {
socket . emit ( 'error' , 'No es tu turno' );
return ;
}
if ( room . gameOver ) {
socket . emit ( 'error' , 'El juego ya terminó' );
return ;
}
if ( ! / ^ \d {4} $ / . test ( guess ) || new Set ( guess ). size !== 4 ) {
socket . emit ( 'error' , 'El intento debe tener 4 cifras distintas' );
return ;
}
const opponentId = socket . playerId === 0 ? 1 : 0 ;
const opponentSecret = room . secrets [ opponentId ];
if ( ! opponentSecret ) {
socket . emit ( 'error' , 'El oponente aún no ha elegido su número' );
return ;
}
const result = getPicasFijas ( opponentSecret , guess );
const turnNumber = room . turnCounts [ socket . playerId ] ++ ;
const data = {
jugadorId: socket . playerId ,
jugador: socket . playerId === 0 ? 'yo' : 'oponente' ,
turno: turnNumber ,
intento: guess ,
fijas: result . fijas ,
picas: result . picas
};
room . players . forEach ( p => p . emit ( 'result' , data ));
if ( result . fijas === 4 ) {
room . gameOver = true ;
} else {
room . turn = opponentId ;
broadcastTurn ( room );
}
});
Validation
Must be player’s turn (room.turn === socket.playerId)
Game must not be over (room.gameOver === false)
Must be exactly 4 digits with no repeats
Opponent must have submitted their secret
Behavior
Validates the guess format and turn
Calculates picas and fijas using getPicasFijas()
Broadcasts result to both players
If 4 fijas, sets gameOver = true
Otherwise, switches turn to opponent
Response Events
error - If validation fails
result - Guess outcome (broadcast to both players)
turn - Next turn notification (if game continues)
pasarTurnoPorTiempo
Forces the turn to switch to the opponent when time runs out.
This event takes no parameters.
Client Example
// Called when the turn timer expires
socket . emit ( 'pasarTurnoPorTiempo' );
Server Handler
socket . on ( 'pasarTurnoPorTiempo' , () => {
const room = rooms [ socket . roomCode ];
if ( ! room ) return ;
// Only the player with the current turn can force it
if ( room . turn !== socket . playerId ) return ;
// Simply switch the turn
room . turn = room . turn === 0 ? 1 : 0 ;
broadcastTurn ( room );
});
Behavior
Only the current turn holder can trigger this
Immediately switches turn to opponent
No guess is recorded
Response Events
turn - Next turn notification (broadcast to both players)
Server → Client Events
These events are emitted by the server to notify clients of state changes.
salaCreada
Sent to the room creator after successful room creation.
The generated 6-character room code (e.g., “XK9P2L”)
Server Code
socket . emit ( 'salaCreada' , { codigo: code });
Client Handler Example
socket . on ( 'salaCreada' , ({ codigo }) => {
console . log ( `Room created with code: ${ codigo } ` );
displayRoomCode ( codigo );
});
salaLista
Sent to both players when the room is full and ready to start.
Turn time limit in seconds
Server Code
room . players . forEach (( player , idx ) => {
player . emit ( 'salaLista' , {
jugador: idx + 1 ,
sala: code ,
tiempoTurno: room . options . tiempoTurno
});
});
Client Handler Example
socket . on ( 'salaLista' , ({ jugador , sala , tiempoTurno }) => {
console . log ( `You are Player ${ jugador } in room ${ sala } ` );
console . log ( `Turn time limit: ${ tiempoTurno } seconds` );
showSecretInput ();
});
start
Broadcast to both players when both secrets have been submitted.
This event carries no data payload.
Server Code
io . to ( socket . roomCode ). emit ( 'start' );
Client Handler Example
socket . on ( 'start' , () => {
console . log ( 'Game starting!' );
hideSecretInput ();
showGameBoard ();
});
turn
Notifies each player whether it’s their turn.
true if it’s this player’s turn, false otherwise
Server Code
function broadcastTurn ( room ) {
room . players . forEach (( s , i ) => {
s . emit ( 'turn' , { yourTurn: i === room . turn });
});
}
Client Handler Example
socket . on ( 'turn' , ({ yourTurn }) => {
if ( yourTurn ) {
console . log ( 'Your turn!' );
enableGuessInput ();
startTurnTimer ();
} else {
console . log ( 'Opponent \' s turn' );
disableGuessInput ();
}
});
result
Sent to both players after a guess is evaluated.
ID of the player who made the guess: 0 or 1
Perspective label: "yo" (me) or "oponente" (opponent)
Turn number for the guessing player (1, 2, 3, …)
The 4-digit guess that was made
Number of correct digits in correct positions (0-4)
Number of correct digits in wrong positions (0-4)
Server Code
const data = {
jugadorId: socket . playerId ,
jugador: socket . playerId === 0 ? 'yo' : 'oponente' ,
turno: turnNumber ,
intento: guess ,
fijas: result . fijas ,
picas: result . picas
};
room . players . forEach ( p => p . emit ( 'result' , data ));
Client Handler Example
socket . on ( 'result' , ({ jugador , turno , intento , fijas , picas }) => {
addToHistory ( jugador , turno , intento , fijas , picas );
if ( fijas === 4 ) {
if ( jugador === 'yo' ) {
showWinMessage ();
} else {
showLoseMessage ();
}
}
});
Win Condition
When fijas === 4, the game is over and the guessing player wins.
info
General information or status messages.
Human-readable status message in Spanish
Server Examples
socket . emit ( 'info' , 'Sala creada. Esperando jugador...' );
socket . emit ( 'info' , 'Número secreto guardado' );
socket . emit ( 'info' , 'Conectado como Jugador 1' );
socket . emit ( 'info' , 'Tu oponente se ha desconectado' );
Client Handler Example
socket . on ( 'info' , ( message ) => {
console . log ( '[INFO]' , message );
showNotification ( message , 'info' );
});
error
Error messages for invalid actions.
Human-readable error message in Spanish
Server Examples
socket . emit ( 'error' , 'Sala no encontrada' );
socket . emit ( 'error' , 'La sala ya está llena' );
socket . emit ( 'error' , 'No es tu turno' );
socket . emit ( 'error' , 'El número debe tener 4 cifras diferentes' );
socket . emit ( 'error' , 'El juego ya terminó' );
Client Handler Example
socket . on ( 'error' , ( message ) => {
console . error ( '[ERROR]' , message );
showNotification ( message , 'error' );
});
Complete Client Example
Here’s a full client implementation showing all event handlers:
import { io } from 'socket.io-client' ;
const socket = io ( 'http://localhost:9090' );
// Create a room
function createRoom () {
socket . emit ( 'crearSala' , {
tiempoTurno: 60 ,
publica: true ,
requiereAprobacion: false
});
}
// Join a public room
function findPublicRoom () {
socket . emit ( 'buscarSala' );
}
// Join by code
function joinRoom ( code ) {
socket . emit ( 'unirseSala' , code );
}
// Submit secret
function submitSecret ( secret ) {
socket . emit ( 'secret' , secret );
}
// Make a guess
function makeGuess ( guess ) {
socket . emit ( 'guess' , guess );
}
// Handle turn timeout
function onTurnTimeout () {
socket . emit ( 'pasarTurnoPorTiempo' );
}
// Event listeners
socket . on ( 'salaCreada' , ({ codigo }) => {
console . log ( 'Room created:' , codigo );
});
socket . on ( 'salaLista' , ({ jugador , sala , tiempoTurno }) => {
console . log ( `Player ${ jugador } in room ${ sala } ` );
});
socket . on ( 'start' , () => {
console . log ( 'Game starting!' );
});
socket . on ( 'turn' , ({ yourTurn }) => {
console . log ( yourTurn ? 'Your turn' : 'Opponent turn' );
});
socket . on ( 'result' , ({ jugador , turno , intento , fijas , picas }) => {
console . log ( ` ${ jugador } - Turn ${ turno } : ${ intento } → ${ fijas } F ${ picas } P` );
});
socket . on ( 'info' , ( message ) => {
console . log ( '[INFO]' , message );
});
socket . on ( 'error' , ( message ) => {
console . error ( '[ERROR]' , message );
});
Event Flow Diagram
All events are real-time. The server broadcasts state changes immediately to maintain synchronization between players.