Show proper game summary
This commit is contained in:
parent
b5cc395456
commit
7de2352c61
@ -2,38 +2,84 @@ import Foundation
|
|||||||
|
|
||||||
struct EnglishGameSummarizer: GameSummarizer {
|
struct EnglishGameSummarizer: GameSummarizer {
|
||||||
|
|
||||||
let game: GameSummary
|
let table: FinishedTable
|
||||||
|
|
||||||
private var winText: String {
|
private var winText: String {
|
||||||
game.didWin ? "won" : "lost"
|
table.selectorDidWin ? "won" : "lost"
|
||||||
}
|
}
|
||||||
|
|
||||||
private var gameText: String {
|
private var gameText: String {
|
||||||
"game"
|
switch table.game {
|
||||||
|
case .rufBlatt:
|
||||||
|
return "the call of Blatt"
|
||||||
|
case .rufEichel:
|
||||||
|
return "the call of Eichel"
|
||||||
|
case .rufSchelln:
|
||||||
|
return "the call of Schelln"
|
||||||
|
case .bettel:
|
||||||
|
return "the Bettel"
|
||||||
|
case .geier:
|
||||||
|
return "the Geier"
|
||||||
|
case .wenz:
|
||||||
|
return "the Wenz"
|
||||||
|
case .hochzeit:
|
||||||
|
return "the wedding"
|
||||||
|
case .soloBlatt:
|
||||||
|
return "the Solo Blatt"
|
||||||
|
case .soloEichel:
|
||||||
|
return "the Solo Eichel"
|
||||||
|
case .soloHerz:
|
||||||
|
return "the Solo Herz"
|
||||||
|
case .soloSchelln:
|
||||||
|
return "the Solo Schelln"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var coPlayerNames: String {
|
private var coPlayerNames: String {
|
||||||
switch game.coPlayers.count {
|
let coPlayers = table.coPlayers
|
||||||
|
switch coPlayers.count {
|
||||||
case 0:
|
case 0:
|
||||||
return ""
|
return ""
|
||||||
case 1:
|
case 1:
|
||||||
return " with \(game.coPlayers[0])"
|
return " with \(coPlayers[0].name)"
|
||||||
case 2:
|
case 2:
|
||||||
return " with \(game.coPlayers[0]) and \(game.coPlayers[1])"
|
return " with \(coPlayers[0].name) and \(coPlayers[1].name)"
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var costText: String {
|
private var costText: String {
|
||||||
guard game.cost >= 100 else {
|
let cost = table.cost
|
||||||
return "\(game.cost) cents"
|
guard cost >= 100 else {
|
||||||
|
return "\(cost) cents"
|
||||||
}
|
}
|
||||||
return String(format: "%d.%02d €", game.cost / 100, game.cost % 100)
|
return String(format: "%d.%02d €", cost / 100, cost % 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var costExplanation: String {
|
||||||
|
var components = [String]()
|
||||||
|
components.append("Game \(table.game.basicCost)")
|
||||||
|
if !table.isBettel {
|
||||||
|
if table.isSchwarz {
|
||||||
|
components.append("Schwarz")
|
||||||
|
} else if table.isSchneider {
|
||||||
|
components.append("Schneider")
|
||||||
|
}
|
||||||
|
if table.leadingTrumps > 0 {
|
||||||
|
components.append("\(table.leadingTrumps) Laufende")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
components.append("\(table.totalNumberOfDoubles)x doubled")
|
||||||
|
return components.joined(separator: ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
var text: String {
|
var text: String {
|
||||||
"\(game.leader) \(winText) a \(gameText)\(coPlayerNames) collecting \(game.leaderPoints) points. " +
|
let start = "\(table.gameSelector.name) \(winText) the \(gameText)"
|
||||||
"The game cost \(costText)."
|
let cost = " The game costs \(costText) (\(costExplanation))."
|
||||||
|
guard table.game != .bettel else {
|
||||||
|
return start + cost
|
||||||
|
}
|
||||||
|
return start + "\(coPlayerNames) with \(table.selectorTeamPoints) points." + cost
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,9 @@ import Foundation
|
|||||||
|
|
||||||
protocol GameSummarizer {
|
protocol GameSummarizer {
|
||||||
|
|
||||||
init(game: GameSummary)
|
var table: FinishedTable { get }
|
||||||
|
|
||||||
|
init(table: FinishedTable)
|
||||||
|
|
||||||
var text: String { get }
|
var text: String { get }
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,14 @@ import Foundation
|
|||||||
|
|
||||||
struct GermanGameSummarizer: GameSummarizer {
|
struct GermanGameSummarizer: GameSummarizer {
|
||||||
|
|
||||||
let game: GameSummary
|
let table: FinishedTable
|
||||||
|
|
||||||
var winText: String {
|
private var winText: String {
|
||||||
game.didWin ? "gewinnt" : "verliert"
|
table.selectorDidWin ? "gewinnt" : "verliert"
|
||||||
}
|
}
|
||||||
|
|
||||||
var gameText: String {
|
private var gameText: String {
|
||||||
switch GameType(id: game.game)! {
|
switch table.game {
|
||||||
case .rufBlatt:
|
case .rufBlatt:
|
||||||
return "den Ruf Blatt"
|
return "den Ruf Blatt"
|
||||||
case .rufEichel:
|
case .rufEichel:
|
||||||
@ -35,28 +35,51 @@ struct GermanGameSummarizer: GameSummarizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var coPlayerNames: String {
|
private var coPlayerNames: String {
|
||||||
switch game.coPlayers.count {
|
let coPlayers = table.coPlayers
|
||||||
|
switch coPlayers.count {
|
||||||
case 0:
|
case 0:
|
||||||
return ""
|
return ""
|
||||||
case 1:
|
case 1:
|
||||||
return " mit \(game.coPlayers[0])"
|
return " mit \(coPlayers[0].name)"
|
||||||
case 2:
|
case 2:
|
||||||
return " mit \(game.coPlayers[0]) und \(game.coPlayers[1])"
|
return " mit \(coPlayers[0].name) und \(coPlayers[1].name)"
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var costText: String {
|
private var costText: String {
|
||||||
guard game.cost >= 100 else {
|
let cost = table.cost
|
||||||
return "\(game.cost) Cent"
|
guard cost >= 100 else {
|
||||||
|
return "\(cost) Cent"
|
||||||
}
|
}
|
||||||
return String(format: "%d.%02d €", game.cost / 100, game.cost % 100)
|
return String(format: "%d.%02d €", cost / 100, cost % 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var costExplanation: String {
|
||||||
|
var components = [String]()
|
||||||
|
components.append("Grundspiel \(table.game.basicCost)")
|
||||||
|
if !table.isBettel {
|
||||||
|
if table.isSchwarz {
|
||||||
|
components.append("Schwarz")
|
||||||
|
} else if table.isSchneider {
|
||||||
|
components.append("Schneider")
|
||||||
|
}
|
||||||
|
if table.leadingTrumps > 0 {
|
||||||
|
components.append("\(table.leadingTrumps) Laufende")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
components.append("\(table.totalNumberOfDoubles)x gedoppelt")
|
||||||
|
return components.joined(separator: ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
var text: String {
|
var text: String {
|
||||||
"\(game.leader) \(winText) \(gameText)\(coPlayerNames) mit \(game.leaderPoints) Punkten. " +
|
let start = "\(table.gameSelector.name) \(winText) \(gameText)"
|
||||||
"Das Spiel kostet \(costText)."
|
let cost = " Das Spiel kostet \(costText) (\(costExplanation))."
|
||||||
|
guard table.game != .bettel else {
|
||||||
|
return start + cost
|
||||||
|
}
|
||||||
|
return start + "\(coPlayerNames) mit \(table.selectorTeamPoints) Punkten." + cost
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import Foundation
|
|||||||
|
|
||||||
struct GameSummary: Codable, Equatable {
|
struct GameSummary: Codable, Equatable {
|
||||||
|
|
||||||
let leader: PlayerName
|
let selector: PlayerName
|
||||||
|
|
||||||
let coPlayers: [PlayerName]
|
let coPlayers: [PlayerName]
|
||||||
|
|
||||||
@ -10,24 +10,20 @@ struct GameSummary: Codable, Equatable {
|
|||||||
|
|
||||||
let game: GameId
|
let game: GameId
|
||||||
|
|
||||||
let leaderPoints: Int
|
let points: Int
|
||||||
|
|
||||||
let cost: Int
|
let cost: Int
|
||||||
|
|
||||||
var text: String = ""
|
var text: String = ""
|
||||||
|
|
||||||
init(table: FinishedTable, language: SupportedLanguage) {
|
init(table: FinishedTable, language: SupportedLanguage) {
|
||||||
let leader = table.players.first { $0.selectedGame }!
|
self.selector = table.gameSelector.name
|
||||||
self.coPlayers = table.players
|
self.coPlayers = table.coPlayers.map { $0.name }
|
||||||
.filter { $0 != leader && $0.leadsGame == leader.leadsGame }
|
|
||||||
.map { $0.name }
|
|
||||||
self.leader = leader.name
|
|
||||||
self.game = table.game.id
|
self.game = table.game.id
|
||||||
self.leaderPoints = table.leadingPoints
|
self.points = table.selectorTeamPoints
|
||||||
self.didWin = table.winners.contains(player: leader.name)
|
self.didWin = table.selectorDidWin
|
||||||
self.cost = table.game.basicCost
|
self.cost = table.cost
|
||||||
// TODO: Calculate cost correctly
|
self.text = language.gameSummarizer.init(table: table).text
|
||||||
self.text = language.gameSummarizer.init(game: self).text
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ final class PlayingPlayer: CardHoldingPlayer {
|
|||||||
|
|
||||||
var leadsGame: Bool
|
var leadsGame: Bool
|
||||||
|
|
||||||
var numberOfDoubles = 0
|
var numberOfRaises = 0
|
||||||
|
|
||||||
/// All tricks won by the player in this game
|
/// All tricks won by the player in this game
|
||||||
var wonTricks: [Trick] = []
|
var wonTricks: [Trick] = []
|
||||||
@ -34,8 +34,13 @@ final class PlayingPlayer: CardHoldingPlayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The players has been called in a call game
|
||||||
|
var isCallee: Bool {
|
||||||
|
isCalledWithAce != nil
|
||||||
|
}
|
||||||
|
|
||||||
private var isUnknownCallee: Bool {
|
private var isUnknownCallee: Bool {
|
||||||
isCalledWithAce != nil && !didPlayCalledAce
|
isCallee && !didPlayCalledAce
|
||||||
}
|
}
|
||||||
|
|
||||||
override var actions: [PlayerAction] {
|
override var actions: [PlayerAction] {
|
||||||
@ -165,7 +170,7 @@ final class PlayingPlayer: CardHoldingPlayer {
|
|||||||
if leadsGame {
|
if leadsGame {
|
||||||
states.append(.leadsGame)
|
states.append(.leadsGame)
|
||||||
}
|
}
|
||||||
if numberOfDoubles > 0 {
|
if numberOfRaises > 0 {
|
||||||
states.append(.didRaise)
|
states.append(.didRaise)
|
||||||
}
|
}
|
||||||
return states
|
return states
|
||||||
|
@ -9,7 +9,6 @@ final class DealingTable: AbstractTable<DealingPlayer> {
|
|||||||
player.cards = cards[index]
|
player.cards = cards[index]
|
||||||
}
|
}
|
||||||
super.init(table: table, players: players)
|
super.init(table: table, players: players)
|
||||||
print("\(self.players[0].cards.count) cards")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All players either doubled or didn't double
|
/// All players either doubled or didn't double
|
||||||
|
@ -4,42 +4,60 @@ final class FinishedTable: AbstractTable<FinishedPlayer> {
|
|||||||
|
|
||||||
let game: GameType
|
let game: GameType
|
||||||
|
|
||||||
|
let totalNumberOfDoubles: Int
|
||||||
|
|
||||||
|
let leadingTrumps: Int
|
||||||
|
|
||||||
|
var cost: Int {
|
||||||
|
guard !isBettel else {
|
||||||
|
return game.basicCost * 2^^totalNumberOfDoubles
|
||||||
|
}
|
||||||
|
var cost = game.basicCost
|
||||||
|
if isSchwarz {
|
||||||
|
cost += 10
|
||||||
|
} else if isSchneider {
|
||||||
|
cost += 5
|
||||||
|
}
|
||||||
|
cost += 5 * leadingTrumps
|
||||||
|
return cost * 2^^totalNumberOfDoubles
|
||||||
|
}
|
||||||
|
|
||||||
|
var gameSelector: FinishedPlayer {
|
||||||
|
players.first { $0.selectedGame }!
|
||||||
|
}
|
||||||
|
|
||||||
|
let selectorDidWin: Bool
|
||||||
|
|
||||||
|
var coPlayers: [FinishedPlayer] {
|
||||||
|
let selector = gameSelector
|
||||||
|
return players.filter { $0 != selector && $0.leadsGame == selector.leadsGame }
|
||||||
|
}
|
||||||
|
|
||||||
var winners: [FinishedPlayer] {
|
var winners: [FinishedPlayer] {
|
||||||
leadersHaveWon ? leaders : opponents
|
let selectorLeads = gameSelector.leadsGame
|
||||||
|
return players.filter { $0.leadsGame == (selectorDidWin == selectorLeads) }
|
||||||
}
|
}
|
||||||
|
|
||||||
var loosers: [FinishedPlayer] {
|
var selectorTeamPoints: Int {
|
||||||
leadersHaveWon ? opponents : leaders
|
gameSelector.points + coPlayers.map { $0.points }.reduce(0, +)
|
||||||
}
|
}
|
||||||
|
|
||||||
var leaders: [FinishedPlayer] {
|
var isBettel: Bool {
|
||||||
players.filter { $0.leadsGame }
|
game == .bettel
|
||||||
}
|
|
||||||
|
|
||||||
var opponents: [FinishedPlayer] {
|
|
||||||
players.filter { !$0.leadsGame }
|
|
||||||
}
|
|
||||||
|
|
||||||
var winningPoints: Int {
|
|
||||||
leadersHaveWon ? leadingPoints : 120 - leadingPoints
|
|
||||||
}
|
|
||||||
|
|
||||||
var loosingPoints: Int {
|
|
||||||
leadersHaveWon ? 120 - leadingPoints : leadingPoints
|
|
||||||
}
|
|
||||||
|
|
||||||
let leadingPoints: Int
|
|
||||||
|
|
||||||
var leadersHaveWon: Bool {
|
|
||||||
leadingPoints > 60
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var isSchwarz: Bool {
|
var isSchwarz: Bool {
|
||||||
loosingPoints == 0
|
!isBettel && (selectorTeamPoints == 0 || selectorTeamPoints == 120)
|
||||||
}
|
}
|
||||||
|
|
||||||
var isSchneider: Bool {
|
var isSchneider: Bool {
|
||||||
loosingPoints < (leadersHaveWon ? 30 : 31)
|
guard !isBettel else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let points = selectorTeamPoints
|
||||||
|
let leads = gameSelector.leadsGame
|
||||||
|
let limit = leads ? 31 : 30
|
||||||
|
return points < limit || 120 - points < limit
|
||||||
}
|
}
|
||||||
|
|
||||||
override var playedGame: GameType? {
|
override var playedGame: GameType? {
|
||||||
@ -47,16 +65,29 @@ final class FinishedTable: AbstractTable<FinishedPlayer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init(table: PlayingTable) {
|
init(table: PlayingTable) {
|
||||||
|
|
||||||
let players = table.players.map(FinishedPlayer.init)
|
let players = table.players.map(FinishedPlayer.init)
|
||||||
|
let selector = table.players.first { $0.selectsGame }!
|
||||||
self.game = table.game
|
self.game = table.game
|
||||||
leadingPoints = players
|
self.totalNumberOfDoubles = table.totalNumberOfDoubles
|
||||||
.filter { $0.leadsGame }
|
defer {
|
||||||
|
for player in winners {
|
||||||
|
player.isNextActor = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
guard table.game != .bettel else {
|
||||||
|
self.selectorDidWin = selector.wonTricks.isEmpty
|
||||||
|
self.leadingTrumps = 0
|
||||||
|
super.init(table: table, players: players)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let selectorLeads = selector.leadsGame
|
||||||
|
let teamPoints = players
|
||||||
|
.filter { $0.leadsGame == selectorLeads }
|
||||||
.map { $0.points }
|
.map { $0.points }
|
||||||
.reduce(0, +)
|
.reduce(0, +)
|
||||||
// TODO: Set isNextActor for winners
|
self.selectorDidWin = teamPoints > (selectorLeads ? 60 : 59)
|
||||||
// TODO: Check for bettel
|
self.leadingTrumps = table.leadingTrumps
|
||||||
// TODO: Set schneider, schwarz, cost
|
|
||||||
super.init(table: table, players: players)
|
super.init(table: table, players: players)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ final class PlayingTable: AbstractTable<PlayingPlayer> {
|
|||||||
|
|
||||||
let game: GameType
|
let game: GameType
|
||||||
|
|
||||||
|
let leadingTrumps: Int
|
||||||
|
|
||||||
var indexOfTrickStarter = 0
|
var indexOfTrickStarter = 0
|
||||||
|
|
||||||
var didDoubleInCurrentRound = false
|
var didDoubleInCurrentRound = false
|
||||||
@ -32,6 +34,12 @@ final class PlayingTable: AbstractTable<PlayingPlayer> {
|
|||||||
!players.contains { !$0.cards.isEmpty }
|
!players.contains { !$0.cards.isEmpty }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var totalNumberOfDoubles: Int {
|
||||||
|
players.map {
|
||||||
|
$0.numberOfRaises + ($0.didDouble ? 1 : 0)
|
||||||
|
}.reduce(0,+)
|
||||||
|
}
|
||||||
|
|
||||||
override var playedGame: GameType? {
|
override var playedGame: GameType? {
|
||||||
game
|
game
|
||||||
}
|
}
|
||||||
@ -53,6 +61,11 @@ final class PlayingTable: AbstractTable<PlayingPlayer> {
|
|||||||
|
|
||||||
private init(table: ManageableTable, players: [PlayingPlayer], game: GameType) {
|
private init(table: ManageableTable, players: [PlayingPlayer], game: GameType) {
|
||||||
self.game = game
|
self.game = game
|
||||||
|
let selectorCards = players.filter { $0.leadsGame || $0.isCallee }.map { $0.cards }.reduce([], +)
|
||||||
|
let otherCards = players.filter { !$0.leadsGame && !$0.isCallee }.map { $0.cards }.reduce([], +)
|
||||||
|
let selectorTrumps = game.sortingType.consecutiveTrumps(selectorCards)
|
||||||
|
let otherTrumps = game.sortingType.consecutiveTrumps(otherCards)
|
||||||
|
self.leadingTrumps = max(selectorTrumps, otherTrumps)
|
||||||
super.init(table: table, players: players)
|
super.init(table: table, players: players)
|
||||||
players.forEach { $0.sortCards(for: game) }
|
players.forEach { $0.sortCards(for: game) }
|
||||||
players.first!.isNextActor = true
|
players.first!.isNextActor = true
|
||||||
@ -75,7 +88,7 @@ final class PlayingTable: AbstractTable<PlayingPlayer> {
|
|||||||
print("Player \(name) is not allowed to raise")
|
print("Player \(name) is not allowed to raise")
|
||||||
return (.tableStateInvalid, nil)
|
return (.tableStateInvalid, nil)
|
||||||
}
|
}
|
||||||
player.numberOfDoubles += 1
|
player.numberOfRaises += 1
|
||||||
players.forEach { $0.switchLead() }
|
players.forEach { $0.switchLead() }
|
||||||
self.didDoubleInCurrentRound = true
|
self.didDoubleInCurrentRound = true
|
||||||
return (.success, nil)
|
return (.success, nil)
|
||||||
@ -122,8 +135,8 @@ final class PlayingTable: AbstractTable<PlayingPlayer> {
|
|||||||
winner.wonTricks.append(trick)
|
winner.wonTricks.append(trick)
|
||||||
winner.isNextActor = true
|
winner.isNextActor = true
|
||||||
|
|
||||||
if game == .bettel && winner.leadsGame {
|
if game == .bettel && winner.selectsGame {
|
||||||
// A bettel is lost if a single trick is won by the leader
|
// A bettel is lost if a single trick is won by the game selector
|
||||||
return finishedGame()
|
return finishedGame()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +149,6 @@ final class PlayingTable: AbstractTable<PlayingPlayer> {
|
|||||||
|
|
||||||
private func finishedGame() -> (result: PlayerActionResult, table: ManageableTable?) {
|
private func finishedGame() -> (result: PlayerActionResult, table: ManageableTable?) {
|
||||||
let table = FinishedTable(table: self)
|
let table = FinishedTable(table: self)
|
||||||
print("\(table.winners) have won with \(table.winningPoints) to \(table.loosingPoints) points")
|
|
||||||
return (.success, table)
|
return (.success, table)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user