diff --git a/Sources/App/Model/OldPlayer.swift b/Sources/App/Model/OldPlayer.swift deleted file mode 100644 index fcdaa45..0000000 --- a/Sources/App/Model/OldPlayer.swift +++ /dev/null @@ -1,479 +0,0 @@ -import Foundation -import WebSocketKit -import CloudKit - -private let encoder = JSONEncoder() - -/** - Specifies the number of cards of the called suit that a player must have - to be allowed to play any card of the suit instead of having to play the ace. - */ -private let numberOfCardsToProtectAce = 4 - -let numberOfCardsPerPlayer = 8 - - -final class OldPlayer { - - let name: PlayerName - - /// The player is the first to play a card in a new game - var playsFirstCard = false - - /// The player is the next to perform an action (e.g. play a card) - var isNextActor = false - - /// The player must select the game to play after winning the auction - var selectsGame = false - - /// The players plays/played the first card for the current trick - var startedCurrentTrick = false - - /// Indicate the currently highest bidder during bidding - var isHighestBidder = false - - /// The action available to the player - var actions: [PlayerAction] = [] - - /// Indicates if the player doubled ("legen") - var didDoubleAfterFourCards: Bool? = nil - - /// Indicates if the player is still involved in the bidding process - var isStillBidding = true - - /// Indicates that the player leads the game ("Spieler") - var isGameLeader = false - - /// Indicates the number of raises ("Schuss") of the player - var numberOfRaises = 0 - - /// The remaining cards of the player - var handCards: [PlayableCard] = [] - - /// The card played for the current trick - var playedCard: Card? = nil - - /// All tricks won by the player in this game - var wonTricks: [Trick] = [] - - var socket: WebSocket? = nil - - var canOfferWedding: Bool { - rawCards.canOfferWedding - } - - var offersWedding = false - - var wouldAcceptWedding = false - - init(name: PlayerName) { - self.name = name - } - - var rawCards: [Card] { - handCards.map { $0.card } - } - - func has(card: Card) -> Bool { - handCards.contains { $0.card == card } - } - - func hasPlayable(card: Card) -> Bool { - handCards.contains { $0.card == card && $0.isPlayable } - } - - func remove(card: Card) { - handCards = handCards.filter { $0.card != card } - } - - func play(card: Card) { - remove(card: card) - playedCard = card - actions = actions.filter { $0 != .doubleDuringGame } - } - - func connect(using socket: WebSocket) { - _ = self.socket?.close() - self.socket = socket - } - - func send(_ info: TableInfo) { - try? socket?.send(encodeJSON(info)) - } - - func disconnect() -> Bool { - guard let socket = socket else { - return false - } - do { - try socket.close().wait() - } catch { - print("Failed to close socket for player: \(name): \(error)") - } - self.socket = nil - return true - } - - func canPerform(_ action: PlayerAction) -> Bool { - actions.contains(action) - } - - func prepareForNewGame(isFirstPlayer: Bool) { - playsFirstCard = isFirstPlayer - isNextActor = isFirstPlayer - selectsGame = false - startedCurrentTrick = isFirstPlayer - actions = [.deal] - didDoubleAfterFourCards = nil - isStillBidding = true - isGameLeader = false - isHighestBidder = false - handCards = [] - playedCard = nil - wonTricks = [] - } - - func assignFirstCards(_ cards: Hand) { - actions = [.initialDoubleCost, .noDoubleCost] - handCards = cards.map { .init(card: $0, isPlayable: false) } - } - - func didDouble(_ double: Bool) { - actions = [] - didDoubleAfterFourCards = double - } - - func assignRemainingCards(_ cards: Hand) { - handCards = (rawCards + cards) - .sortedCards(order: NormalCardOrder.self) - .map { .init(card: $0, isPlayable: false) } - } - - func startAuction() { - if playsFirstCard { - actions = [.withdrawFromAuction, .increaseOrMatchGame] - } else { - actions = [] - } - if canOfferWedding { - actions.append(.offerWedding) - } - } - - func offerWedding() { - offersWedding = true - isStillBidding = false - actions = [] - } - - func weddingOfferExists() { - guard isStillBidding else { - return - } - actions = [.increaseOrMatchGame, .withdrawFromAuction] - } - - func hasWeddingOffer() { - guard isStillBidding else { - return - } - actions = [.acceptWedding, .increaseOrMatchGame, .withdrawFromAuction] - } - - func weddingOutbid() { - isNextActor = false - actions = [] - offersWedding = false - } - - func didPerformBid() { - isNextActor = false - isHighestBidder = true - actions = [] - } - - func requiresBid(hasWedding: Bool) { - isNextActor = true - actions = [.increaseOrMatchGame, .withdrawFromAuction] - if hasWedding { - actions.append(.acceptWedding) - } - } - - func acceptWedding() { - wouldAcceptWedding = true - actions = [] - } - - func weddingAccepted() { - guard isStillBidding else { - actions = [] - return - } - actions = [.increaseOrMatchGame, .withdrawFromAuction] - } - - func auctionEnded() { - actions = [] - isStillBidding = false - isHighestBidder = false - isNextActor = false - } - - func mustSelectWeddingCard() { - isNextActor = true - // Only cards which are not trump can be given to the other player - handCards = handCards.map { - let card = $0.card - return .init(card: card, isPlayable: !card.isTrump(in: .hochzeit)) - } - // Hochzeit costs double - numberOfRaises += 1 - } - - func canPlay(game: GameType) -> Bool { - guard let suit = game.calledSuit else { - if game == .hochzeit { - return canOfferWedding - } - return true - } - let sorter = game.sortingType - let cards = rawCards - guard sorter.hasCardToCall(suit, in: cards) else { - // Player needs at least one card of the called suit - return false - } - let ace = Card(suit, .ass) - return !cards.contains(ace) - } - - func mustSelectGame() { - isNextActor = true - selectsGame = true - } - - func replace(card: Card, with other: Card) { - remove(card: card) - handCards.append(.init(card: other, isPlayable: false)) - } - - func replaceWeddingCard(with card: Card) -> Card { - let index = handCards.firstIndex { $0.card.isTrump(in: .hochzeit) }! - let removed = handCards.remove(at: index).card - handCards.append(.init(card: card, isPlayable: false)) - return removed - } - - func start(game: GameType) { - isNextActor = playsFirstCard - startedCurrentTrick = playsFirstCard - selectsGame = false - actions = [.doubleDuringGame] - isGameLeader = false - handCards = game.sortingType.sort(rawCards).map { .init(card: $0, isPlayable: false) } - if playsFirstCard { - setPlayableCardsForStarter(game: game) - } - } - - func switchLeadership() { - isGameLeader.toggle() - if isGameLeader { - actions = actions.filter { $0 != .doubleDuringGame } - } else if !actions.contains(.doubleDuringGame) { - actions.append(.doubleDuringGame) - } - } - - func withdrawFromBidding() { - isNextActor = false - isStillBidding = false - actions = [] - } - - func didFinish(trick: Trick, winner: Bool, canDoubleInNextRound: Bool) { - isNextActor = winner - //startedCurrentTrick = winner - if winner { - wonTricks.append(trick) - } - if canDoubleInNextRound, !isGameLeader { - actions = [.doubleDuringGame] - } else { - actions = [] - } - } - - func didFinishGame() { - actions = [.deal] - } - - func clearLastTrick() { - playedCard = nil - // This flag is not set until the last trick is cleared, because - // it would mess up the stacking of the cards on the table - // which relies on this property - startedCurrentTrick = isNextActor - } - - - func setPlayableCards(forCurrentTrick trick: Trick, in game: GameType?) { - guard let game = game, isNextActor else { - for i in 0.. 1 else { - // Last card can always be played - setAllCards(playable: true) - return - } - guard let firstCard = trick.first else { - setPlayableCardsForStarter(game: game) - return - } - - let sorter = game.sortingType - - guard sorter.isTrump(firstCard) else { - setPlayableCardsFollowing(suit: firstCard.suit, game: game) - return - } - guard !sorter.hasTrump(in: cards) else { - // Must follow with trump - handCards = cards.map { - .init(card: $0, isPlayable: sorter.isTrump($0)) - } - if !handCards.contains(where: { $0.isPlayable }) { - print("No cards to play when having to follow trump") - } - return - } - // Can play any card if not in calling game - guard let suit = game.calledSuit else { - setAllCards(playable: true) - return - } - // Can play any card, except the called ace - let ace = Card(suit, .ass) - handCards = cards.map { - .init(card: $0, isPlayable: $0 != ace) - } - if !handCards.contains(where: { $0.isPlayable }) { - print("No cards to play when not having to follow trump in a called game") - } - } - - private func setPlayableCardsFollowing(suit playedSuit: Card.Suit, game: GameType) { - let cards = rawCards - let sorter = game.sortingType - let suitCards = sorter.cards(with: playedSuit, in: cards) - - func followSuit() { - handCards = cards.map { - .init(card: $0, isPlayable: !sorter.isTrump($0) && $0.suit == playedSuit) - } - if !handCards.contains(where: { $0.isPlayable }) { - print("No cards to play when following suit") - } - } - - guard let calledSuit = game.calledSuit else { - if suitCards.isEmpty { - // Can play any card - setAllCards(playable: true) - } else { - // Must follow suit - followSuit() - } - return - } - print("Has called suit \(calledSuit)") - let ace = Card(calledSuit, .ass) - guard !suitCards.isEmpty else { - // Exclude called ace, all others allowed - handCards = cards.map { - .init(card: $0, isPlayable: $0 != ace) - } - if !handCards.contains(where: { $0.isPlayable }) { - print("No cards to play when following called suit without suit cards") - } - return - } - guard calledSuit == playedSuit else { - print("Following uncalled suit since no suitable cards") - // Must follow suit (called ace not present) - followSuit() - return - } - - // The called suit is played, must commit ace - guard cards.contains(ace) else { - // Must follow suit - followSuit() - return - } - // Must play ace - handCards = cards.map { .init(card: $0, isPlayable: $0 == ace) } - if !handCards.contains(where: { $0.isPlayable }) { - print("No cards to play when having to play ace of called suit") - } - } - - private func setPlayableCardsForStarter(game: GameType) { - guard let suit = game.calledSuit else { - setAllCards(playable: true) - return - } - let cards = rawCards - let ace = Card(suit, .ass) - // Check if called ace exists, to prohibit other cards of the same suit - guard cards.contains(ace) else { - setAllCards(playable: true) - return - } - // Jodeln - if cards.count == numberOfCardsPerPlayer, - cards.suitCount(suit, in: game) >= numberOfCardsToProtectAce { - setAllCards(playable: true) - return - } - - // Only ace allowed for the called suit - handCards = cards.map { card in - let notPlayable = card.suit == suit && !card.symbol.isTrumpOrAce - return PlayableCard(card: card, isPlayable: !notPlayable) - } - } - - private func setAllCards(playable: Bool) { - for i in 0.. Bool { - lhs.name == rhs.name - } -} diff --git a/Sources/App/Model/OldTable.swift b/Sources/App/Model/OldTable.swift deleted file mode 100644 index e098e42..0000000 --- a/Sources/App/Model/OldTable.swift +++ /dev/null @@ -1,577 +0,0 @@ -import Foundation -import WebSocketKit - -private extension Int { - - mutating func advanceInTable() { - self = (self + 1) % maximumPlayersPerTable - } -} - -final class OldTable { - - let id: TableId - - let name: TableName - - let isPublic: Bool - - var players: [OldPlayer] = [] - - var phase: GamePhase = .waitingForPlayers - - var gameType: GameType? = nil - - var minimumPlayableGame: GameType.GameClass = .none - - /// Indicates if any player doubled during the current round, extending it to the next round - var didDoubleInCurrentRound = false - - /// Indicates that all players acted after the first four cards - var allPlayersFinishedDoubling: Bool { - !players.contains { $0.didDoubleAfterFourCards == nil } - } - - /// At least one double exists after all players acted on their first cards - var initialDoubleExists: Bool { - players.contains { $0.didDoubleAfterFourCards == true } - } - - var weddingOfferExists: Bool { - players.contains { $0.offersWedding } - } - - var weddingAcceptExists: Bool { - players.contains { $0.wouldAcceptWedding } - } - - var hasAuctionWinner: Bool { - numberOfRemainingBidders == 1 - } - - var numberOfRemainingBidders: Int { - players.filter { $0.isStillBidding }.count - } - - var auctionWinner: OldPlayer { - players.first { $0.isStillBidding }! - } - - var hasCompletedTrick: Bool { - !players.contains { $0.playedCard == nil } - } - - var completedTrick: Trick? { - let trick = players.compactMap { $0.playedCard } - guard trick.count == maximumPlayersPerTable else { - return nil - } - return trick - } - - var currentTrick: [Card] { - players.compactMap { $0.playedCard } - } - - var didFinishGame: Bool { - !players.contains { !$0.handCards.isEmpty } - } - - init(id: TableId, name: TableName, isPublic: Bool) { - self.id = id - self.name = name - self.isPublic = isPublic - } - - init(newTable name: TableName, isPublic: Bool) { - self.id = .newToken() - self.name = name - self.isPublic = isPublic - } - - func add(player: PlayerName) -> Bool { - guard !isFull else { - return false - } - let player = OldPlayer(name: player) - players.append(player) - if isFull { - prepareTableForFirstGame() - } - sendUpdateToAllPlayers() - return true - } - - func contains(player: PlayerName) -> Bool { - players.contains { $0.name == player } - } - - /// The player to play the first card of the current game - var firstPlayer: OldPlayer { - players.first { $0.playsFirstCard }! - } - - func select(player: PlayerName) -> OldPlayer? { - players.first { $0.name == player } - } - - var indexOfTrickStarter: Int { - players.firstIndex { $0.startedCurrentTrick }! - } - - func player(at index: Int) -> OldPlayer? { - guard index < players.count else { - return nil - } - return players[index] - } - - func index(of player: OldPlayer) -> Int { - players.firstIndex(of: player)! - } - - func nextPlayer(after player: OldPlayer) -> OldPlayer { - let i = index(of: player) - let newIndex = (i + 1) % maximumPlayersPerTable - return players[newIndex] - } - - func nextBidder(after player: OldPlayer) -> OldPlayer { - // Find next player to place bid - let index = index(of: player) - for i in 1..<4 { - let player = players[(index + i) % 4] - guard player.isStillBidding, !player.offersWedding else { - continue - } - return player - } - return player - } - - func availableGames(forPlayerAt index: Int) -> [GameType] { - - return [] - } - - func remove(player: PlayerName) { - guard let index = players.firstIndex(where: { $0.name == player }) else { - return - } - let removedPlayer = players[index] - if removedPlayer.playsFirstCard { - players[(index + 1) % players.count].playsFirstCard = true - } - players.remove(at: index) - reset() - } - - func connect(player name: PlayerName, using socket: WebSocket) -> Bool { - guard let player = select(player: name) else { - return false - } - player.connect(using: socket) - sendUpdateToAllPlayers() - return true - } - - func disconnect(player name: PlayerName) { - guard let player = select(player: name) else { - return - } - guard player.disconnect() else { - return - } - sendUpdateToAllPlayers() - return - } - - private func prepareTableForFirstGame() { - phase = .waitingForPlayers - gameType = nil - minimumPlayableGame = .none // Not relevant in this phase - didDoubleInCurrentRound = false // Not relevant in this phase - let index = players.firstIndex { $0.playsFirstCard } ?? 0 - for i in 0.. PlayCardResult { - let player = select(player: name)! - if phase == .selectWeddingCard { - return selectedCardForWedding(card: card, player: player) - } - guard let game = gameType, player.hasPlayable(card: card) else { - // Player only has playable cards when it is active - return .invalidCard - } - if hasCompletedTrick { - // Hide cards from last trick when next card is played - players.forEach { $0.clearLastTrick() } - } - player.play(card: card) - if let completedTrick = completedTrick { - didFinish(trick: completedTrick, in: game) - // Update cards for empty trick - players.forEach { $0.setPlayableCards(forCurrentTrick: [], in: game) } - } else { - let next = nextPlayer(after: player) - next.isNextActor = true - player.isNextActor = false - // Update cards for empty trick - players.forEach { $0.setPlayableCards(forCurrentTrick: currentTrick, in: game) } - } - if didFinishGame { - finishedGame() - } - sendUpdateToAllPlayers() - return .success - } - - private func finishedGame() { - phase = .gameFinished - players.forEach { $0.didFinishGame() } - guard didFinishGame else { - // Either no doubles or bids - return - } - // TODO: Calculate winner, points, cost - - } - - func didFinish(trick: Trick, in game: GameType) { - // If trick is completed, calculate winner - let startIndex = indexOfTrickStarter - let rotated = trick.rotated(toStartAt: startIndex) - let index = rotated.highCardIndex(forGame: game) - print("Winner \(index) for \(rotated)") - let winner = players[(startIndex + index) % 4] - players.forEach { - $0.didFinish(trick: trick, - winner: winner == $0, - canDoubleInNextRound: didDoubleInCurrentRound) - } - if game == .bettel && winner.isGameLeader { - // A bettel is lost if a single trick is won by the leader - finishedGame() - return - } - didDoubleInCurrentRound = false - } - - func perform(action: PlayerAction, forPlayer player: PlayerName) -> PlayerActionResult { - let player = select(player: player)! - guard player.canPerform(action) else { - print("Player \(player) wants to \(action.id), but only allowed: \(player.actions)") - return .tableStateInvalid - } - defer { sendUpdateToAllPlayers() } - switch action { - case .deal: - return dealInitialCards() - case .initialDoubleCost: - return perform(double: true, forPlayer: player) - case .noDoubleCost: - return perform(double: false, forPlayer: player) - case .offerWedding: - return performWeddingCall(forPlayer: player) - case .acceptWedding: - return handleWeddingAccept(forPlayer: player) - case .increaseOrMatchGame: - return performBidIncrease(forPlayer: player) - case .withdrawFromAuction: - return performWithdrawl(forPlayer: player) - case .doubleDuringGame: - return performDoubleDuringGame(forPlayer: player) - } - } - - private func dealInitialCards() -> PlayerActionResult { - guard isFull else { - return .tableNotFull - } - guard phase == .waitingForPlayers || phase == .gameFinished else { - return .tableStateInvalid - } - if phase == .gameFinished { - prepareForNextGame() - } - - let cards = Dealer.dealFirstCards() - for (index, player) in players.enumerated() { - player.assignFirstCards(cards[index]) - } - phase = .collectingDoubles - gameType = nil - return .success - } - - func perform(double: Bool, forPlayer player: OldPlayer) -> PlayerActionResult { - player.didDouble(double) - guard allPlayersFinishedDoubling else { - return .success - } - if initialDoubleExists { - dealAdditionalCards() - } else { - finishedGame() - } - return .success - } - - private func dealAdditionalCards() { - let cards = Dealer.dealRemainingCards(of: players.map { $0.rawCards }) - for (index, player) in players.enumerated() { - player.assignRemainingCards(cards[index]) - } - players.forEach { $0.startAuction() } - minimumPlayableGame = .none - phase = .bidding - } - - private func performWeddingCall(forPlayer player: OldPlayer) -> PlayerActionResult { - guard phase == .bidding else { - print("Invalid phase \(phase) for wedding call") - return .tableStateInvalid - } - guard minimumPlayableGame.allowsWedding else { - print("Invalid minimum game \(minimumPlayableGame) for wedding call") - return .tableStateInvalid - } - guard player.canOfferWedding else { - print("Player does not offer wedding") - return .tableStateInvalid - } - guard !weddingOfferExists else { - // Only one wedding allowed at the table - print("Already one wedding at table") - return .tableStateInvalid - } - // Only allow wedding acceptance or outbidding - players.forEach { $0.weddingOfferExists() } - player.offerWedding() - firstPlayer.hasWeddingOffer() - minimumPlayableGame = .bettel - return .success - } - - private func performBidIncrease(forPlayer player: OldPlayer) -> PlayerActionResult { - guard phase == .bidding else { - return .tableStateInvalid - } - if weddingOfferExists { - // Anyone except the offerer can outbid a wedding - return handleWeddingOutbid(forPlayer: player) - } - guard player.isNextActor else { - return .tableStateInvalid - } - // TODO: Check if new player sits before old player - // then don't increase game - minimumPlayableGame.increase() - if !minimumPlayableGame.allowsWedding { - // Remove wedding offers - players.forEach { $0.weddingOutbid() } - } - - // TODO: Remove highest bidder from old player - player.didPerformBid() - - if numberOfRemainingBidders == 1 { - selectGame(player: player) - return .success - } - // Find next player to place bid - nextBidder(after: player).requiresBid(hasWedding: false) - return .success - } - - private func handleWeddingOutbid(forPlayer player: OldPlayer) -> PlayerActionResult { - if player.offersWedding { - // A player offering a wedding can't outbid itself - return .tableStateInvalid - } - players.forEach { $0.weddingOutbid() } - nextBidder(after: player).requiresBid(hasWedding: false) - return .success - } - - private func handleWeddingAccept(forPlayer player: OldPlayer) -> PlayerActionResult { - guard phase == .bidding else { - return .tableStateInvalid - } - guard minimumPlayableGame.allowsWedding else { - return .tableStateInvalid - } - guard weddingOfferExists else { - return .tableStateInvalid - } - guard player.isNextActor else { - return .tableStateInvalid - } - guard !player.offersWedding else { - return .tableStateInvalid - } - guard !weddingAcceptExists else { - return .tableStateInvalid - } - if hasAuctionWinner { - selectedWedding(player: player) - return .success - } - minimumPlayableGame = .bettel - players.forEach { - $0.weddingAccepted() - } - player.acceptWedding() - nextBidder(after: player).requiresBid(hasWedding: false) - return .success - } - - private func selectedWedding(player: OldPlayer) { - minimumPlayableGame = .none - gameType = .hochzeit - phase = .selectWeddingCard - players.forEach { $0.auctionEnded() } - player.mustSelectWeddingCard() - } - - private func selectedCardForWedding(card: Card, player: OldPlayer) -> PlayCardResult { - guard player.isNextActor, - player.wouldAcceptWedding, - weddingOfferExists else { - return .tableStateInvalid - } - guard !card.isTrump(in: .hochzeit), - player.has(card: card) else { - return .invalidCard - } - // Swap the cards - let offerer = players.first { $0.offersWedding }! - let offeredCard = offerer.replaceWeddingCard(with: card) - player.replace(card: card, with: offeredCard) - - // Start the game - gameType = .hochzeit - players.forEach { $0.start(game: .hochzeit) } - player.switchLeadership() - offerer.switchLeadership() - return .success - } - - private func performWithdrawl(forPlayer player: OldPlayer) -> PlayerActionResult { - guard phase == .bidding, - player.isNextActor, - player.isStillBidding else { - return .tableStateInvalid - } - player.withdrawFromBidding() - switch numberOfRemainingBidders { - case 1: - if minimumPlayableGame != .none { - // Will only be called when at least one player placed a bid - selectGame(player: auctionWinner) - return .success - } - case 0: - // All players withdrawn, deal new cards - finishedGame() - return .success - default: - break - } - nextBidder(after: player).requiresBid(hasWedding: weddingOfferExists) - return .success - } - - private func prepareForNextGame() { - let first = firstPlayer - let newPlayer = self.nextBidder(after: first) - first.playsFirstCard = false - newPlayer.playsFirstCard = true - print("Made \(newPlayer.name) to new starter") - prepareTableForFirstGame() - } - - private func selectGame(player: OldPlayer) { - gameType = nil - phase = .selectGame - players.forEach { $0.auctionEnded() } - player.mustSelectGame() - } - - func select(game: GameType, player: PlayerName) -> PlayerActionResult { - let player = select(player: player)! - guard phase == .selectGame, player.selectsGame, game != .hochzeit else { - return .tableStateInvalid - } - guard game.gameClass >= minimumPlayableGame else { - return .tableStateInvalid - } - defer { sendUpdateToAllPlayers() } - guard let suit = game.calledSuit else { - phase = .playing - gameType = game - minimumPlayableGame = .none - players.forEach { $0.start(game: game) } - player.switchLeadership() - - return .success - } - - guard player.canPlay(game: game) else { - return .tableStateInvalid - } - phase = .playing - gameType = game - minimumPlayableGame = .none - players.forEach { $0.start(game: game) } - player.switchLeadership() - // Find called player - let ace = Card(suit, .ass) - players.first { $0.rawCards.contains(ace) }!.switchLeadership() - return .success - } - - private func performDoubleDuringGame(forPlayer player: OldPlayer) -> PlayerActionResult { - guard phase == .playing, !player.isGameLeader else { - return .tableStateInvalid - } - player.numberOfRaises += 1 - players.forEach { $0.switchLeadership() } - didDoubleInCurrentRound = true - return .success - } - - private func reset() { - phase = .waitingForPlayers - gameType = nil - minimumPlayableGame = .none - for player in players { - player.prepareForNewGame(isFirstPlayer: player.playsFirstCard) - } - } -} - -extension OldTable { - - var isFull: Bool { - players.count == maximumPlayersPerTable - } - - var publicInfo: PublicTableInfo { - .init(id: id, name: name, players: playerNames) - } - - var playerNames: [PlayerName] { - players.map { $0.name } - } - -} diff --git a/Sources/App/Model/Tables/AbstractTable.swift b/Sources/App/Model/Tables/AbstractTable.swift index 1617f87..414a6ef 100644 --- a/Sources/App/Model/Tables/AbstractTable.swift +++ b/Sources/App/Model/Tables/AbstractTable.swift @@ -1,6 +1,9 @@ import Foundation import WebSocketKit + +let numberOfCardsPerPlayer = 8 + class AbstractTable where TablePlayer: Player { /// The unique id of the table