247 lines
5.4 KiB
Go
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)
|
|
}
|