← poker-tutor
import Foundation
import PokerCore
import PokerAI
import PokerCoach
import PokerSession
import PokerTests
/// Plays a scripted player through a run of ordinary hands and writes the history to a file.
///
/// Exists for the store screenshots, which have to show the app with a game behind it — an empty
/// scorecard and a rating of "—" are the honest first-run state and a terrible advertisement. Also
/// useful for looking at the analysis screens with real numbers in them without playing an evening
/// by hand, which is what it was immediately used for.
///
/// The player is scripted with a mild flaw rather than played perfectly, because a scorecard with
/// nothing on it teaches a reader nothing about what the app is for.
///
/// pokerlab demo-history --out ~/hands.jsonl --hands 320 --player loose
func runDemoHistory(playerName: String, seed: UInt64, hands: Int, out: String,
format: AppVariant.Format = .tournament, setup: CashSetup = .standard) {
let mode: GameMode = format == .cash ? .cash : .tournament
let url = URL(fileURLWithPath: (out as NSString).expandingTildeInPath)
try? FileManager.default.removeItem(at: url)
try? FileManager.default.createDirectory(at: url.deletingLastPathComponent(),
withIntermediateDirectories: true)
let player = plantedPlayer(named: playerName)
let history = HistoryStore(url: url)
let session = TableSession(seed: seed, history: history,
variant: format == .cash ? .pokerTutorCash : .pokerTutor)
session.cashSetup = setup
var rng = SeededRandom(seed: seed &* 13 &+ 7)
var steps = 0
session.start(mode)
while history.hands.count < hands {
steps += 1
guard steps < 400_000 else { break }
if !session.isPlaying { session.start(mode); continue }
if session.heroToAct, let view = session.engine?.view(for: session.heroSeat) {
session.act(player.decide(view, &rng))
} else if session.engine?.isComplete == true {
session.continueAfterReview()
} else {
session.stepOpponent()
}
}
print("wrote \(history.hands.count) hands to \(url.path)")
let card = LeakScorecard(of: history.hands)
print("rating \(card.rating.value) — \(card.rating.label)")
for entry in card.costing.prefix(4) {
print(" \(entry.leak.name): \(entry.times) of \(entry.chances)")
}
}