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

121 lines
4.0 KiB
Swift
Raw Normal View History

import Foundation
/**
Represents a table where players are still joining and leaving.
*/
2021-12-18 15:08:43 +01:00
final class WaitingTable: AbstractTable<WaitingPlayer> {
/// The table contains enough players to start a game
var isFull: Bool {
players.count >= maximumPlayersPerTable
}
2021-12-18 15:08:43 +01:00
init(id: TableId, name: TableName, isPublic: Bool, players: [PlayerName]) {
let players = players.map { WaitingPlayer(name: $0) }
players.first!.isNextActor = true
super.init(id: id, name: name, isPublic: isPublic, players: players)
if isFull {
self.players.forEach { $0.canStartGame = true }
}
}
/**
Create a new table.
- Parameter name: The name of the table
- Parameter isPublic: The table is visible and joinable by everyone
*/
2021-12-18 15:08:43 +01:00
init(newTable name: TableName, isPublic: Bool, creator: PlayerName) {
let player = WaitingPlayer(name: creator)
player.isNextActor = true
super.init(id: .newToken(), name: name, isPublic: isPublic, players: [player])
}
/**
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 name of the player to remove from the table.
*/
init(oldTable: ManageableTable, removing player: PlayerName) {
let players = oldTable.allPlayers
.filter {
guard $0.name == player else {
return true
}
_ = $0.disconnect()
return false
}
.map { WaitingPlayer(name: $0.name, socket: $0.socket) }
players.first!.isNextActor = true
super.init(table: oldTable, players: players)
}
/**
Convert another table to a waiting table.
This is needed when a player leaves an active table.
- Parameter oldTable: The table to convert
*/
2021-12-18 15:08:43 +01:00
init(oldTableAdvancedByOne table: ManageableTable) {
let players = table.allPlayers
.rotatedByOne()
.map { WaitingPlayer(name: $0.name, socket: $0.socket) }
super.init(table: table, players: players)
players.forEach { $0.canStartGame = true }
players.first!.isNextActor = true
}
/**
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
*/
2021-12-18 15:08:43 +01:00
override func perform(action: PlayerAction, forPlayer name: PlayerName) -> (result: PlayerActionResult, table: ManageableTable?) {
// Only dealing is allowed...
guard action == .deal else {
return (.tableStateInvalid, nil)
}
// and only when table is full
guard isFull else {
return (.tableStateInvalid, nil)
}
2021-12-18 15:08:43 +01:00
guard let player = players.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)
}
2021-12-18 15:08:43 +01:00
override func play(card: Card, player name: PlayerName) -> (result: PlayerActionResult, table: ManageableTable?) {
// No cards playable while waiting
(.tableStateInvalid, nil)
}
}