AOC-2024/12/main.go
2024-12-13 00:45:58 +01:00

247 lines
5.4 KiB
Go

package main
import (
"bufio"
"fmt"
"os"
"time"
)
const FILE_PATH = "./input.txt"
//const FILE_PATH = "./sample.txt"
func LoadInput(filename string) ([]string, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
var lines []string
scanner := bufio.NewScanner(file)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
if err := scanner.Err(); err != nil {
return nil, err
}
return lines, nil
}
type structuredInput = [][]byte
func TransformInput(lines []string) structuredInput {
var result = make([][]byte, 0)
for _, line := range lines {
result = append(result, []byte(line))
}
return result
}
func calcCircumAndSize(input structuredInput, visited [][]bool, char byte, x int, y int) (int, int) {
visited[y][x] = true
var size = 1
var circum = 0
var tempSize = 0
var tempCircum = 0
if x-1 < 0 || input[y][x-1] != char {
circum += 1
} else if !visited[y][x-1] {
tempCircum, tempSize = calcCircumAndSize(input, visited, char, x-1, y)
size += tempSize
circum += tempCircum
}
if x+1 >= len(input[y]) || input[y][x+1] != char {
circum += 1
} else if !visited[y][x+1] {
tempCircum, tempSize = calcCircumAndSize(input, visited, char, x+1, y)
size += tempSize
circum += tempCircum
}
if y-1 < 0 || input[y-1][x] != char {
circum += 1
} else if !visited[y-1][x] {
tempCircum, tempSize = calcCircumAndSize(input, visited, char, x, y-1)
size += tempSize
circum += tempCircum
}
if y+1 >= len(input) || input[y+1][x] != char {
circum += 1
} else if !visited[y+1][x] {
tempCircum, tempSize = calcCircumAndSize(input, visited, char, x, y+1)
size += tempSize
circum += tempCircum
}
return circum, size
}
type Fence struct {
verL bool
horU bool
verR bool
horD bool
}
func calcFenceAndSize(input structuredInput, visited [][]bool, char byte, x int, y int, fence [][]Fence) int {
visited[y][x] = true
var size = 1
if x-1 < 0 || input[y][x-1] != char {
fence[y+1][x-1+1].verL = true
} else if !visited[y][x-1] {
size += calcFenceAndSize(input, visited, char, x-1, y, fence)
}
if x+1 >= len(input[y]) || input[y][x+1] != char {
fence[y+1][x+1+1].verR = true
} else if !visited[y][x+1] {
size += calcFenceAndSize(input, visited, char, x+1, y, fence)
}
if y-1 < 0 || input[y-1][x] != char {
fence[y-1+1][x+1].horU = true
} else if !visited[y-1][x] {
size += calcFenceAndSize(input, visited, char, x, y-1, fence)
}
if y+1 >= len(input) || input[y+1][x] != char {
fence[y+1+1][x+1].horD = true
} else if !visited[y+1][x] {
size += calcFenceAndSize(input, visited, char, x, y+1, fence)
}
return size
}
func Part1(input structuredInput) int {
var result = 0
var visited [][]bool = make([][]bool, len(input))
var size int = 0
var circum int = 0
for i := 0; i < len(input); i++ {
visited[i] = make([]bool, len(input[i]))
}
for y := 0; y < len(input); y++ {
for x := 0; x < len(input[y]); x++ {
if !visited[y][x] {
circum, size = calcCircumAndSize(input, visited, input[y][x], x, y)
result += circum * size
}
}
}
return result
}
func Part2(input structuredInput) int {
var result = 0
var visited [][]bool = make([][]bool, len(input))
var size int = 0
var fence [][]Fence
var sides int
var insideSide1 bool
var insideSide2 bool
for i := 0; i < len(input); i++ {
visited[i] = make([]bool, len(input[i]))
}
for y := 0; y < len(input); y++ {
for x := 0; x < len(input[y]); x++ {
if !visited[y][x] {
fence = make([][]Fence, len(input)+2)
for i := 0; i < len(input)+2; i++ {
fence[i] = make([]Fence, len(input[0])+2)
}
size = calcFenceAndSize(input, visited, input[y][x], x, y, fence)
sides = 0
for m := 0; m < len(fence); m++ {
insideSide1 = false
insideSide2 = false
for n := 0; n < len(fence[m]); n++ {
if insideSide1 && !fence[m][n].horU {
insideSide1 = false
sides += 1
} else if !insideSide1 && fence[m][n].horU {
insideSide1 = true
}
if insideSide2 && !fence[m][n].horD {
insideSide2 = false
sides += 1
} else if !insideSide2 && fence[m][n].horD {
insideSide2 = true
}
}
if insideSide1 {
sides += 1
}
if insideSide2 {
sides += 1
}
}
for n := 0; n < len(fence[0]); n++ {
insideSide1 = false
insideSide2 = false
for m := 0; m < len(fence); m++ {
if insideSide1 && !fence[m][n].verL {
insideSide1 = false
sides += 1
} else if !insideSide1 && fence[m][n].verL {
insideSide1 = true
}
if insideSide2 && !fence[m][n].verR {
insideSide2 = false
sides += 1
} else if !insideSide2 && fence[m][n].verR {
insideSide2 = true
}
}
if insideSide1 {
sides += 1
}
if insideSide2 {
sides += 1
}
}
result += size * sides
}
}
}
return result
}
func main() {
var start time.Time
var elapsed time.Duration = 0
input, err := LoadInput(FILE_PATH)
if err != nil {
fmt.Println("Error loading input:", err)
return
}
structuredInput := TransformInput(input)
fmt.Println("Structured Input:", structuredInput)
start = time.Now()
fmt.Println("Solution Part 1: ", Part1(structuredInput))
elapsed = time.Since(start)
fmt.Printf("Part 1 took %s\n", elapsed)
start = time.Now()
fmt.Println("Solution Part 2: ", Part2(structuredInput))
elapsed = time.Since(start)
fmt.Printf("Part 2 took %s\n", elapsed)
}