Last active
December 11, 2023 10:32
-
-
Save sqrtM/81037698c63dc2c0cf5ba2437b3d1511 to your computer and use it in GitHub Desktop.
aoc2023 (sometimes just the part 2s oops)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
🦀🦀🦀🦀🦀🦀🦀🦀🦀 | |
🦀🦀🦀🦀🦀🦀🦀🦀🦀 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::fs::File; | |
use std::io::{self, BufRead}; | |
use std::path::Path; | |
fn main() { | |
let mut final_answer = 0; | |
if let Ok(lines) = read_lines("input.txt") { | |
for line in lines { | |
if let Ok(unparsed_value) = line { | |
let v = unparsed_value | |
.replace("one", "o1e") | |
.replace("two", "t2o") | |
.replace("three", "t3e") | |
.replace("four", "f4r") | |
.replace("five", "f5e") | |
.replace("six", "s6x") | |
.replace("seven", "s7n") | |
.replace("eight", "e8t") | |
.replace("nine", "n9e"); | |
let mut numerals: Vec<i32> = vec![]; | |
for (_, c) in v.chars().enumerate() { | |
if c.is_numeric() { | |
numerals.push(c.to_string().parse::<i32>().unwrap()) | |
} | |
} | |
let first = *numerals.get(0).unwrap(); | |
let last = numerals.pop().unwrap(); | |
numerals = vec![first, last]; | |
let result = numerals.iter().fold(0, |acc, elem| acc * 10 + elem); | |
final_answer += result; | |
} | |
} | |
} | |
println!("{}", final_answer); | |
} | |
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> | |
where P: AsRef<Path>, { | |
let file = File::open(filename)?; | |
Ok(io::BufReader::new(file).lines()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
use std::fs::File; | |
use std::io::{self, BufRead}; | |
use std::path::Path; | |
use regex::Regex; | |
fn main() { | |
let mut games: HashMap<i32, HashMap<&str, i32>> = HashMap::new(); | |
let game_regex = Regex::new(r"^Game (?<digit>\d+): ").unwrap(); | |
let color_regex = Regex::new(r"(?P<number>\d+)\s*(?P<color>\w+)").unwrap(); | |
if let Ok(lines) = read_lines("input.txt") { | |
for line in lines.flatten() { | |
let mut red = 0; | |
let mut blue = 0; | |
let mut green = 0; | |
let _: Vec<_> = game_regex | |
.replace_all(&line, "") | |
.split(';') | |
.collect::<Vec<&str>>() | |
.iter() | |
.map(|set| { | |
let game_number = game_regex | |
.captures(&line) | |
.unwrap() | |
.name("digit") | |
.unwrap() | |
.as_str() | |
.parse::<i32>() | |
.unwrap(); | |
for capture in color_regex.captures_iter(set) { | |
let color = capture.name("color").unwrap().as_str(); | |
let number = capture.name("number").unwrap().as_str().parse::<i32>().unwrap(); | |
match color { | |
"red" => { | |
if number > red { | |
red = number | |
} | |
} | |
"blue" => { | |
if number > blue { | |
blue = number | |
} | |
} | |
"green" => { | |
if number > green { | |
green = number | |
} | |
} | |
_ => {} | |
} | |
} | |
let mut colors = HashMap::new(); | |
colors.insert("red", red); | |
colors.insert("blue", blue); | |
colors.insert("green", green); | |
games.insert(game_number, colors); | |
}) | |
.collect(); | |
} | |
} | |
let power = games.iter().fold(0, |acc, x| { | |
println!("outer -> {:?}", acc); | |
acc + x.1.iter().fold(1, |bdd, y| { | |
println!("inner -> {:?}", bdd); | |
bdd * y.1 | |
}) | |
}); | |
println!("power {:?}", power) | |
} | |
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> | |
where P: AsRef<Path>, { | |
let file = File::open(filename)?; | |
Ok(io::BufReader::new(file).lines()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
use std::fs::File; | |
use std::io::{self, BufRead}; | |
use std::path::Path; | |
fn main() { | |
if let Ok(lines) = read_lines("input.txt") { | |
let mut engine_rows: Vec<Vec<char>> = vec![]; | |
for line in lines.flatten() { | |
engine_rows.push(line.chars().collect::<Vec<char>>()); | |
} | |
//find_part_numbers(&engine_rows); | |
find_gears(&engine_rows); | |
} | |
} | |
fn find_part_numbers(arr: &[Vec<char>]) { | |
let mut part_numbers: HashMap<(usize, usize), i32> = HashMap::new(); | |
for (i, line) in arr.iter().enumerate() { | |
for (j, char) in line.iter().enumerate() { | |
// found a number | |
if char.is_numeric() && find_adjacent_symbol(arr, i, j) { | |
let val = get_value(arr, i, j); | |
part_numbers.insert(val.0, val.1); | |
} | |
} | |
} | |
println!("{}", part_numbers.values().sum::<i32>()); | |
} | |
fn find_gears(arr: &[Vec<char>]) { | |
let mut part_numbers: Vec<i32> = vec![]; | |
for (i, line) in arr.iter().enumerate() { | |
for (j, char) in line.iter().enumerate() { | |
// found a gear | |
if *char == '*' { | |
// find numbers | |
let nums = find_adjacent_numerals(arr, i, j); | |
if !nums.is_empty() { | |
println!("found {} numerals around the gear at {} {} -> {:?}", nums.len(), i, j, nums); | |
let r = nums | |
.iter() | |
.map(|num| num.1) | |
.collect::<Vec<i32>>() | |
.iter() | |
.product::<i32>(); | |
part_numbers.push(r); | |
} | |
} | |
} | |
} | |
println!("{:?}", part_numbers.iter().sum::<i32>()); | |
} | |
fn find_adjacent_symbol(arr: &[Vec<char>], i: usize, j: usize) -> bool { | |
// search above | |
if i > 0 { | |
for k in usize::saturating_sub(j, 1)..usize::saturating_add(j, 2) { | |
if k <= arr[i - 1].len() && !arr[i - 1].get(k).unwrap_or(&'1').is_numeric() && *arr[i - 1].get(k).unwrap_or(&'.') as i32 != 46 { | |
// found a symbol | |
return true; | |
} | |
} | |
} | |
// search same line | |
for k in usize::saturating_sub(j, 1)..usize::saturating_add(j, 2) { | |
if k <= arr[i].len() && !arr[i].get(k).unwrap_or(&'1').is_numeric() && *arr[i].get(k).unwrap_or(&'.') as i32 != 46 { | |
// found a symbol | |
return true; | |
} | |
} | |
// search below | |
if i < arr.len() - 1 { | |
for k in usize::saturating_sub(j, 1)..usize::saturating_add(j, 2) { | |
if k <= arr[i + 1].len() && !arr[i + 1].get(k).unwrap_or(&'1').is_numeric() && *arr[i + 1].get(k).unwrap_or(&'.') as i32 != 46 { | |
// found a symbol | |
return true; | |
} | |
} | |
} | |
false | |
} | |
fn find_adjacent_numerals(arr: &[Vec<char>], i: usize, j: usize) -> Vec<((usize, usize), i32)> { | |
let mut numerals: Vec<((usize, usize), i32)> = vec![]; | |
// search above | |
if i > 0 { | |
for k in usize::saturating_sub(j, 1)..usize::saturating_add(j, 2) { | |
if k <= arr[i - 1].len() && arr[i - 1].get(k).unwrap_or(&'.').is_numeric() { | |
// found a symbol | |
let num = get_value(arr, i - 1, k); | |
numerals.push(num); | |
} | |
} | |
} | |
// search same line | |
for k in usize::saturating_sub(j, 1)..usize::saturating_add(j, 2) { | |
if k <= arr[i].len() && arr[i].get(k).unwrap_or(&'.').is_numeric() { | |
// found a symbol | |
let num = get_value(arr, i, k); | |
numerals.push(num); | |
} | |
} | |
// search below | |
if i < arr.len() - 1 { | |
for k in usize::saturating_sub(j, 1)..usize::saturating_add(j, 2) { | |
if k <= arr[i + 1].len() && arr[i + 1].get(k).unwrap_or(&'.').is_numeric() { | |
// found a symbol | |
let num = get_value(arr, i + 1, k); | |
numerals.push(num); | |
} | |
} | |
} | |
numerals.dedup(); | |
if numerals.len() == 2 { | |
numerals | |
} else { | |
vec![] | |
} | |
} | |
fn get_value(arr: &[Vec<char>], i: usize, j: usize) -> ((usize, usize), i32) { | |
let mut value: Vec<i32> = vec![]; | |
if j > 0 && arr[i].get(usize::saturating_sub(j, 1)).unwrap().is_numeric() { | |
return get_value(arr, i, usize::saturating_sub(j, 1)); | |
} else { | |
let mut index = j; | |
while arr[i].get(index).unwrap_or(&'.').is_numeric() { | |
value.push(arr[i][index].to_digit(10).unwrap() as i32); | |
index += 1; | |
} | |
} | |
((i, j), value.iter().fold(0, |acc, elem| acc * 10 + elem)) | |
} | |
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> | |
where P: AsRef<Path>, { | |
let file = File::open(filename)?; | |
Ok(io::BufReader::new(file).lines()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
use std::fs::File; | |
use std::io::{self, BufRead}; | |
use std::path::Path; | |
use regex::Regex; | |
fn main() { | |
one(); | |
two(); | |
} | |
fn two() { | |
let mut copies: HashMap<i32, i32> = HashMap::new(); | |
for i in 1..=196 { | |
copies.insert(i, 1); | |
} | |
if let Ok(lines) = read_lines("input.txt") { | |
for line in lines.flatten() { | |
let card_number = Regex::new(r"\bCard\s+(?P<game_number>\d+): ") | |
.unwrap().captures(&line) | |
.and_then(|captures| captures.name("game_number")) | |
.and_then(|match_| match_.as_str().parse().ok()) | |
.unwrap(); | |
let vecs = vecify(&line); | |
let matches = vecs[0].iter().filter(|&x| vecs[1].contains(x)).collect::<Vec<_>>().len() as i32; | |
for i in card_number + 1..=card_number + matches { | |
let val = copies.get(&i).unwrap(); | |
copies.insert(i, val + copies.get(&card_number).unwrap()); | |
} | |
} | |
} | |
println!("{:?}", copies.values().sum::<i32>()); | |
} | |
fn one() { | |
let mut total_score = 0; | |
if let Ok(lines) = read_lines("input.txt") { | |
for line in lines.flatten() { | |
let vecs = vecify(&line); | |
let matches = vecs[0].iter().filter(|&x| vecs[1].contains(x)).collect::<Vec<_>>(); | |
let ticket_score: i32 = 2_i32.pow(matches.len().saturating_sub(1) as u32); | |
if !matches.is_empty() { | |
total_score += ticket_score; | |
} | |
} | |
} | |
println!("{:?}", total_score); | |
} | |
fn vecify(line: &str) -> Vec<Vec<i32>> { | |
Regex::new(r"\bCard\s+(?P<game_number>\d+): ") | |
.unwrap() | |
.replace_all(line, "") | |
.split(" | ") | |
.map( | |
|s| s.split(' ').filter_map( | |
|y| y.parse::<i32>().ok()).collect() | |
) | |
.collect() | |
} | |
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> | |
where P: AsRef<Path>, { | |
let file = File::open(filename)?; | |
Ok(io::BufReader::new(file).lines()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::fs::File; | |
use std::io::{self, BufRead}; | |
use std::ops::Range; | |
use std::path::Path; | |
use std::sync::{Arc, Mutex}; | |
use rayon::iter::ParallelIterator; | |
use rayon::prelude::ParallelSlice; | |
#[derive(Default, Debug, Clone)] | |
struct Almanac { | |
destination: u64, | |
source: u64, | |
modifier: u64, | |
} | |
impl Almanac { | |
fn from_vec(vec: Vec<u64>) -> Self { | |
Self { | |
destination: vec[0], | |
source: vec[1], | |
modifier: vec[2], | |
} | |
} | |
fn incoming_range(&self) -> Range<u64> { | |
self.source..(self.source + self.modifier) | |
} | |
} | |
fn main() { | |
let mut almanacs: Vec<Vec<Almanac>> = vec![vec![]; 7]; | |
let mut seeds: Vec<u64> = vec![]; | |
let mut almanac_index: i32 = -1; | |
if let Ok(lines) = read_lines("input.txt") { | |
// ignore the parsing i know it's ugly its AOC give me a break | |
for line in lines.flatten() { | |
if line.contains("seeds:") { | |
seeds = line | |
.split(' ') | |
.filter_map(|x| x.parse().ok()) | |
.collect(); | |
} | |
if line.contains("map") { | |
almanac_index += 1; | |
continue; | |
} | |
if almanac_index < 0 || line.trim().is_empty() { | |
continue; | |
} | |
let arr = line | |
.split(' ') | |
.map(|x| x.parse::<u64>().unwrap()) | |
.collect::<Vec<u64>>(); | |
almanacs[almanac_index as usize].push(Almanac::from_vec(arr)); | |
} | |
} | |
let nearest_location = Arc::new(Mutex::new(u64::MAX)); | |
seeds.par_chunks(2).for_each(|chunk| { | |
println!("new chunk"); | |
let local_nearest_location = Arc::clone(&nearest_location); | |
let range = chunk[0]..(chunk[0] + chunk[1]); | |
for number in range { | |
let value = traverse(&number, &almanacs, 0); | |
let mut lock = local_nearest_location.lock().unwrap(); | |
if value < *lock { | |
*lock = value; | |
println!("new lowest: {}", *lock) | |
} | |
} | |
}); | |
let nearest_location_value = *nearest_location.lock().unwrap(); | |
println!("ANSWER: {}", nearest_location_value) | |
} | |
fn traverse(seed: &u64, almanacs: &[Vec<Almanac>], iteration: usize) -> u64 { | |
if iteration == almanacs.len() { | |
return *seed; | |
} | |
for almanac in &almanacs[iteration] { | |
if almanac.incoming_range().contains(seed) { | |
let new_seed = (seed - almanac.source) + almanac.destination; | |
return traverse(&new_seed, almanacs, iteration + 1); | |
} | |
} | |
traverse(seed, almanacs, iteration + 1) | |
} | |
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> | |
where P: AsRef<Path>, { | |
let file = File::open(filename)?; | |
Ok(io::BufReader::new(file).lines()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::fs::File; | |
use std::io::{self, BufRead}; | |
use std::path::Path; | |
use regex::Regex; | |
const TIME: usize = 0; | |
const DIST: usize = 1; | |
fn main() { | |
one(); | |
two(); | |
} | |
fn two() { | |
if let Ok(lines) = read_lines("input.txt") { | |
let mut race_stats: Vec<u64> = vec![]; | |
for line in lines.flatten() { | |
// this should just .zip, i'm dumb | |
let num = Regex::new(r"\b\d+\b") | |
.unwrap() | |
.find_iter(&line) | |
.map(|mat| mat.as_str()) | |
.collect::<String>() | |
.parse::<u64>() | |
.unwrap(); | |
race_stats.push(num) | |
} | |
let mut possible_solutions: Vec<u64> = vec![]; | |
for t in 1..race_stats[TIME] { | |
let distance_travelled = t * (race_stats[TIME] - t); | |
if distance_travelled > race_stats[DIST] { | |
possible_solutions.push(distance_travelled); | |
} | |
if distance_travelled < *possible_solutions.last().unwrap_or(&0) { | |
break; | |
} | |
} | |
println!("{:?}", possible_solutions.len()); | |
} | |
} | |
fn one() { | |
if let Ok(lines) = read_lines("input.txt") { | |
let mut time_distance: Vec<Vec<i32>> = vec![]; | |
for line in lines.flatten() { | |
let numerals: Vec<i32> = Regex::new(r"\b\d+\b") | |
.unwrap() | |
.find_iter(&line) | |
.map(|mat| mat.as_str().parse().unwrap()) | |
.collect(); | |
time_distance.push(numerals); | |
} | |
let mut possible_solutions: Vec<Vec<i32>> = vec![]; | |
for (index, td) in time_distance[TIME].iter().enumerate() { | |
possible_solutions.push(vec![]); | |
for t in 1..*td { | |
let distance_travelled = t * (td - t); | |
if distance_travelled > time_distance[DIST][index] { | |
possible_solutions[index].push(distance_travelled); | |
} | |
if distance_travelled < *possible_solutions[index].last().unwrap_or(&0) { | |
break; | |
} | |
} | |
} | |
println!("{:?}", possible_solutions.iter().map(|x| x.len()).product::<usize>()); | |
} | |
} | |
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> | |
where P: AsRef<Path>, { | |
let file = File::open(filename)?; | |
Ok(io::BufReader::new(file).lines()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
use std::fs::File; | |
use std::io::{self, BufRead}; | |
use std::path::Path; | |
use crate::HandType::{ | |
FiveOfAKind, FourOfAKind, FullHouse, HighCard, OnePair, ThreeOfAKind, TwoPair, | |
}; | |
const PRIORITY: [char; 13] = [ | |
'J', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'Q', 'K', 'A', | |
]; | |
#[derive(PartialOrd, PartialEq, Debug)] | |
enum HandType { | |
FiveOfAKind = 6, | |
FourOfAKind = 5, | |
FullHouse = 4, | |
ThreeOfAKind = 3, | |
TwoPair = 2, | |
OnePair = 1, | |
HighCard = 0, | |
} | |
#[derive(Debug, PartialEq, Eq)] | |
struct Hand { | |
cards: [char; 5], | |
bid: i32, | |
} | |
impl Hand { | |
fn from_slice(slice: &[char], bid: i32) -> Self { | |
Self { | |
cards: <[char; 5]>::try_from(slice).unwrap(), | |
bid, | |
} | |
} | |
} | |
impl PartialOrd for Hand { | |
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { | |
Some(self.cmp(other)) | |
} | |
} | |
impl Ord for Hand { | |
fn cmp(&self, other: &Self) -> std::cmp::Ordering { | |
let self_score = score_hand(self); | |
let other_score = score_hand(other); | |
if self_score != other_score { | |
return (self_score as usize).cmp(&(other_score as usize)); | |
} | |
// if same type -> get high card | |
for (&self_card, &other_card) in self.cards.iter().zip(other.cards.iter()) { | |
if self_card != other_card { | |
return PRIORITY | |
.iter() | |
.position(|&x| x == self_card) | |
.cmp(&PRIORITY.iter().position(|&x| x == other_card)); | |
} | |
} | |
std::cmp::Ordering::Equal | |
} | |
} | |
fn main() { | |
let mut hands: Vec<Hand> = vec![]; | |
if let Ok(lines) = read_lines("input.txt") { | |
for line in lines.flatten() { | |
let parsed = line.split(' ').collect::<Vec<&str>>(); | |
let cards = parsed.first().unwrap().chars().collect::<Vec<char>>(); | |
let bid: i32 = parsed.get(1).unwrap().parse().unwrap(); | |
let hand = Hand::from_slice(&cards, bid); | |
hands.push(hand); | |
} | |
} | |
hands.sort(); | |
println!( | |
"{:?}", | |
hands | |
.iter() | |
.enumerate() | |
.map(|(i, h)| h.bid * (i + 1) as i32) | |
.sum::<i32>() | |
); | |
} | |
fn score_hand(hand: &Hand) -> HandType { | |
let mut hand_map = HashMap::new(); | |
hand.cards.iter().for_each(|x| { | |
let c = hand.cards.iter().filter(|n| n == &x).count(); | |
hand_map.insert(x, c); | |
}); | |
let jokers = hand_map.get(&'J').unwrap_or(&0); | |
// doing it like this was such a mistake, wow | |
return match hand_map.values().max().unwrap() { | |
5 => FiveOfAKind, | |
4 => { | |
return if jokers == &1usize || jokers == &4usize { | |
FiveOfAKind | |
} else { | |
FourOfAKind | |
}; | |
} | |
3 => { | |
return if hand_map.values().len() == 2 { | |
if jokers == &2usize || jokers == &3usize { | |
FiveOfAKind | |
} else { | |
FullHouse | |
} | |
} else if jokers == &1usize { | |
FourOfAKind | |
} else { | |
ThreeOfAKind | |
}; | |
} | |
2 => { | |
return if hand_map.values().len() == 3 { | |
if jokers == &2usize { | |
FourOfAKind | |
} else if jokers == &1usize { | |
FullHouse | |
} else { | |
TwoPair | |
} | |
} else if jokers == &1usize || jokers == &2usize { | |
ThreeOfAKind | |
} else { | |
OnePair | |
}; | |
} | |
1 => { | |
return if jokers == &1usize { OnePair } else { HighCard }; | |
} | |
_ => { | |
panic!() | |
} | |
}; | |
} | |
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> | |
where | |
P: AsRef<Path>, | |
{ | |
let file = File::open(filename)?; | |
Ok(io::BufReader::new(file).lines()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::fs::File; | |
use std::io::{self, BufRead}; | |
use std::path::Path; | |
use num::integer::lcm; | |
use regex::Regex; | |
use crate::Direction::{L, R}; | |
#[derive(Debug)] | |
struct Node { | |
name: String, | |
looking_for_left: String, | |
looking_for_right: String, | |
left: Option<Box<Node>>, | |
right: Option<Box<Node>>, | |
} | |
#[derive(PartialEq, Debug)] | |
enum Direction { | |
L, | |
R, | |
} | |
impl Direction { | |
fn from_str(input: char) -> Self { | |
if input == 'L' { | |
L | |
} else { | |
R | |
} | |
} | |
} | |
impl Node { | |
fn from_str(input: &str) -> Self { | |
let regex = | |
Regex::new(r#"^(?P<name>\w{3})\s*=\s*\((?P<left>\w{3}),\s*(?P<right>\w{3})\)$"#) | |
.unwrap(); | |
let name = regex | |
.captures(input) | |
.unwrap() | |
.name("name") | |
.unwrap() | |
.as_str(); | |
let left = regex | |
.captures(input) | |
.unwrap() | |
.name("left") | |
.unwrap() | |
.as_str(); | |
let right = regex | |
.captures(input) | |
.unwrap() | |
.name("right") | |
.unwrap() | |
.as_str(); | |
Self { | |
name: String::from(name), | |
looking_for_left: String::from(left), | |
looking_for_right: String::from(right), | |
left: None, | |
right: None, | |
} | |
} | |
fn populate(&mut self, direction: &Direction) { | |
// reading from the input like this each time was a pretty big mistake, | |
// and led to really slow execution time, but it does work... | |
if let Ok(lines) = read_lines("input.txt") { | |
for line in lines.flatten() { | |
let fmt_dir = if direction == &L { | |
format!("{} ", self.looking_for_left) | |
} else { | |
format!("{} ", self.looking_for_right) | |
}; | |
if direction == &R && line.contains(&fmt_dir) && self.right.is_none() { | |
self.right = Some(Box::new(Node::from_str(&line))); | |
} | |
if direction == &L && line.contains(&fmt_dir) && self.left.is_none() { | |
self.left = Some(Box::new(Node::from_str(&line))); | |
} | |
} | |
} | |
} | |
fn traverse(self, direction: &Direction) -> Box<Node> { | |
if direction == &L { | |
self.left.unwrap() | |
} else { | |
self.right.unwrap() | |
} | |
} | |
} | |
fn main() { | |
//one(); | |
two() | |
} | |
fn two() { | |
let directions: Vec<Direction> = get_directions() | |
.unwrap() | |
.chars() | |
.map(Direction::from_str) | |
.collect(); | |
let starting_points = find_starting_points().unwrap(); | |
let mut cycle = directions.iter().cycle(); | |
let time_to_reach_z = starting_points | |
.into_iter() | |
.map(|mut x| { | |
let mut steps: u64 = 0; | |
while !x.name.ends_with('Z') { | |
if let Some(dir) = cycle.next() { | |
x.populate(dir); | |
x = *x.traverse(dir); | |
steps += 1; | |
} | |
} | |
steps | |
}) | |
.collect::<Vec<u64>>(); | |
println!( | |
"FINAL ANSWER : {:?}", | |
time_to_reach_z.into_iter().fold(1, lcm) | |
); | |
} | |
fn one() { | |
let directions: Vec<Direction> = get_directions() | |
.unwrap() | |
.chars() | |
.map(Direction::from_str) | |
.collect(); | |
let first_node = find_aaa().unwrap(); | |
let mut cycle = directions.iter().cycle(); | |
let mut current_location = Box::new(first_node); | |
let mut steps = 0; | |
// slow but it works | |
while current_location.name != "ZZZ" { | |
if let Some(dir) = cycle.next() { | |
current_location.populate(dir); | |
current_location = current_location.traverse(dir); | |
steps += 1; | |
} | |
} | |
println!("{}", steps); | |
} | |
fn find_aaa() -> Result<Node, ()> { | |
if let Ok(lines) = read_lines("input.txt") { | |
for line in lines.flatten() { | |
if line.contains("AAA =") { | |
return Ok(Node::from_str(&line)); | |
} | |
} | |
Err(()) | |
} else { | |
Err(()) | |
} | |
} | |
fn find_starting_points() -> Result<Vec<Node>, ()> { | |
let mut nodes: Vec<Node> = vec![]; | |
if let Ok(lines) = read_lines("input.txt") { | |
for line in lines.flatten() { | |
if line.contains("A =") { | |
nodes.push(Node::from_str(&line)); | |
} | |
} | |
Ok(nodes) | |
} else { | |
Err(()) | |
} | |
} | |
fn get_directions() -> Option<String> { | |
if let Ok(lines) = read_lines("input.txt") { | |
for line in lines.flatten().enumerate() { | |
if line.0 == 0 { | |
return Some(line.1); | |
} | |
} | |
} | |
None | |
} | |
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> | |
where | |
P: AsRef<Path>, | |
{ | |
let file = File::open(filename)?; | |
Ok(io::BufReader::new(file).lines()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::fs::File; | |
use std::io::{self, BufRead}; | |
use std::path::Path; | |
fn main() { | |
if let Ok(lines) = read_lines("input.txt") { | |
let v: Vec<(i64, i64)> = lines | |
.flatten() | |
.map(|line| { | |
let mut vals: Vec<i64> = line.split(' ').flat_map(str::parse).collect(); | |
let mut lasts: Vec<i64> = vec![]; | |
let mut firsts: Vec<i64> = vec![]; | |
while vals.iter().any(|&x| x != 0) { | |
firsts.push(*vals.first().unwrap()); | |
lasts.push(*vals.last().unwrap()); | |
vals = vals.windows(2).map(|w| w[1] - w[0]).collect(); | |
} | |
( | |
firsts.into_iter().rev().reduce(|acc, x| x - acc).unwrap(), | |
lasts.iter().sum::<i64>(), | |
) | |
}) | |
.collect::<Vec<(i64, i64)>>(); | |
println!("past : {}", v.iter().map(|x| x.0).sum::<i64>()); | |
println!("future: {}", v.iter().map(|x| x.1).sum::<i64>()); | |
} | |
} | |
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> | |
where | |
P: AsRef<Path>, | |
{ | |
let file = File::open(filename)?; | |
Ok(io::BufReader::new(file).lines()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::collections::HashMap; | |
use std::fs::File; | |
use std::io::{self, BufRead}; | |
use std::path::Path; | |
use crate::Direction::{E, N, S, W}; | |
use crate::PipeType::{ | |
EastToWest, Ground, NorthToEast, NorthToSouth, NorthToWest, SouthToEast, SouthToWest, | |
StartingPoint, | |
}; | |
// Just part one for today. | |
fn main() { | |
if let Ok(lines) = read_lines("input.txt") { | |
let map = lines | |
.flatten() | |
.enumerate() | |
.flat_map(|(y, line)| { | |
line.chars() | |
.enumerate() | |
.map(|(x, char)| ((x, y), Pipe::from_char_and_coords(&char, x, y))) | |
.collect::<Vec<((usize, usize), Pipe)>>() | |
}) | |
.collect::<HashMap<(usize, usize), Pipe>>(); | |
let answer = map.traverse( | |
Animal { | |
x: map.find_starting_point().0, | |
y: map.find_starting_point().1, | |
facing: E, | |
}, | |
0, | |
); | |
println!("{:?}", (answer + 1) / 2); | |
} | |
} | |
trait Traverse { | |
fn traverse(&self, animal: Animal, steps: u32) -> u32; | |
fn find_starting_point(&self) -> (usize, usize); | |
fn facing_location(&self, animal: &Animal) -> (usize, usize) { | |
match animal.facing { | |
N => (animal.x, animal.y - 1), | |
S => (animal.x, animal.y + 1), | |
E => (animal.x + 1, animal.y), | |
W => (animal.x - 1, animal.y), | |
} | |
} | |
} | |
impl Traverse for HashMap<(usize, usize), Pipe> { | |
fn traverse(&self, animal: Animal, steps: u32) -> u32 { | |
let facing_pipe = self.get(&self.facing_location(&animal)).unwrap(); | |
let new_data = facing_pipe.slide(&animal); | |
if !facing_pipe.is_starting_point() { | |
self.traverse( | |
Animal { | |
x: new_data.0 .0, | |
y: new_data.0 .1, | |
facing: new_data.1, | |
}, | |
steps + 1, | |
) | |
} else { | |
steps | |
} | |
} | |
fn find_starting_point(&self) -> (usize, usize) { | |
self.iter() | |
.find_map(|(_, pipe)| { | |
if pipe.is_starting_point() { | |
Some(pipe.coords()) | |
} else { | |
None | |
} | |
}) | |
.unwrap() | |
} | |
} | |
#[derive(Debug, Copy, Clone)] | |
enum PipeType { | |
StartingPoint, | |
NorthToSouth, | |
EastToWest, | |
NorthToEast, | |
NorthToWest, | |
SouthToWest, | |
SouthToEast, | |
Ground, | |
} | |
#[derive(Debug)] | |
struct Pipe { | |
x: usize, | |
y: usize, | |
kind: PipeType, | |
} | |
#[derive(Debug)] | |
enum Direction { | |
N, | |
S, | |
E, | |
W, | |
} | |
#[derive(Debug)] | |
struct Animal { | |
x: usize, | |
y: usize, | |
facing: Direction, | |
} | |
impl Pipe { | |
fn is_starting_point(&self) -> bool { | |
match self.kind { | |
StartingPoint => true, | |
NorthToSouth | EastToWest | NorthToEast | NorthToWest | SouthToWest | SouthToEast | |
| Ground => false, | |
} | |
} | |
fn from_char_and_coords(char: &char, x: usize, y: usize) -> Self { | |
match char { | |
'S' => Self { | |
x, | |
y, | |
kind: StartingPoint, | |
}, | |
'|' => Self { | |
x, | |
y, | |
kind: NorthToSouth, | |
}, | |
'-' => Self { | |
x, | |
y, | |
kind: EastToWest, | |
}, | |
'L' => Self { | |
x, | |
y, | |
kind: NorthToEast, | |
}, | |
'J' => Self { | |
x, | |
y, | |
kind: NorthToWest, | |
}, | |
'7' => Self { | |
x, | |
y, | |
kind: SouthToWest, | |
}, | |
'F' => Self { | |
x, | |
y, | |
kind: SouthToEast, | |
}, | |
'.' => Self { x, y, kind: Ground }, | |
_ => panic!(), | |
} | |
} | |
fn coords(&self) -> (usize, usize) { | |
(self.x, self.y) | |
} | |
fn slide(&self, animal: &Animal) -> ((usize, usize), Direction) { | |
match animal.facing { | |
N => match self.kind { | |
NorthToSouth => ((animal.x, animal.y - 1), N), | |
SouthToEast => ((animal.x, animal.y - 1), E), | |
SouthToWest => ((animal.x, animal.y - 1), W), | |
_ => ((animal.x, animal.y), N), | |
}, | |
S => match self.kind { | |
NorthToSouth => ((animal.x, animal.y + 1), S), | |
NorthToEast => ((animal.x, animal.y + 1), E), | |
NorthToWest => ((animal.x, animal.y + 1), W), | |
_ => ((animal.x, animal.y), S), | |
}, | |
E => match self.kind { | |
EastToWest => ((animal.x + 1, animal.y), E), | |
NorthToWest => ((animal.x + 1, animal.y), N), | |
SouthToWest => ((animal.x + 1, animal.y), S), | |
_ => ((animal.x, animal.y), E), | |
}, | |
W => match self.kind { | |
EastToWest => ((animal.x - 1, animal.y), W), | |
NorthToEast => ((animal.x - 1, animal.y), N), | |
SouthToEast => ((animal.x - 1, animal.y), S), | |
_ => ((animal.x, animal.y), W), | |
}, | |
} | |
} | |
} | |
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> | |
where | |
P: AsRef<Path>, | |
{ | |
let file = File::open(filename)?; | |
Ok(io::BufReader::new(file).lines()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use itertools::Itertools; | |
use std::collections::HashSet; | |
use std::fs::File; | |
use std::io::{self, BufRead}; | |
use std::path::Path; | |
// this didn't actually get the right answer | |
// but i don't have any more time to work on | |
// this and it DID get the right answer for | |
// the test input so ¯\_(ツ)_/¯ | |
fn main() { | |
if let Ok(lines) = read_lines("input.txt") { | |
let original_map = lines | |
.flatten() | |
.map(|line| line.chars().collect::<Vec<char>>()) | |
.collect::<Vec<Vec<char>>>(); | |
let empty_rows = original_map | |
.iter() | |
.enumerate() | |
.filter(|(_, row)| row.iter().all(|ch| ch == &'.')) | |
.collect::<Vec<(usize, &Vec<char>)>>() | |
.iter() | |
.map(|(i, _)| *i) | |
.collect::<Vec<usize>>(); | |
let empty_cols = (0..original_map[0].len()) | |
.map(|col| { | |
original_map | |
.iter() | |
.map(|row| row[col]) | |
.collect::<Vec<char>>() | |
}) | |
.collect::<Vec<Vec<char>>>() | |
.iter() | |
.enumerate() | |
.filter(|(_, column)| column.iter().all(|ch| ch == &'.')) | |
.collect::<Vec<(usize, &Vec<char>)>>() | |
.iter() | |
.map(|(i, _)| *i) | |
.collect::<Vec<usize>>(); | |
let mut expanded_map = original_map.clone(); | |
// this shows a certain immaturity i have when I solve | |
// questions like this. as i was solving this, i felt | |
// the need to create a whole new physical representation | |
// of the data i was manipulating rather than just running | |
// the points through calculations and getting the diffs | |
// abstractly. that "create a physical representation" | |
// instinct is something i know i need to work on. | |
for i in 0..original_map.len() + empty_rows.len() { | |
let mut added_rows = 0; | |
if empty_rows.contains(&i) { | |
added_rows += 1; | |
expanded_map.insert(i + added_rows, vec!['.'; original_map[0].len()]) | |
} | |
let mut added_cols = 0; | |
for j in 0..expanded_map[i].len() { | |
if empty_cols.contains(&j) { | |
added_cols += 1; | |
expanded_map[i].insert(j + added_cols, '.'); | |
} | |
} | |
} | |
let mut set: HashSet<(usize, usize)> = HashSet::new(); | |
expanded_map.iter().enumerate().for_each(|(i, row)| { | |
row.iter().enumerate().for_each(|(j, c)| { | |
if c == &'#' { | |
set.insert((i, j)); | |
} | |
}) | |
}); | |
let mut distances = vec![]; | |
for (x, y) in set.iter().tuple_combinations() { | |
distances.push(manhattan(x, y)) | |
} | |
for map in expanded_map { | |
println!("{:?}", map); | |
} | |
println!("{:?}", empty_cols); | |
println!("{:?}", empty_rows); | |
println!("{:?}", set.len()); | |
println!("{:?}", distances.iter().sum::<usize>()) | |
/* | |
9546608 -- too high | |
*/ | |
} | |
} | |
fn manhattan((x1, y1): &(usize, usize), (x2, y2): &(usize, usize)) -> usize { | |
println!( | |
"{:?} -- {:?} -- {:?}", | |
(x1, y1), | |
(x2, y2), | |
(*x2 as isize - *x1 as isize).unsigned_abs() + (*y2 as isize - *y1 as isize).unsigned_abs() | |
); | |
(*x2 as isize - *x1 as isize).unsigned_abs() + (*y2 as isize - *y1 as isize).unsigned_abs() | |
} | |
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> | |
where | |
P: AsRef<Path>, | |
{ | |
let file = File::open(filename)?; | |
Ok(io::BufReader::new(file).lines()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment