2016, 2017, 2018, 2024 puzzle progress

This commit is contained in:
2025-10-08 13:17:46 -04:00
parent af075edb24
commit e1bdbe21c8
21 changed files with 3658 additions and 43 deletions
+50 -26
View File
@@ -1,5 +1,5 @@
const SCREEN_COLS: usize = 8;
const SCREEN_ROWS: usize = 3;
const SCREEN_COLS: usize = 50;
const SCREEN_ROWS: usize = 6;
const SCREEN_SIZE: usize = SCREEN_COLS * SCREEN_ROWS;
#[derive(Debug, Copy, Clone)]
@@ -17,25 +17,35 @@ struct World {
impl Actions {
// rotate a column 1 time.
fn rotate_column(&self, column_index: u32, target: &mut [bool; SCREEN_SIZE]) {
let first_value = target[column_index as usize];
let mut last_value = false;
for index in (0..SCREEN_COLS).rev() {
let offset = index as u32 * SCREEN_COLS as u32 + column_index;
let next_offset = offset + SCREEN_COLS as u32;
println!("index: {} offset: {} next_offset: {}",
index, offset, next_offset);
last_value = target[offset as usize];
target[offset as usize] = last_value;
fn rotate_column(&self, column_index: usize, target: &mut [bool; SCREEN_SIZE]) {
// Save the bottom value (wrap-around)
let bottom = target[(SCREEN_ROWS - 1) * SCREEN_COLS + column_index];
// Shift everything down
for row in (1..SCREEN_ROWS).rev() {
let from = (row - 1) * SCREEN_COLS + column_index;
let to = row * SCREEN_COLS + column_index;
target[to] = target[from];
}
// Put the old bottom value at the top
target[column_index] = bottom;
}
// rotate a row 1 time.
fn rotate_row(&self, row_index: u32, target: &mut [bool; SCREEN_SIZE]) {
for index in (SCREEN_ROWS..0).rev() {
let offset = index as u32 * SCREEN_COLS as u32 + index as u32;
println!("index = {index} offset = {offset}");
}
// Save the last element of the row
let rightmost = target[(row_index * SCREEN_COLS as u32 + (SCREEN_COLS - 1) as u32) as usize];
// Shift everything to the right
for col in (1..SCREEN_COLS).rev() {
let from = row_index * SCREEN_COLS as u32 + (col - 1) as u32;
let to = row_index * SCREEN_COLS as u32 + col as u32;
target[to as usize] = target[from as usize];
}
// Put the old rightmost value at the start
target[(row_index * SCREEN_COLS as u32) as usize] = rightmost;
}
pub fn apply(&self, target: &mut [bool; SCREEN_SIZE]) {
@@ -61,7 +71,7 @@ impl Actions {
let actual_rotate = distance_to_rotate % 6;
println!("Rotate Column {column_to_rotate} by {distance_to_rotate} ({actual_rotate})");
for _ in 0..*distance_to_rotate {
self.rotate_column(*column_to_rotate, target)
self.rotate_column(*column_to_rotate as usize, target)
}
}
}
@@ -83,13 +93,27 @@ impl Actions {
let (_, axis_to_rotate_s) = axis_stub.split_once('=').unwrap();
let distance_to_rotate = distance_to_rotate_s.parse::<u32>().unwrap();
let axis_to_rotate = axis_to_rotate_s.parse::<u32>().unwrap();
Actions::RotateColumn(axis_to_rotate, distance_to_rotate)
match direction {
"column" => {Actions::RotateColumn(axis_to_rotate, distance_to_rotate)}
"row" => {Actions::RotateRow(axis_to_rotate, distance_to_rotate)}
_ => { unreachable!("Invalid rotation"); }
}
}
_ => {
unreachable!("Invalid command -> [[{input}]]");
}
}
}
pub fn num_lit(body: &[bool; SCREEN_SIZE]) -> u32 {
let mut num_lit = 0;
for index in 0..SCREEN_SIZE {
if body[index] { num_lit += 1; }
}
num_lit
}
}
@@ -97,28 +121,25 @@ fn dump_screen(to_display: &[bool; SCREEN_SIZE]) {
for row in 0..SCREEN_ROWS {
for column in 0..SCREEN_COLS {
let offset = row * SCREEN_COLS + column;
// println!("Rendering offset {offset}");
print!("{}", if to_display[offset] { '#' } else { ' ' });
}
println!();
}
}
use core::read_data;
fn main() {
let mut screen_space:[bool; SCREEN_SIZE] = [false; SCREEN_SIZE];
let mut world = World {
width: 8,
height: 3,
memory: Box::new([false; 8*3]),
};
let directions = vec![
"rect 3x2",
"rotate column x=1 by 1",
"rotate row y=0 by 4",
"rotate column x=1 by 1"
];
let binding = read_data("2016_08_data.txt");
let directions = binding.lines();
for direction in directions {
let parsed = Actions::parse(direction);
@@ -126,6 +147,9 @@ fn main() {
println!("[[{direction}]] -> [[{parsed:?}]]");
dump_screen(&screen_space);
}
println!("There are {} lit.", Actions::num_lit(&screen_space));
}
// 106 lit.
// b> Code is CFLELOYFCS
+3
View File
@@ -0,0 +1,3 @@
fn main() {
println!("The answer is CFLELOYFCS. Part A display showed that.");
}
+1 -1
View File
@@ -56,4 +56,4 @@ fn main() {
}
}
// 138735 ChatGPT held my hand through this as parsing text is not my strong point.
// 138735 ChatGPT held my hand through this as parsing text is not my strong point.
+59
View File
@@ -0,0 +1,59 @@
use std::ptr::hash;
use core::read_data;
/// Calculate the decompressed length of a string.
/// If `recursive` is true, markers are expanded recursively (Part 2).
/// If `recursive` is false, markers are expanded only once (Part 1).
fn decompressed_len(input: &str, recursive: bool) -> usize {
let mut total = 0;
let mut i = 0;
let binding = input.to_ascii_uppercase();
let bytes = binding.as_bytes();
while i < bytes.len() {
if bytes[i] == b'(' {
// find end of marker
let end = input[i..].find(')').unwrap() + i;
let marker = &input[i + 1..end];
let (a, b) = marker.split_once('x').unwrap();
let a: usize = a.parse().unwrap();
let b: usize = b.parse().unwrap();
i = end + 1;
let segment = &input[i..i + a];
let seg_len = if recursive {
decompressed_len(segment, true)
} else {
segment.len()
};
total += seg_len * b;
i += a;
} else {
total += 1;
i += 1;
}
}
total
}
fn main() {
let puzzle_input = read_data("2016_09_data.txt");
let params = vec![
("ADVENT", 6),
("A(1x5)BC", 7),
("(3x3)XYZ", 9),
("A(2x2)BCD(2x2)EFG", 11),
("(6x1)(1x3)A", 6),
("X(8x2)(3x3)ABCY", 18),
(puzzle_input.as_str(), 100)
];
for (input, size) in params {
let decompressed_size = decompressed_len(input, true);
println!("Tested {} char string for expanded size of {} -> Calculated {}", input.len(), size, decompressed_size);
}
}
// 11125026826 ChatGPT held my hand through this as parsing text is not my strong point.
+77
View File
@@ -0,0 +1,77 @@
use std::collections::HashMap;
use core::read_data;
#[derive(Debug)]
enum InputLines {
Distribution { bot_id: u32, low_target: u32, high_target: u32 },
Allocation { bot_id: u32, value: u32 },
}
struct Bot {
id: u32,
values: [u32; 2],
low_target: u32,
high_target: u32
}
impl Default for Bot {
fn default() -> Self {
Bot {
id: u32::MAX,
values: [u32::MAX; 2],
low_target: u32::MAX,
high_target: u32::MAX
}
}
}
fn parse_line(input: &str) -> InputLines {
let parts: Vec<_> = input.split_whitespace().collect();
match parts[0] {
"bot" => {
InputLines::Distribution {
bot_id: parts[1].parse::<u32>().unwrap(),
low_target: parts[6].parse::<u32>().unwrap(),
high_target: parts[11].parse::<u32>().unwrap(),
}
}
"value" => {
InputLines::Allocation {
bot_id: parts[5].parse::<u32>().unwrap(),
value: parts[1].parse::<u32>().unwrap(),
}
}
_ => { unreachable!("") }
}
}
fn main() {
let lines = "value 5 goes to bot 2\nbot 2 gives low to bot 1 and high to bot 0\nvalue 3 goes to bot 1\nbot 1 gives low to output 1 and high to bot 0\nbot 0 gives low to output 2 and high to output 0\nvalue 2 goes to bot 2";
let lines = read_data("2016_10_data.txt");
let mut botmap: HashMap<u32, Bot> = HashMap::new();
for line in lines.lines() {
let parsed = parse_line(line);
match parse_line(line) {
InputLines::Distribution { bot_id, low_target, high_target } => {
// find the bot if it exists...
botmap.entry(bot_id).or_insert(Bot { id: bot_id, values: [0, 0], low_target, high_target } );
}
InputLines::Allocation { bot_id, value: value_new } => {
botmap.entry(bot_id).or_insert(Bot { id: bot_id, values: [0, 0], low_target: 0, high_target: 0 } );
}
}
}
println!("Botmap has {} entries.", botmap.keys().len());
let mut num_2chips = 0;
for (key, bot) in botmap {
println!("Bot ID : {key} / {} & {}", bot.values[0], bot.values[1]);
if bot.values[0] != 0 && bot.values[1] != 0 {
num_2chips += 1;
}
}
println!("Found {num_2chips} bots with 2 chips.");
}
+61
View File
@@ -0,0 +1,61 @@
const NUM_ELVES: u32 = 3014603;
fn next_elf_id(current_elf: u32, elves: &Vec<u32>) -> u32 {
let mut real_return_value: i32 = -1;
while real_return_value < 0 {
let mut working_next = if current_elf + 1 == NUM_ELVES {
0
} else {
current_elf + 1
};
while elves[working_next as usize] == 0 {
working_next += 1;
if working_next == NUM_ELVES {
working_next = 0;
}
}
real_return_value = working_next as i32
}
real_return_value as u32
}
fn main() {
let mut elves = vec![1; NUM_ELVES as usize];
let mut elf_with_presents = -1;
let mut num_loops = 0;
let mut num_with_presents = 0;
while num_with_presents != 1 && num_loops < 80 {
for current_elf in 0..NUM_ELVES {
// if the elf has a present...
if elves[current_elf as usize] > 0 {
let next_elf_id = next_elf_id(current_elf, &elves);
// ...look at the next elf and take their presents.
let num_to_take = elves[next_elf_id as usize];
elves[current_elf as usize] += num_to_take;
let new_total = elves[current_elf as usize];
elves[next_elf_id as usize] = 0;
// println!("Elf {} took {} presents from {} and has {} now.", current_elf + 1, num_to_take, next_elf_id + 1, new_total);
} else {
// println!("Elf {} has no presents and is skipped.", current_elf + 1);
}
}
let mut last_elf = -1i32;
num_with_presents = 0;
last_elf = 0;
for count_elf in 0..NUM_ELVES {
if elves[count_elf as usize] > 0 {
num_with_presents += 1;
last_elf = count_elf as i32;
}
}
println!("There are {num_with_presents} elves with presents. Last ID was {last_elf}");
num_loops += 1;
}
// println!("Elves: {elves:?}");
}
// 1834903
+63
View File
@@ -0,0 +1,63 @@
use std::arch::x86_64::__get_cpuid_max;
use std::io::{stdout, Write};
use core::read_data;
struct Firewall {
blocked_ranges: Vec<(u32, u32)>
}
impl Firewall {
pub fn new() -> Self {
Firewall { blocked_ranges: vec![] }
}
pub fn add_range(&mut self, min: u32, max: u32) {
self.blocked_ranges.push((min, max));
}
/// Check if the target IP is allowed.
pub fn valid(&self, target: u32) -> (bool, u32) {
let mut is_valid = true;
let mut return_max = target + 1;
for (cmin, cmax) in self.blocked_ranges.clone() {
if target <= cmax && target >= cmin {
return_max = cmax;
is_valid = false
}
}
(is_valid, return_max)
}
pub fn add_range_str(&mut self, line: &str) {
let (new_min_s, new_max_s) = line.split_once('-').unwrap();
self.blocked_ranges.push((new_min_s.parse::<u32>().unwrap(), new_max_s.parse::<u32>().unwrap()));
}
}
fn main() {
let binding = read_data("2016_20_data.txt");
let lines = binding.lines();
// let lines = "5-8\n0-2\n4-7".lines();
let mut firewall = Firewall::new();
for line in lines {
firewall.add_range_str(line)
}
println!("Firewall has {} rules.", firewall.blocked_ranges.len());
let mut current_target = 0;
while current_target < i32::MAX {
let (check_result, next_id) = firewall.valid(current_target as u32);
if check_result {
println!("Rule for {current_target} passed.");
break
}
current_target = next_id as i32;
current_target += 1;
if current_target % 10000 == 0 { print!("."); stdout().flush().unwrap() }
}
}
// 4793564
+101
View File
@@ -0,0 +1,101 @@
use std::collections::HashMap;
use std::io::{stdout, Write};
use core::read_data;
struct Firewall {
blocked_ranges: Vec<(u32, u32)>,
}
impl Firewall {
pub fn new() -> Self {
Firewall { blocked_ranges: vec![] }
}
pub fn add_range(&mut self, min: u32, max: u32) {
self.blocked_ranges.push((min, max));
}
/// Check if the target IP is allowed.
pub fn valid(&self, target: u32) -> bool {
let mut is_valid = true;
for (cmin, cmax) in self.blocked_ranges.clone() {
if target <= cmax && target >= cmin {
is_valid = false
}
}
is_valid
}
pub fn add_range_str(&mut self, line: &str) {
let (new_min_s, new_max_s) = line.split_once('-').unwrap();
self.blocked_ranges.push((new_min_s.parse::<u32>().unwrap(), new_max_s.parse::<u32>().unwrap()));
}
pub fn sort_rules(&mut self) {
self.blocked_ranges.sort_by_key(|x| x.0)
}
}
use core::merge_ranges;
use core::format_with_commas;
fn main() {
let binding = read_data("2016_20_data.txt");
let lines = binding.lines();
let mut firewall = Firewall::new();
for line in lines {
print!(".");
stdout().flush().unwrap();
firewall.add_range_str(line);
}
firewall.sort_rules();
println!("Found {} ranges.", firewall.blocked_ranges.len());
let mut working_lines = vec![];
let mut index = 0;
let mut last_num_rows = i32::MAX;
while index < firewall.blocked_ranges.len() - 1 {
let r1 = firewall.blocked_ranges[index];
let r2 = firewall.blocked_ranges[index + 1];
let merge_result = merge_ranges(r1, r2);
match merge_result {
None => {
// println!("NO MERGE -> {}-{} / {}-{}",
// format_with_commas(r1.0),
// format_with_commas(r1.1),
// format_with_commas(r2.0),
// format_with_commas(r2.1));
}
Some(merged) => {
// println!("MERGED -> {}-{} / {}-{} = {}-{}",
// format_with_commas(r1.0),
// format_with_commas(r1.1),
// format_with_commas(r2.0),
// format_with_commas(r2.1),
// format_with_commas(merged.0),
// format_with_commas(merged.1));
working_lines.push(merged);
}
}
index += 1;
}
println!("Went from {} to {}", firewall.blocked_ranges.len(), working_lines.len());
let mut num_blocked = 0u64;
let mut last_max = 0;
for index in 0..working_lines.len() {
let (cmin, cmax) = working_lines[index];
num_blocked += (cmax - cmin) as u64;
last_max = cmax;
}
println!("Found {num_blocked} blocked.");
let allowed = last_max - num_blocked as u32;
println!("Found {allowed} permitted.");
}
// 852102276 too high
// 851631862