Compare commits

...

19 Commits

Author SHA1 Message Date
f00d2805fd day 15 2022-12-26 17:29:38 -07:00
b705b68051 finally finish day 9 part 2 2022-12-26 14:36:04 -07:00
205ecb4acc day 25 2022-12-25 20:42:52 -07:00
a97522988a unify addSand implementations 2022-12-18 21:18:45 -05:00
30cb6c5cd6 day fourteen 2022-12-18 21:15:26 -05:00
2e1d7e2f84 day 11 2022-12-17 18:13:43 -05:00
2ba25a192c day 10 2022-12-17 17:08:09 -05:00
54c81ba1ca part 2 done; just did it the hard way 2022-12-08 20:29:02 -05:00
ae55b29ff4 day8part1 done... part 2 might require another approach 2022-12-08 19:47:08 -05:00
0cb9b68971 add clarifying comment on where to_delete comes from 2022-12-07 22:18:08 -05:00
5426357cd7 simplify rust code somewhat 2022-12-07 22:16:15 -05:00
5809d442da and part 2 2022-12-07 22:12:24 -05:00
7aa2025dff day 7 part 1 in rust! 2022-12-07 22:07:18 -05:00
82a1ecab7d day 7. gave up on fighting the borrow checker after three hours and wrote the go version in 45 minutes. 2022-12-07 20:03:26 -05:00
10eca9d419 day six 2022-12-06 08:36:27 -05:00
b0f72b2230 day 5. most of the work here was getting the parsing right 2022-12-05 08:35:47 -05:00
c875ec5826 remove all those unwraps and just index directly into the vector 2022-12-04 19:25:13 -05:00
c3a6c3d117 day four is done and kinda dull to actually work through 2022-12-04 19:16:05 -05:00
fc2099c14c simplify priority math 2022-12-03 09:36:44 -05:00
21 changed files with 2118 additions and 14 deletions

View File

@@ -43,11 +43,7 @@ fn part_one() {
}
for item in pocket_two.chars() {
if knapsack.contains_key(&item) {
if item as u32 > 96 {
priorities += item as u32 - 96
} else {
priorities += item as u32 - 38
}
priorities += (item as u32 - 38) % 58;
break;
}
}
@@ -78,12 +74,8 @@ fn part_two() {
HashSet::from_iter(one.intersection(three));
let mut result = intermediate_one.intersection(&intermediate_two);
if let Some(item) = result.next() {
// double pointers!
if **item as u32 > 96 {
priorities += **item as u32 - 96
} else {
priorities += **item as u32 - 38
}
// double pointer!
priorities += (**item as u32 - 38) % 58;
}
}
group.clear();

75
04/main.rs Normal file
View File

@@ -0,0 +1,75 @@
#![allow(dead_code)]
use std::fs::File;
use std::io;
use std::io::BufRead;
use std::path::Path;
use std::time::Instant;
fn main() {
let now = Instant::now();
part_one();
let part_one_duration = now.elapsed();
part_two();
let part_two_duration = now.elapsed();
println!(
"p1: {}ms, p2: {}ms",
part_one_duration.as_millis(),
(part_two_duration - part_one_duration).as_millis()
);
}
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where
P: AsRef<Path>,
{
// note that this discards a final newline
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
fn part_one() {
if let Ok(lines) = read_lines("./inputs/input") {
let mut overlaps = 0;
for line in lines {
if let Ok(ranges) = line {
let v: Vec<Vec<i8>> = ranges
.split(",")
.map(|r| r.split("-").map(|i| i.parse::<i8>().unwrap()).collect())
.collect();
// 00 ... 01
// 10 ... 11
if (v[0][0] <= v[1][0] && v[0][1] >= v[1][1])
|| (v[1][0] <= v[0][0] && v[1][1] >= v[0][1])
{
overlaps += 1;
}
}
}
println!("{}", overlaps);
}
}
fn part_two() {
if let Ok(lines) = read_lines("./inputs/input") {
let mut overlaps = 0;
for line in lines {
if let Ok(ranges) = line {
let v: Vec<Vec<i8>> = ranges
.split(",")
.map(|r| r.split("-").map(|i| i.parse::<i8>().unwrap()).collect())
.collect();
// 00 ... 01
// 10 ... 11
// uuuuuugh
if (v[0][0] <= v[1][0] && v[0][1] >= v[1][1])
|| (v[1][0] <= v[0][0] && v[1][1] >= v[0][1])
|| (v[0][0] <= v[1][1] && v[0][0] >= v[1][0])
|| (v[0][1] >= v[1][0] && v[0][1] <= v[1][1])
{
overlaps += 1;
}
}
}
println!("{}", overlaps);
}
}

115
05/main.rs Normal file
View File

@@ -0,0 +1,115 @@
#![allow(dead_code)]
use std::collections::VecDeque;
use std::fs::File;
use std::io;
use std::io::BufRead;
use std::path::Path;
use std::time::Instant;
fn main() {
let now = Instant::now();
part_one();
let part_one_duration = now.elapsed();
part_two();
let part_two_duration = now.elapsed();
println!(
"p1: {}ms, p2: {}ms",
part_one_duration.as_millis(),
(part_two_duration - part_one_duration).as_millis()
);
}
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where
P: AsRef<Path>,
{
// note that this discards a final newline
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
fn part_one() {
if let Ok(lines) = read_lines("./inputs/input") {
let mut stacks = vec![VecDeque::<char>::new(); 9];
let mut lines_parsed = 0;
for line in lines {
lines_parsed += 1;
// build our stacks...
if lines_parsed < 9 {
if let Ok(stack) = line {
for (i, s) in stack.chars().enumerate() {
if (i % 4) == 1 && s != ' ' {
// we load in from the head, so the end of the vec is the "top" of the stack
stacks[(i / 4)].push_front(s)
}
}
continue;
}
}
if lines_parsed < 11 {
continue; // skip the break
}
// ok, so now we need to move the crates around
if let Ok(instruction) = line {
let steps = instruction.split(" ").collect::<Vec<&str>>();
let (mut count, from, to) = (
steps[1].parse::<usize>().unwrap(),
steps[3].parse::<usize>().unwrap(),
steps[5].parse::<usize>().unwrap(),
);
while count > 0 {
let c = stacks[from - 1].pop_back().unwrap();
stacks[to - 1].push_back(c);
count -= 1;
}
}
}
let mut result = "".to_string();
for mut s in stacks {
result.push(s.pop_back().unwrap());
}
println!("{}", result);
}
}
fn part_two() {
if let Ok(lines) = read_lines("./inputs/input") {
let mut stacks = vec![VecDeque::<char>::new(); 9];
let mut lines_parsed = 0;
for line in lines {
lines_parsed += 1;
// build our stacks...
if lines_parsed < 9 {
if let Ok(stack) = line {
for (i, s) in stack.chars().enumerate() {
if (i % 4) == 1 && s != ' ' {
// we load in from the head, so the end of the vec is the "top" of the stack
stacks[(i / 4)].push_front(s)
}
}
continue;
}
}
if lines_parsed < 11 {
continue; // skip the break
}
// ok, so now we need to move the crates around
if let Ok(instruction) = line {
let steps = instruction.split(" ").collect::<Vec<&str>>();
let (count, from, to) = (
steps[1].parse::<usize>().unwrap(),
steps[3].parse::<usize>().unwrap(),
steps[5].parse::<usize>().unwrap(),
);
let s = stacks[from - 1].len();
let mut c = stacks[from - 1].split_off(s - count);
stacks[to - 1].append(&mut c);
}
}
let mut result = "".to_string();
for mut s in stacks {
result.push(s.pop_back().unwrap());
}
println!("{}", result);
}
}

85
06/main.rs Normal file
View File

@@ -0,0 +1,85 @@
#![allow(dead_code)]
use std::collections::VecDeque;
use std::fs::File;
use std::io;
use std::io::BufRead;
use std::path::Path;
use std::time::Instant;
fn main() {
let now = Instant::now();
part_one();
let part_one_duration = now.elapsed();
part_two();
let part_two_duration = now.elapsed();
println!(
"p1: {}ms, p2: {}ms",
part_one_duration.as_millis(),
(part_two_duration - part_one_duration).as_millis()
);
}
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where
P: AsRef<Path>,
{
// note that this discards a final newline
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
fn part_one() {
if let Ok(mut lines) = read_lines("./inputs/input") {
if let Some(Ok(signal)) = lines.next() {
let mut buf = VecDeque::<char>::new();
for (i, c) in signal.chars().enumerate() {
if buf.len() < 3 {
// start of stream
buf.push_back(c);
continue;
} else if buf.contains(&c)
|| buf[0] == buf[1]
|| buf[1] == buf[2]
|| buf[2] == buf[0]
{
// repeated character
buf.pop_front();
buf.push_back(c);
} else {
// found it; offset to the next character
println!("{}", i + 1);
return;
}
}
}
}
}
fn part_two() {
if let Ok(mut lines) = read_lines("./inputs/input") {
if let Some(Ok(signal)) = lines.next() {
let mut buf = VecDeque::<char>::new();
for (i, c) in signal.chars().enumerate() {
if buf.len() < 13 {
// start of stream
buf.push_back(c);
continue;
} else if buf.contains(&c)
|| (1..buf.len()).any(|i| {
buf.range(i..)
.collect::<VecDeque<&char>>()
.contains(&&buf[i - 1]) // neat trick
})
{
// repeated character
buf.pop_front();
buf.push_back(c);
} else {
// found it; offset to the next character
println!("{}", i + 1);
return;
}
}
}
}
}

162
07/main.go Normal file
View File

@@ -0,0 +1,162 @@
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"time"
)
func mustAtoi(line string) int {
i, _ := strconv.Atoi(line)
return i
}
func main() {
start := time.Now()
partOne()
duration := time.Since(start)
partTwo()
duration2 := time.Since(start)
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
}
func makeScanner(test bool) *bufio.Scanner {
var f *os.File
if test {
f, _ = os.Open("inputs/testinput")
} else {
f, _ = os.Open("inputs/input")
}
reader := bufio.NewReader(f)
return bufio.NewScanner(reader)
}
type Folder struct {
name string
files map[string]int
folders map[string]*Folder
size int
}
func partOne() {
scanner := makeScanner(false)
root := Folder{
name: "/",
files: map[string]int{},
folders: map[string]*Folder{},
}
sum := 0
stack := []*Folder{&root}
for scanner.Scan() {
line := scanner.Text()
switch {
case line == "$ cd /": // don't care
continue
case line == "$ ls": // definitely don't care
continue
case line == "$ cd ..":
// since we're done in that child, compute it's size.
curr := stack[len(stack)-1]
for _, size := range curr.files {
curr.size += size
}
for _, f := range curr.folders {
curr.size += f.size
}
if curr.size <= 100000 {
sum += curr.size
}
// pop off stack
stack = stack[0 : len(stack)-1]
case strings.HasPrefix(line, "$ cd "): // descend into folder
stack = append(stack, stack[len(stack)-1].folders[strings.Split(line, " ")[2]])
case strings.HasPrefix(line, "dir "): // add directory to current folder
name := strings.Split(line, " ")[1]
stack[len(stack)-1].folders[name] = &Folder{
name: name,
files: map[string]int{},
folders: map[string]*Folder{},
}
default: // add file to current folder
stack[len(stack)-1].files[strings.Split(line, " ")[1]] = mustAtoi(strings.Split(line, " ")[0])
}
}
// finish computing directory sizes
for len(stack) > 0 {
curr := stack[len(stack)-1]
for _, size := range curr.files {
curr.size += size
}
for _, f := range curr.folders {
curr.size += f.size
}
stack = stack[0 : len(stack)-1]
}
fmt.Println(sum)
}
func partTwo() {
scanner := makeScanner(false)
root := Folder{
name: "/",
files: map[string]int{},
folders: map[string]*Folder{},
}
spaceToFree := 30000000 - (70000000 - 49192532) // size of all files, precomputed
toDelete := 70000000
stack := []*Folder{&root}
for scanner.Scan() {
line := scanner.Text()
switch {
case line == "$ cd /": // don't care
continue
case line == "$ ls": // definitely don't care
continue
case line == "$ cd ..":
// since we're done in that child, compute it's size.
curr := stack[len(stack)-1]
for _, size := range curr.files {
curr.size += size
}
for _, f := range curr.folders {
curr.size += f.size
}
if curr.size > spaceToFree && curr.size < toDelete {
toDelete = curr.size
}
// pop off stack
stack = stack[0 : len(stack)-1]
case strings.HasPrefix(line, "$ cd "): // descend into folder
stack = append(stack, stack[len(stack)-1].folders[strings.Split(line, " ")[2]])
case strings.HasPrefix(line, "dir "): // add directory to current folder
name := strings.Split(line, " ")[1]
stack[len(stack)-1].folders[name] = &Folder{
name: name,
files: map[string]int{},
folders: map[string]*Folder{},
}
default: // add file to current folder
stack[len(stack)-1].files[strings.Split(line, " ")[1]] = mustAtoi(strings.Split(line, " ")[0])
}
}
// finish computing directory sizes
for len(stack) > 0 {
curr := stack[len(stack)-1]
for _, size := range curr.files {
curr.size += size
}
for _, f := range curr.folders {
curr.size += f.size
}
if curr.size > spaceToFree && curr.size < toDelete {
toDelete = curr.size
}
stack = stack[0 : len(stack)-1]
}
fmt.Println(toDelete)
}

97
07/main.rs Normal file
View File

@@ -0,0 +1,97 @@
#![allow(dead_code)]
use std::fs::File;
use std::io;
use std::io::BufRead;
use std::path::Path;
use std::time::Instant;
fn main() {
let now = Instant::now();
part_one();
let part_one_duration = now.elapsed();
part_two();
let part_two_duration = now.elapsed();
println!(
"p1: {}ms, p2: {}ms",
part_one_duration.as_millis(),
(part_two_duration - part_one_duration).as_millis()
);
}
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where
P: AsRef<Path>,
{
// note that this discards a final newline
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
fn part_one() {
if let Ok(lines) = read_lines("./inputs/input") {
let mut sum = 0;
let mut stack: Vec<u32> = vec![0];
for line in lines {
if let Ok(command) = line {
match command.as_str() {
"$ cd /" => continue, // skip start
"$ ls" => continue, // we can assume this if we're not moving between directories
s if s.starts_with("dir ") => continue, // we'll get there when we `cd`
"$ cd .." => {
let f = stack.pop().unwrap();
if f < 100000 {
sum += f
}
let last_on_stack = stack.len() - 1;
stack[last_on_stack] += f;
}
s if s.starts_with("$ cd ") => {
stack.push(0);
}
s => {
// otherwise it must be a file
let mut sp = s.split(" ");
let last_on_stack = stack.len() - 1;
stack[last_on_stack] += sp.next().unwrap().parse::<u32>().unwrap();
}
};
}
}
println!("{:?}", sum);
}
}
fn part_two() {
if let Ok(lines) = read_lines("./inputs/input") {
let mut stack: Vec<u32> = vec![0];
let space_to_free = 30000000 - (70000000 - 49192532); // size of all files, precomputed
let mut to_delete = 70000000; // arbitrarily large
for line in lines {
if let Ok(command) = line {
match command.as_str() {
"$ cd /" => continue, // skip start
"$ ls" => continue, // we can assume this if we're not moving between directories
s if s.starts_with("dir ") => continue, // we'll get there when we `cd`
"$ cd .." => {
let f = stack.pop().unwrap();
if f > space_to_free && f < to_delete {
to_delete = f
}
let last_on_stack = stack.len() - 1;
stack[last_on_stack] += f;
}
s if s.starts_with("$ cd ") => {
stack.push(0);
}
s => {
// otherwise it must be a file
let mut sp = s.split(" ");
let last_on_stack = stack.len() - 1;
stack[last_on_stack] += sp.next().unwrap().parse::<u32>().unwrap();
}
};
}
}
println!("{:?}", to_delete);
}
}

147
08/main.rs Normal file
View File

@@ -0,0 +1,147 @@
#![allow(dead_code)]
use std::fs::File;
use std::io;
use std::io::BufRead;
use std::path::Path;
use std::time::Instant;
#[derive(Debug, Clone, Copy)]
struct Tree(i8, bool); // height, visible from outside
fn main() {
let now = Instant::now();
part_one();
let part_one_duration = now.elapsed();
part_two();
let part_two_duration = now.elapsed();
println!(
"p1: {}ms, p2: {}ms",
part_one_duration.as_millis(),
(part_two_duration - part_one_duration).as_millis()
);
}
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where
P: AsRef<Path>,
{
// note that this discards a final newline
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
fn part_one() {
let mut grid: Vec<Vec<Tree>> = vec![];
let mut total = 0;
if let Ok(lines) = read_lines("./inputs/input") {
for (i, line) in lines.enumerate() {
if let Ok(row) = line {
grid.push(vec![]);
let mut max = -1;
for c in row.chars() {
if (c as i8) - 48 > max {
total += 1;
max = (c as i8) - 48;
grid[i].push(Tree((c as i8) - 48, true));
} else {
grid[i].push(Tree((c as i8) - 48, false));
}
}
max = -1;
let invert = grid[i].len() - 1;
for (j, t) in grid[i].clone().iter().rev().enumerate() {
if t.0 > max {
if !grid[i][invert - j].1 {
total += 1;
}
max = t.0;
grid[i][invert - j] = Tree(t.0, true);
}
}
}
}
}
let invert = grid.len() - 1;
for i in 0..grid.len() {
let mut in_max = -1;
let mut out_max = -1;
for j in 0..grid.len() {
if grid[j][i].0 > in_max {
if !grid[j][i].1 {
total += 1;
}
in_max = grid[j][i].0;
grid[j][i] = Tree(grid[j][i].0, true);
}
if grid[invert - j][i].0 > out_max {
if !grid[invert - j][i].1 {
total += 1;
}
out_max = grid[invert - j][i].0;
grid[invert - j][i] = Tree(grid[invert - j][i].0, true);
}
}
}
println!("{}", total);
}
fn part_two() {
let mut grid: Vec<Vec<Tree>> = vec![];
let mut best = 0;
if let Ok(lines) = read_lines("./inputs/input") {
for (i, line) in lines.enumerate() {
if let Ok(row) = line {
grid.push(vec![]);
for c in row.chars() {
grid[i].push(Tree((c as i8) - 48, false));
}
}
}
}
// alright, we'll do this the hard way
// we can skip the edges, because they all multiply by 0 in one way or another
for i in 1..grid.len() - 1 {
for j in 1..grid.len() - 1 {
let (mut score, mut acc) = (1, 0); // a base score and the counter we'll reuse
for x in (0..j).rev() {
// left
acc += 1;
if grid[i][x].0 >= grid[i][j].0 {
break;
}
}
score *= acc;
acc = 0;
for x in (0..i).rev() {
// up
acc += 1;
if grid[x][j].0 >= grid[i][j].0 {
break;
}
}
score *= acc;
acc = 0;
for x in (j + 1)..grid.len() {
// right
acc += 1;
if grid[i][x].0 >= grid[i][j].0 {
break;
}
}
score *= acc;
acc = 0;
for x in (i + 1)..grid.len() {
// down
acc += 1;
if grid[x][j].0 >= grid[i][j].0 {
break;
}
}
score *= acc;
if score > best {
best = score;
}
}
}
println!("{}", best);
}

179
09/main.go Normal file
View File

@@ -0,0 +1,179 @@
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"time"
)
func mustAtoi(line string) int {
i, _ := strconv.Atoi(line)
return i
}
func main() {
start := time.Now()
partOne()
duration := time.Since(start)
partTwo()
duration2 := time.Since(start)
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
}
func makeScanner(test bool) *bufio.Scanner {
var f *os.File
if test {
f, _ = os.Open("inputs/testinput")
} else {
f, _ = os.Open("inputs/input")
}
reader := bufio.NewReader(f)
return bufio.NewScanner(reader)
}
type coord struct {
x int
y int
}
func moveNextKnot(parent, child *coord) {
if parent.y-child.y == 2 {
child.y++
if parent.x-child.x == 2 {
child.x++
} else if child.x-parent.x == 2 {
child.x--
} else {
child.x = parent.x
}
}
if child.y-parent.y == 2 {
child.y--
if parent.x-child.x == 2 {
child.x++
} else if child.x-parent.x == 2 {
child.x--
} else {
child.x = parent.x
}
}
if parent.x-child.x == 2 {
child.x++
if parent.y-child.y == 2 {
child.y++
} else if child.y-parent.y == 2 {
child.y--
} else {
child.y = parent.y
}
}
if child.x-parent.x == 2 {
child.x--
if parent.y-child.y == 2 {
child.y++
} else if child.y-parent.y == 2 {
child.y--
} else {
child.y = parent.y
}
}
}
func displayGrid(rope []coord) {
for x := 0; x < 10; x++ {
for y := 0; y < 10; y++ {
printed := false
for k, c := range rope {
if c.x == x && c.y == y && !printed {
printed = true
if k == 0 {
fmt.Print("H")
} else {
fmt.Print(k)
}
}
}
if !printed {
fmt.Print(".")
}
}
fmt.Println()
}
}
func partOne() {
scanner := makeScanner(false)
grid := map[coord]bool{{x: 0, y: 0}: true}
head := coord{x: 0, y: 0}
tail := coord{x: 0, y: 0}
for scanner.Scan() {
line := scanner.Text()
l := strings.Split(line, " ")
direction, steps := l[0], mustAtoi(l[1])
for i := 0; i < steps; i++ {
switch direction {
case "U":
head.y++
case "D":
head.y--
case "L":
head.x--
case "R":
head.x++
default:
panic("oh no")
}
moveNextKnot(&head, &tail)
grid[tail] = true
}
}
fmt.Println(len(grid))
}
func partTwo() {
scanner := makeScanner(false)
grid := map[coord]bool{{x: 0, y: 0}: true}
rope := []coord{
{x: 0, y: 0},
{x: 0, y: 0},
{x: 0, y: 0},
{x: 0, y: 0},
{x: 0, y: 0},
{x: 0, y: 0},
{x: 0, y: 0},
{x: 0, y: 0},
{x: 0, y: 0},
{x: 0, y: 0},
}
for scanner.Scan() {
line := scanner.Text()
l := strings.Split(line, " ")
direction, steps := l[0], mustAtoi(l[1])
for i := 0; i < steps; i++ {
switch direction {
case "U":
rope[0].y++
case "D":
rope[0].y--
case "L":
rope[0].x--
case "R":
rope[0].x++
default:
panic("oh no")
}
for i := 0; i < 9; i++ {
moveNextKnot(&rope[i], &rope[i+1])
}
grid[rope[9]] = true
}
}
fmt.Println(len(grid))
}

193
09/main.rs Normal file
View File

@@ -0,0 +1,193 @@
#![allow(dead_code)]
use std::collections::HashMap;
use std::fs::File;
use std::io;
use std::io::BufRead;
use std::path::Path;
use std::time::Instant;
#[derive(Debug, Eq, Hash, PartialEq, Copy, Clone)]
struct Coord(i32, i32);
fn main() {
let now = Instant::now();
part_one();
let part_one_duration = now.elapsed();
part_two();
let part_two_duration = now.elapsed();
println!(
"p1: {}ms, p2: {}ms",
part_one_duration.as_millis(),
(part_two_duration - part_one_duration).as_millis()
);
}
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where
P: AsRef<Path>,
{
// note that this discards a final newline
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
fn part_one() {
let mut grid = HashMap::<Coord, bool>::new();
let (mut head_x, mut head_y) = (0, 0);
let (mut tail_x, mut tail_y) = (0, 0);
grid.insert(Coord(0, 0), true);
if let Ok(lines) = read_lines("./inputs/input") {
for line in lines {
if let Ok(m) = line {
let mut i = m.split(" ");
let dir = i.next().unwrap();
let steps = i.next().unwrap().parse::<i32>().unwrap();
match dir {
"U" => {
for _ in 0..steps {
head_y += 1;
(tail_x, tail_y) = update_tail(head_x, head_y, tail_x, tail_y);
grid.insert(Coord(tail_x, tail_y), true);
}
}
"D" => {
for _ in 0..steps {
head_y -= 1;
(tail_x, tail_y) = update_tail(head_x, head_y, tail_x, tail_y);
grid.insert(Coord(tail_x, tail_y), true);
}
}
"L" => {
for _ in 0..steps {
head_x -= 1;
(tail_x, tail_y) = update_tail(head_x, head_y, tail_x, tail_y);
grid.insert(Coord(tail_x, tail_y), true);
}
}
"R" => {
for _ in 0..steps {
head_x += 1;
(tail_x, tail_y) = update_tail(head_x, head_y, tail_x, tail_y);
grid.insert(Coord(tail_x, tail_y), true);
}
}
_ => {
println!("unknown instruction {:?}", m);
}
}
}
}
}
println!("{}", grid.len());
}
fn part_two() {
let mut grid = HashMap::<Coord, bool>::new();
let mut knots: Vec<Coord> = vec![
Coord(0, 0),
Coord(0, 0),
Coord(0, 0),
Coord(0, 0),
Coord(0, 0),
Coord(0, 0),
Coord(0, 0),
Coord(0, 0),
Coord(0, 0),
Coord(0, 0),
];
if let Ok(lines) = read_lines("./inputs/input") {
for line in lines {
if let Ok(m) = line {
let mut i = m.split(" ");
let dir = i.next().unwrap();
let steps = i.next().unwrap().parse::<i32>().unwrap();
match dir {
"U" => {
for _ in 0..steps {
knots[0] = Coord(knots[0].0, knots[0].1 + 1);
for j in 0..9 {
let (tail_x, tail_y) = update_tail(
knots[j].0,
knots[j].1,
knots[j + 1].0,
knots[j + 1].1,
);
knots[j + 1] = Coord(tail_x, tail_y);
}
grid.insert(knots[9], true);
}
}
"D" => {
for _ in 0..steps {
knots[0] = Coord(knots[0].0, knots[0].1 - 1);
for j in 0..9 {
let (tail_x, tail_y) = update_tail(
knots[j].0,
knots[j].1,
knots[j + 1].0,
knots[j + 1].1,
);
knots[j + 1] = Coord(tail_x, tail_y);
}
grid.insert(knots[9], true);
}
}
"L" => {
for _ in 0..steps {
knots[0] = Coord(knots[0].0 - 1, knots[0].1);
for j in 0..9 {
let (tail_x, tail_y) = update_tail(
knots[j].0,
knots[j].1,
knots[j + 1].0,
knots[j + 1].1,
);
knots[j + 1] = Coord(tail_x, tail_y);
}
grid.insert(knots[9], true);
}
}
"R" => {
for _ in 0..steps {
knots[0] = Coord(knots[0].0 + 1, knots[0].1);
for j in 0..9 {
let (tail_x, tail_y) = update_tail(
knots[j].0,
knots[j].1,
knots[j + 1].0,
knots[j + 1].1,
);
knots[j + 1] = Coord(tail_x, tail_y);
}
grid.insert(knots[9], true);
}
}
_ => {
println!("unknown instruction {:?}", m);
}
}
}
}
}
println!("{}", grid.len());
}
fn update_tail(head_x: i32, head_y: i32, mut tail_x: i32, mut tail_y: i32) -> (i32, i32) {
if head_y - tail_y == 2 {
tail_y += 1;
tail_x = head_x;
}
if tail_y - head_y == 2 {
tail_y -= 1;
tail_x = head_x;
}
if head_x - tail_x == 2 {
tail_x += 1;
tail_y = head_y;
}
if tail_x - head_x == 2 {
tail_x -= 1;
tail_y = head_y;
}
return (tail_x, tail_y);
}

111
10/main.go Normal file
View File

@@ -0,0 +1,111 @@
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"time"
)
func mustAtoi(line string) int {
i, _ := strconv.Atoi(line)
return i
}
func main() {
start := time.Now()
partOne()
duration := time.Since(start)
partTwo()
duration2 := time.Since(start)
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
}
func makeScanner(test bool) *bufio.Scanner {
var f *os.File
if test {
f, _ = os.Open("inputs/testinput")
} else {
f, _ = os.Open("inputs/input")
}
reader := bufio.NewReader(f)
return bufio.NewScanner(reader)
}
func partOne() {
scanner := makeScanner(false)
register := 1
cycleCount := 0
signalStrength := 0
for scanner.Scan() {
line := scanner.Text()
switch {
case line == "noop":
cycleCount++
if cycleCount%40 == 20 {
signalStrength += (cycleCount) * register
}
default:
s := strings.Split(line, " ")
x := mustAtoi(s[1])
cycleCount++
if cycleCount%40 == 20 {
signalStrength += (cycleCount) * register
}
cycleCount++
if cycleCount%40 == 20 {
signalStrength += (cycleCount) * register
}
register += x
}
}
fmt.Println(signalStrength)
}
func partTwo() {
scanner := makeScanner(false)
screen := make([]string, 241)
register := 1
cycleCount := 0
for scanner.Scan() {
line := scanner.Text()
switch {
case line == "noop":
if register == cycleCount%40 || register-1 == cycleCount%40 || register+1 == cycleCount%40 {
screen[cycleCount] = "#"
} else {
screen[cycleCount] = "."
}
cycleCount++
default:
s := strings.Split(line, " ")
x := mustAtoi(s[1])
if register == cycleCount%40 || register-1 == cycleCount%40 || register+1 == cycleCount%40 {
screen[cycleCount] = "#"
} else {
screen[cycleCount] = "."
}
cycleCount++
if register == cycleCount%40 || register-1 == cycleCount%40 || register+1 == cycleCount%40 {
screen[cycleCount] = "#"
} else {
screen[cycleCount] = "."
}
cycleCount++
register += x
}
}
fmt.Println(screen[1:40])
fmt.Println(screen[41:80])
fmt.Println(screen[81:120])
fmt.Println(screen[121:160])
fmt.Println(screen[161:200])
fmt.Println(screen[201:240])
}

38
10/main.rs Normal file
View File

@@ -0,0 +1,38 @@
#![allow(dead_code)]
use std::fs::File;
use std::io;
use std::io::BufRead;
use std::path::Path;
use std::time::Instant;
fn main() {
let now = Instant::now();
part_one();
let part_one_duration = now.elapsed();
part_two();
let part_two_duration = now.elapsed();
println!(
"p1: {}ms, p2: {}ms",
part_one_duration.as_millis(),
(part_two_duration - part_one_duration).as_millis()
);
}
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where
P: AsRef<Path>,
{
// note that this discards a final newline
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
fn part_one() {
if let Ok(lines) = read_lines("./inputs/input") {
for line in lines {
// do stuff
}
}
}
fn part_two() {}

201
11/main.go Normal file
View File

@@ -0,0 +1,201 @@
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"time"
)
func mustAtoi(line string) int {
i, _ := strconv.Atoi(line)
return i
}
func main() {
start := time.Now()
partOne()
duration := time.Since(start)
partTwo()
duration2 := time.Since(start)
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
}
func makeScanner(test bool) *bufio.Scanner {
var f *os.File
if test {
f, _ = os.Open("inputs/testinput")
} else {
f, _ = os.Open("inputs/input")
}
reader := bufio.NewReader(f)
return bufio.NewScanner(reader)
}
type monkey struct {
items []int
operation string // either "plus", "times", or "square"
value int // ignored for "square"
test int // "divisible by <test>"
testpass int // monkey to throw to if test passes
testfail int // monkey to throw to if test fails
inspections int
}
func partOne() {
scanner := makeScanner(false)
currentMonkey := 0
monkeys := []monkey{}
// parse monkeys
for scanner.Scan() {
line := scanner.Text()
switch {
case strings.HasPrefix(line, "M"):
currentMonkey = mustAtoi(strings.Trim(line, "Monkey :"))
monkeys = append(monkeys, monkey{items: make([]int, 0)})
case strings.HasPrefix(line, " S"):
_, after, _ := strings.Cut(line, ":")
items := strings.Split(after, ",")
for _, i := range items {
monkeys[currentMonkey].items = append(monkeys[currentMonkey].items, mustAtoi(strings.TrimSpace(i)))
}
case strings.HasPrefix(line, " O"):
if strings.Contains(line, "+") {
monkeys[currentMonkey].operation = "plus"
l := strings.Split(line, " ")
monkeys[currentMonkey].value = mustAtoi(l[len(l)-1])
} else if strings.Contains(line, "old * old") {
monkeys[currentMonkey].operation = "square"
} else if strings.Contains(line, "*") {
monkeys[currentMonkey].operation = "times"
l := strings.Split(line, " ")
monkeys[currentMonkey].value = mustAtoi(l[len(l)-1])
}
case strings.HasPrefix(line, " T"):
l := strings.Split(line, " ")
monkeys[currentMonkey].test = mustAtoi(l[len(l)-1])
case strings.HasPrefix(line, " If t"):
l := strings.Split(line, " ")
monkeys[currentMonkey].testpass = mustAtoi(l[len(l)-1])
case strings.HasPrefix(line, " If f"):
l := strings.Split(line, " ")
monkeys[currentMonkey].testfail = mustAtoi(l[len(l)-1])
}
}
for i := 0; i < 20; i++ {
for m := range monkeys {
monkeys[m].inspections += len(monkeys[m].items)
for _, i := range monkeys[m].items {
if monkeys[m].operation == "plus" {
i = (i + monkeys[m].value) / 3
}
if monkeys[m].operation == "times" {
i = (i * monkeys[m].value) / 3
}
if monkeys[m].operation == "square" {
i = (i * i) / 3
}
if i%monkeys[m].test == 0 {
monkeys[monkeys[m].testpass].items = append(monkeys[monkeys[m].testpass].items, i)
} else {
monkeys[monkeys[m].testfail].items = append(monkeys[monkeys[m].testfail].items, i)
}
}
monkeys[m].items = []int{}
}
}
one, two := 0, 0
for _, m := range monkeys {
if m.inspections > one && m.inspections > two {
one, two = two, m.inspections
} else if m.inspections > one {
one = m.inspections
}
}
fmt.Println(one * two)
}
func partTwo() {
scanner := makeScanner(false)
currentMonkey := 0
monkeys := []monkey{}
// parse monkeys
for scanner.Scan() {
line := scanner.Text()
switch {
case strings.HasPrefix(line, "M"):
currentMonkey = mustAtoi(strings.Trim(line, "Monkey :"))
monkeys = append(monkeys, monkey{items: make([]int, 0)})
case strings.HasPrefix(line, " S"):
_, after, _ := strings.Cut(line, ":")
items := strings.Split(after, ",")
for _, i := range items {
monkeys[currentMonkey].items = append(
monkeys[currentMonkey].items, mustAtoi(strings.TrimSpace(i)),
)
}
case strings.HasPrefix(line, " O"):
if strings.Contains(line, "+") {
monkeys[currentMonkey].operation = "plus"
l := strings.Split(line, " ")
monkeys[currentMonkey].value = mustAtoi(l[len(l)-1])
} else if strings.Contains(line, "old * old") {
monkeys[currentMonkey].operation = "square"
} else if strings.Contains(line, "*") {
monkeys[currentMonkey].operation = "times"
l := strings.Split(line, " ")
monkeys[currentMonkey].value = mustAtoi(l[len(l)-1])
}
case strings.HasPrefix(line, " T"):
l := strings.Split(line, " ")
monkeys[currentMonkey].test = mustAtoi(l[len(l)-1])
case strings.HasPrefix(line, " If t"):
l := strings.Split(line, " ")
monkeys[currentMonkey].testpass = mustAtoi(l[len(l)-1])
case strings.HasPrefix(line, " If f"):
l := strings.Split(line, " ")
monkeys[currentMonkey].testfail = mustAtoi(l[len(l)-1])
}
}
common := 1
for i := range monkeys {
common = common * monkeys[i].test
}
for j := 0; j < 10000; j++ {
for m := range monkeys {
monkeys[m].inspections += len(monkeys[m].items)
for _, i := range monkeys[m].items {
if monkeys[m].operation == "plus" {
i = i + monkeys[m].value
}
if monkeys[m].operation == "times" {
i = i * monkeys[m].value
}
if monkeys[m].operation == "square" {
i = i * i
}
if i%monkeys[m].test == 0 {
monkeys[monkeys[m].testpass].items = append(monkeys[monkeys[m].testpass].items, i%common)
} else {
monkeys[monkeys[m].testfail].items = append(monkeys[monkeys[m].testfail].items, i%common)
}
}
monkeys[m].items = []int{}
}
}
one, two := 0, 0
for _, m := range monkeys {
if m.inspections > one && m.inspections > two {
one, two = two, m.inspections
} else if m.inspections > one {
one = m.inspections
}
}
fmt.Println(one * two)
}

38
11/main.rs Normal file
View File

@@ -0,0 +1,38 @@
#![allow(dead_code)]
use std::fs::File;
use std::io;
use std::io::BufRead;
use std::path::Path;
use std::time::Instant;
fn main() {
let now = Instant::now();
part_one();
let part_one_duration = now.elapsed();
part_two();
let part_two_duration = now.elapsed();
println!(
"p1: {}ms, p2: {}ms",
part_one_duration.as_millis(),
(part_two_duration - part_one_duration).as_millis()
);
}
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where
P: AsRef<Path>,
{
// note that this discards a final newline
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
fn part_one() {
if let Ok(lines) = read_lines("./inputs/input") {
for line in lines {
// do stuff
}
}
}
fn part_two() {}

50
12/main.go Normal file
View File

@@ -0,0 +1,50 @@
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"time"
)
func mustAtoi(line string) int {
i, _ := strconv.Atoi(line)
return i
}
func main() {
start := time.Now()
partOne()
duration := time.Since(start)
partTwo()
duration2 := time.Since(start)
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
}
func makeScanner(test bool) *bufio.Scanner {
var f *os.File
if test {
f, _ = os.Open("inputs/testinput")
} else {
f, _ = os.Open("inputs/input")
}
reader := bufio.NewReader(f)
return bufio.NewScanner(reader)
}
func partOne() {
scanner := makeScanner(false)
for scanner.Scan() {
// line := scanner.Text()
}
}
func partTwo() {
scanner := makeScanner(false)
for scanner.Scan() {
// line := scanner.Text()
}
}

103
13/main.go Normal file
View File

@@ -0,0 +1,103 @@
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"time"
)
func mustAtoi(line string) int {
i, _ := strconv.Atoi(line)
return i
}
func main() {
start := time.Now()
partOne()
duration := time.Since(start)
partTwo()
duration2 := time.Since(start)
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
}
func makeScanner(test bool) *bufio.Scanner {
var f *os.File
if test {
f, _ = os.Open("inputs/testinput")
} else {
f, _ = os.Open("inputs/input")
}
reader := bufio.NewReader(f)
return bufio.NewScanner(reader)
}
type thing interface {
IsNum() bool
Num() int
IsList() bool
List() list
}
type list struct {
children []thing
}
func (_ list) IsNum() bool {
return false
}
func (n list) Num() int {
panic("oops")
}
func (_ list) IsList() bool {
return true
}
func (l list) List() list {
return l
}
func (l list) Len() int {
return len(l.children)
}
type num int
func (_ num) IsNum() bool {
return true
}
func (n num) Num() int {
return int(n)
}
func (_ num) IsList() bool {
return false
}
func (_ num) List() list {
panic("oops")
}
func partOne() {
scanner := makeScanner(false)
pairCount := 0
sum := 0
for scanner.Scan() {
left := scanner.Text()
right := scanner.Text()
}
}
func partTwo() {
scanner := makeScanner(false)
for scanner.Scan() {
// line := scanner.Text()
}
}

223
14/main.go Normal file
View File

@@ -0,0 +1,223 @@
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"time"
)
func mustAtoi(line string) int {
i, _ := strconv.Atoi(line)
return i
}
func main() {
start := time.Now()
partOne()
duration := time.Since(start)
partTwo()
duration2 := time.Since(start)
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
}
func makeScanner(test bool) *bufio.Scanner {
var f *os.File
if test {
f, _ = os.Open("inputs/testinput")
} else {
f, _ = os.Open("inputs/input")
}
reader := bufio.NewReader(f)
return bufio.NewScanner(reader)
}
type coord struct {
x int
y int
}
func getRange(start, end int) []int {
if start > end {
s := make([]int, start-end+1)
for i := range s {
s[i] = start
start--
}
return s
}
if end > start {
s := make([]int, end-start+1)
for i := range s {
s[i] = start
start++
}
return s
}
return []int{}
}
func printCave(cave map[coord]int, xmin, xmax, depth int, floor bool) {
for _, d := range getRange(0, depth) {
fmt.Printf("%3d ", d)
for _, x := range getRange(xmin, xmax) {
if d == 0 && x == 500 {
fmt.Print("+")
} else if score, ok := cave[coord{x: x, y: d}]; ok {
if score == 1 {
fmt.Print("#")
} else if score == 2 {
fmt.Print("o")
}
} else {
fmt.Print(".")
}
}
fmt.Printf("\n")
}
if floor {
fmt.Printf("%3d ", depth+1)
for range getRange(xmin, xmax) {
fmt.Print("#")
}
fmt.Printf("\n")
}
}
// return value is false if sand reached max depth
func addSand(cave map[coord]int, depth int, floor bool) bool {
x := 500
y := 0
for {
if y > depth {
if floor {
// made it to the floor, come to rest
cave[coord{x: x, y: y}] = 2
return true
}
return false
}
if _, blocked := cave[coord{x: x, y: y + 1}]; !blocked {
y += 1
continue
}
if _, blocked := cave[coord{x: x - 1, y: y + 1}]; !blocked {
y += 1
x -= 1
continue
}
if _, blocked := cave[coord{x: x + 1, y: y + 1}]; !blocked {
y += 1
x += 1
continue
}
// filled the cavern, return false
if y == 0 {
cave[coord{x: x, y: y}] = 2
return false
}
// blocked in all directions, come to rest
cave[coord{x: x, y: y}] = 2
return true
}
}
func partOne() {
scanner := makeScanner(false)
cave := map[coord]int{}
maxx, minx, depth := 0, 1000, 0
for scanner.Scan() {
line := scanner.Text()
coords := strings.Split(line, " -> ")
prevx, prevy := 0, 0
for _, i := range coords {
x, y, _ := strings.Cut(i, ",")
if prevx == 0 && prevy == 0 {
prevx, prevy = mustAtoi(x), mustAtoi(y)
continue
}
if prevx == mustAtoi(x) {
for _, curry := range getRange(prevy, mustAtoi(y)) {
cave[coord{x: prevx, y: curry}] = 1
}
prevy = mustAtoi(y)
} else if prevy == mustAtoi(y) {
for _, currx := range getRange(prevx, mustAtoi(x)) {
cave[coord{x: currx, y: prevy}] = 1
}
prevx = mustAtoi(x)
}
if mustAtoi(x) > maxx {
maxx = mustAtoi(x)
} else if mustAtoi(x) < minx {
minx = mustAtoi(x)
}
if mustAtoi(y) > depth {
depth = mustAtoi(y)
}
}
}
for addSand(cave, depth, false) {
}
printCave(cave, minx-1, maxx+1, depth+1, false)
score := 0
for _, c := range cave {
if c == 2 {
score++
}
}
fmt.Println(score)
}
func partTwo() {
scanner := makeScanner(false)
cave := map[coord]int{}
maxx, minx, depth := 0, 1000, 0
for scanner.Scan() {
line := scanner.Text()
coords := strings.Split(line, " -> ")
prevx, prevy := 0, 0
for _, i := range coords {
x, y, _ := strings.Cut(i, ",")
if prevx == 0 && prevy == 0 {
prevx, prevy = mustAtoi(x), mustAtoi(y)
continue
}
if prevx == mustAtoi(x) {
for _, curry := range getRange(prevy, mustAtoi(y)) {
cave[coord{x: prevx, y: curry}] = 1
}
prevy = mustAtoi(y)
} else if prevy == mustAtoi(y) {
for _, currx := range getRange(prevx, mustAtoi(x)) {
cave[coord{x: currx, y: prevy}] = 1
}
prevx = mustAtoi(x)
}
if mustAtoi(x) > maxx {
maxx = mustAtoi(x)
} else if mustAtoi(x) < minx {
minx = mustAtoi(x)
}
if mustAtoi(y) > depth {
depth = mustAtoi(y)
}
}
}
for addSand(cave, depth, true) {
}
printCave(cave, minx-1, maxx+1, depth+1, true)
score := 0
for _, c := range cave {
if c == 2 {
score++
}
}
fmt.Println(score)
}

161
15/main.go Normal file
View File

@@ -0,0 +1,161 @@
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"time"
)
func mustAtoi(line string) int {
i, _ := strconv.Atoi(line)
return i
}
func main() {
start := time.Now()
partOne()
duration := time.Since(start)
partTwo()
duration2 := time.Since(start)
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
}
func makeScanner(test bool) *bufio.Scanner {
var f *os.File
if test {
f, _ = os.Open("inputs/testinput")
} else {
f, _ = os.Open("inputs/input")
}
reader := bufio.NewReader(f)
return bufio.NewScanner(reader)
}
type coord struct {
x int
y int
}
func abs(i, j int) int {
if i < j {
return j - i
}
return i - j
}
func getCoords(x, y string, _ bool) coord {
return coord{x: mustAtoi(x), y: mustAtoi(y)}
}
func distance(sensor, beacon coord) int {
return abs(sensor.x, beacon.x) + abs(sensor.y, beacon.y)
}
func partOne() {
test := false
scanner := makeScanner(test)
row := 2000000
if test {
row = 10
}
cave := map[coord]int{} // 0 for unknown space, 1 for sensor, 2 for beacon, 3 for known empty
for scanner.Scan() {
line := scanner.Text()
s, b, _ := strings.Cut(line, ": ")
sensor := getCoords(strings.Cut(strings.Trim(s, "Sensor at x="), ", y="))
beacon := getCoords(strings.Cut(strings.Trim(b, "closest beacon is at x="), ", y="))
dist := distance(sensor, beacon)
cave[sensor] = 1
cave[beacon] = 2
rel := distance(sensor, coord{x: sensor.x, y: row})
if rel <= dist {
c := dist - rel
for i := sensor.x - c; i <= sensor.x+c; i++ {
if _, ok := cave[coord{x: i, y: row}]; !ok {
cave[coord{x: i, y: row}] = 3
}
}
}
}
sum := 0
for _, i := range cave {
if i == 3 {
sum++
}
}
fmt.Println(sum)
}
func sensorHalo(sensor coord, distance int) []coord {
halo := []coord{}
corners := []coord{
{x: sensor.x, y: sensor.y + distance + 1},
{x: sensor.x + distance + 1, y: sensor.y},
{x: sensor.x, y: sensor.y - distance - 1},
{x: sensor.x - distance - 1, y: sensor.y},
}
y := corners[0].y
for i := corners[0].x; i < corners[1].x; i++ {
halo = append(halo, coord{i, y})
y--
}
for i := corners[1].x; i > corners[2].x; i-- {
halo = append(halo, coord{i, y})
y--
}
for i := corners[2].x; i > corners[3].x; i-- {
halo = append(halo, coord{i, y})
y++
}
for i := corners[3].x; i > corners[0].x; i++ {
halo = append(halo, coord{i, y})
y++
}
halo = append(halo, corners[3])
return halo
}
func partTwo() {
test := false
scanner := makeScanner(test)
max := 4000000
if test {
max = 20
}
cave := map[coord]int{} // sensor: distance to beacon
for scanner.Scan() {
line := scanner.Text()
s, b, _ := strings.Cut(line, ": ")
sensor := getCoords(strings.Cut(strings.Trim(s, "Sensor at x="), ", y="))
beacon := getCoords(strings.Cut(strings.Trim(b, "closest beacon is at x="), ", y="))
dist := distance(sensor, beacon)
cave[sensor] = dist
}
// since there's only one of these holes in the search space,
// it must be just outside the maximum distance from a sensor
// it'll take far too long to search the entire cavern, after all
possibleCoords := []coord{}
for sensor, dist := range cave {
possibleCoords = append(possibleCoords, sensorHalo(sensor, dist)...)
}
for _, poss := range possibleCoords {
if poss.x < 0 || poss.y < 0 || poss.x > max || poss.y > max {
continue
}
hit := false
for sensor, dist := range cave {
if distance(sensor, poss) < dist {
hit = true
}
}
if !hit {
fmt.Println(poss.x*4000000 + poss.y)
return
}
}
}

77
25/main.go Normal file
View File

@@ -0,0 +1,77 @@
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"time"
)
func mustAtoi(line string) int {
i, _ := strconv.Atoi(line)
return i
}
func main() {
start := time.Now()
partOne()
duration := time.Since(start)
fmt.Printf("p1: %s\n", duration)
}
func makeScanner(test bool) *bufio.Scanner {
var f *os.File
if test {
f, _ = os.Open("inputs/testinput")
} else {
f, _ = os.Open("inputs/input")
}
reader := bufio.NewReader(f)
return bufio.NewScanner(reader)
}
func parseSNAFU(str string) int {
num := 0
place := 1
for i := len(str) - 1; i >= 0; i-- {
switch str[i] {
case '2':
num += place * 2
case '1':
num += place
case '0':
// noop
case '-':
num -= place
case '=':
num -= place * 2
default:
panic("oh no")
}
place *= 5
}
return num
}
func toSNAFU(normal int) string {
num := ""
digits := []string{"0", "1", "2", "=", "-"}
for {
num = digits[normal%5] + num
if normal == 0 {
return num
}
normal = (normal + 2) / 5
}
}
func partOne() {
scanner := makeScanner(false)
sum := 0
for scanner.Scan() {
line := scanner.Text()
sum += parseSNAFU(line)
}
fmt.Println(toSNAFU(sum)[1:])
}

50
main.go.tmpl Normal file
View File

@@ -0,0 +1,50 @@
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"time"
)
func mustAtoi(line string) int {
i, _ := strconv.Atoi(line)
return i
}
func main() {
start := time.Now()
partOne()
duration := time.Since(start)
partTwo()
duration2 := time.Since(start)
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
}
func makeScanner(test bool) *bufio.Scanner {
var f *os.File
if test {
f, _ = os.Open("inputs/testinput")
} else {
f, _ = os.Open("inputs/input")
}
reader := bufio.NewReader(f)
return bufio.NewScanner(reader)
}
func partOne() {
scanner := makeScanner(false)
for scanner.Scan() {
// line := scanner.Text()
}
}
func partTwo() {
scanner := makeScanner(false)
for scanner.Scan() {
// line := scanner.Text()
}
}

7
new.sh
View File

@@ -11,8 +11,11 @@ if [ "${1}" != "" ]; then
-A "https://git.yetaga.in/alazyreader/AdventOfCode2022/" \
-H "Cookie: session=`cat .cookie`" https://adventofcode.com/${__year}/day/${1##0}/input > "${padded}/inputs/input"
fi
if [ ! -f "${padded}/main.rs" ]; then
cp -n main.rs.tmpl ${padded}/main.rs
# if [ ! -f "${padded}/main.rs" ]; then
# cp -n main.rs.tmpl ${padded}/main.rs
# fi
if [ ! -f "${padded}/main.go" ]; then
cp -n main.go.tmpl ${padded}/main.go
fi
echo "https://adventofcode.com/2022/day/${1}"
fi

4
run.sh
View File

@@ -3,6 +3,10 @@
if [ "${1}" != "" ]; then
padded=$(printf "%02g" ${1})
cd ${padded}
if [ "${2}" == "go" ]; then
go run main.go
else
rustc main.rs && ./main && rm main
fi
cd - > /dev/null
fi