package main
import (
"bufio"
"fmt"
"log"
"os"
)
func digitsToString(input []int) string {
var str string
for i := range input {
str += fmt.Sprintf("%d", input[i])
}
return str
}
func digitsToInt(input []int) int {
var result int
tens := 1000000
for i := range input {
result += input[i] * tens
tens /= 10
}
return result
}
func getPattern(phase int) []int {
base := []int{0, 1, 0, -1}
pattern := make([]int, 0)
for i := range base {
for j := 0; j < phase; j++ {
pattern = append(pattern, base[i])
}
}
return pattern
}
func phase(input []int, debug bool) []int {
result := make([]int, len(input))
for i := range input {
pattern := getPattern(i + 1)
p := 1
for j := range input {
var prefix string
if j > 0 {
prefix = " + "
}
result[i] += input[j] * pattern[p]
if debug {
fmt.Printf("%s%d*%2d", prefix, input[j], pattern[p])
}
p = (p + 1) % len(pattern)
}
if result[i] < 0 {
result[i] = -result[i]
}
if result[i] > 9 {
result[i] %= 10
}
if debug {
fmt.Printf(" = %d\n", result[i])
}
}
return result
}
func FFT(input []int, phases int, debug bool) []int {
result := make([]int, len(input))
copy(result, input)
if debug {
fmt.Printf("Input signal: %s\n\n", digitsToString(input))
}
var current int
for current < phases {
current++
result = phase(result, debug)
if debug {
fmt.Printf("\nAfter %d phase: %s\n\n", current, digitsToString(result))
}
}
return result
}
func FFT2(input []int, phases, offset int, debug bool) []int {
length := (len(input) * 10000) - offset
result := make([]int, length)
step := offset
for i := 0; i < length; i++ {
result[i] = input[step%len(input)]
step++
}
if debug {
fmt.Printf("Input signal: %s\n\n", digitsToString(input))
}
var current int
for current < phases {
current++
for i := length - 2; i >= 0; i-- {
result[i] = (result[i] + result[i+1]) % 10
}
if debug {
fmt.Printf("\nAfter %d phase: %s\n\n", current, digitsToString(result))
}
}
return result
}
func main() {
input, err := os.Open("input.txt")
if err != nil {
log.Fatal(fmt.Errorf("could not open input file: %w", err))
}
defer input.Close()
scanner := bufio.NewScanner(input)
digits := make([]int, 0)
for scanner.Scan() {
r := scanner.Bytes()
for i := range r {
digits = append(digits, int(r[i]-48))
}
}
p1 := FFT(digits, 100, false)
p2 := FFT2(digits, 100, digitsToInt(digits[:7]), false)
fmt.Printf("Part 1: %s\n", digitsToString(p1[:8]))
fmt.Printf("Part 2: %s\n", digitsToString(p2[:8]))
}