import Foundation final class TableManagement { /// A list of table ids for public games private var publicTables = Set() /// A mapping from table id to table name (for all tables) private var tableNames = [TableId: TableName]() /// A mapping from table id to participating players private var tablePlayers = [TableId: [PlayerName]]() /// A reverse list of players and their table id private var playerTables = [PlayerName: TableId]() init() { } func tableExists(withId id: TableId) -> Bool { tableNames[id] != nil } func tableIsFull(withId id: TableId) -> Bool { (tablePlayers[id]?.count ?? playerPerTable) < playerPerTable } /** Create a new table with optional players. - Parameter name: The name of the table - Parameter players: The player creating the table - Parameter visible: Indicates that this is a game joinable by everyone - Returns: The table id */ func createTable(named name: TableName, player: PlayerName, visible: Bool) -> TableId { let tableId = TableId.newToken() tableNames[tableId] = name tablePlayers[tableId] = [player] playerTables[player] = tableId if visible { publicTables.insert(tableId) } return tableId } func getPublicTableInfos() -> [TableInfo] { publicTables.map { tableId in TableInfo(id: tableId, name: tableNames[tableId]!, players: tablePlayers[tableId]!) }.sorted() } /** Join a table. - Returns: The player names present at the table */ func join(tableId: TableId, player: PlayerName) -> [PlayerName] { guard var players = tablePlayers[tableId] else { return [] } players.append(player) if let oldTable = playerTables[tableId] { remove(player: player, fromTable: oldTable) } tablePlayers[tableId] = players playerTables[tableId] = tableId return players } func remove(player: PlayerName, fromTable tableId: TableId) { tablePlayers[tableId] = tablePlayers[tableId]?.filter { $0 != player } } }