## Shared helper: build the 13 ModularBot guns as type-erased offline range ## drivers, in ModularBot's gun-id order, with the same readiness gate the live ## loop uses (Tsetlin only spawns once its 10-frame window is full). import std/random import gun_harness/offline_range import guns/head_on import guns/linear import guns/circular import guns/tsetlin import guns/guess_factor import guns/pattern_matcher import guns/wall_bounce import guns/accel_predictor import guns/stop_shot import guns/displacement import guns/averaged_lead import guns/decay_gf import guns/knn_gun proc buildAllGunDrivers*(seed = -1): seq[GunDriver] = ## seed >= 0 re-seeds the global RNG after constructing Tsetlin so the ## stochastic gun's learning is reproducible for offline runs. (Its ## constructor calls randomize(); we override that seed afterwards.) var tsetlin = initTsetlinGun() if seed >= 0: randomize(seed) result = @[ makeDriver("HeadOn", HeadOnGun()), makeDriver("Linear", LinearGun()), makeDriver("Tsetlin", tsetlin), makeDriver("Circular", CircularGun()), makeDriver("GuessFactor", initGFGun()), makeDriver("Pattern", PatternMatcherGun()), makeDriver("WallBounce", initWallBounceGun()), makeDriver("Accel", initAccelGun()), makeDriver("StopShot", initStopShotGun()), makeDriver("Displace", initDisplacementGun()), makeDriver("AvgLead", initAveragedLeadGun()), makeDriver("DecayGF", initDecayGFGun()), makeDriver("KNN", initKNNGun()), ] proc makeTsetlinDriver*(seed = -1): tuple[driver: GunDriver, gun: ref TsetlinGun] = ## Same as makeDriver("Tsetlin", ...) but keeps a handle to the concrete gun, ## so a test can read its clause-sparsity / correction instrumentation after a ## replay. `makeDriver` heap-boxes a copy internally and drops the handle. let g = new(TsetlinGun) g[] = initTsetlinGun() if seed >= 0: randomize(seed) result.gun = g result.driver = GunDriver( name: "Tsetlin", predictCb: proc(state: WorldState, bulletSpeed: float): GunPrediction = g[].predict(state, bulletSpeed), resultCb: proc(e: FeedbackEvent) = g[].onResult(e), readyCb: proc(): bool = g[].isWarmedUp(), )