import Foundation import Fluent final class FinishedTable: AbstractTable { let game: GameType let totalNumberOfDoubles: Int let leadingTrumps: Int /// Required for the last cards on the table let indexOfTrickStarter: Int var cost: Int { guard !isBettel else { return game.basicCost * 2^^totalNumberOfDoubles } var cost = game.basicCost if isSchwarz { cost += 10 } else if isSchneider { cost += 5 } cost += 5 * leadingTrumps guard game != .hochzeit else { // Wedding is doubled return cost * 2^^(totalNumberOfDoubles + 1) } return cost * 2^^totalNumberOfDoubles } var gameSelector: FinishedPlayer { players.first { $0.selectedGame }! } let selectorDidWin: Bool var coPlayers: [FinishedPlayer] { let selector = gameSelector return players.filter { $0 != selector && $0.leadsGame == selector.leadsGame } } var winners: [FinishedPlayer] { let selectorLeads = gameSelector.leadsGame return players.filter { $0.leadsGame == (selectorDidWin == selectorLeads) } } var selectorTeamPoints: Int { gameSelector.points + coPlayers.map { $0.points }.reduce(0, +) } var isBettel: Bool { game == .bettel } var isHochzeit: Bool { game == .hochzeit } var isSchwarz: Bool { !isBettel && (selectorTeamPoints == 0 || selectorTeamPoints == 120) } var isSchneider: Bool { guard !isBettel else { return false } let points = selectorTeamPoints let leads = gameSelector.leadsGame let limit = leads ? 31 : 30 return points < limit || 120 - points < limit } override var playedGame: GameType? { game } init(table: PlayingTable) { let players = table.players.map(FinishedPlayer.init) let selector = table.players.first { $0.selectsGame }! self.game = table.game self.totalNumberOfDoubles = table.totalNumberOfDoubles self.indexOfTrickStarter = table.indexOfTrickStarter defer { for player in winners { player.isNextActor = true } } guard table.game != .bettel else { self.selectorDidWin = selector.wonTricks.isEmpty self.leadingTrumps = 0 super.init(table: table, players: players) return } let selectorLeads = selector.leadsGame let teamPoints = players .filter { $0.leadsGame == selectorLeads } .map { $0.points } .reduce(0, +) self.selectorDidWin = teamPoints > (selectorLeads ? 60 : 59) self.leadingTrumps = table.leadingTrumps super.init(table: table, players: players) } /** Perform a deal action on the finished table. - Parameter action: The action to perform - Parameter player: The name of the player */ override func perform(action: PlayerAction, forPlayer name: PlayerName) -> (result: PlayerActionResult, table: ManageableTable?) { // Only dealing is allowed... guard action == .deal else { return (.tableStateInvalid, nil) } guard let player = players.player(named: name) else { print("Unexpectedly missing player \(name) for deal action at finished table \(self.name)") return (.tableStateInvalid, nil) } guard player.canPerform(.deal) else { print("Finished table: Player \(name) can't perform deal") return (.tableStateInvalid, nil) } let waiting = WaitingTable(oldTableAdvancedByOne: self) let table = DealingTable(table: waiting) return (.success, table) } override func tableInfo(forPlayerAt index: Int) -> TableInfo { var info = super.tableInfo(forPlayerAt: index) info.summary = GameSummary(table: self, language: language) return info } override func cardStackPosition(ofPlayerAt index: Int) -> Int { (4 + index - indexOfTrickStarter) % 4 } func updatePlayerPoints(in database: Database) async throws { let points = cost let winnerNames = winners.map { $0.name } for player in allPlayers { guard let user = try await User.query(on: database).filter(\.$name == player.name).first() else { continue } if winnerNames.contains(player.name) { user.points += points player.totalPoints += points } else { user.points -= points player.totalPoints -= points } try await user.save(on: database) } } }