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) }