Spaces:
Sleeping
Sleeping
File size: 6,490 Bytes
463f868 9bd4ce5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | use std::fs;
use std::time::Instant;
use engine_rust::core::logic::{CardDatabase, GameState, ACTION_BASE_PASS};
use engine_rust::core::logic::turn_sequencer::{TurnSequencer};
use engine_rust::core::enums::Phase;
fn load_vanilla_db() -> CardDatabase {
let candidates = [
"data/cards_vanilla.json",
"../data/cards_vanilla.json",
"../../data/cards_vanilla.json",
];
for path in &candidates {
if !std::path::Path::new(path).exists() {
continue;
}
let json = fs::read_to_string(path).expect("Failed to read DB");
let mut db = CardDatabase::from_json(&json).expect("Failed to parse DB");
db.is_vanilla = true;
return db;
}
panic!("cards_vanilla.json not found");
}
fn load_deck(path: &str, db: &CardDatabase) -> (Vec<i32>, Vec<i32>) {
let content = fs::read_to_string(path).expect("Failed to read deck");
let mut members = Vec::new();
let mut lives = Vec::new();
for line in content.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
let parts: Vec<&str> = line.split_whitespace().collect();
if parts.is_empty() {
continue;
}
let card_no = parts[0];
let count: usize = if parts.len() >= 3 && parts[1] == "x" {
parts[2].parse().unwrap_or(1)
} else {
1
};
if let Some(id) = db.id_by_no(card_no) {
for _ in 0..count {
if db.lives.contains_key(&id) {
lives.push(id);
} else {
members.push(id);
}
}
}
}
while members.len() < 48 {
if let Some(&id) = db.members.keys().next() {
members.push(id);
} else {
break;
}
}
while lives.len() < 12 {
if let Some(&id) = db.lives.keys().next() {
lives.push(id);
} else {
break;
}
}
members.truncate(48);
lives.truncate(12);
(members, lives)
}
fn main() {
println!("\n=== MICRO-BENCHMARKS ===\n");
let db = load_vanilla_db();
let (p0_members, p0_lives) = load_deck("ai/decks/liella_cup.txt", &db);
let (p1_members, p1_lives) = load_deck("ai/decks/liella_cup.txt", &db);
let mut state = GameState::default();
let energy_vec: Vec<i32> = db.energy_db.keys().take(12).cloned().collect();
println!("[INIT] Creating game state...");
let t = Instant::now();
state.initialize_game(
p0_members,
p1_members,
energy_vec.clone(),
energy_vec,
p0_lives,
p1_lives,
);
println!(" Game init: {:.3}ms", t.elapsed().as_secs_f32() * 1000.0);
state.ui.silent = true;
// Measure state clone
let t = Instant::now();
for _ in 0..1000 {
let _ = state.clone();
}
println!("[CLONE] 1000 clones: {:.3}µs per clone", t.elapsed().as_secs_f32() * 1_000_000.0 / 1000.0);
// Measure action generation
let mut actions: Vec<i32> = Vec::new();
let t = Instant::now();
for _ in 0..10000 {
actions.clear();
state.generate_legal_actions(&db, state.current_player as usize, &mut actions);
}
println!("[ACTIONS] 10000 gens: {:.3}µs per gen ({} actions)", t.elapsed().as_secs_f32() * 1_000_000.0 / 10000.0, actions.len());
// Measure state.step()
let t = Instant::now();
for _ in 0..1000 {
let mut temp = state.clone();
let _ = temp.step(&db, ACTION_BASE_PASS);
}
println!("[STEP] 1000 steps: {:.3}µs per step", t.elapsed().as_secs_f32() * 1_000_000.0 / 1000.0);
// Measure full op
let t = Instant::now();
for _ in 0..1000 {
let mut acts: Vec<i32> = Vec::new();
state.generate_legal_actions(&db, state.current_player as usize, &mut acts);
if !acts.is_empty() {
let mut temp = state.clone();
let _ = temp.step(&db, acts[0]);
}
}
println!("[FULL-OP] 1000x (gen+clone+step): {:.3}µs per op", t.elapsed().as_secs_f32() * 1_000_000.0 / 1000.0);
println!("\n=== PHASE TRANSITION ===\n");
// Skip to Main phase
let t = Instant::now();
while state.phase != Phase::Main && !state.is_terminal() {
state.auto_step(&db);
}
println!("[STARTUP] Reached Main phase in {:.3}s", t.elapsed().as_secs_f32());
println!(" Current state: Player={}, Phase={:?}", state.current_player, state.phase);
// Generate actions
let mut main_actions: Vec<i32> = Vec::new();
state.generate_legal_actions(&db, state.current_player as usize, &mut main_actions);
println!(" Legal actions in Main: {}", main_actions.len());
println!("\n=== SINGLE TURN SEARCH ===\n");
let search_start = Instant::now();
let (best_seq, best_val, (board_ev, live_ev), evals) = TurnSequencer::plan_full_turn(&state, &db);
let search_elapsed = search_start.elapsed();
println!("[SEARCH] Completed in {:.3}ms", search_elapsed.as_secs_f32() * 1000.0);
println!(" Best sequence: {} actions", best_seq.len());
println!(" Evaluation: {:.2} (board={:.2}, live={:.2})", best_val, board_ev, live_ev);
println!(" Evaluations run: {}", evals);
println!(" Time per eval: {:.3}µs", search_elapsed.as_secs_f32() * 1_000_000.0 / evals.max(1) as f32);
println!("\n=== EXECUTE SEQUENCE ===\n");
let exec_start = Instant::now();
for &action in &best_seq {
if state.phase != Phase::Main {
break;
}
let legal = state.get_legal_action_ids(&db);
if !legal.contains(&action) {
break;
}
let _ = state.step(&db, action);
}
println!("[EXEC] Executed {} actions in {:.3}ms", best_seq.len(), exec_start.elapsed().as_secs_f32() * 1000.0);
if state.phase == Phase::Main {
let _ = state.step(&db, ACTION_BASE_PASS);
println!("[PASS] Turn ended");
}
println!("\n=== ANALYSIS ===\n");
println!("Turn search (search + exec): {:.3}ms", (search_elapsed + exec_start.elapsed()).as_secs_f32() * 1000.0);
println!("If repeated 10 times: {:.3}s", (search_elapsed + exec_start.elapsed()).as_secs_f32() * 1000.0 * 10.0 / 1000.0);
} |