days 7-10
parent
474ad0a248
commit
db450943a0
@ -0,0 +1,16 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day07"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"rustc-hash",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "day07"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rustc-hash = "1.1.0"
|
@ -0,0 +1,134 @@
|
|||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
const TOTAL_SPACE: usize = 70_000_000;
|
||||||
|
const REQUIRED_SPACE: usize = 30_000_000;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s = std::fs::read_to_string("/dev/stdin").unwrap();
|
||||||
|
let mut commands = s.split("$ ");
|
||||||
|
commands.next(); // chuck out first empty string
|
||||||
|
let mut pwd: Option<String> = None;
|
||||||
|
let mut file_tree: FxHashMap<String, Vec<(String, Option<usize>)>> = FxHashMap::default();
|
||||||
|
let mut dir_totals: FxHashMap<String, usize> = FxHashMap::default();
|
||||||
|
|
||||||
|
for command in commands {
|
||||||
|
let lines = command.lines().collect::<Vec<&str>>();
|
||||||
|
let cmd = lines.first().unwrap();
|
||||||
|
let args = cmd.split(' ').collect::<Vec<&str>>();
|
||||||
|
let cmd = args.first().unwrap();
|
||||||
|
let args = args.get(1..).unwrap();
|
||||||
|
|
||||||
|
match *cmd {
|
||||||
|
"cd" => cd(&mut pwd, args),
|
||||||
|
"ls" => ls(
|
||||||
|
&pwd,
|
||||||
|
lines.get(1..).unwrap(),
|
||||||
|
&mut file_tree,
|
||||||
|
&mut dir_totals,
|
||||||
|
),
|
||||||
|
invalid => panic!("unexpected command: {:?}", invalid),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for directory in file_tree.iter() {
|
||||||
|
let mut total = 0;
|
||||||
|
let dir_str = Path::new(&directory.0);
|
||||||
|
|
||||||
|
if dir_str.file_name().is_some()
|
||||||
|
&& dir_totals.contains_key(&dir_str.to_str().unwrap().to_string())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for item in directory.1.iter() {
|
||||||
|
if let Some(file_size) = item.1 {
|
||||||
|
total += file_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dir_totals.insert(directory.0.to_string(), total);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut dirs = file_tree.iter().collect::<Vec<_>>();
|
||||||
|
dirs.sort_by(|a, b| {
|
||||||
|
b.0.split('/')
|
||||||
|
.count()
|
||||||
|
.cmp(&a.0.split('/').count())
|
||||||
|
.then(b.0.len().cmp(&a.0.len()))
|
||||||
|
});
|
||||||
|
for dir in dirs.iter() {
|
||||||
|
for sub_dir in dir.1.iter().filter(|dir| dir.1.is_none()) {
|
||||||
|
let balls = (dir.0.to_owned() + &sub_dir.0.replace("dir ", "/")).replace("//", "/");
|
||||||
|
|
||||||
|
dir_totals.insert(
|
||||||
|
dir.0.to_owned(),
|
||||||
|
*dir_totals.get(&dir.0.to_owned()).unwrap() + *dir_totals.get(&balls).unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let sum = dir_totals
|
||||||
|
.iter()
|
||||||
|
.filter(|dir| dir.1 < &100000)
|
||||||
|
.fold(0, |total, dir| total + dir.1);
|
||||||
|
|
||||||
|
let free_space = TOTAL_SPACE - dir_totals.get("/").unwrap();
|
||||||
|
let minimum_required = REQUIRED_SPACE - free_space;
|
||||||
|
|
||||||
|
let mut deletable: Vec<(&String, &usize)> = dir_totals
|
||||||
|
.iter()
|
||||||
|
.filter(|dir| dir.1 >= &minimum_required)
|
||||||
|
.collect();
|
||||||
|
deletable.sort_by(|a, b| a.1.cmp(b.1));
|
||||||
|
println!("P1: {} P2: {}", sum, deletable.first().unwrap().1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cd(pwd: &mut Option<String>, args: &[&str]) {
|
||||||
|
let path_str = String::new();
|
||||||
|
let path = pwd.as_ref().unwrap_or(&path_str);
|
||||||
|
let dir = args.first().expect("cd requries an arg").to_string();
|
||||||
|
if dir == ".." {
|
||||||
|
let mut split_path = path.split('/').collect::<Vec<&str>>();
|
||||||
|
split_path.pop();
|
||||||
|
if split_path.len() == 1 {
|
||||||
|
split_path.push("");
|
||||||
|
}
|
||||||
|
*pwd = Some(split_path.join("/"));
|
||||||
|
} else if !path.is_empty() && path != "/" {
|
||||||
|
*pwd = Some(path.to_owned() + "/" + &dir);
|
||||||
|
} else {
|
||||||
|
*pwd = Some(path.to_owned() + &dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ls(
|
||||||
|
pwd: &Option<String>,
|
||||||
|
lines: &[&str],
|
||||||
|
file_tree: &mut FxHashMap<String, Vec<(String, Option<usize>)>>,
|
||||||
|
dir_totals: &mut FxHashMap<String, usize>,
|
||||||
|
) {
|
||||||
|
let mut contents: Vec<(String, Option<usize>)> = Vec::new();
|
||||||
|
let mut contains_dirs = false; // if no inner dirs, work out total here
|
||||||
|
|
||||||
|
for line in lines {
|
||||||
|
if line.starts_with("dir ") {
|
||||||
|
contents.push((line.to_string(), None));
|
||||||
|
contains_dirs = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let file_data = line.split_once(' ').unwrap();
|
||||||
|
let (file_size, file_name) = (
|
||||||
|
file_data.0.parse::<usize>().unwrap(),
|
||||||
|
file_data.1.to_string(),
|
||||||
|
);
|
||||||
|
contents.push((file_name, Some(file_size)));
|
||||||
|
}
|
||||||
|
if !contains_dirs {
|
||||||
|
let mut total = 0;
|
||||||
|
for (_, size) in contents.iter() {
|
||||||
|
total += size.unwrap();
|
||||||
|
}
|
||||||
|
dir_totals.insert(pwd.as_ref().unwrap().to_string(), total);
|
||||||
|
}
|
||||||
|
file_tree.insert(pwd.as_ref().unwrap().to_string(), contents);
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day09"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"rustc-hash",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "day09"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rustc-hash = "1.1.0"
|
@ -0,0 +1,73 @@
|
|||||||
|
use rustc_hash::FxHashSet;
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::io::{self, BufRead};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let lines = io::stdin().lock().lines().map(|l| l.unwrap());
|
||||||
|
|
||||||
|
let mut head = (0, 0);
|
||||||
|
let mut knots: Vec<(isize, isize)> = vec![(0, 0); 9];
|
||||||
|
let mut visited_p1: FxHashSet<(isize, isize)> = FxHashSet::default();
|
||||||
|
let mut visited_p2: FxHashSet<(isize, isize)> = FxHashSet::default();
|
||||||
|
|
||||||
|
visited_p1.insert((0, 0));
|
||||||
|
visited_p2.insert((0, 0));
|
||||||
|
|
||||||
|
for line in lines {
|
||||||
|
let (dir, len) = line.split_once(' ').unwrap();
|
||||||
|
let position = (dir, len.parse::<isize>().unwrap());
|
||||||
|
let mut current;
|
||||||
|
|
||||||
|
for _ in 0..position.1 {
|
||||||
|
step_head(&mut head, position.0);
|
||||||
|
current = head;
|
||||||
|
|
||||||
|
for i in 0..9 {
|
||||||
|
let knot = knots.get_mut(i).unwrap();
|
||||||
|
follow(i, current, knot, &mut visited_p1, &mut visited_p2);
|
||||||
|
current = *knot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("P1: {}, P2: {}", visited_p1.len(), visited_p2.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn step_head(head: &mut (isize, isize), dir: &str) {
|
||||||
|
match dir {
|
||||||
|
"L" => head.1 -= 1,
|
||||||
|
"R" => head.1 += 1,
|
||||||
|
"U" => head.0 -= 1,
|
||||||
|
"D" => head.0 += 1,
|
||||||
|
invalid => panic!("invalid direction '{}'", invalid),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn follow(
|
||||||
|
idx: usize,
|
||||||
|
head: (isize, isize),
|
||||||
|
tail: &mut (isize, isize),
|
||||||
|
visited_p1: &mut FxHashSet<(isize, isize)>,
|
||||||
|
visited_p2: &mut FxHashSet<(isize, isize)>,
|
||||||
|
) {
|
||||||
|
let diffx = (tail.0 - head.0).abs();
|
||||||
|
let diffy = (tail.1 - head.1).abs();
|
||||||
|
if (diffx == 1 || diffx == 0) && (diffy == 1 || diffy == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
match tail.0.cmp(&head.0) {
|
||||||
|
Ordering::Greater => tail.0 -= 1,
|
||||||
|
Ordering::Less => tail.0 += 1,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
match tail.1.cmp(&head.1) {
|
||||||
|
Ordering::Greater => tail.1 -= 1,
|
||||||
|
Ordering::Less => tail.1 += 1,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
if idx == 0 {
|
||||||
|
visited_p1.insert(*tail);
|
||||||
|
}
|
||||||
|
if idx == 8 {
|
||||||
|
visited_p2.insert(*tail);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "day10"
|
||||||
|
version = "0.1.0"
|
@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "day10"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
@ -0,0 +1,83 @@
|
|||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::io::{self, BufRead, Write};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Operation {
|
||||||
|
opcode: String,
|
||||||
|
arg: Option<isize>,
|
||||||
|
cycles: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
const SIGNAL_TICK_COUNT: usize = 220;
|
||||||
|
const DRAW_CRT: usize = 240;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let lines = io::stdin().lock().lines().map(|l| l.unwrap());
|
||||||
|
|
||||||
|
let mut program: Vec<Operation> = vec![];
|
||||||
|
let mut queue: VecDeque<&Operation> = VecDeque::new();
|
||||||
|
|
||||||
|
for line in lines {
|
||||||
|
let cmd = line.split(' ').collect::<Vec<&str>>();
|
||||||
|
let op = cmd.first().unwrap();
|
||||||
|
let mut arg: Option<isize> = None;
|
||||||
|
|
||||||
|
if let Some(num) = cmd.get(1) {
|
||||||
|
arg = Some(num.parse::<isize>().unwrap());
|
||||||
|
}
|
||||||
|
let cycles = match op {
|
||||||
|
&"noop" => 1,
|
||||||
|
&"addx" => 2,
|
||||||
|
invalid => panic!("invalid opcode {}", invalid),
|
||||||
|
};
|
||||||
|
program.push(Operation {
|
||||||
|
opcode: op.to_string(),
|
||||||
|
arg,
|
||||||
|
cycles,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// init counters, program and queue
|
||||||
|
let mut x = 1;
|
||||||
|
let mut current_op = program.first().unwrap();
|
||||||
|
let mut cycles_remaining_for_current = current_op.cycles;
|
||||||
|
let mut signal_sum = 0;
|
||||||
|
let mut screen = [[false; 40]; 6];
|
||||||
|
|
||||||
|
for (screen_idx, i) in (1..DRAW_CRT + 1).enumerate() {
|
||||||
|
if cycles_remaining_for_current == 0 {
|
||||||
|
if current_op.opcode == "addx" {
|
||||||
|
x += current_op.arg.unwrap();
|
||||||
|
}
|
||||||
|
current_op = queue.pop_front().unwrap();
|
||||||
|
cycles_remaining_for_current = current_op.cycles;
|
||||||
|
}
|
||||||
|
let cmd = program.get(i % program.len()).unwrap();
|
||||||
|
queue.push_back(cmd);
|
||||||
|
cycles_remaining_for_current -= 1;
|
||||||
|
match i {
|
||||||
|
20 | 60 | 100 | 140 | 180 | 220 => signal_sum += x * i as isize,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
let (scrx, scry): (usize, usize) = (screen_idx / 40, screen_idx % 40);
|
||||||
|
screen[scrx][scry] = x == screen_idx as isize % 40
|
||||||
|
|| x - 1 == screen_idx as isize % 40
|
||||||
|
|| x + 1 == screen_idx as isize % 40;
|
||||||
|
|
||||||
|
if i == SIGNAL_TICK_COUNT {
|
||||||
|
println!("{}", signal_sum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw_screen(&screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_screen(screen: &[[bool; 40]; 6]) {
|
||||||
|
let mut lock = io::stdout().lock();
|
||||||
|
for y in 0..6 {
|
||||||
|
for x in 0..40 {
|
||||||
|
write!(lock, "{}", if screen[y][x] { "#" } else { "." }).unwrap()
|
||||||
|
}
|
||||||
|
writeln!(lock).unwrap();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue