use std::convert::TryFrom;
use crate::generators::Generator;
use crate::pokemon::{IndividualValues, Pokemon};
pub struct LinearCongruential {
seed: u32,
multiplier: u32,
increment: u32,
}
impl LinearCongruential {
pub fn new(initial_seed: u32) -> Self {
LinearCongruential {
seed: initial_seed,
multiplier: 0x41C64E6Du32,
increment: 0x6073u32,
}
}
pub fn set_seed(&mut self, seed: u32) {
self.seed = seed
}
pub fn step(&mut self) {
self.next_u32();
}
pub fn next_u32(&mut self) -> u32 {
let result = (self.seed as u64 * self.multiplier as u64) + self.increment as u64;
let bitmapped_result = result & 0xFFFFFFFF; let result_u32 = u32::try_from(bitmapped_result).unwrap();
self.seed = result_u32;
result_u32
}
pub fn next_u16(&mut self) -> u16 {
let new_u32 = self.next_u32();
let shifted_u32 = new_u32 >> 16; u16::try_from(shifted_u32).unwrap()
}
pub fn generate_pid(&mut self) -> u32 {
let n1 = self.next_u16();
let n2 = self.next_u16();
let pid: u32 = ((n2 as u32) << 16) + n1 as u32;
pid
}
}
impl Generator for LinearCongruential {
fn method_1(&mut self) -> Pokemon {
let og_seed = self.seed;
let pid = self.generate_pid();
let n1 = self.next_u16();
let n2 = self.next_u16();
let ivs = IndividualValues::new_from_numbers(n1, n2);
self.set_seed(og_seed);
self.step();
Pokemon::new(pid, ivs)
}
fn method_2(&mut self) -> Pokemon {
let og_seed = self.seed;
let pid = self.generate_pid();
self.next_u16();
let n1 = self.next_u16();
let n2 = self.next_u16();
let ivs = IndividualValues::new_from_numbers(n1, n2);
self.set_seed(og_seed);
self.step();
Pokemon::new(pid, ivs)
}
fn method_4(&mut self) -> Pokemon {
let og_seed = self.seed;
let pid = self.generate_pid();
let n1 = self.next_u16();
self.next_u16();
let n2 = self.next_u16();
let ivs = IndividualValues::new_from_numbers(n1, n2);
self.set_seed(og_seed);
self.step();
Pokemon::new(pid, ivs)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::pokemon::{Gender, Nature};
#[test]
fn test_lcrng_new() -> Result<(), String> {
let lcrng = LinearCongruential::new(0);
assert_eq!(lcrng.seed, 0);
Ok(())
}
#[test]
fn test_lcrng_next_32() -> Result<(), String> {
let mut lcrng = LinearCongruential::new(0x1A56B091u32);
let new_u32 = lcrng.next_u32();
assert_eq!(new_u32, 0x01DBBC30u32);
assert_eq!(lcrng.seed, 0x01DBBC30u32);
Ok(())
}
#[test]
fn test_lcrng_next_16() -> Result<(), String> {
let mut lcrng = LinearCongruential::new(0x1A56B091u32);
let new_u16 = lcrng.next_u16();
assert_eq!(new_u16, 0x01DBu16);
Ok(())
}
#[test]
fn test_lcrng_next_16_sequence() -> Result<(), String> {
let mut lcrng = LinearCongruential::new(0x1A56B091u32);
let expected_numbers: [u16; 6] = [
0x01DBu16, 0x7B06u16, 0x5233u16, 0xE470u16, 0x5CC4u16, 0x36BBu16,
];
for expected_number in expected_numbers.iter() {
assert_eq!(*expected_number, lcrng.next_u16());
}
Ok(())
}
#[test]
fn test_generate_pid() -> Result<(), String> {
let mut lcrng = LinearCongruential::new(0x1A56B091u32);
let pid = lcrng.generate_pid();
assert_eq!(pid, 0x7B0601DBu32);
Ok(())
}
#[test]
fn test_generate_pokemon_method_2() -> Result<(), String> {
let mut lcrng = LinearCongruential::new(0x560B9CE3u32);
let generated_pokemon = lcrng.method_2();
assert_eq!(generated_pokemon.pid, 2118657873);
assert_eq!(
generated_pokemon.ivs,
IndividualValues::new(28, 20, 24, 23, 23, 9)
);
assert_eq!(generated_pokemon.get_nature(), Nature::Careful);
assert_eq!(generated_pokemon.get_ability(), 1);
assert_eq!(generated_pokemon.get_gender_50_f(), Gender::Female);
Ok(())
}
#[test]
fn test_generate_method_1_frame_sequence() -> Result<(), String> {
let mut lcrng = LinearCongruential::new(0);
let expected_pid_sequence: [u32; 5] = [
0xe97e0000u32,
0x5271e97eu32,
0x31b05271u32,
0x8e4231b0u32,
0xe2cc8e42u32,
];
for expected_pid in expected_pid_sequence.iter() {
assert_eq!(*expected_pid, lcrng.method_1().pid);
}
Ok(())
}
}