Schafkopf-Server/Sources/App/Model/Tables/WaitingTable.swift
2021-12-09 11:11:17 +01:00

111 lines
3.2 KiB
Swift

import Foundation
/**
Represents a table where players are still joining and leaving.
*/
final class WaitingTable: AbstractTable {
/**
The players sitting at the table.
The players are ordered clockwise around the table, with the first player starting the game.
*/
var players: [WaitingPlayer] = []
/// The table contains enough players to start a game
var isFull: Bool {
players.count >= maximumPlayersPerTable
}
override init(id: TableId, name: TableName, isPublic: Bool) {
super.init(id: id, name: name, isPublic: isPublic)
}
/**
Create a new table.
- Parameter name: The name of the table
- Parameter isPublic: The table is visible and joinable by everyone
*/
init(newTable name: TableName, isPublic: Bool) {
super.init(id: .newToken(), name: name, isPublic: isPublic)
}
/**
Convert another table to a waiting table.
This is needed when a player leaves an active table.
- Parameter oldTable: The table to convert
- Parameter player: The player to remove from the table.
*/
init(oldTable: Table, removing player: PlayerName) {
self.players = oldTable.allPlayers
.filter { $0.name != player }
.map(WaitingPlayer.init)
super.init(table: oldTable)
}
/**
Add a player to the table.
- Parameter player: The name of the player to add
- Returns: `true`, if the player could be added, `false` if the table is full
*/
func add(player: PlayerName) -> Bool {
guard !isFull else {
return false
}
let player = WaitingPlayer(name: player)
players.append(player)
// Allow dealing of cards if table is full
if isFull {
players.forEach { $0.canStartGame = true }
}
return true
}
/**
Perform an action on the waiting table.
Only dealing is a valid action (if the table is full)
- Parameter action: The action to perform
- Parameter player: The name of the player
*/
func perform(action: PlayerAction, forPlayer name: PlayerName) -> (result: PlayerActionResult, table: Table?) {
// Only dealing is allowed...
guard action == .deal else {
return (.tableStateInvalid, nil)
}
// and only when table is full
guard isFull else {
return (.tableStateInvalid, nil)
}
guard let player = player(named: name) else {
print("Unexpected action \(action) for missing player \(name) at table \(self.name)")
return (.tableStateInvalid, nil)
}
guard player.canPerform(.deal) else {
print("Player \(name) cant perform deal, although table is full")
return (.tableStateInvalid, nil)
}
let table = DealingTable(table: self)
return (.success, table)
}
}
extension WaitingTable: Table {
var allPlayers: [Player] {
players as [Player]
}
var indexOfNextActor: Int {
// The first player at the table starts the game
0
}
func play(card: Card, player name: PlayerName) -> (result: PlayerActionResult, table: Table?) {
// No cards playable while waiting
(.tableStateInvalid, nil)
}
}