2023 Day 21 Complete

This commit is contained in:
2023-12-26 10:25:53 -06:00
parent b393c79247
commit 3d42462d4c
4 changed files with 230 additions and 169 deletions

View File

@@ -1,194 +1,85 @@
package main
import (
"container/list"
"fmt"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
"image"
"os"
"strings"
)
func main() {
inp := h.StdinToStringSlice()
part1(inp)
fmt.Println()
part2(inp)
}
data, _ := os.ReadFile("input")
answer := solution(data, 64)
func part1(input []string) {
m := h.StringSliceToCoordByteMap(input)
start, _ := m.FindFirst('S')
m.Put(start, '.')
result := []h.Coordinate{start}
for i := 0; i < 64; i++ {
result = findNext(&m, result)
}
fmt.Println("# Part 1")
fmt.Println(len(result))
}
// 253370351984188 is too low
func part2(input []string) {
m := h.StringSliceToCoordByteMap(input)
start, _ := m.FindFirst('S')
m.Put(start, '.')
steps := 26501365
p := make([]int, 3)
size := len(input)
half := size / 2
fmt.Println("Getting Plots: p[0]")
p[0], _ = getPlots(&m, half, 5)
fmt.Println("Getting Plots: p[1]")
m = h.StringSliceToCoordByteMap(input)
p[1], _ = getPlots(&m, half+size, 5)
fmt.Println("Getting Plots: p[2]")
m = h.StringSliceToCoordByteMap(input)
p[2], _ = getPlots(&m, half+2*size, 5)
a := (p[2] + p[0] - 2*p[1]) / 2
b := p[1] - p[0] - a
c := p[0]
n := steps / size
result := a*n*n + b*n + c
fmt.Println(answer[0])
fmt.Println("# Part 2")
fmt.Println(result)
fmt.Println(answer[1])
}
var visited map[string]bool
func getPlots(m *h.CoordByteMap, steps int, factor int) (int, error) {
sx, sy := m.ColCount(), m.RowCount()
l := sy
expandMap(m, factor)
sx = l * (factor / 2)
sy = l * (factor / 2)
visited = make(map[string]bool)
return len(nextStep(sx, sy, 0, steps, m)), nil
}
func isPlot(m *h.CoordByteMap, x, y int) bool {
return m.Get(h.Coordinate{X: x, Y: y}) == '.'
}
func nextStep(x, y, step, max int, m *h.CoordByteMap) []h.Coordinate {
var acc []h.Coordinate
var key = fmt.Sprintf("%d;%d;%d", x, y, step)
if _, ok := visited[key]; ok {
return []h.Coordinate{}
} else {
visited[key] = true
}
if step == max {
return []h.Coordinate{{X: x, Y: y}}
}
if x > 0 && isPlot(m, x-1, y) {
acc = append(acc, nextStep(x-1, y, step+1, max, m)...)
}
if x < m.ColCount() && isPlot(m, x+1, y) {
acc = append(acc, nextStep(x, y-1, step+1, max, m)...)
}
if y > 0 && isPlot(m, x, y-1) {
acc = append(acc, nextStep(x, y-1, step+1, max, m)...)
}
if y < m.RowCount() && isPlot(m, x, y+1) {
acc = append(acc, nextStep(x, y+1, step+1, max, m)...)
}
return acc
}
func expandMap(m *h.CoordByteMap, factor int) {
stx, edx := m.TLX, m.BRX
for f := 1; f < factor; f++ {
for x := stx; x <= edx; x++ {
col := m.GetCol(x)
m.AddCol(col)
}
sty, edy := m.TLY, m.BRY
for y := sty; y <= edy; y++ {
row := m.GetRow(y)
m.AddRow(row)
func solution(data []byte, total_steps int) []int {
lines := strings.Split(strings.TrimSpace(string(data)), "\n")
q := list.New()
symbols := map[image.Point]string{}
for y, line := range lines {
l := strings.TrimSpace(line)
//fmt.Println(len(s))
for x, r := range l {
symbols[image.Point{x, y}] = string(r)
if r == 'S' {
q.PushBack(image.Point{x, y})
}
}
}
}
func part2BruteForce(input []string) {
// Brute force just isn't going to cut it...
m := h.StringSliceToCoordByteMap(input)
m.StringEmptyIsSpace = true
m.StringEmptyByte = '.'
seen := make(map[h.Coordinate]bool)
start, _ := m.FindFirst('S')
m.Put(start, '.')
result := []h.Coordinate{start}
steps := 26501365
for i := 0; i < steps; i++ {
fmt.Println(h.CLEAR_SCREEN)
fmt.Printf("%d/%d (%f)\n", i, steps, float64(i)/float64(steps))
seen, result = findNextInfiniteRepeat(&m, seen, result)
if i == 100 {
break
}
}
fmt.Println("# Part 2")
fmt.Println(len(result))
for i := range result {
m.Put(result[i], 'O')
}
fmt.Println(m)
// It's making a diamond shape...
}
steps := 0
total := 26501365
part_1 := 0
part_2 := 0
func findNext(m *h.CoordByteMap, curr []h.Coordinate) []h.Coordinate {
var result []h.Coordinate
for _, c := range curr {
for _, tst := range []h.Coordinate{
c.North(), c.East(), c.South(), c.West(),
} {
if m.ContainsCoord(tst) && m.Get(tst) == '.' {
var contains bool
for i := range result {
if result[i].Equals(tst) {
contains = true
break
directions := []image.Point{
{-1, 0}, {0, -1}, {0, 1}, {1, 0},
}
polynomial := make([]int, 0)
for steps < total {
new_Q := list.New()
visited := make(map[image.Point]bool)
for q.Len() > 0 {
element := q.Front()
val := element.Value.(image.Point)
q.Remove(element)
x, y := val.X, val.Y
for _, d := range directions {
newPos := image.Point{x + d.X, y + d.Y}
ref := image.Point{((newPos.Y % len(lines)) + len(lines)) % len(lines), ((newPos.X % len(lines)) + len(lines)) % len(lines)}
if symbols[ref] != "#" {
if _, ok := visited[newPos]; !ok {
visited[newPos] = true
new_Q.PushBack(newPos)
}
}
if !contains {
result = append(result, tst)
}
}
}
}
return result
}
steps += 1
q = new_Q //update queue
if steps%(len(lines)) == total%len(lines) {
polynomial = append(polynomial, len(visited))
if len(polynomial) == 3 {
p0 := polynomial[0]
p1 := polynomial[1] - polynomial[0]
p2 := polynomial[2] - polynomial[1]
func findNextInfiniteRepeat(m *h.CoordByteMap, seen map[h.Coordinate]bool, curr []h.Coordinate) (map[h.Coordinate]bool, []h.Coordinate) {
var result []h.Coordinate
for _, c := range curr {
for _, tst := range []h.Coordinate{
c.North(), c.East(), c.South(), c.West(),
} {
if seen[tst] {
continue
}
wrkX, wrkY := tst.X, tst.Y
for wrkX < m.TLX {
wrkX += m.BRX
}
for wrkY < m.TLY {
wrkY += m.BRY
}
wrk := h.Coordinate{X: (wrkX % m.BRX), Y: (wrkY % m.BRY)}
if m.Get(wrk) == '.' {
var contains bool
for i := range result {
if result[i].Equals(tst) {
contains = true
break
}
}
if !contains {
result = append(result, tst)
seen[tst] = true
}
part_2 = p0 + (p1 * (total / len(lines))) + ((total/len(lines))*((total/len(lines))-1)/2)*(p2-p1)
break
}
}
if steps == total_steps {
part_1 = len(visited)
}
}
return seen, result
return []int{part_1, part_2}
}