163 lines
2.4 KiB
Go
163 lines
2.4 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
_ "embed"
|
||
|
"fmt"
|
||
|
|
||
|
aoc "go.sour.is/advent-of-code"
|
||
|
)
|
||
|
|
||
|
// var log = aoc.Log
|
||
|
|
||
|
func main() { aoc.MustResult(aoc.Runner(run)) }
|
||
|
|
||
|
type result struct {
|
||
|
valuePT1 int
|
||
|
valuePT2 int
|
||
|
}
|
||
|
|
||
|
type record struct {
|
||
|
p aoc.Point[int]
|
||
|
d [2]int
|
||
|
}
|
||
|
|
||
|
func (r result) String() string { return fmt.Sprintf("%#v", r) }
|
||
|
|
||
|
func run(scan *bufio.Scanner) (*result, error) {
|
||
|
|
||
|
m := make([][]rune, 0, 1000)
|
||
|
var records []record
|
||
|
var records2 []record
|
||
|
|
||
|
for scan.Scan() {
|
||
|
txt := scan.Text()
|
||
|
m = append(m, []rune(txt))
|
||
|
}
|
||
|
|
||
|
for x, row := range m {
|
||
|
for y, c := range row {
|
||
|
if c == 'X' {
|
||
|
rs := search1(record{
|
||
|
p: aoc.Point[int]{x, y},
|
||
|
}, m)
|
||
|
records = append(records, rs...)
|
||
|
}
|
||
|
|
||
|
if c == 'A' {
|
||
|
rs := search2(record{
|
||
|
p: aoc.Point[int]{x, y},
|
||
|
}, m)
|
||
|
if len(rs) == 2 {
|
||
|
records2 = append(records2, rs...)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for _, r := range records2 {
|
||
|
fmt.Println(r)
|
||
|
}
|
||
|
|
||
|
|
||
|
return &result{len(records), len(records2)/2}, nil
|
||
|
}
|
||
|
|
||
|
func search1(r record, m [][]rune) []record {
|
||
|
var ds = [][2]int{
|
||
|
{1, 0}, // up
|
||
|
{0, 1}, // right
|
||
|
{-1, 0}, // down
|
||
|
{0, -1}, // left
|
||
|
{1, 1}, // up-right
|
||
|
{1, -1}, // up-left
|
||
|
{-1, 1}, // down-right
|
||
|
{-1, -1}, // down-left
|
||
|
}
|
||
|
|
||
|
var records []record
|
||
|
|
||
|
for _, d := range ds {
|
||
|
p := r.p
|
||
|
if !check1(m, p, d) {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
records = append(records, record{
|
||
|
p: p,
|
||
|
d: d,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
return records
|
||
|
}
|
||
|
|
||
|
func check1(m [][]rune, p aoc.Point[int], d [2]int) bool {
|
||
|
for _, r := range []rune{'M', 'A', 'S'} {
|
||
|
p[0] += d[0]
|
||
|
p[1] += d[1]
|
||
|
if p[0] < 0 || p[0] >= len(m) {
|
||
|
return false
|
||
|
}
|
||
|
if p[1] < 0 || p[1] >= len(m[0]) {
|
||
|
return false
|
||
|
}
|
||
|
if m[p[0]][p[1]] != r {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func search2(r record, m [][]rune) []record {
|
||
|
var ds = [][2]int{
|
||
|
{1, 1}, // up-right
|
||
|
{1, -1}, // up-left
|
||
|
{-1, 1}, // down-right
|
||
|
{-1, -1}, // down-left
|
||
|
}
|
||
|
var records []record
|
||
|
|
||
|
for _, d := range ds {
|
||
|
p := r.p
|
||
|
if !check2(m, p, d) {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
records = append(records, record{
|
||
|
p: p,
|
||
|
d: d,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
return records
|
||
|
}
|
||
|
|
||
|
func check2(m [][]rune, p aoc.Point[int], d [2]int) bool {
|
||
|
p0 := p[0] - d[0]
|
||
|
p1 := p[1] - d[1]
|
||
|
if p0 < 0 || p0 >= len(m) {
|
||
|
return false
|
||
|
}
|
||
|
if p1 < 0 || p1 >= len(m[0]) {
|
||
|
return false
|
||
|
}
|
||
|
if m[p0][p1] != 'M' {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
p0 = p[0] + d[0]
|
||
|
p1 = p[1] + d[1]
|
||
|
if p0 < 0 || p0 >= len(m) {
|
||
|
return false
|
||
|
}
|
||
|
if p1 < 0 || p1 >= len(m[0]) {
|
||
|
return false
|
||
|
}
|
||
|
if m[p0][p1] != 'S' {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
return true
|
||
|
}
|