diff --git a/06/main.rs b/06/main.rs
new file mode 100644
index 0000000..0f2e94e
--- /dev/null
+++ b/06/main.rs
@@ -0,0 +1,85 @@
+#![allow(dead_code)]
+use std::collections::VecDeque;
+use std::fs::File;
+use std::io;
+use std::io::BufRead;
+use std::path::Path;
+use std::time::Instant;
+
+fn main() {
+ let now = Instant::now();
+ part_one();
+ let part_one_duration = now.elapsed();
+ part_two();
+ let part_two_duration = now.elapsed();
+ println!(
+ "p1: {}ms, p2: {}ms",
+ part_one_duration.as_millis(),
+ (part_two_duration - part_one_duration).as_millis()
+ );
+}
+
+fn read_lines
(filename: P) -> io::Result>>
+where
+ P: AsRef,
+{
+ // note that this discards a final newline
+ let file = File::open(filename)?;
+ Ok(io::BufReader::new(file).lines())
+}
+
+fn part_one() {
+ if let Ok(mut lines) = read_lines("./inputs/input") {
+ if let Some(Ok(signal)) = lines.next() {
+ let mut buf = VecDeque::::new();
+ for (i, c) in signal.chars().enumerate() {
+ if buf.len() < 3 {
+ // start of stream
+ buf.push_back(c);
+ continue;
+ } else if buf.contains(&c)
+ || buf[0] == buf[1]
+ || buf[1] == buf[2]
+ || buf[2] == buf[0]
+ {
+ // repeated character
+ buf.pop_front();
+ buf.push_back(c);
+ } else {
+ // found it; offset to the next character
+ println!("{}", i + 1);
+ return;
+ }
+ }
+ }
+ }
+}
+
+fn part_two() {
+ if let Ok(mut lines) = read_lines("./inputs/input") {
+ if let Some(Ok(signal)) = lines.next() {
+ let mut buf = VecDeque::::new();
+ for (i, c) in signal.chars().enumerate() {
+ if buf.len() < 13 {
+ // start of stream
+ buf.push_back(c);
+ continue;
+ } else if buf.contains(&c)
+ || (1..buf.len()).any(|i| {
+ buf.range(i..)
+ .collect::>()
+ .contains(&&buf[i - 1]) // neat trick
+ })
+ {
+ // repeated character
+ buf.pop_front();
+ buf.push_back(c);
+ } else {
+ // found it; offset to the next character
+ println!("{}", i + 1);
+ return;
+ }
+ }
+ }
+ }
+}