Schafkopf-Server/Sources/App/Model/Tables/PlayingTable.swift

145 lines
5.1 KiB
Swift
Raw Normal View History

import Foundation
2021-12-18 15:08:43 +01:00
final class PlayingTable: AbstractTable<PlayingPlayer> {
2021-12-18 15:08:43 +01:00
let game: GameType
2021-12-18 15:08:43 +01:00
var indexOfTrickStarter = 0
var didDoubleInCurrentRound = false
var hasCompletedTrick: Bool {
!players.contains { $0.playedCard == nil }
}
var nextTrick: [Card] {
hasCompletedTrick ? [] : currentTrick
}
var currentTrick: [Card] {
players.rotated(toStartAt: indexOfTrickStarter).compactMap { $0.playedCard }
}
var completedTrick: Trick? {
let trick = currentTrick
guard trick.count == maximumPlayersPerTable else {
return nil
}
return trick
}
2021-12-18 15:08:43 +01:00
var allCardsPlayed: Bool {
!players.contains { !$0.cards.isEmpty }
}
override var playedGame: GameType? {
game
}
2021-12-18 15:08:43 +01:00
convenience init(table: BiddingTable, game: GameType, playedBy player: BiddingPlayer) {
let calledAce = game.calledSuit?.ace
let players = table.players.map {
PlayingPlayer(player: $0, leads: $0 == player, calledAce: calledAce)
}
self.init(table: table, players: players, game: game)
}
2021-12-18 15:08:43 +01:00
convenience init(wedding table: WeddingTable, offeredBy offerer: WeddingPlayer, acceptedBy player: WeddingPlayer) {
let players = table.players.map {
PlayingPlayer(player: $0, leads: $0 == player || $0 == offerer, calledAce: nil)
}
self.init(table: table, players: players, game: .hochzeit)
}
2021-12-18 15:08:43 +01:00
private init(table: ManageableTable, players: [PlayingPlayer], game: GameType) {
self.game = game
super.init(table: table, players: players)
players.forEach { $0.sortCards(for: game) }
players.first!.isNextActor = true
}
2021-12-18 15:08:43 +01:00
override func cardStackPosition(ofPlayerAt index: Int) -> Int {
(4 + index - indexOfTrickStarter) % 4
}
2021-12-18 15:08:43 +01:00
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 playing table \(self.name)")
return (.tableStateInvalid, nil)
}
guard action == .doubleDuringGame else {
print("Player \(name) wants to perform action \(action) on playing table")
return (.tableStateInvalid, nil)
}
guard player.canPerform(.doubleDuringGame) else {
print("Player \(name) is not allowed to raise")
return (.tableStateInvalid, nil)
}
player.numberOfDoubles += 1
players.forEach { $0.switchLead() }
self.didDoubleInCurrentRound = true
return (.success, nil)
}
override func play(card: Card, player name: PlayerName) -> (result: PlayerActionResult, table: ManageableTable?) {
guard let player = players.player(named: name) else {
print("Player \(name) unexpectedly missing from playing table \(self.name)")
return (.tableStateInvalid, nil)
}
guard player.isNextActor else {
print("Player \(name) wants to play card but is not active")
return (.tableStateInvalid, nil)
}
guard player.canPlay(card: card, for: nextTrick, in: game) else {
return (.tableStateInvalid, nil)
}
if hasCompletedTrick {
players.forEach { $0.playedCard = nil }
indexOfTrickStarter = players.index(of: player)
}
player.play(card: card)
if let completedTrick = completedTrick {
return didFinish(trick: completedTrick, in: game)
} else {
let next = players.next(after: player)
next.isNextActor = true
player.isNextActor = false
return (.success, nil)
}
}
override func playerData(at index: Int) -> (actions: [PlayerAction], games: [GameConvertible], cards: [PlayableCard], selectsGame: Bool) {
let player = players[index]
let cards = player.playableCards(for: nextTrick, in: game)
return (actions: player.actions, games: [], cards: cards, selectsGame: false)
}
private func didFinish(trick: Trick, in game: GameType) -> (result: PlayerActionResult, table: ManageableTable?) {
let index = trick.highCardIndex(forGame: game)
let winner = players[(indexOfTrickStarter + index) % 4]
players.forEach {
$0.isNextActor = false
$0.canStillRaise = didDoubleInCurrentRound
}
winner.wonTricks.append(trick)
winner.isNextActor = true
if game == .bettel && winner.leadsGame {
// A bettel is lost if a single trick is won by the leader
return finishedGame()
}
didDoubleInCurrentRound = false
if allCardsPlayed {
return finishedGame()
}
return (.success, nil)
}
private func finishedGame() -> (result: PlayerActionResult, table: ManageableTable?) {
let table = FinishedTable(table: self)
print("\(table.winners) have won with \(table.winningPoints) to \(table.loosingPoints) points")
return (.success, table)
}
}