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 (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -36,3 +38,49 @@ func MustInt(s string) int {
|
||||||
}
|
}
|
||||||
return i
|
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