AoC 2025 Day1
This commit is contained in:
@@ -1,75 +0,0 @@
|
||||
## \-\-\- Day 24: Never Tell Me The Odds ---
|
||||
|
||||
It seems like something is going wrong with the snow-making process. Instead of forming snow, the water that's been absorbed into the air seems to be forming [hail](https://en.wikipedia.org/wiki/Hail)!
|
||||
|
||||
Maybe there's something you can do to break up the hailstones?
|
||||
|
||||
Due to strong, probably-magical winds, the hailstones are all flying through the air in perfectly linear trajectories. You make a note of each hailstone's _position_ and _velocity_ (your puzzle input). For example:
|
||||
|
||||
```
|
||||
19, 13, 30 @ -2, 1, -2
|
||||
18, 19, 22 @ -1, -1, -2
|
||||
20, 25, 34 @ -2, -2, -4
|
||||
12, 31, 28 @ -1, -2, -1
|
||||
20, 19, 15 @ 1, -5, -3
|
||||
|
||||
```
|
||||
|
||||
Each line of text corresponds to the position and velocity of a single hailstone. The positions indicate where the hailstones are _right now_ (at time `0`). The velocities are constant and indicate exactly how far each hailstone will move in _one nanosecond_.
|
||||
|
||||
Each line of text uses the format `px py pz @ vx vy vz`. For instance, the hailstone specified by `20, 19, 15 @ 1, -5, -3` has initial X position `20`, Y position `19`, Z position `15`, X velocity `1`, Y velocity `-5`, and Z velocity `-3`. After one nanosecond, the hailstone would be at `21, 14, 12`.
|
||||
|
||||
Perhaps you won't have to do anything. How likely are the hailstones to collide with each other and smash into tiny ice crystals?
|
||||
|
||||
To estimate this, consider only the X and Y axes; _ignore the Z axis_. Looking _forward in time_, how many of the hailstones' _paths_ will intersect within a test area? (The hailstones themselves don't have to collide, just test for intersections between the paths they will trace.)
|
||||
|
||||
In this example, look for intersections that happen with an X and Y position each at least `7` and at most `27`; in your actual data, you'll need to check a much larger test area. Comparing all pairs of hailstones' future paths produces the following results:
|
||||
|
||||
```
|
||||
Hailstone A: 19, 13, 30 @ -2, 1, -2
|
||||
Hailstone B: 18, 19, 22 @ -1, -1, -2
|
||||
Hailstones' paths will cross inside the test area (at x=14.333, y=15.333).
|
||||
|
||||
Hailstone A: 19, 13, 30 @ -2, 1, -2
|
||||
Hailstone B: 20, 25, 34 @ -2, -2, -4
|
||||
Hailstones' paths will cross inside the test area (at x=11.667, y=16.667).
|
||||
|
||||
Hailstone A: 19, 13, 30 @ -2, 1, -2
|
||||
Hailstone B: 12, 31, 28 @ -1, -2, -1
|
||||
Hailstones' paths will cross outside the test area (at x=6.2, y=19.4).
|
||||
|
||||
Hailstone A: 19, 13, 30 @ -2, 1, -2
|
||||
Hailstone B: 20, 19, 15 @ 1, -5, -3
|
||||
Hailstones' paths crossed in the past for hailstone A.
|
||||
|
||||
Hailstone A: 18, 19, 22 @ -1, -1, -2
|
||||
Hailstone B: 20, 25, 34 @ -2, -2, -4
|
||||
Hailstones' paths are parallel; they never intersect.
|
||||
|
||||
Hailstone A: 18, 19, 22 @ -1, -1, -2
|
||||
Hailstone B: 12, 31, 28 @ -1, -2, -1
|
||||
Hailstones' paths will cross outside the test area (at x=-6, y=-5).
|
||||
|
||||
Hailstone A: 18, 19, 22 @ -1, -1, -2
|
||||
Hailstone B: 20, 19, 15 @ 1, -5, -3
|
||||
Hailstones' paths crossed in the past for both hailstones.
|
||||
|
||||
Hailstone A: 20, 25, 34 @ -2, -2, -4
|
||||
Hailstone B: 12, 31, 28 @ -1, -2, -1
|
||||
Hailstones' paths will cross outside the test area (at x=-2, y=3).
|
||||
|
||||
Hailstone A: 20, 25, 34 @ -2, -2, -4
|
||||
Hailstone B: 20, 19, 15 @ 1, -5, -3
|
||||
Hailstones' paths crossed in the past for hailstone B.
|
||||
|
||||
Hailstone A: 12, 31, 28 @ -1, -2, -1
|
||||
Hailstone B: 20, 19, 15 @ 1, -5, -3
|
||||
Hailstones' paths crossed in the past for both hailstones.
|
||||
|
||||
```
|
||||
|
||||
So, in this example, `2` hailstones' future paths cross inside the boundaries of the test area.
|
||||
|
||||
However, you'll need to search a much larger test area if you want to see if any hailstones might collide. Look for intersections that happen with an X and Y position each at least `200000000000000` and at most `400000000000000`. Disregard the Z axis entirely.
|
||||
|
||||
Considering only the X and Y axes, check all pairs of hailstones' future paths for intersections. _How many of these intersections occur within the test area?_
|
||||
170
2023/24/code.go
170
2023/24/code.go
@@ -1,170 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jpillora/puzzler/harness/aoc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
aoc.Harness(run)
|
||||
}
|
||||
|
||||
// on code change, run will be executed 4 times:
|
||||
// 1. with: false (part1), and example input
|
||||
// 2. with: true (part2), and example input
|
||||
// 3. with: false (part1), and user input
|
||||
// 4. with: true (part2), and user input
|
||||
// the return value of each run is printed to stdout
|
||||
|
||||
type Hailstone struct {
|
||||
X int
|
||||
Y int
|
||||
Z int
|
||||
|
||||
Xv int
|
||||
Yv int
|
||||
Zv int
|
||||
}
|
||||
|
||||
func (h *Hailstone) DoPathsCrossXY(o *Hailstone, boundMin, boundMax float64) (x, y float64, err error) {
|
||||
|
||||
// Find which bounds this hailstone is going to
|
||||
hyBound, hxBound := float64(h.Y), float64(h.X)
|
||||
if h.Yv < 0 {
|
||||
hyBound = boundMin
|
||||
} else if h.Yv > 0 {
|
||||
hyBound = boundMax
|
||||
}
|
||||
|
||||
if h.Xv < 0 {
|
||||
hxBound = boundMin
|
||||
} else if h.Xv > 0 {
|
||||
hxBound = boundMax
|
||||
}
|
||||
|
||||
// which one reached first
|
||||
|
||||
/*
|
||||
|
||||
19, 13, _ @ -2, 1, _
|
||||
|
||||
y=19 -2c
|
||||
x=13 + c
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
func (h *Hailstone) FindIntersectionXY(o *Hailstone) (ns, x, y float64, err error) {
|
||||
if h == o {
|
||||
return -1, -1, -1, errors.New("same hailstone")
|
||||
}
|
||||
|
||||
yc := (float64(h.Y) - float64(o.Y)) / (float64(o.Yv) - float64(h.Yv))
|
||||
xc := (float64(h.X) - float64(o.X)) / (float64(o.Xv) - float64(h.Xv))
|
||||
|
||||
// if xInt == yInt is the same, we have a match
|
||||
|
||||
fmt.Printf("%v ; %v\n", xc, yc)
|
||||
|
||||
if yc == xc && yc > 0 {
|
||||
return xc, float64(h.X) + float64(h.Xv)*xc, float64(h.Y) + float64(h.Yv)*yc, nil
|
||||
}
|
||||
|
||||
return -1, -1, -1, errors.New("No intersect")
|
||||
|
||||
// y = ax+b Y =
|
||||
/*
|
||||
19, 13, _ @ -2, 1, _
|
||||
18, 19, _ @ -1, -1, _
|
||||
|
||||
1:
|
||||
y= 19 - 2c
|
||||
x= 13 + c
|
||||
|
||||
|
||||
hY = h.Y + c*h.Yv
|
||||
oY = o.Y + c.o.Yv
|
||||
|
||||
if hY=oY:
|
||||
|
||||
h.Y + c*h.Yv = o.Y + c*o.Yv
|
||||
|
||||
h.Y - o.Y = c*o.Yv - c*h.Yv
|
||||
|
||||
h.Y - o.Y = c(o.Yv - h.Yv)
|
||||
(h.Y - o.Y) / (o.Yv - h.Yv) =
|
||||
|
||||
2:
|
||||
y= 18 - c
|
||||
x= 19 - c
|
||||
|
||||
--- ?
|
||||
|
||||
where does y1 = y2
|
||||
19 - 2c = 18 - c
|
||||
19 - 18 - 2c = -c
|
||||
1 = -c + 2c
|
||||
1 = c
|
||||
@ 1
|
||||
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
func run(part2 bool, input string) any {
|
||||
hailRxp := regexp.MustCompile(`(?P<X>\d+), +(?P<Y>\d+), +(?P<Z>\d+) @ +(?P<VX>-?\d+), +(?P<VY>-?\d+), +(?P<VZ>-?\d+)`)
|
||||
|
||||
stones := make([]Hailstone, 0)
|
||||
|
||||
for _, l := range strings.Split(input, "\n") {
|
||||
matches := hailRxp.FindStringSubmatch(l)
|
||||
if len(matches) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
px, _ := strconv.Atoi(matches[1])
|
||||
py, _ := strconv.Atoi(matches[2])
|
||||
pz, _ := strconv.Atoi(matches[3])
|
||||
vx, _ := strconv.Atoi(matches[4])
|
||||
vy, _ := strconv.Atoi(matches[5])
|
||||
vz, _ := strconv.Atoi(matches[6])
|
||||
|
||||
stones = append(stones, Hailstone{px, py, pz, vx, vy, vz})
|
||||
}
|
||||
|
||||
// when you're ready to do part 2, remove this "not implemented" block
|
||||
if part2 {
|
||||
return "not implemented"
|
||||
}
|
||||
// solve part 1 here
|
||||
|
||||
testMin, testMax := 7, 27
|
||||
|
||||
insideRange := 0
|
||||
for _, h := range stones {
|
||||
for _, o := range stones {
|
||||
ns, x, y, err := h.FindIntersectionXY(&o)
|
||||
|
||||
if err == nil {
|
||||
fmt.Printf("Intersection of %v:%v at %vns (%v, %v)\n", h, o, ns, x, y)
|
||||
if x > float64(testMin) && x < float64(testMax) && y > float64(testMin) && y < float64(testMax) {
|
||||
insideRange += 1
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("ERROR %v\n", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return insideRange
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
19, 13, 30 @ -2, 1, -2
|
||||
18, 19, 22 @ -1, -1, -2
|
||||
20, 25, 34 @ -2, -2, -4
|
||||
12, 31, 28 @ -1, -2, -1
|
||||
20, 19, 15 @ 1, -5, -3
|
||||
63
2025/01/README.md
Executable file
63
2025/01/README.md
Executable file
@@ -0,0 +1,63 @@
|
||||
## \-\-\- Day 1: Secret Entrance ---
|
||||
|
||||
The Elves have good news and bad news.
|
||||
|
||||
The good news is that they've discovered [project management](https://en.wikipedia.org/wiki/Project_management)! This has given them the tools they need to prevent their usual Christmas emergency. For example, they now know that the North Pole decorations need to be finished soon so that other critical tasks can start on time.
|
||||
|
||||
The bad news is that they've realized they have a _different_ emergency: according to their resource planning, none of them have any time left to decorate the North Pole!
|
||||
|
||||
To save Christmas, the Elves need _you_ to _finish decorating the North Pole by December 12th_.
|
||||
|
||||
Collect stars by solving puzzles. Two puzzles will be made available on each day; the second puzzle is unlocked when you complete the first. Each puzzle grants _one star_. Good luck!
|
||||
|
||||
You arrive at the secret entrance to the North Pole base ready to start decorating. Unfortunately, the _password_ seems to have been changed, so you can't get in. A document taped to the wall helpfully explains:
|
||||
|
||||
"Due to new security protocols, the password is locked in the safe below. Please see the attached document for the new combination."
|
||||
|
||||
The safe has a dial with only an arrow on it; around the dial are the numbers `0` through `99` in order. As you turn the dial, it makes a small _click_ noise as it reaches each number.
|
||||
|
||||
The attached document (your puzzle input) contains a sequence of _rotations_, one per line, which tell you how to open the safe. A rotation starts with an `L` or `R` which indicates whether the rotation should be to the _left_ (toward lower numbers) or to the _right_ (toward higher numbers). Then, the rotation has a _distance_ value which indicates how many clicks the dial should be rotated in that direction.
|
||||
|
||||
So, if the dial were pointing at `11`, a rotation of `R8` would cause the dial to point at `19`. After that, a rotation of `L19` would cause it to point at `0`.
|
||||
|
||||
Because the dial is a circle, turning the dial _left from `0`_ one click makes it point at `99`. Similarly, turning the dial _right from `99`_ one click makes it point at `0`.
|
||||
|
||||
So, if the dial were pointing at `5`, a rotation of `L10` would cause it to point at `95`. After that, a rotation of `R5` could cause it to point at `0`.
|
||||
|
||||
The dial starts by pointing at `50`.
|
||||
|
||||
You could follow the instructions, but your recent required official North Pole secret entrance security training seminar taught you that the safe is actually a decoy. The actual password is _the number of times the dial is left pointing at `0` after any rotation in the sequence_.
|
||||
|
||||
For example, suppose the attached document contained the following rotations:
|
||||
|
||||
```
|
||||
L68
|
||||
L30
|
||||
R48
|
||||
L5
|
||||
R60
|
||||
L55
|
||||
L1
|
||||
L99
|
||||
R14
|
||||
L82
|
||||
|
||||
```
|
||||
|
||||
Following these rotations would cause the dial to move as follows:
|
||||
|
||||
- The dial starts by pointing at `50`.
|
||||
- The dial is rotated `L68` to point at `82`.
|
||||
- The dial is rotated `L30` to point at `52`.
|
||||
- The dial is rotated `R48` to point at `0`.
|
||||
- The dial is rotated `L5` to point at `95`.
|
||||
- The dial is rotated `R60` to point at `55`.
|
||||
- The dial is rotated `L55` to point at `0`.
|
||||
- The dial is rotated `L1` to point at `99`.
|
||||
- The dial is rotated `L99` to point at `0`.
|
||||
- The dial is rotated `R14` to point at `14`.
|
||||
- The dial is rotated `L82` to point at `32`.
|
||||
|
||||
Because the dial points at `0` a total of three times during this process, the password in this example is `3`.
|
||||
|
||||
Analyze the rotations in your attached document. _What's the actual password to open the door?_
|
||||
94
2025/01/code.go
Normal file
94
2025/01/code.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jpillora/puzzler/harness/aoc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
aoc.Harness(run)
|
||||
}
|
||||
|
||||
// on code change, run will be executed 4 times:
|
||||
// 1. with: false (part1), and example input
|
||||
// 2. with: true (part2), and example input
|
||||
// 3. with: false (part1), and user input
|
||||
// 4. with: true (part2), and user input
|
||||
// the return value of each run is printed to stdout
|
||||
func run(part2 bool, input string) any {
|
||||
// when you're ready to do part 2, remove this "not implemented" block
|
||||
if part2 {
|
||||
|
||||
dial_val := 50
|
||||
zcount := 0
|
||||
for _, line := range strings.Split(input, "\n") {
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
dir, cstr := line[0], line[1:]
|
||||
c, _ := strconv.Atoi(cstr)
|
||||
|
||||
full_rotations := c / 100
|
||||
zcount += full_rotations
|
||||
|
||||
c -= full_rotations * 100
|
||||
|
||||
new_val := dial_val
|
||||
if dir == 'R' {
|
||||
new_val += c
|
||||
if new_val > 99 {
|
||||
new_val -= 100
|
||||
zcount++
|
||||
}
|
||||
} else {
|
||||
new_val -= c
|
||||
if new_val < 0 {
|
||||
new_val += 100
|
||||
if dial_val != 0 {
|
||||
zcount++
|
||||
}
|
||||
} else if new_val == 0 {
|
||||
zcount++
|
||||
}
|
||||
}
|
||||
|
||||
dial_val = new_val
|
||||
}
|
||||
|
||||
return zcount
|
||||
}
|
||||
// solve part 1 here
|
||||
|
||||
dial_val := 50
|
||||
zcount := 0
|
||||
for _, line := range strings.Split(input, "\n") {
|
||||
//fmt.Printf("%v\n", line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
dir, cstr := line[0], line[1:]
|
||||
c, _ := strconv.Atoi(cstr)
|
||||
c = c % 100
|
||||
|
||||
if dir == 'R' {
|
||||
dial_val += c
|
||||
} else {
|
||||
dial_val += (100 - c)
|
||||
}
|
||||
|
||||
if dial_val >= 100 {
|
||||
dial_val = dial_val % 100
|
||||
}
|
||||
|
||||
if dial_val == 0 {
|
||||
zcount++
|
||||
}
|
||||
//fmt.Printf("Pos: %v (%v)\n", dial_val, zcount)
|
||||
}
|
||||
|
||||
return zcount
|
||||
}
|
||||
10
2025/01/input-example.txt
Executable file
10
2025/01/input-example.txt
Executable file
@@ -0,0 +1,10 @@
|
||||
L68
|
||||
L30
|
||||
R48
|
||||
L5
|
||||
R60
|
||||
L55
|
||||
L1
|
||||
L99
|
||||
R14
|
||||
L82
|
||||
4037
2025/01/input-user.txt
Normal file
4037
2025/01/input-user.txt
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user