111 lines
3.2 KiB
Swift
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)
|
|
}
|
|
}
|