package main import ( "fmt" "strings" h "git.bullercodeworks.com/brian/adventofcode/helpers" ) var minX, maxX, minY, maxY int func main() { maxX = h.MIN_INT minX = h.MAX_INT maxY = h.MIN_INT minY = h.MAX_INT inp := h.StdinToStringSlice() lines := parseLines(inp) fmt.Println("# Part 1") findDangerSpots(filterStraight(lines)) fmt.Println("# Part 2") findDangerSpots(lines) } var ventMap map[h.Coordinate]int var dangerSpots []h.Coordinate func dingMap(c h.Coordinate) { s := ventMap[c] s++ if s == 2 { dangerSpots = append(dangerSpots, c) } ventMap[c] = s } func findDangerSpots(lines []Line) { ventMap = make(map[h.Coordinate]int) for i := range lines { updateMinMax(lines[i]) } for _, l := range lines { // Find all points on this line // All lines are 0 or 45 deg, so slope should always be 0,1,-1,INF,-INF if l.start.X == l.end.X { // INF, -INF: vertical for y := l.lowestY(); y <= l.highestY(); y++ { dingMap(h.Coordinate{X: l.start.X, Y: y}) } } else if l.start.Y == l.end.Y { //0: horizontal for x := l.start.X; x <= l.end.X; x++ { dingMap(h.Coordinate{Y: l.start.Y, X: x}) } } else { // 1 or -1 y := l.start.Y x := l.start.X dingMap(h.Coordinate{Y: y, X: x}) diffY := -1 if l.start.Y < l.end.Y { diffY = 1 } for x != l.end.X && y != l.end.Y { x += 1 y += diffY dingMap(h.Coordinate{Y: y, X: x}) } } } fmt.Println("Danger Spots:", len(dangerSpots)) } type Line struct { start h.Coordinate end h.Coordinate stX float64 stY float64 edX float64 edY float64 slope float64 } func (l *Line) lowestY() int { if l.start.Y < l.end.Y { return l.start.Y } return l.end.Y } func (l *Line) highestY() int { if l.start.Y > l.end.Y { return l.start.Y } return l.end.Y } func (l *Line) intersects(c h.Coordinate) bool { ptX := float64(c.X) ptY := float64(c.Y) if (c.X == l.start.X && c.Y == l.start.Y) || (c.X == l.end.X && c.Y == l.end.Y) { return true } if c.X < l.start.X || c.X > l.end.X { return false } if (c.Y < l.start.Y && c.Y < l.end.Y) || (c.Y > l.start.Y && c.Y > l.end.Y) { return false } // Check if our slope is infinite if l.start.X == l.end.X { if l.start.Y < l.end.Y { return c.X == l.start.X && c.Y >= l.start.Y && c.Y <= l.end.Y } else { return c.X == l.start.X && c.Y <= l.start.Y && c.Y >= l.end.Y } } return slope(ptX, ptY, l.stX, l.stY) == l.slope } func (l Line) String() string { return fmt.Sprintf("%d,%d -> %d,%d; [%f]", l.start.X, l.start.Y, l.end.X, l.end.Y, l.slope) } func LineFromString(str string) Line { start := h.Coordinate{} end := h.Coordinate{} r := strings.NewReader(str) _, err := fmt.Fscanf(r, "%d,%d -> %d,%d", &start.X, &start.Y, &end.X, &end.Y) if err != nil { panic(err) } var l Line if start.X < end.X { l = Line{ start: start, end: end, } } else { l = Line{ start: end, end: start, } } l.stX = float64(l.start.X) l.stY = float64(l.start.Y) l.edX = float64(l.end.X) l.edY = float64(l.end.Y) l.slope = slope(l.stX, l.stY, l.edX, l.edY) return l } func updateMinMax(line Line) { if line.start.X < minX { minX = line.start.X } if line.start.X > maxX { maxX = line.start.X } if line.end.X < minX { minX = line.end.X } if line.end.X > maxX { maxX = line.end.X } if line.start.Y < minY { minY = line.start.Y } if line.start.Y > maxY { maxY = line.start.Y } if line.end.Y < minY { minY = line.end.Y } if line.end.Y > maxY { maxY = line.end.Y } } func parseLines(inp []string) []Line { var ret []Line for i := range inp { ret = append(ret, LineFromString(inp[i])) } return ret } func filterStraight(lines []Line) []Line { var ret []Line for i := range lines { if lines[i].start.X == lines[i].end.X || lines[i].start.Y == lines[i].end.Y { ret = append(ret, lines[i]) } } return ret } func slope(x1, y1, x2, y2 float64) float64 { return (y1 - y2) / (x1 - x2) }