diff --git a/gen_efficacy.rb b/gen_efficacy.rb index 5480e18..34e7ebd 100644 --- a/gen_efficacy.rb +++ b/gen_efficacy.rb @@ -13,13 +13,13 @@ end branches = eff.flat_map do |eff| type = eff['name'] [ - *make_branches(type, eff['immunes'], 'Immune'), + *make_branches(type, eff['immunes'], 'Zero'), *make_branches(type, eff['weaknesses'], 'Weak'), *make_branches(type, eff['strengths'], 'Strong'), - *make_branches(type, ['_'], 'Neutral'), ] end puts "match (self, defender) { #{branches.join("\n ")} + #{make_branches('_', ['_'], 'Neutral')[0]} }" diff --git a/src/main.rs b/src/main.rs index b554087..432bdf0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use clap::Parser; use image::{ImageBuffer, Rgb}; use rand::{ distr::{Distribution, StandardUniform}, - Rng, + Rng, RngCore, }; use serde::Deserialize; @@ -33,17 +33,22 @@ fn main() { let mut buffer = ImageBuffer::new(u32::from(width), u32::from(height)); + let mut rolls = vec![0; width as usize * height as usize]; + + let step_digits = format!("{steps}").len(); for i in 0..steps { - let GameStep { old, new } = game.step(last, &mut rng); + rng.fill_bytes(&mut rolls); + let GameStep { old, new } = game.step(last, &mut rng, &rolls); game = new; last = old; - game.write_to_buffer(&mut buffer); + let path = format!("{output_prefix}{i:0OUTPUT_DIGITS$}.png"); if let Err(e) = buffer.save(path) { eprintln!("error saving image: {e}"); process::exit(1); } + eprintln!("step {:step_digits$}/{steps}", i + 1); } } @@ -105,7 +110,7 @@ impl Game { // let's see if we can get away with not swapping the field // nah it's easy - fn step(self, mut next: Self, rng: &mut impl Rng) -> GameStep { + fn step(self, mut next: Self, rng: &mut impl Rng, rolls: &[u8]) -> GameStep { for x in 0..self.width { for y in 0..self.height { let dx = rng.random_range(-1..=1); @@ -126,7 +131,8 @@ impl Game { continue; } - let won = rng.random::<f32>() <= here.win_chance(other); + let roll = rolls[x as usize + y as usize * self.width as usize]; + let won = roll <= here.win_chance(other); if won { next.set(ox, oy, here); } else { @@ -173,12 +179,37 @@ enum Type { Fairy, } +impl From<Type> for usize { + fn from(value: Type) -> Self { + match value { + Type::Normal => 0, + Type::Fire => 1, + Type::Water => 2, + Type::Electric => todo!(), + Type::Grass => todo!(), + Type::Ice => todo!(), + Type::Fighting => todo!(), + Type::Poison => todo!(), + Type::Ground => todo!(), + Type::Flying => todo!(), + Type::Psychic => todo!(), + Type::Bug => todo!(), + Type::Rock => todo!(), + Type::Ghost => todo!(), + Type::Dragon => todo!(), + Type::Dark => todo!(), + Type::Steel => todo!(), + Type::Fairy => todo!(), + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] enum Efficacy { Strong, Neutral, Weak, - Immune, + Zero, } impl Type { @@ -229,20 +260,20 @@ impl Type { } // nothing is immune to itself, phew - fn win_chance(self, other: Type) -> f32 { - use Efficacy::{Immune, Neutral, Strong, Weak}; + fn win_chance(self, other: Type) -> u8 { + use Efficacy::{Neutral, Strong, Weak, Zero}; let self_eff = self.efficacy(other); let def_eff = other.efficacy(self); // if you are twice as effective, you should win twice as often: 2/3 vs 1/3 // if you are four times as effective, you should win four times as often: 4/5 vs 1/5 match (self_eff, def_eff) { - (Strong, Strong) | (Neutral, Neutral) | (Weak, Weak) | (Immune, Immune) => 0.5, - (Immune, _) => 1.0, - (_, Immune) => 0.0, - (Strong, Neutral) | (Neutral, Weak) => 2. / 3., - (Neutral, Strong) | (Weak, Neutral) => 1. / 3., - (Strong, Weak) => 4. / 5., - (Weak, Strong) => 1. / 5., + (Strong, Strong) | (Neutral, Neutral) | (Weak, Weak) | (Zero, Zero) => u8::MAX / 2, + (Zero, _) => 0, + (_, Zero) => u8::MAX, + (Strong, Neutral) | (Neutral, Weak) => 170, // 2/3 + (Neutral, Strong) | (Weak, Neutral) => 85, // 1/3 + (Strong, Weak) => 204, // 4/5 + (Weak, Strong) => 51, // 1/5 } } @@ -254,67 +285,50 @@ impl Type { use Efficacy::*; use Type::*; match (self, defender) { - (Normal, Ghost) => Immune, + (Normal, Ghost) => Zero, (Normal, Rock | Steel) => Weak, - (Normal, _) => Neutral, (Fire, Fire | Water | Rock | Dragon) => Weak, (Fire, Grass | Ice | Bug | Steel) => Strong, - (Fire, _) => Neutral, (Water, Water | Grass | Dragon) => Weak, (Water, Fire | Ground | Rock) => Strong, - (Water, _) => Neutral, - (Electric, Ground) => Immune, + (Electric, Ground) => Zero, (Electric, Electric | Grass | Dragon) => Weak, (Electric, Water | Flying) => Strong, - (Electric, _) => Neutral, (Grass, Fire | Grass | Poison | Flying | Bug | Dragon | Steel) => Weak, (Grass, Water | Ground | Rock) => Strong, - (Grass, _) => Neutral, (Ice, Fire | Water | Ice | Steel) => Weak, (Ice, Grass | Ground | Flying | Dragon) => Strong, - (Ice, _) => Neutral, - (Fighting, Ghost) => Immune, + (Fighting, Ghost) => Zero, (Fighting, Poison | Flying | Psychic | Bug | Fairy) => Weak, (Fighting, Normal | Ice | Rock | Dark | Steel) => Strong, - (Fighting, _) => Neutral, - (Poison, Steel) => Immune, + (Poison, Steel) => Zero, (Poison, Poison | Ground | Rock | Ghost) => Weak, (Poison, Grass | Fairy) => Strong, - (Poison, _) => Neutral, - (Ground, Flying) => Immune, + (Ground, Flying) => Zero, (Ground, Grass | Bug) => Weak, (Ground, Fire | Electric | Poison | Rock | Steel) => Strong, - (Ground, _) => Neutral, (Flying, Electric | Rock | Steel) => Weak, (Flying, Grass | Fighting | Bug) => Strong, - (Flying, _) => Neutral, - (Psychic, Dark) => Immune, + (Psychic, Dark) => Zero, (Psychic, Psychic | Steel) => Weak, (Psychic, Fighting | Poison) => Strong, - (Psychic, _) => Neutral, (Bug, Fire | Fighting | Poison | Flying | Ghost | Steel | Fairy) => Weak, (Bug, Grass | Psychic | Dark) => Strong, - (Bug, _) => Neutral, (Rock, Fighting | Ground | Steel) => Weak, (Rock, Fire | Ice | Flying | Bug) => Strong, - (Rock, _) => Neutral, - (Ghost, Normal) => Immune, + (Ghost, Normal) => Zero, (Ghost, Dark) => Weak, (Ghost, Psychic | Ghost) => Strong, - (Ghost, _) => Neutral, - (Dragon, Fairy) => Immune, + (Dragon, Fairy) => Zero, (Dragon, Steel) => Weak, (Dragon, Dragon) => Strong, - (Dragon, _) => Neutral, (Dark, Fighting | Dark | Fairy) => Weak, (Dark, Psychic | Ghost) => Strong, - (Dark, _) => Neutral, (Steel, Fire | Water | Electric | Steel) => Weak, (Steel, Ice | Rock | Fairy) => Strong, - (Steel, _) => Neutral, (Fairy, Fire | Poison | Steel) => Weak, (Fairy, Fighting | Dragon | Dark) => Strong, - (Fairy, _) => Neutral, + (_, _) => Neutral, } } }