day24, example
This commit is contained in:
parent
2f6120fbd8
commit
b6a56554af
|
@ -0,0 +1,5 @@
|
||||||
|
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
|
|
@ -0,0 +1,147 @@
|
||||||
|
package day24
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CoordMin int = 7
|
||||||
|
CoordMax int = 27
|
||||||
|
)
|
||||||
|
|
||||||
|
type Point struct {
|
||||||
|
x, y, Z int
|
||||||
|
}
|
||||||
|
|
||||||
|
type HailParam struct {
|
||||||
|
p0, p1 Point
|
||||||
|
Dx, Dy, Dz int
|
||||||
|
line string
|
||||||
|
}
|
||||||
|
func (h HailParam)String() string {
|
||||||
|
return "(" + h.line + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckPairwiseIntersections(hails []HailParam) (totalIntersections int) {
|
||||||
|
for i, hail := range hails {
|
||||||
|
for j := i+1; j < len(hails); j++ {
|
||||||
|
otherHail := hails[j]
|
||||||
|
intersect := CheckTaskIntersection(hail, otherHail)
|
||||||
|
if intersect {
|
||||||
|
totalIntersections += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckTaskIntersection(h1, h2 HailParam) (doIntersect bool) {
|
||||||
|
log.Printf("intersecting %+v and %+v\n", h1, h2)
|
||||||
|
x, y, intersectAtAll := IntersectByTwoPoints(h1, h2)
|
||||||
|
if !intersectAtAll {
|
||||||
|
log.Printf("no intersection at all\n")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if x < float64(CoordMin) || x > float64(CoordMax) ||
|
||||||
|
y < float64(CoordMin) || y > float64(CoordMax) {
|
||||||
|
log.Printf("intersect at %f %f but outside of area\n", x, y)
|
||||||
|
return false // outside of area
|
||||||
|
}
|
||||||
|
isH1Future := h1.FloatPointInFuture(x,y)
|
||||||
|
isH2Future := h2.FloatPointInFuture(x,y)
|
||||||
|
|
||||||
|
if !isH1Future {
|
||||||
|
log.Printf("in the past for h1\n")
|
||||||
|
}
|
||||||
|
if !isH2Future {
|
||||||
|
log.Printf("in the past for h2\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isH1Future || !isH2Future {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("intersect inside of the area")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// in 2d only
|
||||||
|
func IntersectByTwoPoints(h1, h2 HailParam) (intersectionX, intersectoinY float64, isIntersecting bool) {
|
||||||
|
p1 := h1.p0
|
||||||
|
p2 := h1.p1
|
||||||
|
p3 := h2.p0
|
||||||
|
p4 := h2.p1
|
||||||
|
|
||||||
|
denominator := (p1.x - p2.x)*(p3.y - p4.y) - (p1.y - p2.y)*(p3.x - p4.x)
|
||||||
|
if denominator == 0 {
|
||||||
|
return 0, 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
divisibleX := (p1.x * p2.y - p1.y * p2.x)*(p3.x - p4.x) - (p1.x - p2.x)*(p3.x * p4.y - p3.y * p4.x)
|
||||||
|
divisibleY := (p1.x * p2.y - p1.y * p2.x)*(p3.y - p4.y) - (p1.y - p2.y)*(p3.x * p4.y - p3.y * p4.x)
|
||||||
|
|
||||||
|
x := float64(divisibleX) / float64(denominator)
|
||||||
|
y := float64(divisibleY) / float64(denominator)
|
||||||
|
|
||||||
|
return x, y, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h HailParam)PointInFuture(p Point) bool {
|
||||||
|
xPositiveSteps := (p.x - h.p0.x) * h.Dx >= 0
|
||||||
|
yPositiveSteps := (p.y - h.p0.y) * h.Dy >= 0
|
||||||
|
zPositiveSteps := (p.Z - h.p0.Z) * h.Dz >= 0
|
||||||
|
return xPositiveSteps && yPositiveSteps && zPositiveSteps
|
||||||
|
}
|
||||||
|
func (h HailParam)FloatPointInFuture(x, y float64) bool {
|
||||||
|
xPositiveSteps := (x - float64(h.p0.x)) * float64(h.Dx) >= 0
|
||||||
|
yPositiveSteps := (y - float64(h.p0.y)) * float64(h.Dy) >= 0
|
||||||
|
return xPositiveSteps && yPositiveSteps
|
||||||
|
}
|
||||||
|
|
||||||
|
// 19, 13, 30 @ -2, 1, -2
|
||||||
|
func ReadHailLine(line string) (h HailParam) {
|
||||||
|
h.line = line
|
||||||
|
line = strings.ReplaceAll(line, "@", "")
|
||||||
|
line = strings.ReplaceAll(line, ",", "")
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
|
||||||
|
h.p0.x = AtoIOrPanic(fields[0])
|
||||||
|
h.p0.y = AtoIOrPanic(fields[1])
|
||||||
|
h.p0.Z = AtoIOrPanic(fields[2])
|
||||||
|
h.Dx = AtoIOrPanic(fields[3])
|
||||||
|
h.Dy = AtoIOrPanic(fields[4])
|
||||||
|
h.Dz = AtoIOrPanic(fields[5])
|
||||||
|
|
||||||
|
h.p1.x = h.p0.x + h.Dx
|
||||||
|
h.p1.y = h.p0.y + h.Dy
|
||||||
|
h.p1.Z = h.p0.Z + h.Dz
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadHailFile(filename string) []HailParam {
|
||||||
|
bytes, err := os.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
text := strings.TrimSpace(string(bytes))
|
||||||
|
lines := strings.Split(text, "\n")
|
||||||
|
result := make([]HailParam, len(lines))
|
||||||
|
|
||||||
|
for i, line := range lines {
|
||||||
|
result[i] = ReadHailLine(line)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func AtoIOrPanic(str string) (num int) {
|
||||||
|
num, err := strconv.Atoi(str)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
package day24
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReadLine(t *testing.T) {
|
||||||
|
lines := `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`
|
||||||
|
|
||||||
|
for _, line := range strings.Split(lines, "\n") {
|
||||||
|
hail := ReadHailLine(line)
|
||||||
|
t.Log(hail)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSecondPointIsInFuture(t *testing.T) {
|
||||||
|
lines := `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`
|
||||||
|
|
||||||
|
for _, line := range strings.Split(lines, "\n") {
|
||||||
|
hail := ReadHailLine(line)
|
||||||
|
t.Log(hail)
|
||||||
|
t.Logf("calced seconds point %+v is in future %t\n", hail.p1, hail.PointInFuture(hail.p1))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntersectExampleOne(t *testing.T) {
|
||||||
|
// 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).
|
||||||
|
|
||||||
|
hA := ReadHailLine("19, 13, 30 @ -2, 1, -2")
|
||||||
|
hB := ReadHailLine("18, 19, 22 @ -1, -1, -2")
|
||||||
|
|
||||||
|
x, y, check := IntersectByTwoPoints(hA, hB)
|
||||||
|
if !check {
|
||||||
|
panic("should intersect")
|
||||||
|
}
|
||||||
|
t.Logf("got intersection at %f %f", x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntersectExampleTwo(t *testing.T) {
|
||||||
|
// Hailstone A: 18, 19, 22 @ -1, -1, -2
|
||||||
|
// Hailstone B: 20, 25, 34 @ -2, -2, -4
|
||||||
|
hA := ReadHailLine("18, 19, 22 @ -1, -1, -2")
|
||||||
|
hB := ReadHailLine("20, 25, 34 @ -2, -2, -4")
|
||||||
|
|
||||||
|
x, y, check := IntersectByTwoPoints(hA, hB)
|
||||||
|
if check {
|
||||||
|
panic("should not intersect")
|
||||||
|
}
|
||||||
|
t.Logf("got intersection at %f %f", x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExamplePairwiseChecks(t *testing.T) {
|
||||||
|
filename := "example"
|
||||||
|
hails := ReadHailFile(filename)
|
||||||
|
|
||||||
|
intersections := CheckPairwiseIntersections(hails)
|
||||||
|
t.Log("counted intersections ", intersections)
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package day24
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Run() int {
|
||||||
|
fmt.Println("hello day 24, i'm getting tired")
|
||||||
|
filenae := "day24/example"
|
||||||
|
hails := ReadHailFile(filenae)
|
||||||
|
return CheckPairwiseIntersections(hails)
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
#+title: Notes
|
||||||
|
* i want help from math
|
||||||
|
https://math.stackexchange.com/questions/28503/how-to-find-intersection-of-two-lines-in-3d
|
||||||
|
|
||||||
|
'vector parametric form' is exactly what we're getting in the input?
|
||||||
|
* huh and only 'looking forward in time' so solutions with negative t are not important.
|
||||||
|
cooool
|
||||||
|
** i see that speeds are integers, so updated points are integers.
|
||||||
|
maybe i do calculation of every line on every time point?
|
||||||
|
|
||||||
|
and if i do that is there a way to get intersections efficietly?
|
||||||
|
** i'll also need the ends for lines? ends to the line segments.
|
||||||
|
with limits on the x & y by the task
|
||||||
|
|
||||||
|
for example both 7 <= <= 27
|
||||||
|
for input 200000000000000 <= <= 400000000000000
|
||||||
|
|
||||||
|
also. can't we move the coords? maybe not? maybe only for one
|
||||||
|
so, what do i do? to get the ends of the lines?
|
||||||
|
i try to calcluate with both x & y in 2 min\max. then if the other is ok, than that's the ends?
|
||||||
|
wait, what happens when i do x = 7, and x = 27 and y is outside? it means no intesections, i guess
|
||||||
|
or it could be outside from different sides, so not all x are ok, but there's still line there
|
||||||
|
* Using homogeneous coordinates
|
||||||
|
https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
|
||||||
|
no, i don't understant that
|
||||||
|
* https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection#Given_two_points_on_each_line
|
||||||
|
with 2 points. i guess
|
||||||
|
but also - check if the point in future of the hail, by comparing with speeds?
|
||||||
|
should be easy
|
6
main.go
6
main.go
|
@ -4,15 +4,15 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"sunshine.industries/aoc2023/day23"
|
"sunshine.industries/aoc2023/day24"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
log.Print("> starting run:")
|
log.Print("> starting run:")
|
||||||
|
|
||||||
result := day23.Run()
|
result := day24.Run()
|
||||||
log.Printf("\n\nday23 result: %d\n****\n", result)
|
log.Printf("\n\nday24 result: %d\n****\n", result)
|
||||||
endTime := time.Now()
|
endTime := time.Now()
|
||||||
diff := endTime.Sub(startTime)
|
diff := endTime.Sub(startTime)
|
||||||
log.Printf("execution took %s", diff.String())
|
log.Printf("execution took %s", diff.String())
|
||||||
|
|
Loading…
Reference in New Issue