PARTE 1: Estructura General del Programa
Clases necesarias:
1. Player
o Propiedades: Id, Level, Thread, IsConnected
o Métodos: JoinMatchmaking()
2. GameRoom
o Propiedades: List<Player> Players, MinLevel, MaxLevel
o Métodos: CanJoin(Player p), AddPlayer(Player p)
3. MatchmakingServer
o Propiedades: List<GameRoom> Rooms
o Métodos: TryJoin(Player p), CreateRoom(Player p)
o Gestión de sincronización y concurrencia
4. Level (enum)
o Valores: Beginner = 0, Intermediate = 1, Advanced = 2, Expert = 3
Hilos:
• Cada jugador será ejecutado en un hilo independiente (simula conexión simultánea).
• Un hilo principal para iniciar múltiples jugadores concurrentemente.
Exclusión mutua:
• Acceso a la lista de salas (Rooms) debe estar protegido con lock para evitar condiciones de carrera.
• Al agregar jugadores a una sala, también se debe usar exclusión mutua.
Sincronización condicional:
• Si no hay sala compatible, el jugador espera durante cierto tiempo (simulación con [Link] o [Link]) antes de decidir crear nueva
sala.
• En la parte 3 se usará [Link]() para forzar la salida.
using System;
using [Link];
using [Link];
using [Link];
// Niveles posibles de los jugadores
public enum Level { BEGINNER = 0, INTERMEDIATE = 1, ADVANCED = 2, EXPERT = 3 }
// Clase que representa un jugador
public class Player
{
public int Id { get; }
public Level Level { get; }
private MatchmakingServer server;
public Player(int id, Level level, MatchmakingServer server)
{
Id = id;
Level = level;
[Link] = server;
}
// Método que simula el intento de emparejamiento
public void JoinMatchmaking()
{
try
{
[Link](2000); // Simula una espera de emparejamiento que puede ser interrumpida
[Link]($"Jugador {Id} (Nivel: {Level}) intentando unirse a una sala...");
// Intenta unirse a una sala existente
if ()
{
// Si no encuentra sala compatible, crea una nueva
[Link]($"Jugador {Id} no encontró sala válida, creando nueva sala.");
[Link](this);
}
}
catch (ThreadInterruptedException)
{
// El hilo fue interrumpido por haber esperado demasiado
[Link]($"Jugador {Id} desconectado por espera excesiva.");
}
}
}
// Clase que representa una sala de juego
public class GameRoom
{
private List<Player> players = new();
private object lockObj = new(); // Protección contra concurrencia
public bool CanJoin(Player p) // Verifica si un jugador puede unirse a la sala actual
{
lock (lockObj)
{
if ([Link] >= 4) return false; // Límite de 4 jugadores
if ([Link] == 0) return true; // Sala vacía, se puede unir
int min = [Link](pl => (int)[Link]);
int max = [Link](pl => (int)[Link]);
int level = (int)[Link];
// Requiere que la diferencia con todos los niveles actuales sea ≤ 1
return [Link](level - min) <= 1 && [Link](level - max) <= 1;
}
}
// Agrega un jugador a la sala
public void AddPlayer(Player p)
{
lock (lockObj)
{
[Link](p);
[Link]($" Jugador {[Link]} añadido a sala con niveles [{[Link](pl => [Link])} -
{[Link](pl => [Link])}]");
}
}
public int Count => [Link]; // Devuelve el número de jugadores en la sala
}
// Clase que representa el SERVIDOR de emparejamiento
public class MatchmakingServer
{
private List<GameRoom> rooms = new(); // Lista de salas
private object lockObj = new(); // Protección contra condiciones de carrera
// Intenta unir un jugador a una sala existente
public bool TryJoin(Player p)
{
lock (lockObj)
{
// Busca la sala compatible más llena
GameRoom? target = rooms
.Where(r => [Link](p))
.OrderByDescending(r => [Link])
.FirstOrDefault();
if (target != null)
{
[Link](p);
return true;
}
return false;
}
}
// Crea una sala nueva para el jugador
public void CreateRoom(Player p)
{
lock (lockObj)
{
GameRoom room = new();
[Link](p);
[Link](room);
[Link]($"Nueva sala creada por Jugador {[Link]}");
}
}
}
class Program
{
static void Main()
{
MatchmakingServer server = new(); // Instancia del servidor
Random rand = new(); // Para asignar niveles aleatorios
List<Thread> threads = new(); // Lista de hilos de jugadores
// Simula 15 jugadores conectándose al servidor
for (int i = 1; i <= 15; i++)
{
int id = i;
Level level = (Level)[Link](0, 4); // Nivel aleatorio (0 a 3)
Player player = new(id, level, server);
// Cada jugador será ejecutado en un hilo
Thread thread = new(() =>
{
[Link](); // Intenta unirse a una sala
});
[Link]();
[Link](thread);
[Link](200); // Simula llegadas escalonadas
}
// Espera hasta 3 segundos por cada jugador antes de interrumpir
foreach (Thread thread in threads)
{
if () // Espera 3 segundos como máximo
{
[Link](); // Interrumpe si sigue esperando
}
}
}
}
PARTE 3: Cancelación por espera excesiva
// Cambios en el MAIN
Thread thread = new(() =>
{
try
{
[Link]();
}
catch (ThreadInterruptedException)
{
[Link]($"Jugador {id} cancelado por espera.");
}
});
[Link]();
[Link](3000); // Tiempo máximo de espera
if ([Link])
{
[Link](); // Fuerza la desconexión si sigue esperando
}