From 95fdad10347a97e5010d361db142c729ee7dbe95 Mon Sep 17 00:00:00 2001 From: vandomej Date: Sun, 7 Sep 2025 22:08:20 -0700 Subject: [PATCH] Formatting code --- evolved-npcs/src/fighter_nn/mod.rs | 63 ++++++++------ .../src/fighter_nn/neural_network_utility.rs | 84 ++++++++++++++----- evolved-npcs/src/main.rs | 2 +- visualize_networks.py | 14 ---- 4 files changed, 103 insertions(+), 60 deletions(-) diff --git a/evolved-npcs/src/fighter_nn/mod.rs b/evolved-npcs/src/fighter_nn/mod.rs index d81812b..bb4fd92 100644 --- a/evolved-npcs/src/fighter_nn/mod.rs +++ b/evolved-npcs/src/fighter_nn/mod.rs @@ -3,7 +3,7 @@ extern crate fann; pub mod fighter_context; pub mod neural_network_utility; -use anyhow::{anyhow, Context}; +use anyhow::{Context, anyhow}; use async_trait::async_trait; use fann::{ActivationFunc, Fann}; use futures::future::join_all; @@ -114,8 +114,10 @@ impl GeneticNode for FighterNN { })?; let mut nn_shapes = HashMap::new(); - let weight_initialization_amplitude = rng().random_range(0.0..NEURAL_NETWORK_INITIAL_WEIGHT_MAX); - let weight_initialization_range = -weight_initialization_amplitude..weight_initialization_amplitude; + let weight_initialization_amplitude = + rng().random_range(0.0..NEURAL_NETWORK_INITIAL_WEIGHT_MAX); + let weight_initialization_range = + -weight_initialization_amplitude..weight_initialization_amplitude; // Create the first generation in this folder for i in 0..POPULATION { @@ -201,7 +203,6 @@ impl GeneticNode for FighterNN { i }; - let secondary_id = loop { if allotted_simulations.is_empty() || allotted_simulations.len() == 1 { // Select a random id @@ -243,11 +244,12 @@ impl GeneticNode for FighterNN { let task = { let self_clone = self.clone(); let semaphore_clone = context.gemla_context.shared_semaphore.clone(); - let display_simulation_semaphore = context.gemla_context.visible_simulations.clone(); - + let display_simulation_semaphore = + context.gemla_context.visible_simulations.clone(); + let folder = self_clone.folder.clone(); let generation = self_clone.r#generation; - + let primary_nn = self_clone .folder .join(format!("{}", self_clone.r#generation)) @@ -257,32 +259,36 @@ impl GeneticNode for FighterNN { .join(format!("{}", generation)) .join(self_clone.get_individual_id(*secondary_id as u64)) .with_extension("net"); - + // Introducing a new scope for acquiring permits and running simulations let simulation_result = async move { - let permit = semaphore_clone.acquire_owned().await + let permit = semaphore_clone + .acquire_owned() + .await .with_context(|| "Failed to acquire semaphore permit")?; - + let display_simulation = display_simulation_semaphore.try_acquire_owned().ok(); - - let (primary_score, secondary_score) = if let Some(display_simulation) = display_simulation { + + let (primary_score, secondary_score) = if let Some(display_simulation) = + display_simulation + { let result = run_1v1_simulation(&primary_nn, &secondary_nn, true).await?; drop(display_simulation); // Explicitly dropping resources no longer needed result } else { run_1v1_simulation(&primary_nn, &secondary_nn, false).await? }; - + drop(permit); // Explicitly dropping resources no longer needed debug!( "{} vs {} -> {} vs {}", primary_id, secondary_id, primary_score, secondary_score ); - + Ok((*primary_id, primary_score, *secondary_id, secondary_score)) }; // Await the scoped async block immediately - + // The result of the simulation, whether Ok or Err, is returned here. // This ensures tx is dropped when the block exits, regardless of success or failure. simulation_result @@ -300,7 +306,8 @@ impl GeneticNode for FighterNN { // resolve results for any errors let mut scores = HashMap::new(); for result in results.into_iter() { - let (primary_id, primary_score, secondary_id, secondary_score) = result.with_context(|| "Failed to run simulation")?; + let (primary_id, primary_score, secondary_id, secondary_score) = + result.with_context(|| "Failed to run simulation")?; // If score exists, add the new score to the existing score if let Some((existing_score, count)) = scores.get_mut(&(primary_id as u64)) { @@ -480,8 +487,9 @@ impl GeneticNode for FighterNN { .with_context(|| format!("Failed to create directory {:?}", folder.join("0")))?; let get_highest_scores = |fighter: &FighterNN| -> Vec<(u64, f32)> { - let mut sorted_scores: Vec<_> = - fighter.scores[fighter.r#generation as usize].iter().collect(); + let mut sorted_scores: Vec<_> = fighter.scores[fighter.r#generation as usize] + .iter() + .collect(); sorted_scores.sort_by(|a, b| b.1.partial_cmp(a.1).unwrap()); sorted_scores .iter() @@ -537,7 +545,10 @@ impl GeneticNode for FighterNN { run_1v1_simulation(&left_nn_path, &right_nn_path, false).await? }; - debug!("{} vs {} -> {} vs {}", left_nn_id, right_nn_id, left_score, right_score); + debug!( + "{} vs {} -> {} vs {}", + left_nn_id, right_nn_id, left_score, right_score + ); drop(permit); @@ -734,7 +745,11 @@ fn should_continue(scores: &[HashMap], lenience: u64) -> Result Result - { + Err(_) => { if attempts >= 2 { // Attempt 5 times before giving up. return Ok(-100.0); diff --git a/evolved-npcs/src/fighter_nn/neural_network_utility.rs b/evolved-npcs/src/fighter_nn/neural_network_utility.rs index bae4551..1f9287b 100644 --- a/evolved-npcs/src/fighter_nn/neural_network_utility.rs +++ b/evolved-npcs/src/fighter_nn/neural_network_utility.rs @@ -1,12 +1,13 @@ -use std::{cmp::min, cmp::Ordering, collections::HashMap, ops::Range}; +use std::{cmp::Ordering, cmp::min, collections::HashMap, ops::Range}; use anyhow::Context; use fann::{ActivationFunc, Fann}; use gemla::error::Error; use rand::{ + Rng, distr::{Distribution, Uniform}, + rng, seq::IteratorRandom, - rng, Rng, }; use super::{ @@ -208,13 +209,37 @@ pub fn consolidate_old_connections( to_non_bias_network_id(connection.from_neuron, &primary_shape); let original_to_neuron = to_non_bias_network_id(connection.to_neuron, &primary_shape); - trace!("Primary: Adding connection from ({} -> {}) translated to ({:?} -> {:?}) with weight {} for primary:{} [{} -> {}] [{} -> {}]", previous_new_id, new_id, original_from_neuron, original_to_neuron, connection.weight, found_in_primary, connection.from_neuron, connection.to_neuron, previous_neuron_id, neuron_id); + trace!( + "Primary: Adding connection from ({} -> {}) translated to ({:?} -> {:?}) with weight {} for primary:{} [{} -> {}] [{} -> {}]", + previous_new_id, + new_id, + original_from_neuron, + original_to_neuron, + connection.weight, + found_in_primary, + connection.from_neuron, + connection.to_neuron, + previous_neuron_id, + neuron_id + ); } else { let original_from_neuron = to_non_bias_network_id(connection.from_neuron, &secondary_shape); let original_to_neuron = to_non_bias_network_id(connection.to_neuron, &secondary_shape); - trace!("Secondary: Adding connection from ({} -> {}) translated to ({:?} -> {:?}) with weight {} for primary:{} [{} -> {}] [{} -> {}]", previous_new_id, new_id, original_from_neuron, original_to_neuron, connection.weight, found_in_primary, connection.from_neuron, connection.to_neuron, previous_neuron_id, neuron_id); + trace!( + "Secondary: Adding connection from ({} -> {}) translated to ({:?} -> {:?}) with weight {} for primary:{} [{} -> {}] [{} -> {}]", + previous_new_id, + new_id, + original_from_neuron, + original_to_neuron, + connection.weight, + found_in_primary, + connection.from_neuron, + connection.to_neuron, + previous_neuron_id, + neuron_id + ); } let translated_from = to_bias_network_id(previous_new_id, &new_shape); let translated_to = to_bias_network_id(new_id, &new_shape); @@ -222,10 +247,7 @@ pub fn consolidate_old_connections( } else { trace!( "Connection not found for ({}, {}) -> ({}, {})", - previous_new_id, - new_id, - previous_neuron_id, - neuron_id + previous_new_id, new_id, previous_neuron_id, neuron_id ); } } @@ -317,23 +339,43 @@ pub fn consolidate_old_connections( to_non_bias_network_id(connection.from_neuron, &primary_shape); let original_to_neuron = to_non_bias_network_id(connection.to_neuron, &primary_shape); - trace!("Primary: Adding connection from ({} -> {}) translated to ({:?} -> {:?}) with weight {} for primary:{} [{} -> {}] [{} -> {}]", bias_neuron, translated_neuron_id, original_from_neuron, original_to_neuron, connection.weight, found_in_primary, connection.from_neuron, connection.to_neuron, bias_neuron, neuron_id); + trace!( + "Primary: Adding connection from ({} -> {}) translated to ({:?} -> {:?}) with weight {} for primary:{} [{} -> {}] [{} -> {}]", + bias_neuron, + translated_neuron_id, + original_from_neuron, + original_to_neuron, + connection.weight, + found_in_primary, + connection.from_neuron, + connection.to_neuron, + bias_neuron, + neuron_id + ); } else { let original_from_neuron = to_non_bias_network_id(connection.from_neuron, &secondary_shape); let original_to_neuron = to_non_bias_network_id(connection.to_neuron, &secondary_shape); - trace!("Secondary: Adding connection from ({} -> {}) translated to ({:?} -> {:?}) with weight {} for primary:{} [{} -> {}] [{} -> {}]", bias_neuron, translated_neuron_id, original_from_neuron, original_to_neuron, connection.weight, found_in_primary, connection.from_neuron, connection.to_neuron, bias_neuron, neuron_id); + trace!( + "Secondary: Adding connection from ({} -> {}) translated to ({:?} -> {:?}) with weight {} for primary:{} [{} -> {}] [{} -> {}]", + bias_neuron, + translated_neuron_id, + original_from_neuron, + original_to_neuron, + connection.weight, + found_in_primary, + connection.from_neuron, + connection.to_neuron, + bias_neuron, + neuron_id + ); } new_fann.set_weight(bias_neuron, translated_neuron_id, connection.weight); } else { trace!( "Connection not found for bias ({}, {}) -> ({}, {}) primary: {}", - bias_neuron, - neuron_id, - bias_neuron, - translated_neuron_id, - is_primary + bias_neuron, neuron_id, bias_neuron, translated_neuron_id, is_primary ); } } @@ -388,8 +430,7 @@ pub fn crossbreed_neuron_arrays( if neuron_id >= &segment.0 && neuron_id <= &segment.1 { // We need to do something different depending on whether the neuron layer is, lower, higher or equal to the target layer - match layer.cmp(¤t_layer) - { + match layer.cmp(¤t_layer) { Ordering::Equal => { new_neurons.push((*neuron_id, is_primary, current_layer, 0)); @@ -399,7 +440,7 @@ pub fn crossbreed_neuron_arrays( secondary_last_layer = current_layer; } } - Ordering:: Less => { + Ordering::Less => { // If it's in an earlier layer, add it to the earlier layer // Check if there's a lower id from the same individual in that earlier layer // As long as there isn't a neuron from the other individual in between the lower id and current id, add the id values from the same individual @@ -455,7 +496,12 @@ pub fn crossbreed_neuron_arrays( .filter(|(id, l)| id > &highest_id.0 && *l == layer - 1) .collect::>(); for (neuron_id, _) in neurons_to_add { - new_neurons.push((*neuron_id, is_primary, current_layer, 0)); + new_neurons.push(( + *neuron_id, + is_primary, + current_layer, + 0, + )); if is_primary { primary_last_layer = current_layer; diff --git a/evolved-npcs/src/main.rs b/evolved-npcs/src/main.rs index 8742e7e..e273180 100644 --- a/evolved-npcs/src/main.rs +++ b/evolved-npcs/src/main.rs @@ -68,4 +68,4 @@ fn main() -> Result<()> { info!("Finished in {:?}", now.elapsed()); Ok(()) -} \ No newline at end of file +} diff --git a/visualize_networks.py b/visualize_networks.py index 280011f..f050779 100644 --- a/visualize_networks.py +++ b/visualize_networks.py @@ -100,19 +100,5 @@ def visualize_fann_network(network_file): plt.show() # Path to the FANN network file -fann_path = 'F:\\\\vandomej\\Projects\\dootcamp-AI-Simulation\\Simulations\\fighter_nn_4f2be613-ab26-4384-9a65-450e043984ea\\6\\4f2be613-ab26-4384-9a65-450e043984ea_fighter_nn_0.net' -# fann_path = "F:\\\\vandomej\\Projects\\dootcamp-AI-Simulation\\Simulations\\fighter_nn_fc294503-7b2a-40f8-be59-ccc486eb3f79\\0\\fc294503-7b2a-40f8-be59-ccc486eb3f79_fighter_nn_0.net" -# fann_path = 'F:\\\\vandomej\\Projects\\dootcamp-AI-Simulation\\Simulations\\fighter_nn_99c30a7f-40ab-4faf-b16a-b44703fdb6cd\\0\\99c30a7f-40ab-4faf-b16a-b44703fdb6cd_fighter_nn_0.net' -# Has a 4 layer network -# # Generation 1 -# fann_path = "F:\\\\vandomej\\Projects\\dootcamp-AI-Simulation\\Simulations\\fighter_nn_16dfa1b4-03c7-45a6-84b4-22fe3c8e2d98\\1\\16dfa1b4-03c7-45a6-84b4-22fe3c8e2d98_fighter_nn_0.net" -# # Generation 5 -# fann_path = "F:\\\\vandomej\\Projects\\dootcamp-AI-Simulation\\Simulations\\fighter_nn_16dfa1b4-03c7-45a6-84b4-22fe3c8e2d98\\5\\16dfa1b4-03c7-45a6-84b4-22fe3c8e2d98_fighter_nn_0.net" -# # Generation 10 -# fann_path = "F:\\\\vandomej\\Projects\\dootcamp-AI-Simulation\\Simulations\\fighter_nn_16dfa1b4-03c7-45a6-84b4-22fe3c8e2d98\\10\\16dfa1b4-03c7-45a6-84b4-22fe3c8e2d98_fighter_nn_0.net" -# # Generation 20 -# fann_path = "F:\\\\vandomej\\Projects\\dootcamp-AI-Simulation\\Simulations\\fighter_nn_16dfa1b4-03c7-45a6-84b4-22fe3c8e2d98\\20\\16dfa1b4-03c7-45a6-84b4-22fe3c8e2d98_fighter_nn_0.net" -# # Generation 32 -# fann_path = "F:\\\\vandomej\\Projects\\dootcamp-AI-Simulation\\Simulations\\fighter_nn_16dfa1b4-03c7-45a6-84b4-22fe3c8e2d98\\32\\16dfa1b4-03c7-45a6-84b4-22fe3c8e2d98_fighter_nn_0.net" fann_path = select_file() visualize_fann_network(fann_path) \ No newline at end of file