use image::{DynamicImage, Rgba, GenericImage};
use crate::resel::{Resel};
use crate::reselboard::{
ReselBoard,
load_image_from_filename,
load_image_from_filename_string
};
use crate::regionmap::{RegionMap};
use crate::incidencemap::{IncidenceMap};
#[derive(Debug, Clone)]
pub struct ResoCircuit {
pub rb: ReselBoard,
pub rm: RegionMap,
pub im: IncidenceMap,
pub wire_state: Vec<bool>,
input_state: Vec<Vec<bool>>,
logic_state: Vec<bool>,
output_state: Vec<bool>,
}
impl From<ReselBoard> for ResoCircuit {
fn from (rb: ReselBoard) -> ResoCircuit {
let rm = RegionMap::from(&rb);
let im = IncidenceMap::from(&rm);
let wire_state: Vec<bool> = rm.wire_regions.iter().map(
|region| {
rm.region_to_resel[*region]
.wire_state().unwrap() }
).collect();
let input_state: Vec<Vec<bool>> = im.input_inc_wires
.iter().map(
|inc_wires| { vec![false; inc_wires.len()] }
).collect();
let logic_state = vec![false; rm.logic_regions.len()];
let output_state = vec![false; rm.output_regions.len()];
ResoCircuit{
rb: rb,
rm: rm,
im: im,
wire_state: wire_state,
input_state: input_state,
logic_state: logic_state,
output_state: output_state,
}
}
}
impl ResoCircuit{
fn reset_intermediate_state(&mut self) {
for ii in 0..self.input_state.len() {
for wi in 0..self.input_state[ii].len() {
self.input_state[ii][wi] = false
}
}
for li in 0..self.logic_state.len() {
self.logic_state[li] = false
}
for oi in 0..self.output_state.len() {
self.output_state[oi] = false
}
}
pub fn iterate(&mut self) {
for (ii, inc_wires) in self.im.input_inc_wires.iter().enumerate() {
for (inc_wi, wi) in inc_wires.iter().enumerate() {
self.input_state[ii][inc_wi] = self.wire_state[*wi]
}
}
for (li, inc_inputs) in self.im.logic_inc_inputs.iter().enumerate() {
let lri = self.rm.logic_regions[li];
for ii in inc_inputs.iter() {
if self.rm.region_to_resel[lri] == Resel::AND {
self.logic_state[li] = (
self.logic_state[li] || self.input_state[*ii].iter().fold(
true, |acc, &x| acc && x )
);
} else if self.rm.region_to_resel[lri] == Resel::XOR {
self.logic_state[li] = (
self.logic_state[li] || self.input_state[*ii].iter().fold(
false, |acc, &x| acc ^ x )
);
} else {
panic!(
"rc.rm.region_to_resel[lri={}]={:?} is not logic?!?",
lri, self.rm.region_to_resel[lri]
);
}
}
}
for (oi, inc_inputs) in self.im.output_inc_inputs.iter().enumerate() {
for ii in inc_inputs.iter() {
self.output_state[oi] = (
self.output_state[oi] || self.input_state[*ii].iter().fold(
false, |acc, &x| acc || x )
)
}
}
for (oi, inc_logics) in self.im.output_inc_logics.iter().enumerate() {
for li in inc_logics.iter() {
self.output_state[oi] = self.output_state[oi] || self.logic_state[*li]
}
}
for (wi, inc_outputs) in self.im.wire_inc_outputs.iter().enumerate() {
self.wire_state[wi] = false;
for oi in inc_outputs.iter() {
self.wire_state[wi] = self.wire_state[wi] || self.output_state[*oi]
}
}
self.reset_intermediate_state()
}
pub fn get_image(&self) -> Option<&DynamicImage> {
self.rb.image.as_ref()
}
pub fn update_pixels(&mut self) {
if self.rb.image == None {
return
}
for (wi, ri) in self.rm.wire_regions.iter().enumerate() {
let update_to_resel = match self.rm.region_to_resel[*ri] {
Resel::WireOrangeOn | Resel::WireOrangeOff => {
if self.wire_state[wi] {Resel::WireOrangeOn} else {Resel::WireOrangeOff}
},
Resel::WireSapphireOn | Resel::WireSapphireOff => {
if self.wire_state[wi] {Resel::WireSapphireOn} else {Resel::WireSapphireOff}
},
Resel::WireLimeOn | Resel::WireLimeOff => {
if self.wire_state[wi] {Resel::WireLimeOn} else {Resel::WireLimeOff}
},
_ => {
panic!("Oh no, ResoCircuit.update_pixels() found a wire_region pointing to something not a wire. This shouldn't be possible.");
}
};
let update_to_pixel = <Rgba<u8>>::from(update_to_resel);
for (x,y) in &self.rm.region_to_xys[*ri] {
self.rb.image.as_mut().unwrap().put_pixel(*x as u32, *y as u32, update_to_pixel);
}
}
}
}
#[cfg(test)]
mod resocircuit_tests {
use crate::reselboard::load_image_from_filename_string;
use super::*;
#[test]
fn test_iterate_halfadder() {
let mut rc = ResoCircuit::from(
ReselBoard::from(
load_image_from_filename(
"./src/testing/test_half_adder_01.png"
).unwrap()
)
);
for (ri, state) in [
(0, true), (1, true), (2, true), (3, true)
] {
assert_eq!(rc.wire_state[ri], state)
}
rc.iterate();
rc.update_pixels();
for (ri, state) in [
(0, true), (1, false), (2, false), (3, true)
] {
assert_eq!(rc.wire_state[ri], state)
}
assert_eq!(
rc.get_image().unwrap().clone(),
load_image_from_filename(
"./src/testing/test_half_adder_02.png"
).unwrap()
);
rc.iterate();
rc.update_pixels();
for (ri, state) in [
(0, true), (1, false), (2, true), (3, false)
] {
assert_eq!(rc.wire_state[ri], state)
}
assert_eq!(
rc.get_image().unwrap().clone(),
load_image_from_filename(
"./src/testing/test_half_adder_03.png"
).unwrap()
);
}
#[test]
fn test_reso_logo() {
let mut rc = ResoCircuit::from(
ReselBoard::from(
load_image_from_filename(
"./reso_logo.png"
).unwrap()
)
);
for tt in 1..9 {
rc.iterate();
rc.update_pixels();
assert_eq!(
*rc.get_image().unwrap(),
load_image_from_filename_string(
format!("./src/testing/reso_logo_{}.png", tt)
).unwrap()
);
}
}
}