2021-12-09 11:11:17 +01:00
|
|
|
import Foundation
|
2021-12-22 22:13:09 +01:00
|
|
|
import Fluent
|
2021-12-09 11:11:17 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
Represents a table where players are still joining and leaving.
|
|
|
|
*/
|
2021-12-18 15:08:43 +01:00
|
|
|
final class WaitingTable: AbstractTable<WaitingPlayer> {
|
2021-12-09 11:11:17 +01:00
|
|
|
|
|
|
|
/// The table contains enough players to start a game
|
|
|
|
var isFull: Bool {
|
|
|
|
players.count >= maximumPlayersPerTable
|
|
|
|
}
|
|
|
|
|
2021-12-22 22:13:09 +01:00
|
|
|
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 }
|
|
|
|
}
|
2021-12-09 11:11:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
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
|
2021-12-09 11:11:17 +01:00
|
|
|
*/
|
2022-10-12 22:02:01 +02:00
|
|
|
init(newTable object: Table, user: User) {
|
2021-12-22 22:13:09 +01:00
|
|
|
let player = WaitingPlayer(name: user.name, points: user.points)
|
2021-12-18 15:08:43 +01:00
|
|
|
player.isNextActor = true
|
2021-12-22 22:13:09 +01:00
|
|
|
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) {
|
2021-12-22 22:13:09 +01:00
|
|
|
// 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
|
|
|
|
}
|
2021-12-22 22:13:09 +01:00
|
|
|
.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)
|
2021-12-09 11:11:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
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-09 11:11:17 +01:00
|
|
|
*/
|
2021-12-18 15:08:43 +01:00
|
|
|
init(oldTableAdvancedByOne table: ManageableTable) {
|
|
|
|
let players = table.allPlayers
|
|
|
|
.rotatedByOne()
|
2021-12-22 22:13:09 +01:00
|
|
|
.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
|
2021-12-09 11:11:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
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
|
|
|
|
*/
|
2021-12-22 22:13:09 +01:00
|
|
|
func add(player: PlayerName, points: Int) -> Bool {
|
2021-12-09 11:11:17 +01:00
|
|
|
guard !isFull else {
|
|
|
|
return false
|
|
|
|
}
|
2021-12-22 22:13:09 +01:00
|
|
|
let player = WaitingPlayer(name: player, points: points)
|
2021-12-09 11:11:17 +01:00
|
|
|
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?) {
|
2021-12-09 11:11:17 +01:00
|
|
|
// 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 {
|
2023-02-06 22:03:02 +01:00
|
|
|
log("Unexpected action \(action) for missing player \(name) at table \(self.name)")
|
2021-12-09 11:11:17 +01:00
|
|
|
return (.tableStateInvalid, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
guard player.canPerform(.deal) else {
|
2023-02-06 22:03:02 +01:00
|
|
|
log("Player \(name) cant perform deal, although table is full")
|
2021-12-09 11:11:17 +01:00
|
|
|
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?) {
|
2021-12-09 11:11:17 +01:00
|
|
|
// No cards playable while waiting
|
|
|
|
(.tableStateInvalid, nil)
|
|
|
|
}
|
|
|
|
}
|