Compare commits

...

6 Commits

12 changed files with 482 additions and 0 deletions

View File

@ -0,0 +1,6 @@
[package]
name = "part1"
version = "0.1.0"
edition = "2021"
[dependencies]

View File

@ -0,0 +1,41 @@
fn can_be_evaluated_to_aux(operands: &Vec<u64>, target: u64, current: u64, index: usize) -> bool {
if index == 0 {
return can_be_evaluated_to_aux(operands, target, operands[0], index + 1);
} else if index == operands.len() {
if current == target {
return true;
} else {
return false;
}
} else {
return can_be_evaluated_to_aux(operands, target, current * operands[index], index + 1) || can_be_evaluated_to_aux(operands, target, current + operands[index], index + 1);
}
}
fn can_be_evaluated_to(operands: &Vec<u64>, target: u64) -> bool {
return can_be_evaluated_to_aux(operands, target, 0, 0);
}
fn main() -> std::io::Result<()> {
let mut total: u64 = 0;
for line in std::io::stdin().lines() {
let line = line.unwrap();
if line != "".to_string() {
let mut parts = line.split(":");
let target = parts.next().unwrap();
let target = target.parse::<u64>().unwrap();
let operands: Vec<u64> = parts.next()
.unwrap()
.split(" ")
.skip(1)
.map(|e| e.parse::<u64>().unwrap())
.collect();
if can_be_evaluated_to(&operands, target) {
total += target;
}
}
}
println!("{}", total);
Ok(())
}

View File

@ -0,0 +1,6 @@
[package]
name = "part1"
version = "0.1.0"
edition = "2021"
[dependencies]

View File

@ -0,0 +1,53 @@
fn concatenate_integers(a: u64, b: u64) -> u64 {
let a_str = a.to_string();
let b_str = b.to_string();
let result_str = a_str + &b_str;
let result: u64 = result_str.parse().unwrap();
return result;
}
fn can_be_evaluated_to_aux(operands: &Vec<u64>, target: u64, current: u64, index: usize) -> bool {
if index == 0 {
return can_be_evaluated_to_aux(operands, target, operands[0], index + 1);
} else if index == operands.len() {
if current == target {
return true;
} else {
return false;
}
} else {
return
can_be_evaluated_to_aux(operands, target, current * operands[index], index + 1)
|| can_be_evaluated_to_aux(operands, target, current + operands[index], index + 1)
|| can_be_evaluated_to_aux(operands, target, concatenate_integers(current, operands[index]), index + 1)
;
}
}
fn can_be_evaluated_to(operands: &Vec<u64>, target: u64) -> bool {
return can_be_evaluated_to_aux(operands, target, 0, 0);
}
fn main() -> std::io::Result<()> {
let mut total: u64 = 0;
for line in std::io::stdin().lines() {
let line = line.unwrap();
if line != "".to_string() {
let mut parts = line.split(":");
let target = parts.next().unwrap();
let target = target.parse::<u64>().unwrap();
let operands: Vec<u64> = parts.next()
.unwrap()
.split(" ")
.skip(1)
.map(|e| e.parse::<u64>().unwrap())
.collect();
if can_be_evaluated_to(&operands, target) {
total += target;
}
}
}
println!("{}", total);
Ok(())
}

View File

@ -0,0 +1,6 @@
[package]
name = "part1"
version = "0.1.0"
edition = "2021"
[dependencies]

View File

@ -0,0 +1,66 @@
use std::collections::BTreeSet;
fn get_antinode(x1: usize, y1: usize, x2: usize, y2: usize) -> (isize, isize) {
let dx = x1 as isize - x2 as isize;
let dy: isize = y1 as isize - y2 as isize;
(x1 as isize + dx, y1 as isize + dy)
}
fn is_in_bound(x: isize, y: isize, height: usize, width: usize) -> bool {
return x >= 0 && y >= 0 && y < height as isize && x < width as isize;
}
fn find_antinodes(map: &Vec<Vec<char>>) -> BTreeSet<(usize, usize)> {
let mut antinodes: BTreeSet<(usize, usize)> = BTreeSet::new();
let height = map.len();
let width = map[0].len();
for y1 in 0..map.len() {
for x1 in 0..map[y1].len() {
if map[y1][x1] != '.' {
let antenna = map[y1][x1];
for y2 in 0..map.len() {
for x2 in 0..map[y2].len() {
if !(x1 == x2 || y1 == y2) {
if map[y2][x2] == antenna {
let antinode = get_antinode(x1, y1, x2, y2);
if is_in_bound(antinode.0, antinode.1, height, width) {
let x = antinode.0 as usize;
let y = antinode.1 as usize;
antinodes.insert((x, y));
}
}
}
}
}
}
}
}
antinodes
}
fn main() {
// Read the antenna location map
let mut map: Vec<Vec<char>> = Vec::new();
for line in std::io::stdin().lines() {
let line = line.unwrap();
let mut map_row: Vec<char> = Vec::new();
for letter in line.chars() {
map_row.push(letter);
}
map.push(map_row);
}
// Find antinodes
let antinodes = find_antinodes(&map);
// for y in 0..map.len() {
// print!("\n");
// for x in 0..map[y].len() {
// if antinodes.contains(&(x, y)) {
// print!("{}", '#');
// } else {
// print!("{}", map[y][x]);
// }
// }
// }
println!("{}", antinodes.len());
}

View File

@ -0,0 +1,6 @@
[package]
name = "day09"
version = "0.1.0"
edition = "2021"
[dependencies]

View File

@ -0,0 +1,116 @@
fn descriptor_to_disk(descriptor: String) -> Vec<i64> {
let mut file_index: i64 = 0;
let mut disk: Vec<i64> = Vec::new();
for (i, item) in descriptor.chars().enumerate() {
let item = item.to_digit(10);
if let Some(item) = item {
// If we are on a file
if i % 2 == 0 {
for _ in 0..item {
disk.push(file_index);
}
file_index += 1;
} else {
for _ in 0..item {
disk.push(-1);
}
}
}
}
disk
}
fn fragment(disk: &Vec<i64>) -> Vec<i64> {
let mut disk = disk.clone();
let mut i: usize = 0;
let mut j: usize = disk.len() - 1;
while i < j {
// If there is an empty slot
if disk[i] == -1 {
if disk[j] == -1 {
j -= 1;
} else {
// Swap an empty slot with an occupied slot
let tmp = disk[i];
disk[i] = disk[j];
disk[j] = tmp;
}
} else {
i += 1;
}
}
disk
}
fn move_file(disk: &mut Vec<i64>, file_index: i64, file_length: usize, previous_start: usize, next_start: usize) {
for i in 0..file_length {
disk[previous_start + i] = -1;
}
for i in 0..file_length {
disk[next_start + i] = file_index;
}
}
fn contiguous_empty(disk: &Vec<i64>, start_index: usize, file_length: usize) -> bool {
for i in start_index..(start_index + file_length) {
if i > disk.len() || disk[i] != -1 {
return false;
}
}
return true;
}
fn find_position(disk: &Vec<i64>, start_index: usize, file_length: usize) -> Option<usize> {
for i in 0..start_index {
if disk[i] == -1 && contiguous_empty(disk, i, file_length) {
return Some(i);
}
}
None
}
fn defragment(disk: &Vec<i64>) -> Vec<i64> {
let mut disk = disk.clone();
let max_file_index = disk.iter().cloned().fold(0, i64::max);
let mut file_index = max_file_index;
while file_index >= 0 {
let mut start_index: usize = 0;
while disk[start_index] != file_index {
start_index += 1;
}
let mut file_length: usize = 0;
while start_index + file_length < disk.len() && disk[start_index + file_length] == file_index {
file_length += 1;
}
if let Some(next_index) = find_position(&disk, start_index, file_length) {
move_file(&mut disk, file_index, file_length, start_index, next_index);
}
file_index -= 1;
}
disk
}
fn checksum(disk: &Vec<i64>) -> i64 {
let mut sum = 0;
for (i, item) in disk.iter().enumerate() {
if *item != -1 {
sum += i as i64 * (*item);
}
}
sum
}
fn main() -> std::io::Result<()> {
let disk_descriptor: String = std::io::read_to_string(std::io::stdin())?;
let disk = descriptor_to_disk(disk_descriptor);
// Part 1.
let disk1 = fragment(&disk);
let check1 = checksum(&disk1);
println!("{}", check1);
// Part 2
let disk2 = defragment(&disk);
let check2 = checksum(&disk2);
println!("{}", check2);
Ok(())
}

View File

@ -0,0 +1,6 @@
[package]
name = "day10"
version = "0.1.0"
edition = "2021"
[dependencies]

View File

@ -0,0 +1,96 @@
use std::collections::BTreeSet;
fn parse_map(string: String) -> Vec<Vec<u32>> {
let mut map: Vec<Vec<u32>> = Vec::new();
for line in string.lines() {
let mut map_slice: Vec<u32> = Vec::new();
for letter in line.chars() {
let height: u32 = letter.to_digit(10).unwrap();
map_slice.push(height);
}
map.push(map_slice);
}
map
}
fn is_in_bound(x: isize, y: isize, width: usize, height: usize) -> bool {
x >= 0 && y >= 0 && y < height as isize && x < width as isize
}
fn trailhead_score(start_x: usize, start_y: usize, map: &Vec<Vec<u32>>) -> u32 {
let mut visited: BTreeSet<(usize, usize)> = BTreeSet::new();
let mut score: u32 = 0;
let mut queue: Vec<(usize, usize)> = Vec::new();
queue.push((start_x, start_y));
let moves: [(isize, isize); 4] = [(-1, 0), (0, -1), (1, 0), (0, 1)];
while !queue.is_empty() {
if let Some((x, y)) = queue.pop() {
if map[y][x] == 9 {
score += 1;
}
for (dx, dy) in moves {
let new_x = x as isize + dx;
let new_y = y as isize + dy;
if is_in_bound(new_x, new_y, map[0].len(), map.len())
&& map[new_y as usize][new_x as usize] > map[y][x]
&& map[new_y as usize][new_x as usize] - map[y][x] == 1
&& !visited.contains(&(new_x as usize, new_y as usize)) {
queue.push((new_x as usize, new_y as usize));
}
}
visited.insert((x as usize, y as usize));
}
}
score
}
fn trailhead_paths(x: usize, y: usize, map: &Vec<Vec<u32>>) -> u32 {
if map[y][x] == 9 {
return 1;
} else {
let moves: [(isize, isize); 4] = [(-1, 0), (0, -1), (1, 0), (0, 1)];
let mut paths: u32 = 0;
for (dx, dy) in moves {
let new_x = x as isize + dx;
let new_y = y as isize + dy;
if is_in_bound(new_x, new_y, map[0].len(), map.len())
&& map[new_y as usize][new_x as usize] > map[y][x]
&& map[new_y as usize][new_x as usize] - map[y][x] == 1 {
let p = trailhead_paths(new_x as usize, new_y as usize, map);
paths += p;
}
}
return paths;
}
}
fn find_trailheads(map: &Vec<Vec<u32>>) -> Vec<(usize, usize)> {
let mut trailheads: Vec<(usize, usize)> = Vec::new();
for y in 0..map.len() {
for x in 0..map[y].len() {
if map[y][x] == 0 {
trailheads.push((x, y));
}
}
}
trailheads
}
fn main() -> std::io::Result<()> {
let input = std::io::read_to_string(std::io::stdin())?;
let map = parse_map(input);
let trailheads = find_trailheads(&map);
// Part 1.
let mut score = 0;
for (start_x, start_y) in &trailheads {
score += trailhead_score(*start_x, *start_y, &map);
}
println!("{}", score);
// Part 2.
let mut paths = 0;
for (start_x, start_y) in &trailheads {
paths += trailhead_paths(*start_x, *start_y, &map);
}
println!("{}", paths);
Ok(())
}

View File

@ -0,0 +1,6 @@
[package]
name = "day11"
version = "0.1.0"
edition = "2021"
[dependencies]

View File

@ -0,0 +1,74 @@
use std::collections::HashMap;
fn blink(stone: u64) -> Vec<u64> {
let mut new_stones: Vec<u64> = Vec::new();
if stone == 0 {
new_stones.push(1);
} else {
let stone_str = stone.to_string();
if stone_str.len() % 2 == 0 {
let index: usize = stone_str.len() / 2;
let part1 = &stone_str[..index];
let part2 = &stone_str[index..];
let part1: u64 = part1.parse().unwrap();
let part2: u64 = part2.parse().unwrap();
new_stones.push(part1);
new_stones.push(part2);
} else {
new_stones.push(stone * 2024);
}
}
new_stones
}
fn blink_synchronous(stones: &Vec<u64>) -> Vec<u64> {
let mut new_stones: Vec<u64> = Vec::new();
for &stone in stones {
let mut stone_children = blink(stone);
new_stones.append(&mut stone_children);
}
new_stones
}
fn blink_memory(stone: u64, nb_blinks: usize, blinked: &mut HashMap<(u64, usize), usize>) -> usize {
if nb_blinks == 0 {
return 1;
} else {
if let Some(size) = blinked.get(&(stone, nb_blinks)) {
return *size;
} else {
let mut sum = 0;
for other_stone in blink(stone) {
sum += blink_memory(other_stone, nb_blinks - 1, blinked);
}
blinked.insert((stone, nb_blinks), sum);
return sum;
}
}
}
fn main() -> std::io::Result<()> {
let stones: String = std::io::read_to_string(std::io::stdin())?;
let mut stones: Vec<u64> = stones
.split(" ")
.map(|e| e.parse::<u64>())
.filter(|e| e.is_ok())
.map(|e| e.unwrap()).collect();
stones.push(1);
println!("{:?}", stones);
// Part 1.
let mut current_stones: Vec<u64> = stones.clone();
for _ in 0..25 {
current_stones = blink_synchronous(&current_stones);
}
println!("{}", current_stones.len());
// Part 2.
let mut blinked: HashMap<(u64, usize), usize> = HashMap::new();
let mut sum: usize = 0;
for stone in stones {
let size = blink_memory(stone, 75, &mut blinked);
sum += size;
}
println!("{}", sum);
Ok(())
}