lib.rs
// Use the same global constants
pub mod constants;
use std::fmt::Display;
use constants::{AVAILABLEPLANKS, CUTADJACENCY, PLANKMAX, PLANKMIN, PLAY, ROOMLENGTH, SAWBLADE};
// Define a plank piece structure
#[derive(Debug)]
pub struct MaterialStorage {
pub total_planks: u32,
pub planks_new: Vec<Plank>,
pub planks_used: Vec<Plank>,
pub planks_too_short: Vec<Plank>,
}
impl Default for MaterialStorage {
/// Create a new, default storage
fn default() -> Self {
Self {
total_planks: AVAILABLEPLANKS,
planks_new: vec![Plank::default(); AVAILABLEPLANKS as usize],
planks_used: vec![],
planks_too_short: vec![],
}
}
}
impl MaterialStorage {
pub fn new(&self) -> Self {
MaterialStorage::default()
}
/// Does there exist used/cut planks?
pub fn exists_used(&self) -> bool {
!self.planks_used.is_empty()
}
/// Get a used plank
pub fn get_used(&mut self) -> Option<Plank> {
self.planks_used.pop()
}
/// Store a used plank
pub fn store_used(&mut self, plank: Plank) {
self.planks_used.push(plank)
}
/// Try get a used plank, fallback by getting a new
pub fn try_get_used(&mut self) -> Option<Plank> {
if let Some(plank) = self.planks_used.pop() {
Some(plank)
} else {
self.get_new()
}
}
/// Get how many cut planks exists
pub fn get_used_count(&self) -> u32 {
self.planks_used.len() as u32
}
/// Does there exist new planks
pub fn exists_new(&self) -> bool {
!self.planks_new.is_empty()
}
/// Get a new plank
pub fn get_new(&mut self) -> Option<Plank> {
self.planks_new.pop()
}
/// Put a too short plank aside
pub fn discard_unusable(&mut self, plank: Plank) {
self.planks_too_short.push(plank)
}
}
// Define a plank cut structure
#[derive(Debug, Clone, Copy)]
pub struct Cut {
pub coordinate: u32,
}
impl Cut {
pub fn new(coordinate: u32) -> Self {
Cut { coordinate }
}
}
impl Display for Cut {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.coordinate)
}
}
// Define a plank piece structure
#[derive(Debug, Clone, Copy)]
pub struct Plank {
pub length: u32,
pub endpiece: bool,
pub new: bool,
}
impl Default for Plank {
/// Create a new, default plank
fn default() -> Self {
Self {
length: PLANKMAX,
endpiece: false,
new: true,
}
}
}
impl Display for Plank {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.length)
}
}
impl Plank {
/// Create a new plank
pub fn new(&self) -> Self {
Plank::default()
}
/// Is this a new plank?
pub fn is_new(&self) -> bool {
self.new
}
/// Is this at the end of a row
pub fn get_endpiece(&self) -> bool {
self.endpiece
}
/// Make this plank an endpiece
pub fn set_endpiece(&mut self) {
self.endpiece = true;
}
/// Return the length of the plank
pub fn length(&self) -> u32 {
self.length
}
/// Return the original plank with the new length along with leftover
pub fn cut_to_length(mut self, measure: u32) -> (Plank, Plank) {
if measure > PLANKMAX {
panic!("Can't cut a plank longer than it is!");
} else if measure == 0 {
panic!("Cutting a plank to length 0 does not make sense!");
}
// Create the leftover plank, correct for material loss due to sawing
let leftover_plank;
let leftover_length;
if self.length() < PLANKMIN {
// Create a new plank instead
let new_plank: Plank = Default::default();
leftover_plank = new_plank;
} else {
leftover_length = self.length - (measure + SAWBLADE);
leftover_plank = Plank {
length: leftover_length,
..Default::default()
};
}
// Trim self to the new length
self.length = measure;
// In case the plank was new, mark it as cut
if self.new {
self.new = false;
}
// Return the original plank and the leftover
(self, leftover_plank)
}
}
// Define a row structure
#[derive(Debug)]
pub struct Row {
planks: Vec<Plank>,
cut_coordinates: Vec<Cut>,
coverage: u32,
full: bool,
row_max_length: u32,
}
impl Default for Row {
/// Create a new, empty row
fn default() -> Self {
Self {
planks: vec![],
cut_coordinates: vec![],
coverage: 0,
full: false,
row_max_length: ROOMLENGTH - 2 * PLAY,
}
}
}
impl Display for Row {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let scalefactor = 50;
// Try to compensate for the extra size taken by
// the number printout
let comp = 50 * self.planks_count();
let mut length_sum = 0;
write!(f, " ")?; // Prefix space for play
for plank in self.planks().iter() {
length_sum += plank.length;
write!(f, "|")?;
// Print the relative length of the plank
for _ in 0..((plank.length()) / scalefactor) {
write!(f, "-")?;
}
}
write!(f, "|")?;
write!(f, " Cut coordinates: ")?;
for cut in self.get_cut_coordinates() {
write!(f, " {cut: ^6}, ")?;
}
writeln!(f)?;
write!(f, "+{PLAY}")?;
for plank in self.planks().iter() {
for _ in 0..((plank.length() - comp) / scalefactor) / 2 {
write!(f, " ")?;
}
// Print the numeric length
write!(f, "{: ^6}", plank.length())?;
// Remainder of the plank
for _ in 0..((plank.length() - comp) / scalefactor) / 2 {
write!(f, " ")?;
}
}
write!(f, "+{PLAY}")?;
writeln!(f, "\t Row length: {length_sum}")?;
write!(f, " ")?; // Prefix space for play
for plank in self.planks().iter() {
write!(f, "|")?;
// Print the bottom self of the plank
for _ in 0..(plank.length() / scalefactor) {
write!(f, "-")?;
}
}
writeln!(f, "|")
}
}
impl Row {
/// Is this row considered full?
pub fn get_full(&self) -> bool {
self.full
}
/// Mark this row as full
pub fn set_full(&mut self) {
self.full = true;
}
pub fn set_first_and_last_as_endpieces(&mut self) {
// #TODO Remove unwrap
self.planks.first_mut().unwrap().set_endpiece();
self.planks.last_mut().unwrap().set_endpiece();
}
/// Get the number of planks for this floor
pub fn planks_count(&self) -> u32 {
self.planks.len() as u32
}
/// Get a mutable reference to the planks
pub fn planks_mut(&mut self) -> &mut Vec<Plank> {
&mut self.planks
}
/// Get a mutable reference to the planks
pub fn planks(&self) -> &Vec<Plank> {
&self.planks
}
/// Return how many planks/pieces are in this row
pub fn get_used_planks(&mut self) {
self.planks.len();
}
/// Increase how much of the row is filled
fn add_coverage(&mut self, coverage: u32) {
self.coverage += coverage;
}
/// Get the coverage so far of this row
pub fn get_coverage(&self) -> u32 {
self.coverage
}
/// Get the maximum length allowed
pub fn get_max_length(&self) -> u32 {
self.row_max_length
}
/// Add a plank to this row
pub fn add(&mut self, plank: Plank) {
// Add the new plank to coverage, coverage is
// thus the coordinate from origin
self.add_coverage(plank.length());
// There is always a cut at the end of a row
// only add Cut if less than this
let coordinate = self.get_coverage();
if coordinate < self.row_max_length {
self.cut_coordinates.push(Cut::new(coordinate));
}
self.planks.push(plank);
}
/// Swap the topmost plank
pub fn swap_latest(&mut self, ms: &mut MaterialStorage) {
let number_of_planks = self.planks.len();
if number_of_planks >= 2 {
self.pop(ms);
self.pop(ms);
if let Some(plank) = ms.get_used() {
self.add(plank);
}
if let Some(plank) = ms.get_used() {
self.add(plank);
}
}
}
/// Remove a plank from this row
pub fn pop(&mut self, ms: &mut MaterialStorage) {
// Remove the plank
if let Some(plank) = self.planks.pop() {
ms.store_used(plank);
// Update the row coverage
self.coverage -= plank.length();
}
// Remove the cut
if let Some(cut) = self.cut_coordinates.pop() {
log::info!("Removed cut at {}", cut.coordinate);
}
}
pub fn get_cut_coordinates(&self) -> Vec<Cut> {
self.cut_coordinates.clone()
}
pub fn check_if_cut_is_valid(&self, new_cut: Cut) -> bool {
// If we have no cuts, no need to check them
if !self.cut_coordinates.is_empty() {
for cut in &self.cut_coordinates {
if cut.coordinate.abs_diff(new_cut.coordinate) < CUTADJACENCY {
// Invalid, cut is too close!
return false;
}
}
}
true
}
}
// Define a floor structure
#[derive(Debug)]
pub struct Floor {
rows: Vec<Row>,
coverage: u32,
complete: bool,
}
impl Default for Floor {
/// Create a new, empty row
fn default() -> Self {
Self {
rows: vec![],
coverage: 0,
complete: false,
}
}
}
impl Display for Floor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for (num, row) in self.rows().iter().enumerate() {
writeln!(f, "Row: {:#?}", num + 1)?;
writeln!(f, "{row}")?;
}
Ok(())
}
}
impl Floor {
/// Is this floor considered complete?
pub fn get_complete(&self) -> bool {
self.complete
}
/// Mark this floor as complete
pub fn set_complete(&mut self) {
self.complete = true;
}
/// Get the number of plank rows for this floor
pub fn rows_count(&self) -> usize {
self.rows.len()
}
/// Get a mutable reference to the rows
pub fn rows_mut(&mut self) -> &mut Vec<Row> {
&mut self.rows
}
/// Get a reference to the rows
pub fn rows(&self) -> &Vec<Row> {
&self.rows
}
/// Get a reference to the previous row
pub fn last_row(&self) -> Option<&Row> {
self.rows.last()
}
/// Add another row to this floor
pub fn add(&mut self, row: Row) {
self.rows.push(row);
}
/// Get the number of plank rows for this floor
pub fn get_coverage(&self) -> u32 {
self.coverage
}
/// Increase how much of the row is filled
pub fn add_coverage(&mut self, coverage: u32) {
self.coverage += coverage;
}
}