Compare commits
6 Commits
fd47622c68
...
8367b63c53
Author | SHA1 | Date |
---|---|---|
|
8367b63c53 | |
|
9347243eee | |
|
2ad18dce23 | |
|
7901645c55 | |
|
4619aaf4ed | |
|
ea51b3091d |
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "part1"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
|
@ -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(())
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "part1"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
|
@ -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(())
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "part1"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
|
@ -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());
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "day09"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
|
@ -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(())
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "day10"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
|
@ -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(())
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "day11"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
|
@ -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(¤t_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(())
|
||||
}
|
Loading…
Reference in New Issue