Spaces:
Sleeping
Sleeping
File size: 5,392 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 | use std::fs;
use engine_rust::core::logic::{GameState, CardDatabase};
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 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() {
let db = load_vanilla_db();
let deck_path = if std::path::Path::new("ai/decks/liella_cup.txt").exists() {
"ai/decks/liella_cup.txt"
} else {
"../ai/decks/liella_cup.txt"
};
let (p0_members, p0_lives) = load_deck(deck_path, &db);
let energy: Vec<i32> = db.energy_db.keys().take(12).cloned().collect();
let mut state = GameState::default();
state.initialize_game(
p0_members.clone(),
p0_members.clone(),
energy.clone(),
energy.clone(),
p0_lives.clone(),
p0_lives.clone(),
);
state.ui.silent = true;
// Advance to first Main phase
while state.phase != Phase::Main && !state.is_terminal() {
state.auto_step(&db);
}
println!("\nβββββββββββββββββββββββββββββββββββββββββββββββββββββ");
println!("β Move Sequence Enumeration & State Explosion β");
println!("βββββββββββββββββββββββββββββββββββββββββββββββββββββ\n");
let legal_root = state.get_legal_action_ids(&db);
println!("Initial State:");
println!(" Current player: P{}", state.current_player);
println!(" Phase: {:?}", state.phase);
println!(" Hand size: {}", state.players[0].hand.len());
println!(" Stage: {} cards", state.players[0].stage.iter().filter(|&&c| c >= 0).count());
println!(" Legal actions: {}\n", legal_root.len());
// Theoretical analysis
println!("Move Space Analysis:\n");
println!("Depth | Branching | Est. Tree Size | Est. Compressed (AB)");
println!("ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ");
let branching = legal_root.len() as f64;
for depth in 1..=10 {
let tree_size = branching.powi(depth as i32);
// Alpha-beta roughly reduces by factor of sqrt(branching)
let compressed = (branching.sqrt()).powi(depth as i32);
println!(
"{:>5} | {:>9.1} | {:>14.0} | {:>19.0}",
depth, branching, tree_size, compressed
);
}
println!("\nβββββββββββββββββββββββββββββββββββββββββββββββββββββ");
println!("β Key Insight: Equivalent Moves β");
println!("βββββββββββββββββββββββββββββββββββββββββββββββββββββ\n");
println!("If all 3 stage slots are empty:");
println!(" Placing card A then B then C");
println!(" Placing card C then B then A");
println!(" Placing card B then A then C");
println!(" β These explore 3! = 6 sequences");
println!(" β But lead to SAME board state if no abilities trigger\n");
println!("With abilities that trigger on placement:");
println!(" Order MATTERS because effects can change what's legal next\n");
println!("Conclusion:");
println!(" β’ Legal branching factor: ~6-8 actions per state (realistic)");
println!(" β’ Depth N explores 6^N states without pruning");
println!(" β’ Move ordering + pruning: reduces to ~6^(N/3) effective nodes");
println!(" β’ Alpha-beta effectiveness depends on ability-triggered order changes\n");
} |