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

126 lines
4.2 KiB
Swift
Raw Normal View History

import Foundation
import Fluent
/**
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
}
init(id: UUID, name: TableName, isPublic: Bool, players: [User]) {
let players = players.map { WaitingPlayer(name: $0.name, points: $0.points) }
2021-12-18 15:08:43 +01:00
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
2022-10-12 22:02:01 +02:00
- Parameter player: The user who created the table
*/
2022-10-12 22:02:01 +02:00
init(newTable object: Table, user: User) {
let player = WaitingPlayer(name: user.name, points: user.points)
2021-12-18 15:08:43 +01:00
player.isNextActor = true
super.init(id: object.id!, name: object.name, isPublic: object.isPublic, players: [player])
2021-12-18 15:08:43 +01:00
}
/**
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.
*/
2021-12-23 11:16:29 +01:00
init?(oldTable: ManageableTable, removing player: PlayerName) {
// TODO: End game and distribute points
2021-12-18 15:08:43 +01:00
let players = oldTable.allPlayers
.filter {
guard $0.name == player else {
return true
}
_ = $0.disconnect()
return false
}
.map { WaitingPlayer(name: $0.name, points: $0.totalPoints, socket: $0.socket) }
2021-12-23 11:16:29 +01:00
guard !players.isEmpty else {
return nil
}
2021-12-18 15:08:43 +01:00
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.
2021-12-23 11:16:29 +01:00
- Parameter table: The table to convert
*/
2021-12-18 15:08:43 +01:00
init(oldTableAdvancedByOne table: ManageableTable) {
let players = table.allPlayers
.rotatedByOne()
.map(WaitingPlayer.init)
2021-12-18 15:08:43 +01:00
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, points: Int) -> Bool {
guard !isFull else {
return false
}
let player = WaitingPlayer(name: player, points: points)
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)
}
}