Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use std::fmt::{self, Display};
- use crate::{Fro, Solution, TaskResult};
- use super::utils::*;
- #[derive(Debug, Clone)]
- struct Block {
- id: usize,
- data: char,
- }
- impl Display for Block {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- if self.data == '.' {
- writeln!(f, "Empty data block")
- } else {
- writeln!(f, "{:?}", self)
- }
- }
- }
- // Can add more shared vars here
- pub struct DiskFragmenter {
- data: Vec<Block>
- }
- // Can be used to implement fancier task-specific parsing
- impl Fro for DiskFragmenter {
- fn fro(input: &str) -> Self{
- let mut data: Vec<Block> = Vec::new();
- let mut i = 0;
- let mut data_idx = 0;
- input
- .chars()
- .for_each(|c| {
- let len = c as u8 -48;
- let mut data_added = false;
- for _ in (0..len) {
- if i % 2 == 0 {
- data.push(Block {id: data_idx, data: c});
- data_added = true;
- } else {
- data.push(Block {id: i, data: '.'});
- }
- }
- if data_added { data_idx += 1; }
- i += 1;
- });
- Self { data }
- }
- }
- // Main solvers
- impl Solution for DiskFragmenter {
- fn silver(&self) -> TaskResult {
- let mut defrag = self.data.clone();
- // first find the next free space, and hold it in index
- let mut next_free = 0;
- let mut next_end = defrag.len()-1;
- while let Some(idx) = Self::next_free_idx(&defrag, next_free) {
- // Find next data block from end
- if let Some(end) = Self::next_end_idx(&defrag, next_end) {
- if idx >= end { break } // Finish condition
- // Swap the free space with data from the end
- defrag.swap(idx, end);
- next_free = idx + 1;
- next_end = end - 1;
- }
- else { break } // No more data blocks to process
- }
- TaskResult::Usize(Self::checksum(defrag))
- }
- fn gold(&self) -> TaskResult {
- let mut defrag = self.data.clone();
- let mut seek_start = 0;
- let mut seek_end = defrag.len()-1;
- //defrag.iter().enumerate().for_each(|(idx, d)| print!("idx: {}, {}", idx, d));
- //println!("start processing");
- // Start processing a file
- while let Some(end) = Self::next_end_idx(&defrag, seek_end) {
- println!("end: {}", end);
- if seek_start == end { // end condition
- break;
- }
- // Skip empty blocks
- if defrag[end].data == '.' {
- seek_end = end.saturating_sub(1);
- continue;
- }
- // Found a file
- let file_length = defrag[end].data.to_digit(10).unwrap() as usize;
- let file_start = end + 1 - file_length;
- //println!("seeking: start: {}, end: {}, fl: {}", seek_start, &(file_start), file_length);
- // Find room for file
- if let Some(free_range) =
- Self::free_block(&defrag, &seek_start, &(file_start), &file_length)
- {
- //println!("defragging: free range: {:?}, end: {}, fl: {}", free_range, end, file_length);
- let file_start = end+1-file_length;
- Self::move_file(&mut defrag, &free_range, &file_start, &file_length);
- }
- seek_end = file_start.saturating_sub(1);
- }
- //println!();
- //defrag.iter().enumerate().for_each(|(idx, d)| print!("idx: {}, {}", idx, d));
- TaskResult::Usize(Self::checksum(defrag))
- // 00992111777.44.333....5555.6666.....8888..
- //TaskResult::Usize(Self::checksum(defrag))
- }
- }
- // For assisting functions
- impl DiskFragmenter {
- // cargo test --lib tests::free_block -- --nocapture
- fn free_block(
- defrag: &[Block],
- start: &usize,
- end: &usize,
- seek_len: &usize
- )
- -> Option<(usize, usize)>
- {
- let mut continuous = false;
- let mut found = 0;
- for offset in (*start..=*end) {
- if defrag[offset].data == '.' {
- if !continuous { continuous = true };
- found += 1;
- if found == *seek_len {
- return Some( (offset + 1 - seek_len, offset) );
- }
- continue;
- }
- // Reset state
- continuous = false;
- found = 0;
- }
- None
- }
- fn move_file(
- defrag: &mut [Block],
- free_block: &(usize, usize),
- file_start: &usize,
- file_length: &usize,
- ) -> bool {
- //println!("{:?}, fe:{}, fl:{}", free_block, file_start, file_length);
- (0..*file_length).for_each(|i| {
- defrag.swap(free_block.0+i, file_start+i);
- });
- true
- }
- fn next_free_idx(defrag: &[Block], start: usize) -> Option<usize> {
- (start..defrag.len()).find(|&i| defrag[i].data == '.')
- }
- fn next_end_idx(defrag: &[Block], end: usize) -> Option<usize> {
- (0..=end).rev().find(|&i| defrag[i].data != '.')
- }
- fn checksum(defrag: Vec<Block>) -> usize {
- defrag
- .iter()
- .enumerate()
- .map(|(i, val)| if val.data != '.' { val.id * i } else { 0 })
- .sum()
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement