import Foundation import WebSocketKit class AbstractTable where TablePlayer: Player { /// The unique id of the table let id: TableId /// The name of the table let name: TableName /// Indicates that the table is visible to all players, and can be joined by anyone let isPublic: Bool /** The players sitting at the table. The players are ordered clockwise around the table, with the first player starting the game. */ var players: [TablePlayer] var playedGame: GameType? { nil } init(table: ManageableTable, players: [TablePlayer]) { self.id = table.id self.name = table.name self.isPublic = table.isPublic self.players = players } init(id: TableId, name: TableName, isPublic: Bool, players: [TablePlayer]) { self.id = id self.name = name self.isPublic = isPublic self.players = players } func perform(action: PlayerAction, forPlayer name: PlayerName) -> (result: PlayerActionResult, table: ManageableTable?) { (.tableStateInvalid, nil) } func play(card: Card, player name: PlayerName) -> (result: PlayerActionResult, table: ManageableTable?) { (.tableStateInvalid, nil) } func playerData(at index: Int) -> (actions: [PlayerAction], games: [GameConvertible], cards: [PlayableCard], selectsGame: Bool) { let player = players[index] return (actions: player.actions, games: [], cards: player.cards.unplayable, selectsGame: false) } func cardStackPosition(ofPlayerAt index: Int) -> Int { index } } extension AbstractTable: ManageableTable { var publicInfo: PublicTableInfo { .init(id: id, name: name, players: playerNames) } var playerNames: [PlayerName] { players.map { $0.name } } var allPlayers: [Player] { players } // MARK: Connection func connect(player name: PlayerName, using socket: WebSocket) -> Bool { guard let player = players.player(named: name) else { return false } player.connect(using: socket) sendUpdateToAllPlayers() return true } func disconnect(player name: PlayerName) { guard let player = players.player(named: name) else { return } guard player.disconnect() else { return } sendUpdateToAllPlayers() return } func sendUpdateToAllPlayers() { players.enumerated().forEach { playerIndex, player in guard player.isConnected else { return } let info = self.tableInfo(forPlayerAt: playerIndex) player.send(info) } } // MARK: Client info func playerInfo(forIndex index: Int) -> PlayerInfo? { guard let player = players.at(index) else { return nil } let height = cardStackPosition(ofPlayerAt: index) return PlayerInfo(player: player, position: height) } func tableInfo(forPlayer player: PlayerName) -> TableInfo { let index = players.index(of: player) return tableInfo(forPlayerAt: index) } func tableInfo(forPlayerAt index: Int) -> TableInfo { .init(table: self, index: index) } }