package main import ( "bufio" "fmt" "os" "strconv" "time" ) 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 mustAtoi(line []byte) int { i, err := strconv.Atoi(string(line)) if err != nil { panic(err) } return i } type point struct { x int y int } type grid struct { m map[int]int } func (g *grid) AddLine(start, end point, includeHorizontal bool) { for _, p := range LineFromPoints(start, end, includeHorizontal) { g.m[p.x+p.y*1000]++ } } func LineFromPoints(start, end point, includeHorizontal bool) []point { if start.x != end.x && start.y != end.y && !includeHorizontal { return []point{} } var xstep, ystep int if start.x > end.x { xstep = -1 } if start.x < end.x { xstep = 1 } if start.y > end.y { ystep = -1 } if start.y < end.y { ystep = 1 } points := []point{} for i, j := start.x, start.y; i != end.x+xstep || j != end.y+ystep; i, j = i+xstep, j+ystep { points = append(points, point{x: i, y: j}) } return points } func parsePoints(line string) (point, point) { var start, end point var num []byte // accumulator var state int // parser state: 0: x1 1: y1 2: x2 3: y2 for i := 0; i < len(line); i++ { switch line[i] { case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': num = append(num, line[i]) case ' ': start.y = mustAtoi(num) num = []byte{} i += 3 // jump past '-> ' state = 2 case ',': if state == 0 { start.x = mustAtoi(num) num = []byte{} state = 1 } if state == 2 { end.x = mustAtoi(num) num = []byte{} state = 3 } } } end.y = mustAtoi(num) return start, end } func partOne() { scanner := makeScanner(false) grid := &grid{ m: make(map[int]int, 1000), } for scanner.Scan() { line := scanner.Text() start, end := parsePoints(line) grid.AddLine(start, end, false) } var danger int for i := range grid.m { if grid.m[i] > 1 { danger++ } } fmt.Println(danger) } func partTwo() { scanner := makeScanner(false) grid := &grid{ m: make(map[int]int, 1000), } for scanner.Scan() { line := scanner.Text() start, end := parsePoints(line) grid.AddLine(start, end, true) } var danger int for i := range grid.m { if grid.m[i] > 1 { danger++ } } fmt.Println(danger) }