trap_hunt: payouts by kind, battle lengths and wins, and MOVE n on a move without effect
This commit is contained in:
parent
f3e3e9cf98
commit
a02d5f7995
1 changed files with 91 additions and 0 deletions
|
|
@ -247,6 +247,12 @@ struct Trace {
|
||||||
/// The pad's composition, measured rather than read off the table: "which sub-state offers
|
/// The pad's composition, measured rather than read off the table: "which sub-state offers
|
||||||
/// `BACK`" is a question about the build under test and not about the document.
|
/// `BACK`" is a question about the build under test and not about the document.
|
||||||
battle_pads: BTreeMap<&'static str, BTreeSet<String>>,
|
battle_pads: BTreeMap<&'static str, BTreeSet<String>>,
|
||||||
|
/// Row 60: every battle as `(frames, macro starts, won)`, the one running, payouts by kind,
|
||||||
|
/// and `MOVE n` starts against how many chose a move the cartridge answers with nothing.
|
||||||
|
battles: Vec<(u64, u64, bool)>,
|
||||||
|
battle_now: Option<(u64, u64, bool)>,
|
||||||
|
payouts_by_kind: BTreeMap<&'static str, (u64, f64)>,
|
||||||
|
move_starts: (u64, u64),
|
||||||
wall_seconds: f64,
|
wall_seconds: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -423,6 +429,10 @@ fn run(
|
||||||
battle_frames: BTreeMap::new(),
|
battle_frames: BTreeMap::new(),
|
||||||
battle_starts: BTreeMap::new(),
|
battle_starts: BTreeMap::new(),
|
||||||
battle_pads: BTreeMap::new(),
|
battle_pads: BTreeMap::new(),
|
||||||
|
battles: Vec::new(),
|
||||||
|
battle_now: None,
|
||||||
|
payouts_by_kind: BTreeMap::new(),
|
||||||
|
move_starts: (0, 0),
|
||||||
wall_seconds: 0.0,
|
wall_seconds: 0.0,
|
||||||
seeded: seeded_note,
|
seeded: seeded_note,
|
||||||
refusals: BTreeMap::new(),
|
refusals: BTreeMap::new(),
|
||||||
|
|
@ -507,6 +517,23 @@ fn run(
|
||||||
if let Some(sub) = battle_sub {
|
if let Some(sub) = battle_sub {
|
||||||
*trace.battle_starts.entry((event.name, sub)).or_insert(0) += 1;
|
*trace.battle_starts.entry((event.name, sub)).or_insert(0) += 1;
|
||||||
}
|
}
|
||||||
|
if let Some(battle) = trace.battle_now.as_mut() {
|
||||||
|
battle.1 += 1;
|
||||||
|
}
|
||||||
|
if let Some(slot) = event.name.strip_prefix("MOVE ") {
|
||||||
|
trace.move_starts.0 += 1;
|
||||||
|
let id = flybrain_gb::pokemon_red::state::battle(&mut emulator)
|
||||||
|
.and_then(|battle| battle.own)
|
||||||
|
.zip(slot.parse::<usize>().ok())
|
||||||
|
.and_then(|(own, slot)| own.moves.get(slot - 1).copied().flatten())
|
||||||
|
.map(|entry| entry.id);
|
||||||
|
if id.is_some_and(|id| {
|
||||||
|
flybrain_gb::pokemon_red::state::move_without_effect(&mut emulator, id)
|
||||||
|
== Some(true)
|
||||||
|
}) {
|
||||||
|
trace.move_starts.1 += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
running = Some(Running {
|
running = Some(Running {
|
||||||
name: event.name,
|
name: event.name,
|
||||||
from: location,
|
from: location,
|
||||||
|
|
@ -588,6 +615,29 @@ fn run(
|
||||||
frame.copy_from_slice(emulator.framebuffer());
|
frame.copy_from_slice(emulator.framebuffer());
|
||||||
|
|
||||||
payouts = adapter.sample(&mut emulator, ms);
|
payouts = adapter.sample(&mut emulator, ms);
|
||||||
|
for payout in &payouts {
|
||||||
|
let entry = trace.payouts_by_kind.entry(payout.kind).or_insert((0, 0.0));
|
||||||
|
*entry = (entry.0 + 1, entry.1 + payout.value);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
use flybrain_gb::MemoryReader;
|
||||||
|
let fighting =
|
||||||
|
emulator.read8(flybrain_gb::pokemon_red::symbols::ram::wIsInBattle) != 0;
|
||||||
|
let won = payouts.iter().any(|payout| matches!(payout.kind, "battle" | "trainer"));
|
||||||
|
match (fighting, trace.battle_now.as_mut()) {
|
||||||
|
(true, Some(battle)) => {
|
||||||
|
battle.0 += 1;
|
||||||
|
battle.2 |= won;
|
||||||
|
}
|
||||||
|
(true, None) => trace.battle_now = Some((1, 0, won)),
|
||||||
|
(false, Some(_)) => {
|
||||||
|
let mut battle = trace.battle_now.take().expect("a battle");
|
||||||
|
battle.2 |= won;
|
||||||
|
trace.battles.push(battle);
|
||||||
|
}
|
||||||
|
(false, None) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
if let Some(layer) = macros.as_mut() {
|
if let Some(layer) = macros.as_mut() {
|
||||||
let ledger = AdapterLedger(&adapter);
|
let ledger = AdapterLedger(&adapter);
|
||||||
let _ = layer.observe(&mut emulator, &ledger, agent.network.ms);
|
let _ = layer.observe(&mut emulator, &ledger, agent.network.ms);
|
||||||
|
|
@ -987,6 +1037,7 @@ fn main() {
|
||||||
println!("| {name} | {sub} | {n} |");
|
println!("| {name} | {sub} | {n} |");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
battle_report(&trace);
|
||||||
println!("\n| scene | frames | longest run | run began (brain min) |");
|
println!("\n| scene | frames | longest run | run began (brain min) |");
|
||||||
println!("| --- | ---: | ---: | ---: |");
|
println!("| --- | ---: | ---: | ---: |");
|
||||||
for (scene, frames) in &trace.scenes {
|
for (scene, frames) in &trace.scenes {
|
||||||
|
|
@ -1017,3 +1068,43 @@ fn main() {
|
||||||
WINDOW_MS / 1000.0
|
WINDOW_MS / 1000.0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Row 60's numbers: payouts by kind, every battle's length and whether it paid a win, and the
|
||||||
|
/// `MOVE n` starts that chose a move the cartridge answers with nothing.
|
||||||
|
fn battle_report(trace: &Trace) {
|
||||||
|
println!("\n| payout kind | n | total |");
|
||||||
|
println!("| --- | ---: | ---: |");
|
||||||
|
for (kind, (n, total)) in &trace.payouts_by_kind {
|
||||||
|
println!("| {kind} | {n} | {total:.2} |");
|
||||||
|
}
|
||||||
|
let mut lengths: Vec<u64> = trace.battles.iter().map(|battle| battle.0).collect();
|
||||||
|
lengths.sort_unstable();
|
||||||
|
let at = |q: f64| -> u64 {
|
||||||
|
if lengths.is_empty() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
lengths[((lengths.len() - 1) as f64 * q).round() as usize]
|
||||||
|
};
|
||||||
|
println!("\n| battles | n |");
|
||||||
|
println!("| --- | ---: |");
|
||||||
|
println!("| ended | {} |", trace.battles.len());
|
||||||
|
println!("| won (a battle or trainer payout) | {} |", trace.battles.iter().filter(|b| b.2).count());
|
||||||
|
println!(
|
||||||
|
"| still running at the end | {} |",
|
||||||
|
trace.battle_now.map_or("no".to_string(), |b| format!("{} frames, {} macros", b.0, b.1))
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"| frames, median / p90 / max | {} / {} / {} |",
|
||||||
|
at(0.5),
|
||||||
|
at(0.9),
|
||||||
|
lengths.last().copied().unwrap_or(0)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"| macros per battle, max | {} |",
|
||||||
|
trace.battles.iter().map(|b| b.1).max().unwrap_or(0)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"| `MOVE n` starts / on a move without effect | {} / {} |",
|
||||||
|
trace.move_starts.0, trace.move_starts.1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue