use std::{rc::Rc, collections::VecDeque};
use bitvec::vec::BitVec;
use crate::{IndexedElement, get_n_choose_k};
use super::{Shifter};
#[derive(Clone, Debug)]
pub struct Segment {
length: usize
}
impl Segment {
pub fn new(length: usize) -> Self {
Segment {
length: length
}
}
}
#[derive(Clone, Debug)]
pub struct LocatedSegment {
pub segment_index: usize,
pub position: usize
}
impl LocatedSegment {
pub fn new(segment_index: usize, position: usize) -> Self {
LocatedSegment {
segment_index: segment_index,
position: position
}
}
}
#[derive(Clone)]
pub struct SegmentPermutationShifter {
segments: Vec<Rc<Segment>>,
origin: (u8, u8),
bounding_length: usize,
is_horizontal: bool,
padding: usize,
is_swapping_permitted: bool,
possible_locations: Vec<Rc<(u8, u8)>>,
current_mask: BitVec,
current_segment_index_per_shift_index: Vec<usize>,
current_initial_position_offset_per_shift_index: Vec<usize>,
current_minimum_position_offset_per_shift_index: Vec<usize>,
current_maximum_position_offset_per_shift_index: Vec<usize>,
current_position_offset_per_shift_index: Vec<Option<usize>>,
current_is_parent_ending: BitVec,
is_shifted_outside: bool,
segments_length: usize,
starting_segment_index_per_shift_index: Vec<usize>,
starting_initial_position_offset_per_shift_index: Vec<usize>,
starting_minimum_position_offset_per_shift_index: Vec<usize>,
starting_maximum_position_offset_per_shift_index: Vec<usize>,
ending_segment_index_per_shift_index: Vec<usize>,
ending_position_offset_per_shift_index: Vec<usize>,
is_starting: bool, is_looped: bool, is_starting_equal_to_ending: bool, is_starting_at_beginning: bool }
impl SegmentPermutationShifter {
pub fn new(segments: Vec<Rc<Segment>>, origin: (u8, u8), bounding_length: usize, is_horizontal: bool, padding: usize, is_swapping_permitted: bool) -> Self {
let segments_length = segments.len();
let mut current_mask: BitVec = BitVec::with_capacity(segments_length);
current_mask.resize(segments.len(), false);
let mut smallest_segment_length_option: Option<usize> = None;
let mut smallest_bounding_length: usize = 0;
for (segment_index, segment) in segments.iter().enumerate() {
if smallest_segment_length_option.is_none() || smallest_segment_length_option.unwrap() > segment.length {
smallest_segment_length_option = Some(segment.length);
}
if segment_index != 0 {
smallest_bounding_length += padding;
}
smallest_bounding_length += segment.length;
}
let reduced_bounding_length_offset: usize;
if let Some(smallest_segment_length) = smallest_segment_length_option {
if smallest_segment_length != 0 {
reduced_bounding_length_offset = smallest_segment_length - 1;
}
else {
reduced_bounding_length_offset = 0;
}
}
else {
reduced_bounding_length_offset = 0;
}
let mut possible_locations: Vec<Rc<(u8, u8)>> = Vec::new();
let mut current_possible_location = origin.clone();
if is_horizontal {
for _ in 0..(bounding_length - reduced_bounding_length_offset) {
possible_locations.push(Rc::new(current_possible_location));
current_possible_location.0 += 1;
}
}
else {
for _ in 0..(bounding_length - reduced_bounding_length_offset) {
possible_locations.push(Rc::new(current_possible_location));
current_possible_location.1 += 1;
}
}
let mut starting_segment_index_per_shift_index: Vec<usize> = Vec::new(); let mut starting_minimum_position_offset_per_shift_index: Vec<usize> = Vec::new();
let mut starting_maximum_position_offset_per_shift_index: Vec<usize> = Vec::new();
let starting_initial_position_offset_per_shift_index: Vec<usize>;
let mut ending_segment_index_per_shift_index: Vec<usize> = Vec::new();
let mut ending_position_offset_per_shift_index: Vec<usize> = Vec::new();
{
for shift_index in 0..segments_length {
if is_swapping_permitted {
ending_segment_index_per_shift_index.push(segments_length - shift_index - 1);
}
else {
ending_segment_index_per_shift_index.push(shift_index);
}
}
if is_swapping_permitted {
ending_position_offset_per_shift_index.push(bounding_length - smallest_bounding_length);
for shift_index in (1..segments_length).rev() {
let previous_segment_length = segments[shift_index].length + padding;
let previous_ending_position_offset = ending_position_offset_per_shift_index[segments_length - shift_index - 1];
ending_position_offset_per_shift_index.push(previous_ending_position_offset + previous_segment_length);
}
}
else {
ending_position_offset_per_shift_index.push(bounding_length - smallest_bounding_length);
for shift_index in 1..segments_length {
let previous_segment_length = segments[shift_index - 1].length + padding;
let previous_ending_position_offset = ending_position_offset_per_shift_index[shift_index - 1];
ending_position_offset_per_shift_index.push(previous_ending_position_offset + previous_segment_length);
}
}
}
{
for shift_index in 0..segments_length {
starting_segment_index_per_shift_index.push(shift_index);
}
let next_minimum_position_offset = 0;
let next_maximum_position_offset = bounding_length - smallest_bounding_length;
starting_minimum_position_offset_per_shift_index.push(next_minimum_position_offset);
starting_maximum_position_offset_per_shift_index.push(next_maximum_position_offset);
for shift_index in 1..segments_length {
let previous_segment_length = segments[shift_index - 1].length + padding;
let previous_minimum_position_offset = starting_minimum_position_offset_per_shift_index[shift_index - 1];
let previous_maximum_position_offset = starting_maximum_position_offset_per_shift_index[shift_index - 1];
starting_minimum_position_offset_per_shift_index.push(previous_minimum_position_offset + previous_segment_length);
starting_maximum_position_offset_per_shift_index.push(previous_maximum_position_offset + previous_segment_length);
}
starting_initial_position_offset_per_shift_index = starting_minimum_position_offset_per_shift_index.clone();
}
let mut is_starting_equal_to_ending: bool = true; for shift_index in 0..segments_length {
if starting_initial_position_offset_per_shift_index[shift_index] != ending_position_offset_per_shift_index[shift_index] {
is_starting_equal_to_ending = false;
break;
}
if starting_segment_index_per_shift_index[shift_index] != ending_segment_index_per_shift_index[shift_index] {
is_starting_equal_to_ending = false;
break;
}
}
let is_starting_at_beginning = true;
let mut segment_permutation_shifter = SegmentPermutationShifter {
segments: segments,
origin: origin,
bounding_length: bounding_length,
is_horizontal: is_horizontal,
padding: padding,
is_swapping_permitted: is_swapping_permitted,
possible_locations: possible_locations,
current_mask: current_mask,
current_segment_index_per_shift_index: Vec::new(),
current_initial_position_offset_per_shift_index: Vec::new(),
current_minimum_position_offset_per_shift_index: Vec::new(),
current_maximum_position_offset_per_shift_index: Vec::new(),
current_position_offset_per_shift_index: Vec::new(),
current_is_parent_ending: BitVec::new(),
is_shifted_outside: false,
segments_length: segments_length,
starting_segment_index_per_shift_index: starting_segment_index_per_shift_index,
starting_initial_position_offset_per_shift_index: starting_initial_position_offset_per_shift_index,
starting_minimum_position_offset_per_shift_index: starting_minimum_position_offset_per_shift_index,
starting_maximum_position_offset_per_shift_index: starting_maximum_position_offset_per_shift_index,
ending_segment_index_per_shift_index: ending_segment_index_per_shift_index,
ending_position_offset_per_shift_index: ending_position_offset_per_shift_index,
is_starting: true,
is_looped: false,
is_starting_equal_to_ending: is_starting_equal_to_ending,
is_starting_at_beginning: is_starting_at_beginning
};
if segment_permutation_shifter.is_initially_looped() {
segment_permutation_shifter.is_looped = true;
}
return segment_permutation_shifter;
}
fn is_initially_looped(&self) -> bool {
return self.is_starting_at_beginning;
let mut is_looped = false; if self.is_starting_equal_to_ending {
is_looped = true;
}
else if self.is_starting_at_beginning {
is_looped = true;
}
else if !self.is_swapping_permitted && self.is_starting_at_beginning {
is_looped = true;
}
else if self.segments_length == 1 && self.is_starting_at_beginning {
is_looped = true;
}
return is_looped;
}
}
impl Shifter for SegmentPermutationShifter {
type T = (u8, u8);
fn try_forward(&mut self) -> bool {
if self.current_mask.first_zero().is_none() {
self.is_shifted_outside = true;
return false;
}
let shift_index = self.current_segment_index_per_shift_index.len();
if self.is_starting {
let segment_index = self.starting_segment_index_per_shift_index[shift_index];
self.current_mask.set(segment_index, true);
self.current_segment_index_per_shift_index.push(segment_index);
self.current_minimum_position_offset_per_shift_index.push(self.starting_minimum_position_offset_per_shift_index[shift_index]);
self.current_maximum_position_offset_per_shift_index.push(self.starting_maximum_position_offset_per_shift_index[shift_index]);
self.current_initial_position_offset_per_shift_index.push(self.starting_initial_position_offset_per_shift_index[shift_index]);
}
else {
for mask_index in 0..self.segments_length {
if !self.current_mask[mask_index] {
self.current_mask.set(mask_index, true);
self.current_segment_index_per_shift_index.push(mask_index);
let minimum_position_offset;
let maximum_position_offset;
if shift_index == 0 {
minimum_position_offset = 0;
maximum_position_offset = self.starting_maximum_position_offset_per_shift_index[0];
}
else {
let previous_segment_index = self.current_segment_index_per_shift_index[shift_index - 1];
let previous_segment_length = self.segments[previous_segment_index].length + self.padding;
minimum_position_offset = self.current_position_offset_per_shift_index[shift_index - 1].unwrap() + previous_segment_length;
maximum_position_offset = self.current_maximum_position_offset_per_shift_index[shift_index - 1] + previous_segment_length;
}
self.current_minimum_position_offset_per_shift_index.push(minimum_position_offset);
self.current_maximum_position_offset_per_shift_index.push(maximum_position_offset);
self.current_initial_position_offset_per_shift_index.push(minimum_position_offset);
break;
}
}
}
self.current_position_offset_per_shift_index.push(None);
self.current_is_parent_ending.push(false);
return true;
}
fn try_backward(&mut self) -> bool {
self.is_starting = false;
if self.is_shifted_outside {
self.is_shifted_outside = false;
return self.segments_length != 0;
}
if self.current_mask.first_one().is_none() {
return false;
}
let segment_index = self.current_segment_index_per_shift_index.pop().unwrap();
self.current_mask.set(segment_index, false);
self.current_minimum_position_offset_per_shift_index.pop();
self.current_maximum_position_offset_per_shift_index.pop();
self.current_initial_position_offset_per_shift_index.pop();
self.current_position_offset_per_shift_index.pop();
self.current_is_parent_ending.pop();
if self.current_mask.first_one().is_none() {
self.is_starting = true;
self.is_looped = self.is_initially_looped();
return false;
}
return true;
}
fn try_increment(&mut self) -> bool {
let shift_index = self.current_position_offset_per_shift_index.len() - 1;
if self.current_position_offset_per_shift_index[shift_index].is_none() {
let current_position_offset = self.current_initial_position_offset_per_shift_index[shift_index];
self.current_position_offset_per_shift_index[shift_index] = Some(current_position_offset);
if self.is_looped {
if shift_index == 0 || self.current_is_parent_ending[shift_index - 1] {
if self.ending_position_offset_per_shift_index[shift_index] == current_position_offset && self.ending_segment_index_per_shift_index[shift_index] == self.current_segment_index_per_shift_index[shift_index] {
self.current_is_parent_ending.set(shift_index, true);
}
}
}
return true;
}
self.is_starting = false;
if self.current_is_parent_ending[shift_index] {
return false;
}
if self.current_position_offset_per_shift_index[shift_index].unwrap() == self.current_maximum_position_offset_per_shift_index[shift_index] {
if !self.is_swapping_permitted {
if shift_index == 0 {
self.current_initial_position_offset_per_shift_index[0] = 0;
self.current_position_offset_per_shift_index[0] = Some(0);
if self.ending_position_offset_per_shift_index[0] == 0 {
self.current_is_parent_ending.set(0, true);
}
else {
self.current_is_parent_ending.set(0, false);
}
self.is_looped = true;
debug!("try_increment: looping back to start");
return true;
}
return false;
}
let segment_index = self.current_segment_index_per_shift_index[shift_index];
for next_segment_index in (segment_index + 1)..self.segments_length {
if !self.current_mask[next_segment_index] {
self.current_mask.set(segment_index, false);
self.current_mask.set(next_segment_index, true);
self.current_segment_index_per_shift_index[shift_index] = next_segment_index;
self.current_position_offset_per_shift_index[shift_index] = Some(self.current_minimum_position_offset_per_shift_index[shift_index]);
if self.is_looped {
if shift_index == 0 || self.current_is_parent_ending[shift_index - 1] {
if self.ending_position_offset_per_shift_index[shift_index] == self.current_position_offset_per_shift_index[shift_index].unwrap() && self.ending_segment_index_per_shift_index[shift_index] == self.current_segment_index_per_shift_index[shift_index] {
self.current_is_parent_ending.set(shift_index, true);
}
}
}
return true;
}
}
if shift_index == 0 {
self.current_mask.set(segment_index, false);
self.current_mask.set(0, true);
self.current_segment_index_per_shift_index[0] = 0;
self.current_initial_position_offset_per_shift_index[0] = 0;
self.current_position_offset_per_shift_index[0] = Some(0);
if self.ending_position_offset_per_shift_index[0] == 0 {
self.current_is_parent_ending.set(0, true);
}
else {
self.current_is_parent_ending.set(0, false);
}
self.is_looped = true;
debug!("try_increment: looping back to start");
return true;
}
return false;
}
self.current_position_offset_per_shift_index[shift_index] = Some(self.current_position_offset_per_shift_index[shift_index].unwrap() + 1);
if self.is_looped {
if shift_index == 0 || self.current_is_parent_ending[shift_index - 1] {
if self.ending_position_offset_per_shift_index[shift_index] == self.current_position_offset_per_shift_index[shift_index].unwrap() && self.ending_segment_index_per_shift_index[shift_index] == self.current_segment_index_per_shift_index[shift_index] {
self.current_is_parent_ending.set(shift_index, true);
}
}
}
return true;
}
fn get_indexed_element(&self) -> IndexedElement<(u8, u8)> {
let (current_segment_index, current_position_offset) = self.get_element_index_and_state_index();
let position: Rc<(u8, u8)>;
if self.is_horizontal {
position = Rc::new((self.origin.0 + current_position_offset as u8, self.origin.1));
}
else {
position = Rc::new((self.origin.0, self.origin.1 + current_position_offset as u8));
}
return IndexedElement::new(position, current_segment_index);
}
fn get_element_index_and_state_index(&self) -> (usize, usize) {
let current_position_offset = self.current_position_offset_per_shift_index.last().unwrap().unwrap();
let current_segment_index = *self.current_segment_index_per_shift_index.last().unwrap();
return (current_segment_index, current_position_offset);
}
fn get_states(&self) -> Vec<Rc<Self::T>> {
return self.possible_locations.clone();
}
fn get_length(&self) -> usize {
return self.segments_length;
}
fn randomize(&mut self) {
if self.is_starting_equal_to_ending {
return;
}
if self.is_swapping_permitted {
fastrand::shuffle(&mut self.ending_segment_index_per_shift_index);
}
let mut is_original_segment_list: BitVec = BitVec::repeat(true, self.segments_length);
let mut remaining_bounding_length = self.bounding_length;
for segment_index in 0..self.segments_length {
if segment_index != 0 {
remaining_bounding_length -= self.padding;
}
let mapped_segment_index = self.ending_segment_index_per_shift_index[segment_index];
remaining_bounding_length -= self.segments[mapped_segment_index].length;
}
is_original_segment_list.resize(self.segments_length + remaining_bounding_length, false);
debug!("randomize: before shuffle: {:?}", is_original_segment_list);
{
for bit_index in 1..is_original_segment_list.len() {
let other_bit_index = fastrand::usize(..=bit_index);
if bit_index != other_bit_index {
is_original_segment_list.swap(bit_index, other_bit_index);
}
}
}
debug!("randomize: after shuffle: {:?}", is_original_segment_list);
let mut current_position_index = 0;
let mut current_segment_index = 0;
self.ending_position_offset_per_shift_index.clear();
for segment_list_index in 0..(self.segments_length + remaining_bounding_length) {
if is_original_segment_list[segment_list_index] {
if current_segment_index != 0 {
current_position_index += self.padding;
}
self.ending_position_offset_per_shift_index.push(current_position_index);
let mapped_current_segment_index = self.ending_segment_index_per_shift_index[current_segment_index];
current_position_index += self.segments[mapped_current_segment_index].length;
current_segment_index += 1;
}
else {
current_position_index += 1;
}
}
self.starting_minimum_position_offset_per_shift_index.clear();
self.starting_maximum_position_offset_per_shift_index.clear();
self.starting_initial_position_offset_per_shift_index = self.ending_position_offset_per_shift_index.clone();
self.starting_segment_index_per_shift_index = self.ending_segment_index_per_shift_index.clone();
let mut current_minimum_position_offset = 0;
let mut current_maximum_position_offset: Option<usize> = None;
for segment_index in 0..self.segments_length {
self.starting_minimum_position_offset_per_shift_index.push(current_minimum_position_offset);
if current_maximum_position_offset.is_none() {
let mut minimum_bounding_length = 0;
for other_segment_index in (segment_index + 1)..self.segments_length {
if minimum_bounding_length != 0 {
minimum_bounding_length += self.padding;
}
minimum_bounding_length += self.segments[self.starting_segment_index_per_shift_index[other_segment_index]].length;
}
if minimum_bounding_length != 0 {
minimum_bounding_length += self.padding;
}
minimum_bounding_length += self.segments[self.starting_segment_index_per_shift_index[segment_index]].length;
let maximum_position_offset = (self.bounding_length - current_minimum_position_offset) - minimum_bounding_length;
debug!("randomize: maximum_position_offset: {:?}", maximum_position_offset);
current_maximum_position_offset = Some(maximum_position_offset);
}
self.starting_maximum_position_offset_per_shift_index.push(current_maximum_position_offset.unwrap());
let segment_length = self.segments[self.starting_segment_index_per_shift_index[segment_index]].length + self.padding;
current_minimum_position_offset = self.starting_initial_position_offset_per_shift_index[segment_index] + segment_length;
current_maximum_position_offset = Some(current_maximum_position_offset.unwrap() + segment_length);
}
let mut shift_index = self.segments_length - 1;
let mut is_still_trying_earlier_shift_indexes = true;
let mut mask: BitVec = BitVec::repeat(true, self.segments_length);
let mut recalculate_position_offsets_from_shift_index: Option<usize> = None;
'looking_for_position: {
while is_still_trying_earlier_shift_indexes {
if self.starting_initial_position_offset_per_shift_index[shift_index] != self.starting_maximum_position_offset_per_shift_index[shift_index] {
self.starting_initial_position_offset_per_shift_index[shift_index] += 1;
if shift_index + 1 < self.segments_length {
recalculate_position_offsets_from_shift_index = Some(shift_index + 1);
}
break 'looking_for_position;
}
if self.is_swapping_permitted {
mask.set(self.starting_segment_index_per_shift_index[shift_index], false);
for next_mask_index in (self.starting_segment_index_per_shift_index[shift_index] + 1)..self.segments_length {
if !mask[next_mask_index] {
mask.set(next_mask_index, true);
self.starting_segment_index_per_shift_index[shift_index] = next_mask_index;
recalculate_position_offsets_from_shift_index = Some(shift_index);
shift_index += 1;
for other_mask_index in 0..self.segments_length {
if !mask[other_mask_index] {
mask.set(other_mask_index, true);
self.starting_segment_index_per_shift_index[shift_index] = other_mask_index;
shift_index += 1;
}
}
break 'looking_for_position;
}
}
}
if shift_index == 0 {
for mask_index in 0..self.segments_length {
self.starting_segment_index_per_shift_index[mask_index] = mask_index;
}
recalculate_position_offsets_from_shift_index = Some(0);
break 'looking_for_position;
}
shift_index -= 1;
}
}
if recalculate_position_offsets_from_shift_index.is_some() {
let shift_index = recalculate_position_offsets_from_shift_index.unwrap();
let mut next_minimum_position_offset;
let mut next_maximum_position_offset;
let mut previous_segment_length;
if shift_index == 0 {
next_minimum_position_offset = 0;
next_maximum_position_offset = 0;
for shift_index in 0..self.segments_length {
if shift_index != 0 {
next_maximum_position_offset += self.padding;
}
let segment_index = self.starting_segment_index_per_shift_index[shift_index];
next_maximum_position_offset += self.segments[segment_index].length;
}
next_maximum_position_offset = self.bounding_length - next_maximum_position_offset;
}
else {
let previous_shift_index = shift_index - 1;
{
let segment_index = self.starting_segment_index_per_shift_index[previous_shift_index];
previous_segment_length = self.segments[segment_index].length + self.padding;
}
next_minimum_position_offset = self.starting_initial_position_offset_per_shift_index[previous_shift_index] + previous_segment_length;
next_maximum_position_offset = self.starting_maximum_position_offset_per_shift_index[previous_shift_index] + previous_segment_length;
}
let segment_index = self.starting_segment_index_per_shift_index[shift_index];
previous_segment_length = self.segments[segment_index].length + self.padding;
for next_shift_index in shift_index..self.segments_length {
debug!("randomize: next_minimum_position_offset {:?} for next_shift_index {:?}", next_minimum_position_offset, next_shift_index);
debug!("randomize: next_maximum_position_offset {:?} for next_shift_index {:?}", next_maximum_position_offset, next_shift_index);
self.starting_minimum_position_offset_per_shift_index[next_shift_index] = next_minimum_position_offset;
self.starting_maximum_position_offset_per_shift_index[next_shift_index] = next_maximum_position_offset;
self.starting_initial_position_offset_per_shift_index[next_shift_index] = next_minimum_position_offset;
next_minimum_position_offset += previous_segment_length;
next_maximum_position_offset += previous_segment_length;
let segment_index = self.starting_segment_index_per_shift_index[next_shift_index];
previous_segment_length = self.segments[segment_index].length + self.padding;
}
}
'check_starting_at_beginning: {
for segment_index in 0..self.segments_length {
if self.ending_segment_index_per_shift_index[segment_index] != segment_index {
self.is_starting_at_beginning = false;
break 'check_starting_at_beginning;
}
}
let mut previous_position_offset = 0;
for shift_index in 0..self.segments_length {
if self.starting_initial_position_offset_per_shift_index[shift_index] != previous_position_offset {
self.is_starting_at_beginning = false;
break 'check_starting_at_beginning;
}
previous_position_offset += self.segments[shift_index].length + self.padding;
}
self.is_starting_at_beginning = true;
}
self.is_looped = self.is_initially_looped();
}
}
#[cfg(test)]
mod segment_permutation_shifter_tests {
use std::{time::{Duration, Instant}, cell::RefCell, collections::BTreeMap};
use crate::incrementer::{shifter_incrementer::ShifterIncrementer, Incrementer};
use super::*;
use rstest::rstest;
fn init() {
std::env::set_var("RUST_LOG", "trace");
}
#[rstest]
fn initialized_no_segments() {
init();
let segments: Vec<Rc<Segment>> = Vec::new();
let _ = SegmentPermutationShifter::new(segments, (10, 100), 5, true, 1, true);
}
#[rstest]
#[case(vec![Rc::new(Segment::new(1))], (10, 100), 2, true, 1)]
#[case(vec![Rc::new(Segment::new(1)), Rc::new(Segment::new(1))], (10, 100), 4, true, 1)]
#[case(vec![Rc::new(Segment::new(1)), Rc::new(Segment::new(1)), Rc::new(Segment::new(1))], (10, 100), 6, true, 1)]
#[case(vec![Rc::new(Segment::new(1)), Rc::new(Segment::new(1)), Rc::new(Segment::new(1)), Rc::new(Segment::new(1))], (10, 100), 8, true, 1)]
fn shift_forward_and_backward_for_multiple_segments(#[case] segments: Vec<Rc<Segment>>, #[case] origin: (u8, u8), #[case] bounding_length: usize, #[case] is_horizontal: bool, #[case] padding: usize) {
init();
let segments_length = segments.len();
let mut segment_permutation_shifter = SegmentPermutationShifter::new(segments, origin, bounding_length, is_horizontal, padding, true);
for index in 0..10 {
debug!("index: {:?}", index);
assert!(!segment_permutation_shifter.try_backward());
assert!(segment_permutation_shifter.try_forward());
assert!(!segment_permutation_shifter.try_backward());
for _ in 0..segments_length {
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
}
assert!(!segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_backward());
assert!(!segment_permutation_shifter.try_forward());
for _ in 0..segments_length {
assert!(segment_permutation_shifter.try_backward());
}
}
}
#[rstest]
#[case(vec![Rc::new(Segment::new(1))], (10, 100), 3, true, 1)]
#[case(vec![Rc::new(Segment::new(1))], (10, 100), 3, false, 1)]
#[case(vec![Rc::new(Segment::new(2))], (10, 100), 3, true, 1)]
#[case(vec![Rc::new(Segment::new(2))], (10, 100), 3, false, 1)]
#[case(vec![Rc::new(Segment::new(3))], (10, 100), 3, true, 1)]
#[case(vec![Rc::new(Segment::new(3))], (10, 100), 3, false, 1)]
fn permutate_through_different_segments_one_segment(#[case] segments: Vec<Rc<Segment>>, #[case] origin: (u8, u8), #[case] bounding_length: usize, #[case] is_horizontal: bool, #[case] padding: usize) {
init();
let segment_length = segments[0].length;
let mut segment_permutation_shifter = SegmentPermutationShifter::new(segments, origin, bounding_length, is_horizontal, padding, true);
for index in 0..10 {
debug!("index: {:?}", index);
assert!(!segment_permutation_shifter.try_backward());
assert!(segment_permutation_shifter.try_forward());
assert!(!segment_permutation_shifter.try_backward());
assert!(segment_permutation_shifter.try_forward());
assert!(!segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_backward());
assert!(!segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_backward());
}
for index in 0..=(bounding_length - segment_length) {
assert!(segment_permutation_shifter.try_increment());
let indexed_element = segment_permutation_shifter.get_indexed_element();
println!("indexed element: {:?}", indexed_element);
if is_horizontal {
assert_eq!(origin.0 + index as u8, indexed_element.element.0);
assert_eq!(origin.1, indexed_element.element.1);
}
else {
assert_eq!(origin.0, indexed_element.element.0);
assert_eq!(origin.1 + index as u8, indexed_element.element.1);
}
}
assert!(!segment_permutation_shifter.try_increment());
}
#[rstest]
fn permutations_of_one_and_two_and_three_length_segments_with_one_padding_with_smallest_bounding_length() {
init();
let segments: Vec<Rc<Segment>> = vec![
Rc::new(Segment::new(1)),
Rc::new(Segment::new(2)),
Rc::new(Segment::new(3))
];
let mut segment_permutation_shifter = SegmentPermutationShifter::new(
segments,
(10, 100),
8,
true,
1,
true
);
for index in 0..10 {
let is_try_forward_at_end_required: bool = index % 2 == 0;
assert!(segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_increment()); {
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(10, 100), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_increment()); {
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(1, indexed_element.index);
assert_eq!(&(12, 100), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_increment()); {
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(2, indexed_element.index);
assert_eq!(&(15, 100), indexed_element.element.as_ref());
}
assert!(!segment_permutation_shifter.try_increment()); if is_try_forward_at_end_required {
assert!(!segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_backward()); }
assert!(!segment_permutation_shifter.try_increment()); assert!(segment_permutation_shifter.try_backward()); assert!(segment_permutation_shifter.try_increment()); {
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(2, indexed_element.index);
assert_eq!(&(12, 100), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_increment()); {
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(1, indexed_element.index);
assert_eq!(&(16, 100), indexed_element.element.as_ref());
}
if is_try_forward_at_end_required {
assert!(!segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_backward());
}
assert!(!segment_permutation_shifter.try_increment()); assert!(segment_permutation_shifter.try_backward()); assert!(!segment_permutation_shifter.try_increment()); assert!(segment_permutation_shifter.try_backward()); assert!(segment_permutation_shifter.try_increment()); {
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(1, indexed_element.index);
assert_eq!(&(10, 100), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_increment()); {
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(13, 100), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_increment()); {
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(2, indexed_element.index);
assert_eq!(&(15, 100), indexed_element.element.as_ref());
}
if is_try_forward_at_end_required {
assert!(!segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_backward()); }
assert!(!segment_permutation_shifter.try_increment()); assert!(segment_permutation_shifter.try_backward()); assert!(segment_permutation_shifter.try_increment()); {
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(2, indexed_element.index);
assert_eq!(&(13, 100), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_increment()); {
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(17, 100), indexed_element.element.as_ref());
}
if is_try_forward_at_end_required {
assert!(!segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_backward()); }
assert!(!segment_permutation_shifter.try_increment()); assert!(segment_permutation_shifter.try_backward()); assert!(!segment_permutation_shifter.try_increment()); assert!(segment_permutation_shifter.try_backward()); assert!(segment_permutation_shifter.try_increment()); {
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(2, indexed_element.index);
assert_eq!(&(10, 100), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_increment()); {
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(14, 100), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_increment()); {
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(1, indexed_element.index);
assert_eq!(&(16, 100), indexed_element.element.as_ref());
}
if is_try_forward_at_end_required {
assert!(!segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_backward()); }
assert!(!segment_permutation_shifter.try_increment()); assert!(segment_permutation_shifter.try_backward()); assert!(segment_permutation_shifter.try_increment()); {
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(1, indexed_element.index);
assert_eq!(&(14, 100), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_increment()); {
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(17, 100), indexed_element.element.as_ref());
}
if is_try_forward_at_end_required {
assert!(!segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_backward()); }
assert!(!segment_permutation_shifter.try_increment()); assert!(segment_permutation_shifter.try_backward()); assert!(!segment_permutation_shifter.try_increment()); assert!(segment_permutation_shifter.try_backward()); assert!(!segment_permutation_shifter.try_increment()); assert!(!segment_permutation_shifter.try_backward()); }
}
#[rstest]
fn permutations_of_two_and_three_with_one_padding_with_one_open_space_bounding_length() {
init();
let segments: Vec<Rc<Segment>> = vec![
Rc::new(Segment::new(2)),
Rc::new(Segment::new(3))
];
let mut segment_permutation_shifter = SegmentPermutationShifter::new(segments, (20, 200), 7, false, 1, true);
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment()); assert_eq!(&(20, 200), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(0, segment_permutation_shifter.get_indexed_element().index);
{
let (element_index, state_index) = segment_permutation_shifter.get_element_index_and_state_index();
assert_eq!(element_index, segment_permutation_shifter.get_indexed_element().index);
assert_eq!(segment_permutation_shifter.get_states()[state_index], segment_permutation_shifter.get_indexed_element().element);
}
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment()); assert_eq!(&(20, 203), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(1, segment_permutation_shifter.get_indexed_element().index);
{
let (element_index, state_index) = segment_permutation_shifter.get_element_index_and_state_index();
assert_eq!(element_index, segment_permutation_shifter.get_indexed_element().index);
assert_eq!(segment_permutation_shifter.get_states()[state_index], segment_permutation_shifter.get_indexed_element().element);
}
assert!(segment_permutation_shifter.try_increment());
assert_eq!(&(20, 204), segment_permutation_shifter.get_indexed_element().element.as_ref()); assert_eq!(1, segment_permutation_shifter.get_indexed_element().index);
{
let (element_index, state_index) = segment_permutation_shifter.get_element_index_and_state_index();
assert_eq!(element_index, segment_permutation_shifter.get_indexed_element().index);
assert_eq!(segment_permutation_shifter.get_states()[state_index], segment_permutation_shifter.get_indexed_element().element);
}
assert!(!segment_permutation_shifter.try_increment());
assert!(segment_permutation_shifter.try_backward());
debug!("test: moving first segment in first shift forward");
assert!(segment_permutation_shifter.try_increment());
debug!("test: moved first segment");
assert_eq!(&(20, 201), segment_permutation_shifter.get_indexed_element().element.as_ref()); assert_eq!(0, segment_permutation_shifter.get_indexed_element().index);
{
let (element_index, state_index) = segment_permutation_shifter.get_element_index_and_state_index();
assert_eq!(element_index, segment_permutation_shifter.get_indexed_element().index);
assert_eq!(segment_permutation_shifter.get_states()[state_index], segment_permutation_shifter.get_indexed_element().element);
}
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
assert_eq!(&(20, 204), segment_permutation_shifter.get_indexed_element().element.as_ref()); assert_eq!(1, segment_permutation_shifter.get_indexed_element().index);
{
let (element_index, state_index) = segment_permutation_shifter.get_element_index_and_state_index();
assert_eq!(element_index, segment_permutation_shifter.get_indexed_element().index);
assert_eq!(segment_permutation_shifter.get_states()[state_index], segment_permutation_shifter.get_indexed_element().element);
}
assert!(!segment_permutation_shifter.try_increment());
assert!(segment_permutation_shifter.try_backward());
debug!("test: back to first shift, pulling second segment.");
assert!(segment_permutation_shifter.try_increment()); debug!("test: pulled second segment.");
assert_eq!(&(20, 200), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(1, segment_permutation_shifter.get_indexed_element().index);
{
let (element_index, state_index) = segment_permutation_shifter.get_element_index_and_state_index();
assert_eq!(element_index, segment_permutation_shifter.get_indexed_element().index);
assert_eq!(segment_permutation_shifter.get_states()[state_index], segment_permutation_shifter.get_indexed_element().element);
}
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment()); assert_eq!(&(20, 204), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(0, segment_permutation_shifter.get_indexed_element().index);
{
let (element_index, state_index) = segment_permutation_shifter.get_element_index_and_state_index();
assert_eq!(element_index, segment_permutation_shifter.get_indexed_element().index);
assert_eq!(segment_permutation_shifter.get_states()[state_index], segment_permutation_shifter.get_indexed_element().element);
}
assert!(segment_permutation_shifter.try_increment()); assert_eq!(&(20, 205), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(0, segment_permutation_shifter.get_indexed_element().index);
{
let (element_index, state_index) = segment_permutation_shifter.get_element_index_and_state_index();
assert_eq!(element_index, segment_permutation_shifter.get_indexed_element().index);
assert_eq!(segment_permutation_shifter.get_states()[state_index], segment_permutation_shifter.get_indexed_element().element);
}
assert!(!segment_permutation_shifter.try_increment()); assert!(segment_permutation_shifter.try_backward()); assert!(segment_permutation_shifter.try_increment()); assert_eq!(&(20, 201), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(1, segment_permutation_shifter.get_indexed_element().index);
{
let (element_index, state_index) = segment_permutation_shifter.get_element_index_and_state_index();
assert_eq!(element_index, segment_permutation_shifter.get_indexed_element().index);
assert_eq!(segment_permutation_shifter.get_states()[state_index], segment_permutation_shifter.get_indexed_element().element);
}
assert!(segment_permutation_shifter.try_forward()); assert!(segment_permutation_shifter.try_increment()); assert_eq!(&(20, 205), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(0, segment_permutation_shifter.get_indexed_element().index);
{
let (element_index, state_index) = segment_permutation_shifter.get_element_index_and_state_index();
assert_eq!(element_index, segment_permutation_shifter.get_indexed_element().index);
assert_eq!(segment_permutation_shifter.get_states()[state_index], segment_permutation_shifter.get_indexed_element().element);
}
assert!(!segment_permutation_shifter.try_increment()); assert!(segment_permutation_shifter.try_backward());
assert!(!segment_permutation_shifter.try_increment()); assert!(!segment_permutation_shifter.try_backward()); }
#[rstest]
fn permutations_two_segments_two_and_three_length_and_eight_bounding_length_no_swapping_permitted() {
init();
let segments: Vec<Rc<Segment>> = vec![
Rc::new(Segment::new(2)),
Rc::new(Segment::new(3))
];
let mut segment_permutation_shifter = SegmentPermutationShifter::new(segments, (20, 200), 8, true, 1, false);
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
assert_eq!(&(20, 200), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(0, segment_permutation_shifter.get_indexed_element().index);
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
assert_eq!(&(23, 200), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(1, segment_permutation_shifter.get_indexed_element().index);
assert!(!segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_backward());
assert!(segment_permutation_shifter.try_increment());
assert_eq!(&(24, 200), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(1, segment_permutation_shifter.get_indexed_element().index);
assert!(!segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_backward());
assert!(segment_permutation_shifter.try_increment());
assert_eq!(&(25, 200), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(1, segment_permutation_shifter.get_indexed_element().index);
assert!(!segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_backward());
assert!(!segment_permutation_shifter.try_increment());
assert!(segment_permutation_shifter.try_backward()); assert!(segment_permutation_shifter.try_increment()); assert_eq!(&(21, 200), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(0, segment_permutation_shifter.get_indexed_element().index);
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
assert_eq!(&(24, 200), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(1, segment_permutation_shifter.get_indexed_element().index);
assert!(!segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_backward());
assert!(segment_permutation_shifter.try_increment());
assert_eq!(&(25, 200), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(1, segment_permutation_shifter.get_indexed_element().index);
assert!(!segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_backward());
assert!(!segment_permutation_shifter.try_increment());
assert!(segment_permutation_shifter.try_backward()); assert!(segment_permutation_shifter.try_increment());
assert_eq!(&(22, 200), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(0, segment_permutation_shifter.get_indexed_element().index);
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
assert_eq!(&(25, 200), segment_permutation_shifter.get_indexed_element().element.as_ref());
assert_eq!(1, segment_permutation_shifter.get_indexed_element().index);
assert!(!segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_backward());
assert!(!segment_permutation_shifter.try_increment());
assert!(segment_permutation_shifter.try_backward()); assert!(!segment_permutation_shifter.try_increment());
assert!(!segment_permutation_shifter.try_backward()); }
#[rstest]
fn permutations_randomly_two_segments_one_and_one_length_and_four_bounding_length_one_padding_no_swapping_permitted() {
init();
let segments: Vec<Rc<Segment>> = vec![
Rc::new(Segment::new(1)),
Rc::new(Segment::new(1))
];
let mut permutations_per_scenario: [u32; 3] = [0, 0, 0];
for _ in 0..20000 {
let mut segment_permutation_shifter = SegmentPermutationShifter::new(segments.clone(), (20, 200), 4, true, 1, false);
segment_permutation_shifter.randomize();
assert!(!segment_permutation_shifter.is_starting_equal_to_ending);
assert_eq!(0, segment_permutation_shifter.ending_segment_index_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.ending_segment_index_per_shift_index[1]);
assert_eq!(0, segment_permutation_shifter.starting_segment_index_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_segment_index_per_shift_index[1]);
if segment_permutation_shifter.ending_position_offset_per_shift_index[0] == 0 && segment_permutation_shifter.ending_position_offset_per_shift_index[1] == 2 {
permutations_per_scenario[0] += 1;
assert_eq!(0, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[0]);
assert_eq!(0, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[0]);
assert_eq!(2, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[1]);
assert_eq!(3, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[1]);
assert_eq!(3, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[1]);
}
else if segment_permutation_shifter.ending_position_offset_per_shift_index[0] == 0 && segment_permutation_shifter.ending_position_offset_per_shift_index[1] == 3 {
permutations_per_scenario[1] += 1;
assert_eq!(0, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[0]);
assert_eq!(3, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[1]);
assert_eq!(3, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[1]);
assert_eq!(3, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[1]);
}
else if segment_permutation_shifter.ending_position_offset_per_shift_index[0] == 1 && segment_permutation_shifter.ending_position_offset_per_shift_index[1] == 3 {
permutations_per_scenario[2] += 1;
assert_eq!(0, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[0]);
assert_eq!(0, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[0]);
assert_eq!(2, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[1]);
assert_eq!(3, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[1]);
assert_eq!(2, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[1]);
}
}
println!("permutations_per_scenario: {:?}", permutations_per_scenario);
println!("0 / 1 = {}", (1.0 - permutations_per_scenario[0] as f32 / permutations_per_scenario[1] as f32).abs());
println!("0 / 2 = {}", (1.0 - permutations_per_scenario[0] as f32 / permutations_per_scenario[2] as f32).abs());
println!("1 / 2 = {}", (1.0 - permutations_per_scenario[1] as f32 / permutations_per_scenario[2] as f32).abs());
assert!((1.0 - (permutations_per_scenario[0] as f32 / permutations_per_scenario[1] as f32)).abs() < 0.1);
assert!((1.0 - (permutations_per_scenario[0] as f32 / permutations_per_scenario[2] as f32)).abs() < 0.1);
assert!((1.0 - (permutations_per_scenario[1] as f32 / permutations_per_scenario[2] as f32)).abs() < 0.1);
}
#[rstest]
fn permutations_randomly_two_segments_one_and_one_length_and_four_bounding_length_one_padding_swapping_permitted() {
init();
let segments: Vec<Rc<Segment>> = vec![
Rc::new(Segment::new(1)),
Rc::new(Segment::new(1))
];
let mut permutations_per_scenario: [u32; 6] = [0, 0, 0, 0, 0, 0];
for _ in 0..20000 {
let mut segment_permutation_shifter = SegmentPermutationShifter::new(segments.clone(), (20, 200), 4, true, 1, true);
segment_permutation_shifter.randomize();
assert!(!segment_permutation_shifter.is_starting_equal_to_ending);
if segment_permutation_shifter.ending_position_offset_per_shift_index[0] == 0 && segment_permutation_shifter.ending_position_offset_per_shift_index[1] == 2 && segment_permutation_shifter.ending_segment_index_per_shift_index[0] == 0 {
permutations_per_scenario[0] += 1;
assert_eq!(1, segment_permutation_shifter.ending_segment_index_per_shift_index[1]);
assert_eq!(0, segment_permutation_shifter.starting_segment_index_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_segment_index_per_shift_index[1]);
assert_eq!(0, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[0]);
assert_eq!(0, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[0]);
assert_eq!(2, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[1]);
assert_eq!(3, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[1]);
assert_eq!(3, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[1]);
}
else if segment_permutation_shifter.ending_position_offset_per_shift_index[0] == 0 && segment_permutation_shifter.ending_position_offset_per_shift_index[1] == 3 && segment_permutation_shifter.ending_segment_index_per_shift_index[0] == 0 {
permutations_per_scenario[1] += 1;
assert_eq!(1, segment_permutation_shifter.ending_segment_index_per_shift_index[1]);
assert_eq!(0, segment_permutation_shifter.starting_segment_index_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_segment_index_per_shift_index[1]);
assert_eq!(0, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[0]);
assert_eq!(3, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[1]);
assert_eq!(3, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[1]);
assert_eq!(3, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[1]);
}
else if segment_permutation_shifter.ending_position_offset_per_shift_index[0] == 1 && segment_permutation_shifter.ending_position_offset_per_shift_index[1] == 3 && segment_permutation_shifter.ending_segment_index_per_shift_index[0] == 0 {
permutations_per_scenario[2] += 1;
assert_eq!(1, segment_permutation_shifter.ending_segment_index_per_shift_index[1]);
assert_eq!(1, segment_permutation_shifter.starting_segment_index_per_shift_index[0]);
assert_eq!(0, segment_permutation_shifter.starting_segment_index_per_shift_index[1]);
assert_eq!(0, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[0]);
assert_eq!(0, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[0]);
assert_eq!(2, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[1]);
assert_eq!(3, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[1]);
assert_eq!(2, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[1]);
}
else if segment_permutation_shifter.ending_position_offset_per_shift_index[0] == 0 && segment_permutation_shifter.ending_position_offset_per_shift_index[1] == 2 && segment_permutation_shifter.ending_segment_index_per_shift_index[0] == 1 {
permutations_per_scenario[3] += 1;
assert_eq!(0, segment_permutation_shifter.ending_segment_index_per_shift_index[1]);
assert_eq!(1, segment_permutation_shifter.starting_segment_index_per_shift_index[0]);
assert_eq!(0, segment_permutation_shifter.starting_segment_index_per_shift_index[1]);
assert_eq!(0, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[0]);
assert_eq!(0, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[0]);
assert_eq!(2, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[1]);
assert_eq!(3, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[1]);
assert_eq!(3, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[1]);
}
else if segment_permutation_shifter.ending_position_offset_per_shift_index[0] == 0 && segment_permutation_shifter.ending_position_offset_per_shift_index[1] == 3 && segment_permutation_shifter.ending_segment_index_per_shift_index[0] == 1 {
permutations_per_scenario[4] += 1;
assert_eq!(0, segment_permutation_shifter.ending_segment_index_per_shift_index[1]);
assert_eq!(1, segment_permutation_shifter.starting_segment_index_per_shift_index[0]);
assert_eq!(0, segment_permutation_shifter.starting_segment_index_per_shift_index[1]);
assert_eq!(0, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[0]);
assert_eq!(3, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[1]);
assert_eq!(3, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[1]);
assert_eq!(3, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[1]);
}
else if segment_permutation_shifter.ending_position_offset_per_shift_index[0] == 1 && segment_permutation_shifter.ending_position_offset_per_shift_index[1] == 3 && segment_permutation_shifter.ending_segment_index_per_shift_index[0] == 1 {
permutations_per_scenario[5] += 1;
assert_eq!(0, segment_permutation_shifter.ending_segment_index_per_shift_index[1]);
assert_eq!(0, segment_permutation_shifter.starting_segment_index_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_segment_index_per_shift_index[1]);
assert_eq!(0, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[0]);
assert_eq!(1, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[0]);
assert_eq!(0, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[0]);
assert_eq!(2, segment_permutation_shifter.starting_minimum_position_offset_per_shift_index[1]);
assert_eq!(3, segment_permutation_shifter.starting_maximum_position_offset_per_shift_index[1]);
assert_eq!(2, segment_permutation_shifter.starting_initial_position_offset_per_shift_index[1]);
}
}
println!("permutations_per_scenario: {:?}", permutations_per_scenario);
for scenario_index in 0..5 {
for other_scenario_index in (scenario_index + 1)..6 {
println!("{} / {} = {}", scenario_index, other_scenario_index, (1.0 - permutations_per_scenario[scenario_index] as f32 / permutations_per_scenario[other_scenario_index] as f32).abs());
assert!((1.0 - (permutations_per_scenario[scenario_index] as f32 / permutations_per_scenario[other_scenario_index] as f32)).abs() < 0.1);
}
}
}
#[rstest]
fn randomized_single_pixel_segment() {
for bounding_length in 2..=6 as usize {
let mut count_per_location: BTreeMap<(u8, u8), usize> = BTreeMap::new();
for offset in 0..bounding_length as u8 {
count_per_location.insert((20, 200 + offset), 0);
}
let iterations_total = 1000;
for _ in 0..iterations_total {
let mut segment_permutation_shifter = SegmentPermutationShifter::new(vec![Rc::new(Segment::new(1))], (20, 200), bounding_length, false, 1, true);
segment_permutation_shifter.randomize();
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
let previous_location;
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
let location: (u8, u8) = *indexed_element.element.as_ref();
count_per_location.insert(location, count_per_location[&location] + 1);
previous_location = location;
}
assert!(!segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_backward());
for _ in 0..(bounding_length - 1) {
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
let location: (u8, u8) = *indexed_element.element.as_ref();
assert_ne!(previous_location, location);
}
assert!(!segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_backward());
}
assert!(!segment_permutation_shifter.try_increment());
assert!(!segment_permutation_shifter.try_backward());
}
println!("count_per_location: {:?}", count_per_location);
for offset in 0..bounding_length as u8 {
let location = (20, 200 + offset);
let count = count_per_location[&location] as f32;
let expected = iterations_total as f32 / bounding_length as f32;
assert!((count - expected).abs() < (iterations_total as f32 / 10.0));
}
}
}
#[rstest]
fn randomize_two_single_pixels_and_reset_before_end() {
init();
let bounding_length = 5;
let iterations_total = 1000;
for _ in 0..iterations_total {
let mut segment_permutation_shifter = SegmentPermutationShifter::new(vec![Rc::new(Segment::new(1)), Rc::new(Segment::new(1))], (20, 200), bounding_length, false, 1, false);
segment_permutation_shifter.randomize();
let mut shifter_incrementer = ShifterIncrementer::new(Box::new(segment_permutation_shifter), vec![0, 1]);
assert!(shifter_incrementer.try_increment());
{
let indexed_elements = shifter_incrementer.get();
println!("starting with {:?}", indexed_elements);
let random_increments_total = fastrand::u8(0..6);
println!("incrementing {random_increments_total} times");
for _ in 0..random_increments_total {
println!("incrementing once");
assert!(shifter_incrementer.try_increment());
let current_indexed_elements = shifter_incrementer.get();
println!("currently with {:?}", current_indexed_elements);
}
shifter_incrementer.reset();
assert!(shifter_incrementer.try_increment());
let identical_indexed_elements = shifter_incrementer.get();
println!("reset back to {:?}", identical_indexed_elements);
assert_eq!(indexed_elements.len(), identical_indexed_elements.len());
for (indexed_element, identical_indexed_element) in indexed_elements.iter().zip(identical_indexed_elements.iter()) {
assert_eq!(indexed_element, identical_indexed_element);
}
}
}
}
#[rstest]
fn nonrandom_two_single_pixels_but_only_first_shift_is_exhausted() {
let mut segment_permutation_shifter = SegmentPermutationShifter::new(vec![Rc::new(Segment::new(1)), Rc::new(Segment::new(1))], (20, 200), 5, false, 1, false);
for _ in 0..10 {
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(20, 200), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(20, 201), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(20, 202), indexed_element.element.as_ref());
}
assert!(!segment_permutation_shifter.try_increment());
assert!(!segment_permutation_shifter.try_backward());
}
}
#[rstest]
fn nonrandom_three_single_pixels_but_only_second_shift_is_exhausted() {
let mut segment_permutation_shifter = SegmentPermutationShifter::new(vec![Rc::new(Segment::new(1)), Rc::new(Segment::new(1)), Rc::new(Segment::new(1))], (20, 200), 7, false, 1, false);
for _ in 0..10 {
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(20, 200), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(1, indexed_element.index);
assert_eq!(&(20, 202), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(1, indexed_element.index);
assert_eq!(&(20, 203), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(1, indexed_element.index);
assert_eq!(&(20, 204), indexed_element.element.as_ref());
}
assert!(!segment_permutation_shifter.try_increment());
assert!(segment_permutation_shifter.try_backward());
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(20, 201), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(1, indexed_element.index);
assert_eq!(&(20, 203), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(1, indexed_element.index);
assert_eq!(&(20, 204), indexed_element.element.as_ref());
}
assert!(!segment_permutation_shifter.try_increment());
assert!(segment_permutation_shifter.try_backward());
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(20, 202), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(1, indexed_element.index);
assert_eq!(&(20, 204), indexed_element.element.as_ref());
}
assert!(!segment_permutation_shifter.try_increment());
assert!(segment_permutation_shifter.try_backward());
assert!(!segment_permutation_shifter.try_increment());
assert!(!segment_permutation_shifter.try_backward());
}
}
#[rstest]
fn random_two_single_pixels_but_only_first_shift_is_exhausted_already_one_position_ahead() {
fastrand::seed(0);
let mut segment_permutation_shifter = SegmentPermutationShifter::new(vec![Rc::new(Segment::new(1)), Rc::new(Segment::new(1))], (20, 200), 5, false, 1, false);
segment_permutation_shifter.randomize();
{
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(20, 201), indexed_element.element.as_ref());
}
segment_permutation_shifter.reset();
}
for _ in 0..10 {
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(20, 201), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(20, 202), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(20, 200), indexed_element.element.as_ref());
}
assert!(!segment_permutation_shifter.try_increment());
assert!(!segment_permutation_shifter.try_backward());
}
}
#[rstest]
fn random_two_single_pixels_but_only_first_shift_is_exhausted_second_segment_already_one_position_ahead() {
fastrand::seed(2);
let mut segment_permutation_shifter = SegmentPermutationShifter::new(vec![Rc::new(Segment::new(1)), Rc::new(Segment::new(1))], (20, 200), 5, false, 1, false);
segment_permutation_shifter.randomize();
{
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(20, 200), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(1, indexed_element.index);
assert_eq!(&(20, 203), indexed_element.element.as_ref());
}
segment_permutation_shifter.reset();
}
for _ in 0..10 {
assert!(segment_permutation_shifter.try_forward());
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(20, 200), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(20, 201), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(20, 202), indexed_element.element.as_ref());
}
assert!(segment_permutation_shifter.try_increment());
{
let indexed_element = segment_permutation_shifter.get_indexed_element();
assert_eq!(0, indexed_element.index);
assert_eq!(&(20, 200), indexed_element.element.as_ref());
}
assert!(!segment_permutation_shifter.try_increment());
assert!(!segment_permutation_shifter.try_backward());
}
}
#[rstest]
fn three_segments_in_large_bounding_length() {
let segments_total = 4;
let mut segments: Vec<Rc<Segment>> = Vec::new();
for _ in 0..segments_total {
segments.push(Rc::new(Segment::new(1)));
}
let mut segment_permutation_shifter_0 = SegmentPermutationShifter::new(segments.clone(), (0, 0), 255, false, 1, false);
segment_permutation_shifter_0.randomize();
let mut shifter_incrementer_0 = ShifterIncrementer::new(Box::new(segment_permutation_shifter_0), vec![0]);
let mut segment_permutation_shifter_1 = SegmentPermutationShifter::new(segments.clone(), (0, 0), 255, false, 1, false);
segment_permutation_shifter_1.randomize();
let mut shifter_incrementer_1 = ShifterIncrementer::new(Box::new(segment_permutation_shifter_1), vec![0]);
let mut iterations = 0;
while shifter_incrementer_0.try_increment() {
iterations += 1;
}
println!("iterations: {iterations}");
}
fn decrement_incrementer() {
todo!();
}
}