import Foundation import WebSocketKit protocol Table: AbstractTable { /// The unique id of the table var id: TableId { get } /// The name of the table var name: TableName { get } /// The table is visible in the list of tables and can be joined by anyone var isPublic: Bool { get } /** The players sitting at the table. The players are ordered clockwise around the table, with the first player starting the game. */ var allPlayers: [Player] { get } var indexOfNextActor: Int { get } func perform(action: PlayerAction, forPlayer: PlayerName) -> (result: PlayerActionResult, table: Table?) func play(card: Card, player name: PlayerName) -> (result: PlayerActionResult, table: Table?) } extension Table { var playerNames: [String] { allPlayers.map { $0.name } } func index(of player: PlayerName) -> Int { allPlayers.firstIndex { $0.name == player }! } func player(named name: PlayerName) -> Player? { allPlayers.first { $0.name == name } } func contains(player: PlayerName) -> Bool { allPlayers.contains { $0.name == player } } // MARK: Connection func sendUpdateToAllPlayers() { allPlayers.enumerated().forEach { playerIndex, player in guard player.isConnected else { return } let info = self.tableInfo(forPlayerAt: playerIndex) player.send(info) } } func connect(player name: PlayerName, using socket: WebSocket) -> Bool { guard let player = player(named: name) else { return false } player.connect(using: socket) sendUpdateToAllPlayers() return true } func disconnect(player name: PlayerName) { guard let player = player(named: name) else { return } guard player.disconnect() else { return } sendUpdateToAllPlayers() return } // MARK: Client info var publicInfo: PublicTableInfo { .init(id: id, name: name, players: playerNames) } private func player(forIndex index: Int) -> Player? { let players = allPlayers guard index < players.count else { return nil } return players[index] } private func playerInfo(forIndex index: Int) -> PlayerInfo? { guard let player = player(forIndex: index) else { return nil } let isNext = indexOfNextActor == index return PlayerInfo(player: player, isNextActor: isNext, position: index) } func tableInfo(forPlayer player: PlayerName) -> TableInfo { let index = index(of: player) return tableInfo(forPlayerAt: index) } func tableInfo(forPlayerAt index: Int) -> TableInfo { let player = player(forIndex: index)! let own = playerInfo(forIndex: index)! let left = playerInfo(forIndex: (index + 1) % 4) let across = playerInfo(forIndex: (index + 2) % 4) let right = playerInfo(forIndex: (index + 3) % 4) return .init( id: id, name: name, own: own, left: left, across: across, right: right, actions: player.actions, cards: player.cards) } }