diff options
Diffstat (limited to 'entries/lilylin/fractran/src/engines')
-rw-r--r-- | entries/lilylin/fractran/src/engines/mod.rs | 2 | ||||
-rw-r--r-- | entries/lilylin/fractran/src/engines/register.rs | 164 |
2 files changed, 166 insertions, 0 deletions
diff --git a/entries/lilylin/fractran/src/engines/mod.rs b/entries/lilylin/fractran/src/engines/mod.rs new file mode 100644 index 0000000..6870b7c --- /dev/null +++ b/entries/lilylin/fractran/src/engines/mod.rs @@ -0,0 +1,2 @@ + +pub mod register; diff --git a/entries/lilylin/fractran/src/engines/register.rs b/entries/lilylin/fractran/src/engines/register.rs new file mode 100644 index 0000000..c7c847b --- /dev/null +++ b/entries/lilylin/fractran/src/engines/register.rs @@ -0,0 +1,164 @@ +use std::collections::HashMap; + +use crate::core::Program; + +#[derive(Debug)] +pub struct Register { + pub program: Program, + pub output_base: u64, // which prime factor registers should be used to determine output +} + +#[derive(Debug)] +struct Instruction { + conditions: Vec<(usize, u64)>, // index, amt pairs + increment: Vec<(usize, u64)>, +} + +impl Register { + fn prime_factorize(x: u64) -> Vec<(u64, u64)> { + let primes = primes::factors_uniq(x); + let mut prime_factorized = Vec::new(); + // println!("val: {:?}", x); + for prime in primes { + let mut amount = 1; + loop { + if x % prime.pow(amount + 1) != 0 { + break; + } + amount += 1; + } + // println!("{:?}, {:?}", prime, amount); + prime_factorized.push((prime, amount as u64)); + } + return prime_factorized; + } + fn convert(&self) -> (Vec<u64>, Vec<Instruction>, HashMap<usize, u64>) { + let mut primes = Vec::new(); + + let mut prime_to_index = |prime: u64| { + let index: usize; + if primes.contains(&prime) { + index = primes.iter().position(|&x| x == prime).unwrap(); + } else { + index = primes.len(); + primes.push(prime); + } + return index; + }; + + let mut instrs = Vec::new(); + for fraction in &self.program.fractions { + let denom_pfs = Register::prime_factorize(fraction.1 as u64); + let num_pfs = Register::prime_factorize(fraction.0 as u64); + instrs.push(Instruction { + conditions: denom_pfs + .iter() + .map(|x| (prime_to_index(x.0), x.1)) + .collect(), + increment: num_pfs.iter().map(|x| (prime_to_index(x.0), x.1)).collect(), + }) + } + + let mut initial_registers = Vec::new(); + initial_registers.resize(primes.len(), 0); + for (prime, amt) in Register::prime_factorize(self.program.initial) { + let idx = primes.iter().position(|&x| x == prime).unwrap(); + initial_registers[idx] = amt; + } + + let output_condition: HashMap<usize, u64> = Register::prime_factorize(self.output_base) + .iter() + .map(|(prime, amt)| (primes.iter().position(|&x| x == *prime).unwrap(), *amt)) + .collect(); + + // println!("Prime layout: {:?}", primes); + // println!("Output condition: {:?}", output_condition); + return (initial_registers, instrs, output_condition); + } +} + +impl IntoIterator for Register { + type Item = u64; + type IntoIter = RegisterIter; + + fn into_iter(self) -> Self::IntoIter { + let (registers, instructions, output_condition) = self.convert(); + RegisterIter { + instructions, + registers, + output_condition, + } + } +} + +pub struct RegisterIter { + instructions: Vec<Instruction>, + registers: Vec<u64>, + output_condition: HashMap<usize, u64>, +} + +// impl RegisterIter { +// fn registers_to_val(&self) -> BigUint { +// let mut val = BigUint::zero(); +// for (amt, prime) in self.registers.iter().zip(&self.prime_mapping) { +// val += prime.to_biguint().unwrap().pow(*amt); +// } +// return val; +// } +// } + +impl Iterator for RegisterIter { + type Item = u64; + + fn next(&mut self) -> Option<Self::Item> { + loop { + for instr in &self.instructions { + if instr + .conditions + .iter() + .all(|(idx, amt)| self.registers[*idx] >= *amt) + { + instr + .conditions + .iter() + .for_each(|(idx, amt)| self.registers[*idx] -= *amt); + instr + .increment + .iter() + .for_each(|(idx, amt)| self.registers[*idx] += *amt); + break; + } + } + + // Output condition checking + // Check that all other registers are 0 + if !self + .registers + .iter() + .enumerate() + .all(|(idx, val)| self.output_condition.contains_key(&idx) || *val == 0) + { + continue; + } + + // Check that the condition registers are multiples of the condition amounts + if !self + .output_condition + .iter() + .all(|(idx, cond)| self.registers[*idx] % cond == 0) + { + continue; + } + + // Check that condition registers are the _same_ multipel of the condition amounts + let mut xs = self + .output_condition + .iter() + .map(|(idx, cond)| self.registers[*idx] / cond); + let first = xs.next().unwrap(); + if xs.all(|y| y == first) { + return Some(first); + } + } + } +} |