2016, 2017, 2018, 2024 puzzle progress
This commit is contained in:
+50
-26
@@ -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
|
||||
@@ -0,0 +1,3 @@
|
||||
fn main() {
|
||||
println!("The answer is CFLELOYFCS. Part A display showed that.");
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
@@ -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.");
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user