import Foundation /** Represents a table where players are still joining and leaving. */ final class WaitingTable: AbstractTable { /** The players sitting at the table. The players are ordered clockwise around the table, with the first player starting the game. */ var players: [WaitingPlayer] = [] /// The table contains enough players to start a game var isFull: Bool { players.count >= maximumPlayersPerTable } override init(id: TableId, name: TableName, isPublic: Bool) { super.init(id: id, name: name, isPublic: isPublic) } /** Create a new table. - Parameter name: The name of the table - Parameter isPublic: The table is visible and joinable by everyone */ init(newTable name: TableName, isPublic: Bool) { super.init(id: .newToken(), name: name, isPublic: isPublic) } /** Convert another table to a waiting table. This is needed when a player leaves an active table. - Parameter oldTable: The table to convert - Parameter player: The player to remove from the table. */ init(oldTable: Table, removing player: PlayerName) { self.players = oldTable.allPlayers .filter { $0.name != player } .map(WaitingPlayer.init) super.init(table: oldTable) } /** Add a player to the table. - Parameter player: The name of the player to add - Returns: `true`, if the player could be added, `false` if the table is full */ func add(player: PlayerName) -> Bool { guard !isFull else { return false } let player = WaitingPlayer(name: player) players.append(player) // Allow dealing of cards if table is full if isFull { players.forEach { $0.canStartGame = true } } return true } /** Perform an action on the waiting table. Only dealing is a valid action (if the table is full) - Parameter action: The action to perform - Parameter player: The name of the player */ func perform(action: PlayerAction, forPlayer name: PlayerName) -> (result: PlayerActionResult, table: Table?) { // Only dealing is allowed... guard action == .deal else { return (.tableStateInvalid, nil) } // and only when table is full guard isFull else { return (.tableStateInvalid, nil) } guard let player = player(named: name) else { print("Unexpected action \(action) for missing player \(name) at table \(self.name)") return (.tableStateInvalid, nil) } guard player.canPerform(.deal) else { print("Player \(name) cant perform deal, although table is full") return (.tableStateInvalid, nil) } let table = DealingTable(table: self) return (.success, table) } } extension WaitingTable: Table { var allPlayers: [Player] { players as [Player] } var indexOfNextActor: Int { // The first player at the table starts the game 0 } func play(card: Card, player name: PlayerName) -> (result: PlayerActionResult, table: Table?) { // No cards playable while waiting (.tableStateInvalid, nil) } }