Advertisement

← poker-tutor

Sources/pokerlab/DemoHistoryCommand.swift

2.5 KB Download file
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)")
    }
}