{{REWRITTEN_CODE}}
Day 6: Code
Below is the complete code for Day 6's solution, which finds marker patterns in a datastream.
Full Solution
use std::fmt::Debug;
trait Duplicate {
fn has_duplicates(&self) -> bool;
}
impl<T> Duplicate for [T] where T: Debug + Copy + PartialEq + Ord {
fn has_duplicates(&self) -> bool {
let mut tmp = self.to_vec();
tmp.sort();
tmp.windows(2).any(|a| a[0]==a[1])
}
}
trait Signaling {
fn marker_position(&self, len:usize) -> usize;
}
impl<T> Signaling for [T] where T : Debug + Copy + PartialEq + Ord {
fn marker_position(&self, len: usize) -> usize {
self.windows(len)
.enumerate()
.skip_while(|&(_,stm)| stm.has_duplicates() )
.next()
.map(|(i,_)| i + len)
.unwrap_or_else(|| panic!("marker_position(): Ops!"))
}
}
fn main() {
let data = std::fs::read_to_string("src/bin/day6_input.txt").expect("");
let out = data.bytes().collect::<Vec<_>>();
println!("Marker Length @4 = {}", out.marker_position(4));
println!("Marker Length @14 = {}", out.marker_position(14));
}
Code Walkthrough
Duplicate Detection Trait
trait Duplicate {
fn has_duplicates(&self) -> bool;
}
impl<T> Duplicate for [T] where T: Debug + Copy + PartialEq + Ord {
fn has_duplicates(&self) -> bool {
let mut tmp = self.to_vec();
tmp.sort();
tmp.windows(2).any(|a| a[0]==a[1])
}
}
This trait provides a method to check if a slice contains duplicate elements:
Duplicate
trait defines a single methodhas_duplicates
that returns a boolean- The implementation for slices
[T]
works with any type that can be debugged, copied, compared for equality, and ordered - The implementation creates a temporary copy of the slice, sorts it (bringing identical elements adjacent to each other), and then checks if any adjacent elements are equal
- The
windows(2)
method creates sliding windows of 2 elements, andany
checks if the predicate is true for any window
Marker Detection Trait
trait Signaling {
fn marker_position(&self, len:usize) -> usize;
}
impl<T> Signaling for [T] where T : Debug + Copy + PartialEq + Ord {
fn marker_position(&self, len: usize) -> usize {
self.windows(len)
.enumerate()
.skip_while(|&(_,stm)| stm.has_duplicates() )
.next()
.map(|(i,_)| i + len)
.unwrap_or_else(|| panic!("marker_position(): Ops!"))
}
}
This trait provides a method to find the position of the first marker of a specified length:
Signaling
trait defines a single methodmarker_position
that takes a length parameter and returns a position- The implementation creates sliding windows of the specified length using
windows(len)
- Each window is paired with its position using
enumerate()
- Windows containing duplicates are skipped using
skip_while
- The first window without duplicates is selected with
next()
- The marker position is calculated as the window index plus the window length
Main Function
fn main() {
let data = std::fs::read_to_string("src/bin/day6_input.txt").expect("");
let out = data.bytes().collect::<Vec<_>>();
println!("Marker Length @4 = {}", out.marker_position(4));
println!("Marker Length @14 = {}", out.marker_position(14));
}
The main function:
- Reads the input file into a string
- Converts the string to a vector of bytes using
bytes().collect()
- Calls
marker_position(4)
to solve Part 1 (finding a start-of-packet marker) - Calls
marker_position(14)
to solve Part 2 (finding a start-of-message marker)
Implementation Notes
- Traits for Reusability: The solution uses Rust's trait system to create reusable behaviors
- Generic Implementation: Both traits work with any type that meets the trait bounds, not just bytes or characters
- Functional Approach: The code uses a functional programming style with method chaining for concise and expressive code
- Algorithm Choice: The solution uses sorting for duplicate detection, which is efficient for small windows (like the 4 and 14 character windows in this problem)
The implementation is elegant and leverages Rust's powerful type system to create a generic, reusable solution that can handle both parts of the problem with the same code.