2021 Day 5
This commit is contained in:
parent
32df24304d
commit
6e64e705b3
2 changed files with 171 additions and 0 deletions
|
|
@ -2,6 +2,8 @@ package aoc
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -36,3 +38,49 @@ func MustInt(s string) int {
|
|||
}
|
||||
return i
|
||||
}
|
||||
|
||||
type Inputs struct {
|
||||
fs fs.FS
|
||||
}
|
||||
|
||||
func (i Inputs) ReadLines(path string) (lines []string) {
|
||||
f, err := i.fs.Open(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
lines = append(lines, scanner.Text())
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
func (i Inputs) ReadFile(path string) string {
|
||||
f, err := i.fs.Open(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
b, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return strings.TrimSpace(string(b))
|
||||
}
|
||||
|
||||
func Input() Inputs {
|
||||
if len(os.Args) > 1 {
|
||||
return Inputs{os.DirFS(os.Args[1])}
|
||||
}
|
||||
return Inputs{os.DirFS("./input")}
|
||||
}
|
||||
|
||||
// Cut will be added to strings in Go 1.18, so hack it in for now!
|
||||
func Cut(s, sep string) (before, after string) {
|
||||
if i := strings.Index(s, sep); i >= 0 {
|
||||
return s[:i], s[i+len(sep):]
|
||||
}
|
||||
panic("Separator was not found in string")
|
||||
}
|
||||
|
|
|
|||
123
2021/day5/main.go
Normal file
123
2021/day5/main.go
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/jdkaplan/advent-of-code/aoc"
|
||||
)
|
||||
|
||||
type Point struct {
|
||||
x, y int
|
||||
}
|
||||
|
||||
func (p Point) Plus(dx, dy int) Point {
|
||||
return Point{x: p.x + dx, y: p.y + dy}
|
||||
}
|
||||
|
||||
type Line struct {
|
||||
p1, p2 Point
|
||||
}
|
||||
|
||||
func (l Line) Slope() float64 {
|
||||
dx := float64(l.p2.x - l.p1.x)
|
||||
dy := float64(l.p2.y - l.p1.y)
|
||||
return dy / dx
|
||||
}
|
||||
|
||||
func (l Line) Delta() (dx, dy int) {
|
||||
switch s := l.Slope(); s {
|
||||
case 0:
|
||||
if l.p1.x < l.p2.x {
|
||||
return 1, 0
|
||||
}
|
||||
return -1, 0
|
||||
case math.Inf(+1):
|
||||
if l.p1.y < l.p2.y {
|
||||
return 0, 1
|
||||
}
|
||||
return 0, -1
|
||||
case +1:
|
||||
if l.p1.x < l.p2.x {
|
||||
return 1, 1
|
||||
}
|
||||
return -1, -1
|
||||
case -1:
|
||||
if l.p1.x < l.p2.x {
|
||||
return 1, -1
|
||||
}
|
||||
return -1, 1
|
||||
default:
|
||||
panic(s)
|
||||
}
|
||||
}
|
||||
|
||||
func parse(flines []string) (lines []Line) {
|
||||
for _, l := range flines {
|
||||
s, e := aoc.Cut(l, " -> ")
|
||||
x1, y1 := aoc.Cut(s, ",")
|
||||
x2, y2 := aoc.Cut(e, ",")
|
||||
p1 := Point{
|
||||
x: aoc.MustInt(x1),
|
||||
y: aoc.MustInt(y1),
|
||||
}
|
||||
p2 := Point{
|
||||
x: aoc.MustInt(x2),
|
||||
y: aoc.MustInt(y2),
|
||||
}
|
||||
if p1.x > p2.x || p1.y > p2.y {
|
||||
// This point is backwards!
|
||||
p1, p2 = p2, p1
|
||||
}
|
||||
lines = append(lines, Line{p1: p1, p2: p2})
|
||||
}
|
||||
return
|
||||
}
|
||||
func part1(flines []string) int {
|
||||
grid := make(map[Point]int)
|
||||
for _, l := range parse(flines) {
|
||||
switch l.Slope() {
|
||||
case 0:
|
||||
y := l.p1.y
|
||||
for x := l.p1.x; x <= l.p2.x; x++ {
|
||||
grid[Point{x: x, y: y}]++
|
||||
}
|
||||
case math.Inf(+1), math.Inf(-1):
|
||||
x := l.p1.x
|
||||
for y := l.p1.y; y <= l.p2.y; y++ {
|
||||
grid[Point{x: x, y: y}]++
|
||||
}
|
||||
}
|
||||
}
|
||||
var count int
|
||||
for _, c := range grid {
|
||||
if c > 1 {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func part2(flines []string) int {
|
||||
grid := make(map[Point]int)
|
||||
for _, l := range parse(flines) {
|
||||
dx, dy := l.Delta()
|
||||
for p := l.p1; p != l.p2; p = p.Plus(dx, dy) {
|
||||
grid[p]++
|
||||
}
|
||||
grid[l.p2]++
|
||||
}
|
||||
var count int
|
||||
for _, c := range grid {
|
||||
if c > 1 {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func main() {
|
||||
lines := aoc.Input().ReadLines("day5.txt")
|
||||
fmt.Println(part1(lines))
|
||||
fmt.Println(part2(lines))
|
||||
}
|
||||
Loading…
Reference in a new issue