197 lines
4.2 KiB
Go
197 lines
4.2 KiB
Go
package day24
|
|
|
|
import (
|
|
"log"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
// CoordMin int = 7
|
|
// CoordMax int = 27
|
|
CoordMin int = 200000000000000
|
|
CoordMax int = 400000000000000
|
|
)
|
|
|
|
type Point struct {
|
|
x, y, z int
|
|
}
|
|
|
|
type HailParam struct {
|
|
p0, p1 Point
|
|
Dx, Dy, Dz int
|
|
line string
|
|
// for 2d : ay + bx = 0
|
|
a, b, c int
|
|
// for 2d : y = slope*x + shift
|
|
slope, shift float64
|
|
}
|
|
|
|
func (h *HailParam) SomeString() string {
|
|
return h.line
|
|
}
|
|
|
|
func (h *HailParam) GetCoord(name string) (result int) {
|
|
switch name {
|
|
case "x":
|
|
result = h.p0.x
|
|
case "y":
|
|
result = h.p0.y
|
|
case "z":
|
|
result = h.p0.z
|
|
default:
|
|
panic("unknown param")
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (h *HailParam) GetSpeedOf(name string) (result int) {
|
|
switch name {
|
|
case "x":
|
|
result = h.Dx
|
|
case "y":
|
|
result = h.Dy
|
|
case "z":
|
|
result = h.Dz
|
|
default:
|
|
panic("unknown param")
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
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)
|
|
x, y, intersectAtAll := IntersectBySlopeAndShift(h1, h2)
|
|
if !intersectAtAll {
|
|
log.Println("no intersection at all\n", x, y)
|
|
return false
|
|
}
|
|
isH1Future := h1.FloatPointInFuture(x, y)
|
|
isH2Future := h2.FloatPointInFuture(x, y)
|
|
|
|
if !isH1Future {
|
|
log.Printf("point %f, %f in the past for h1\n", x, y)
|
|
}
|
|
if !isH2Future {
|
|
log.Printf("point %f, %f in the past for h2\n", x, y)
|
|
}
|
|
if !isH1Future || !isH2Future {
|
|
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
|
|
}
|
|
|
|
log.Println("> intersect inside of the area! ", x, y)
|
|
return true
|
|
}
|
|
|
|
func IntersectInTheeDimentions(h1, h2 HailParam) (interX, interY, interZ float64,
|
|
interT float64, isIntersecting bool) {
|
|
|
|
return
|
|
}
|
|
|
|
func IntersectBySlopeAndShift(h1, h2 HailParam) (intersectionX, intersectionY float64, isIntersecting bool) {
|
|
if h1.slope == h2.slope {
|
|
return
|
|
}
|
|
// y = slope * x + shift
|
|
// slope1 * x + shift1 = slope2 * x + shift2
|
|
// x = ( shift2 - shift1 ) / (slope1 - slope2)
|
|
|
|
x := (h2.shift - h1.shift) / (h1.slope - h2.slope)
|
|
y := h1.slope*x + h1.shift
|
|
|
|
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
|
|
return xPositiveSteps
|
|
}
|
|
|
|
// 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])
|
|
|
|
countP1AfterMillis := 1
|
|
|
|
h.p1.x = h.p0.x + countP1AfterMillis*h.Dx
|
|
h.p1.y = h.p0.y + countP1AfterMillis*h.Dy
|
|
h.p1.z = h.p0.z + countP1AfterMillis*h.Dz
|
|
|
|
h.a = h.p0.y - h.p1.y
|
|
h.b = h.p1.x - h.p0.x
|
|
h.c = -(h.p0.x*h.p1.y - h.p1.x*h.p0.y)
|
|
|
|
h.slope = float64(h.Dy) / float64(h.Dx)
|
|
// y = slope * x + shift
|
|
// shift = y - slope * x // for some point
|
|
h.shift = float64(h.p0.y) - h.slope*float64(h.p0.x)
|
|
|
|
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
|
|
}
|