2021-12-18 15:08:43 +01:00
|
|
|
import Foundation
|
2022-10-18 11:40:08 +02:00
|
|
|
import Fluent
|
2021-12-18 15:08:43 +01:00
|
|
|
|
|
|
|
final class FinishedTable: AbstractTable<FinishedPlayer> {
|
|
|
|
|
|
|
|
let game: GameType
|
|
|
|
|
2021-12-21 14:24:53 +01:00
|
|
|
let totalNumberOfDoubles: Int
|
|
|
|
|
|
|
|
let leadingTrumps: Int
|
|
|
|
|
2021-12-22 15:06:24 +01:00
|
|
|
/// Required for the last cards on the table
|
|
|
|
let indexOfTrickStarter: Int
|
|
|
|
|
2021-12-21 14:24:53 +01:00
|
|
|
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
|
2021-12-22 14:54:31 +01:00
|
|
|
guard game != .hochzeit else {
|
|
|
|
// Wedding is doubled
|
|
|
|
return cost * 2^^(totalNumberOfDoubles + 1)
|
|
|
|
}
|
2021-12-21 14:24:53 +01:00
|
|
|
return cost * 2^^totalNumberOfDoubles
|
2021-12-18 15:08:43 +01:00
|
|
|
}
|
|
|
|
|
2021-12-21 14:24:53 +01:00
|
|
|
var gameSelector: FinishedPlayer {
|
|
|
|
players.first { $0.selectedGame }!
|
2021-12-18 15:08:43 +01:00
|
|
|
}
|
|
|
|
|
2021-12-21 14:24:53 +01:00
|
|
|
let selectorDidWin: Bool
|
2021-12-18 15:08:43 +01:00
|
|
|
|
2021-12-21 14:24:53 +01:00
|
|
|
var coPlayers: [FinishedPlayer] {
|
|
|
|
let selector = gameSelector
|
|
|
|
return players.filter { $0 != selector && $0.leadsGame == selector.leadsGame }
|
2021-12-18 15:08:43 +01:00
|
|
|
}
|
|
|
|
|
2021-12-21 14:24:53 +01:00
|
|
|
var winners: [FinishedPlayer] {
|
|
|
|
let selectorLeads = gameSelector.leadsGame
|
|
|
|
return players.filter { $0.leadsGame == (selectorDidWin == selectorLeads) }
|
2021-12-18 15:08:43 +01:00
|
|
|
}
|
|
|
|
|
2021-12-21 14:24:53 +01:00
|
|
|
var selectorTeamPoints: Int {
|
|
|
|
gameSelector.points + coPlayers.map { $0.points }.reduce(0, +)
|
2021-12-18 15:08:43 +01:00
|
|
|
}
|
|
|
|
|
2021-12-21 14:24:53 +01:00
|
|
|
var isBettel: Bool {
|
|
|
|
game == .bettel
|
2021-12-18 15:08:43 +01:00
|
|
|
}
|
|
|
|
|
2021-12-22 14:54:31 +01:00
|
|
|
var isHochzeit: Bool {
|
|
|
|
game == .hochzeit
|
|
|
|
}
|
|
|
|
|
2021-12-18 15:08:43 +01:00
|
|
|
var isSchwarz: Bool {
|
2021-12-21 14:24:53 +01:00
|
|
|
!isBettel && (selectorTeamPoints == 0 || selectorTeamPoints == 120)
|
2021-12-18 15:08:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
var isSchneider: Bool {
|
2021-12-21 14:24:53 +01:00
|
|
|
guard !isBettel else {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
let points = selectorTeamPoints
|
|
|
|
let leads = gameSelector.leadsGame
|
|
|
|
let limit = leads ? 31 : 30
|
|
|
|
return points < limit || 120 - points < limit
|
2021-12-18 15:08:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
override var playedGame: GameType? {
|
|
|
|
game
|
|
|
|
}
|
|
|
|
|
|
|
|
init(table: PlayingTable) {
|
|
|
|
let players = table.players.map(FinishedPlayer.init)
|
2021-12-21 14:24:53 +01:00
|
|
|
let selector = table.players.first { $0.selectsGame }!
|
2021-12-18 15:08:43 +01:00
|
|
|
self.game = table.game
|
2021-12-21 14:24:53 +01:00
|
|
|
self.totalNumberOfDoubles = table.totalNumberOfDoubles
|
2021-12-22 15:06:24 +01:00
|
|
|
self.indexOfTrickStarter = table.indexOfTrickStarter
|
2021-12-21 14:24:53 +01:00
|
|
|
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 }
|
2021-12-20 20:18:19 +01:00
|
|
|
.map { $0.points }
|
2021-12-18 15:08:43 +01:00
|
|
|
.reduce(0, +)
|
2021-12-21 14:24:53 +01:00
|
|
|
self.selectorDidWin = teamPoints > (selectorLeads ? 60 : 59)
|
|
|
|
self.leadingTrumps = table.leadingTrumps
|
2021-12-18 15:08:43 +01:00
|
|
|
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 {
|
2023-02-06 22:03:02 +01:00
|
|
|
log("Unexpectedly missing player \(name) for deal action at finished table \(self.name)")
|
2021-12-18 15:08:43 +01:00
|
|
|
return (.tableStateInvalid, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
guard player.canPerform(.deal) else {
|
2023-02-06 22:03:02 +01:00
|
|
|
log("Finished table: Player \(name) can't perform deal")
|
2021-12-18 15:08:43 +01:00
|
|
|
return (.tableStateInvalid, nil)
|
|
|
|
}
|
|
|
|
let waiting = WaitingTable(oldTableAdvancedByOne: self)
|
|
|
|
let table = DealingTable(table: waiting)
|
|
|
|
return (.success, table)
|
|
|
|
}
|
2021-12-21 09:53:42 +01:00
|
|
|
|
|
|
|
override func tableInfo(forPlayerAt index: Int) -> TableInfo {
|
|
|
|
var info = super.tableInfo(forPlayerAt: index)
|
2021-12-21 11:16:54 +01:00
|
|
|
info.summary = GameSummary(table: self, language: language)
|
2021-12-21 09:53:42 +01:00
|
|
|
return info
|
|
|
|
}
|
2021-12-22 15:06:24 +01:00
|
|
|
|
|
|
|
override func cardStackPosition(ofPlayerAt index: Int) -> Int {
|
|
|
|
(4 + index - indexOfTrickStarter) % 4
|
|
|
|
}
|
2022-10-18 11:40:08 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
2021-12-18 15:08:43 +01:00
|
|
|
}
|