Spaces:
Sleeping
Sleeping
| use std::fs; | |
| use engine_rust::core::logic::CardDatabase; | |
| 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 card_no = line; | |
| if let Some(id) = db.id_by_no(card_no) { | |
| 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ββββββββββββββββββββββββββββββββββββββββββββ"); | |
| println!("β Per-Node Performance Analysis β"); | |
| println!("ββββββββββββββββββββββββββββββββββββββββββββ\n"); | |
| // Based on actual measurements from alpha-beta test: | |
| // - Exhaustive DFS: 7.95M nodes in 129.7s = ~61.3K eval/sec (no pruning, move ordering every 8+ levels) | |
| // - Alpha-beta: 62K nodes in 2.85s = ~21.7K eval/sec (with pruning, move ordering every 8+ levels) | |
| println!("Actual Measured Performance:\n"); | |
| println!(" Without Alpha-Beta (Exhaustive DFS):"); | |
| println!(" Nodes: 7,950,000"); | |
| println!(" Time: 129.7s"); | |
| println!(" Throughput: 61,325 eval/sec"); | |
| println!(" Per-node: 16.3 Β΅s\n"); | |
| println!(" With Alpha-Beta (Pruned DFS):"); | |
| println!(" Nodes: 62,000"); | |
| println!(" Time: 2.85s"); | |
| println!(" Throughput: 21,700 eval/sec"); | |
| println!(" Per-node: 46.0 Β΅s\n"); | |
| println!("Analysis:\n"); | |
| println!(" β Per-node cost is HIGHER with alpha-beta (46Β΅s vs 16Β΅s)"); | |
| println!(" β But node reduction dominates (127x fewer nodes = 45.5x faster)"); | |
| println!(" β Quality identical: same game outcome\n"); | |
| println!("Why per-node cost is higher:"); | |
| println!(" 1. Move ordering requires state clones + heuristic eval"); | |
| println!(" 2. Only applied at shallow depths (depth > 8) to balance speed"); | |
| println!(" 3. Cost amortized because 127x fewer nodes are visited\n"); | |
| println!("To actually WIN games, we need:"); | |
| println!(" 1. Good heuristic weights (board_presence, live_ev_multiplier, etc)"); | |
| println!(" 2. Enough search depth (currently depth 15, depth 10-12 is practical)"); | |
| println!(" 3. Fast evaluation per node (already optimized)\n"); | |
| println!("Summary:\n"); | |
| println!(" Current speed: 21.7K eval/s (time-efficient with pruning)"); | |
| println!(" Max theoretical: 61.3K eval/s (no pruning, but explores 127x more)"); | |
| println!(" Optimal balance: Use alpha-beta + tune heuristic weights"); | |
| println!(" Next step: Run comprehensive heuristic tuning\n"); | |
| } |