import Foundation final class WeddingTable: AbstractTable { var indexOfWeddingOffer: Int init(table: BiddingTable, offerer: BiddingPlayer) { let players = table.players.map { WeddingPlayer(player: $0, offersWedding: $0 == offerer) } indexOfWeddingOffer = table.players.index(of: offerer) super.init(table: table, players: players) } var hasRemainingActors: Bool { players.contains { $0.requiresAction } } var requiresCardSelection: Bool { players.contains { $0.selectsGame } } override var playedGame: GameType? { .hochzeit } override func perform(action: PlayerAction, forPlayer name: PlayerName) -> (result: PlayerActionResult, table: ManageableTable?) { guard let player = players.player(named: name) else { print("Player \(name) unexpectedly missing from wedding table \(self.name)") return (.tableStateInvalid, nil) } guard player.canPerform(action) else { return (.tableStateInvalid, nil) } switch action { case .acceptWedding: return performWeddingAccept(forPlayer: player) case .withdrawFromAuction: return performWithdrawl(forPlayer: player) case .increaseOrMatchGame: fatalError() default: return (.tableStateInvalid, nil) } } private func performWeddingAccept(forPlayer player: WeddingPlayer) -> (result: PlayerActionResult, table: ManageableTable?) { guard player.requiresAction else { return (.tableStateInvalid, nil) } player.state = .wouldAcceptWedding guard !hasRemainingActors else { return (.success, nil) } // Nobody wants to play a higher game, so let the first player accept the wedding players.first { $0.wouldAcceptWedding }!.selectsGame = true return (.success, nil) } private func performWithdrawl(forPlayer player: WeddingPlayer) -> (result: PlayerActionResult, table: ManageableTable?) { guard player.requiresAction else { return (.tableStateInvalid, nil) } player.state = .withdrawnFromAuction guard !hasRemainingActors else { return (.success, nil) } // Nobody wants to play a higher game, so let the first player accept the wedding guard let player = players.first(where: { $0.wouldAcceptWedding }) else { // Nobody wants to accept the wedding or play something higher, so abort the game let table = WaitingTable(oldTableAdvancedByOne: self) return (.success, table) } player.selectsGame = true return (.success, nil) } private func performOutbid(forPlayer player: WeddingPlayer) -> (result: PlayerActionResult, table: ManageableTable?) { guard player.requiresAction else { return (.tableStateInvalid, nil) } let table = BiddingTable(wedding: self, outbidBy: player) return (.success, table) } override func cards(forPlayerAt index: Int) -> [PlayableCard] { let player = players[index] guard requiresCardSelection, player.selectsGame else { return player.cards.unplayable } return player.exchangeableCards } override func gameIsSelected(byPlayerAt index: Int) -> Bool { players[index].selectsGame } override func play(card: Card, player name: PlayerName) -> (result: PlayerActionResult, table: ManageableTable?) { guard requiresCardSelection else { print("Wedding is not in stage where card should be selected") return (.tableStateInvalid, nil) } guard let player = players.player(named: name) else { print("Player \(name) unexpectedly missing from wedding table \(self.name)") return (.tableStateInvalid, nil) } guard player.selectsGame else { print("Player \(name) is not the one selecting a wedding card") return (.tableStateInvalid, nil) } guard player.canExchange(card: card) else { print("Invalid card \(card) to exchange in wedding") return (.tableStateInvalid, nil) } let offerer = players[indexOfWeddingOffer] let trumpCard = offerer.replaceWeddingCard(with: card) player.replace(card, with: trumpCard) let table = PlayingTable(wedding: self, offeredBy: offerer, acceptedBy: player) return (.success, table) } }