use crate::resel::{Resel};
use crate::reselboard::{
ReselBoard,
get_neighbors
};
#[derive(Debug, Clone)]
pub struct RegionMap {
pub xy_to_region: Vec<Vec<usize>>, pub width: usize,
pub height: usize,
pub region_to_xys: Vec<Vec<(usize, usize)>>, pub region_to_resel: Vec<Resel>,
pub wire_regions: Vec<usize>,
pub input_regions: Vec<usize>,
pub logic_regions: Vec<usize>,
pub output_regions: Vec<usize>,
pub reverse_dense: Vec<usize>
}
impl RegionMap {
pub fn get_adjacent_regions(&self, region: usize) -> Vec<usize> {
let mut adjacent_regions = vec![];
for (x,y) in &self.region_to_xys[region] {
for (nx, ny) in get_neighbors(
vec![(1,0),(0,1),(-1,0),(0,-1)], *x, *y, self.width, self.height
) {
let neighbor_region = self.xy_to_region[nx][ny];
if (
region != neighbor_region
&& !adjacent_regions.contains(&neighbor_region)
) {
adjacent_regions.push(neighbor_region)
}
}
}
adjacent_regions.sort();
adjacent_regions
}
}
fn region_map_from_reselboard(
rb: &ReselBoard,
) -> RegionMap {
let (width, height) = (rb.width, rb.height);
let mut visited: Vec<Vec<bool>> = vec![vec![false; height as usize]; width as usize];
let mut region_idx: usize = 0;
let mut xy_to_region: Vec<Vec<usize>> = vec![vec![0; height as usize]; width as usize];
let mut region_to_xys: Vec<Vec<(usize, usize)>> = vec![vec![]];
let mut region_to_resel: Vec<Resel> = vec![Resel::Empty];
let mut wire_regions: Vec<usize> = vec![];
let mut input_regions: Vec<usize> = vec![];
let mut logic_regions: Vec<usize> = vec![];
let mut output_regions: Vec<usize> = vec![];
let mut reverse_dense: Vec<usize> = vec![0];
for x in 0..width { for y in 0..height { if !visited[x][y] {
let resel = rb.board[x][y];
if resel == Resel::Empty {
visited[x][y] = true;
region_to_xys[0].push((x,y));
} else {
region_idx += 1;
region_to_xys.push(Vec::new());
region_to_resel.push(resel);
if resel.is_wire() {
reverse_dense.push(wire_regions.len());
wire_regions.push(region_idx);
}
if resel.is_input() {
reverse_dense.push(input_regions.len());
input_regions.push(region_idx)
}
if resel.is_logic() {
reverse_dense.push(logic_regions.len());
logic_regions.push(region_idx)
}
if resel.is_output() {
reverse_dense.push(output_regions.len());
output_regions.push(region_idx)
}
let mut neighbors: Vec<(usize, usize)> = vec![(x,y)];
while !neighbors.is_empty() {
let (x, y) = neighbors.pop().unwrap();
xy_to_region[x][y] = region_idx;
region_to_xys[region_idx].push((x,y));
visited[x][y] = true;
for (nx, ny) in rb.get_neighbors(x, y) {
if rb.board[nx][ny].same(resel) && !visited[nx][ny] {
neighbors.push((nx, ny));
visited[nx][ny] = true;
} } } } }}} RegionMap {
xy_to_region,
width,
height,
region_to_xys,
region_to_resel,
wire_regions,
input_regions,
logic_regions,
output_regions,
reverse_dense
}
}
impl From<ReselBoard> for RegionMap {
fn from (rb: ReselBoard) -> RegionMap {
region_map_from_reselboard(&rb)
}
}
impl From<&ReselBoard> for RegionMap {
fn from (rb: &ReselBoard) -> RegionMap {
region_map_from_reselboard(rb)
}
}
#[cfg(test)]
mod reselboard_tests {
use super::*;
use crate::reselboard::{
load_image_from_filename,
};
#[test]
fn test_regon_map_basic() {
for rb in [
ReselBoard::from(vec![vec![Resel::Empty]]),
ReselBoard::from(load_image_from_filename("./src/testing/test_01_new-palette.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_02_new-palette_1.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_02_new-palette.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_03_01.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_03_02.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_03_03.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_03_04.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_03_alloff.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_03_allon.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_04.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_05_01.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_05_02.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_05_03.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_05_04.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_05_05.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_05_06.png").unwrap()),
ReselBoard::from(load_image_from_filename("./src/testing/test_06.png").unwrap()),
] {
let rm = RegionMap::from(&rb);
let (width, height) = (rb.board.len(), rb.board[0].len());
let n_regions = rm.region_to_xys.len();
let mut accounted_xy: Vec<Vec<bool>> = vec![vec![false; height as usize]; width as usize];
let mut accounted_region: Vec<bool> = vec![false; n_regions];
assert!(n_regions >= 1);
for region_idx in 0..n_regions {
let resel_by_region = rm.region_to_resel[region_idx];
for (x,y) in &rm.region_to_xys[region_idx] {
let resel_by_coord = rb.board[*x][*y];
assert!(resel_by_coord.same(resel_by_region));
assert!(!accounted_xy[*x][*y]);
accounted_xy[*x][*y] = true;
assert_eq!(rm.xy_to_region[*x][*y], region_idx);
if !resel_by_region.is_empty() {
assert_eq!(
region_idx,
{ if resel_by_region.is_wire() { &rm.wire_regions } else
if resel_by_region.is_input() { &rm.input_regions } else
if resel_by_region.is_logic() { &rm.logic_regions } else
if resel_by_region.is_output() { &rm.output_regions } else
{ panic!("This should not be possible to reach!") }
}[rm.reverse_dense[region_idx]]
)
}
}
}
for x in 0..width{ for y in 0..height {
assert!(accounted_xy[x][y]);
}}
for region_iterator in [
vec![0],
rm.wire_regions.clone(),
rm.input_regions.clone(),
rm.logic_regions.clone(),
rm.output_regions.clone()
] {
for region_idx in region_iterator {
assert!(!accounted_region[region_idx]);
accounted_region[region_idx] = true;
}
}
for region_idx in 0..n_regions {
assert!(accounted_region[region_idx])
}
for region_idx in 0..n_regions {
for rj in rm.get_adjacent_regions(region_idx) {
assert!(
rm.get_adjacent_regions(rj).contains(®ion_idx)
);
}
}
}
}
#[test]
fn test_region_map_01() {
let rb = ReselBoard::from(
load_image_from_filename(
"./src/testing/test_01_new-palette.png"
).unwrap()
);
let rm = RegionMap::from(&rb);
assert_eq!(
rm.xy_to_region,
vec![vec![1,2,3,0,1], vec![4,1,3,3,0], vec![0,5,3,3,1]]
);
assert_eq!(
rm.region_to_xys,
vec![
vec![(0,3), (1,4), (2,0)],
vec![(0,0), (0,4), (2,4), (1,1)],
vec![(0,1)],
vec![(0,2),(2,2),(2,3),(1,3),(1,2)],
vec![(1,0)],
vec![(2,1)]
]
);
assert_eq!(
rm.region_to_resel,
vec![
Resel::Empty,
Resel::WireOrangeOn, Resel::WireLimeOn, Resel::WireSapphireOff,
Resel::Input, Resel::Input
]
);
assert_eq!(rm.wire_regions, vec![1,2,3]);
assert_eq!(rm.input_regions, vec![4,5]);
assert_eq!(rm.logic_regions, vec![]);
assert_eq!(rm.output_regions, vec![]);
assert_eq!(rm.reverse_dense, vec![0,0,1,2,0,1]);
assert_eq!(
rm.get_adjacent_regions(0),
vec![1,3,4,5]
);
assert_eq!(
rm.get_adjacent_regions(1),
vec![0,2,3,4,5]
);
assert_eq!(
rm.get_adjacent_regions(2),
vec![1,3,5]
);
assert_eq!(
rm.get_adjacent_regions(3),
vec![0,1,2,5]
);
assert_eq!(
rm.get_adjacent_regions(4),
vec![0,1]
);
assert_eq!(
rm.get_adjacent_regions(5),
vec![0,1,2,3]
);
}
#[test]
fn test_region_map_06() {
let rb = ReselBoard::from(
load_image_from_filename(
"./src/testing/test_06.png"
).unwrap()
);
let rm = RegionMap::from(&rb);
assert_eq!(
rm.xy_to_region,
vec![
vec![1,0,2],
vec![1,3,3],
vec![1,4,2],
vec![1,2,5],
vec![2,2,5]
]
);
assert_eq!(
rm.region_to_xys,
vec![
vec![(0,1)],
vec![(0,0), (1,0), (2,0), (3,0)],
vec![(0,2), (4,1), (3,1), (2,2), (4,0)],
vec![(1,1), (1,2)],
vec![(2,1)],
vec![(3,2), (4,2)]
]
);
assert_eq!(
rm.region_to_resel,
vec![
Resel::Empty,
Resel::WireLimeOn,
Resel::WireOrangeOff,
Resel::WireSapphireOn,
Resel::Input,
Resel::Input
]
);
assert_eq!(rm.wire_regions, vec![1,2,3]);
assert_eq!(rm.input_regions, vec![4,5]);
assert_eq!(rm.logic_regions, vec![]);
assert_eq!(rm.output_regions, vec![]);
assert_eq!(rm.reverse_dense, vec![0,0,1,2,0,1]);
assert_eq!(
rm.get_adjacent_regions(0),
vec![1,2,3,]
);
assert_eq!(
rm.get_adjacent_regions(1),
vec![0,2,3,4,5,]
);
assert_eq!(
rm.get_adjacent_regions(2),
vec![0,1,3,4,5,]
);
assert_eq!(
rm.get_adjacent_regions(3),
vec![0,1,2,4,]
);
assert_eq!(
rm.get_adjacent_regions(4),
vec![1,2,3,]
);
assert_eq!(
rm.get_adjacent_regions(5),
vec![1,2,]
);
}
#[test]
fn test_region_map_half_adder() {
let rb = ReselBoard::from(
load_image_from_filename(
"./src/testing/test_half_adder.png"
).unwrap()
);
let rm = RegionMap::from(&rb);
assert_eq!(
rm.xy_to_region,
vec![
vec![0,0,1,2,0,0],
vec![0,0,1,2,0,0],
vec![0,0,1,2,0,0],
vec![0,0,3,3,0,0],
vec![0,4,5,6,7,0],
vec![0,8,0,0,9,0],
vec![0,8,0,0,9,0],
vec![0,8,0,0,9,0],
]
);
for (region_idx, expected) in [
(1, vec![(0,2),(1,2),(2,2)]),
(2, vec![(0,3),(1,3),(2,3)]),
(3, vec![(3,2),(3,3)]),
(4, vec![(4,1)]),
(5, vec![(4,2)]),
(6, vec![(4,3)]),
(7, vec![(4,4)]),
(8, vec![(5,1),(6,1),(7,1)]),
(9, vec![(5,4),(6,4),(7,4)]),
] {
assert_eq!(
rm.region_to_xys[region_idx],
expected
)
}
assert_eq!(
rm.region_to_resel,
vec![
Resel::Empty,
Resel::WireOrangeOff,
Resel::WireSapphireOff,
Resel::Input,
Resel::Output,
Resel::XOR,
Resel::AND,
Resel::Output,
Resel::WireLimeOff,
Resel::WireLimeOff
]
);
assert_eq!(rm.wire_regions, vec![1,2,8,9]);
assert_eq!(rm.input_regions, vec![3,]);
assert_eq!(rm.logic_regions, vec![5,6]);
assert_eq!(rm.output_regions, vec![4,7]);
assert_eq!(rm.reverse_dense, vec![0,0,1,0,0,0,1,1,2,3]);
assert_eq!(
rm.get_adjacent_regions(0),
vec![1,2,3,4,5,6,7,8,9]
);
assert_eq!(
rm.get_adjacent_regions(1),
vec![0,2,3,]
);
assert_eq!(
rm.get_adjacent_regions(2),
vec![0,1,3,]
);
assert_eq!(
rm.get_adjacent_regions(3),
vec![0,1,2,5,6]
);
assert_eq!(
rm.get_adjacent_regions(4),
vec![0,5,8]
);
assert_eq!(
rm.get_adjacent_regions(5),
vec![0,3,4,6],
);
assert_eq!(
rm.get_adjacent_regions(6),
vec![0,3,5,7],
);
assert_eq!(
rm.get_adjacent_regions(7),
vec![0,6,9],
);
assert_eq!(
rm.get_adjacent_regions(8),
vec![0,4,],
);
assert_eq!(
rm.get_adjacent_regions(9),
vec![0,7,],
);
}
}