package main
import (
"bufio"
"log"
"math"
"os"
"regexp"
"strconv"
"strings"
)
func main() {
if err := myMain(); err != nil {
log.Println(err)
}
}
func myMain() error {
in, err := parseInput("input.txt")
if err != nil {
return err
}
log.Println(solveFirst(in))
log.Println(solveSecond(in))
return nil
}
func solveSecond(in []string) int {
var max int
for _, x := range in {
for _, y := range in {
if x == y {
continue
}
xy := reduce("[" + x + "," + y + "]")
m, _ := magnitude(xy, 0)
if m > max {
max = m
}
}
}
return max
}
func solveFirst(in []string) int {
var ret string
for _, st := range in {
if ret == "" {
ret = st
} else {
ret = reduce("[" + ret + "," + st + "]")
}
}
res, _ := magnitude(ret, 0)
return res
}
func magnitude(in string, pos int) (int, int) {
left, right := -1, -1
var rght bool
var skip int
for i := pos; i < len(in); i++ {
if in[i] == ']' {
skip = i - pos + 1
break
}
if in[i] == '[' {
var p int
if rght {
right, p = magnitude(in, i+1)
} else {
left, p = magnitude(in, i+1)
}
i += p
continue
}
switch in[i] {
case ',':
rght = true
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
tmp, err := strconv.Atoi(string(in[i]))
if err != nil {
log.Panicln(err)
}
if rght {
right = tmp
} else {
left = tmp
}
}
}
if left == -1 || right == -1 {
return left + right + 1, skip
}
return 3*left + 2*right, skip
}
func reduce(in string) string {
if next := explode(in); next != in {
in = reduce(next)
} else if next := split(in); next != in {
in = reduce(next)
}
return in
}
func explode(in string) string {
var count int
for i, ch := range in {
if ch == '[' {
count++
if count == 5 {
return doExplode(in, i)
}
}
if ch == ']' {
count--
}
}
return in
}
var number = regexp.MustCompile(`\d+`)
func doExplode(in string, pivot int) string {
lefts := number.FindAllStringSubmatchIndex(in[:pivot+1], -1)
rights := number.FindAllStringSubmatchIndex(in[pivot:], 3)
expLeft := []int{pivot + rights[0][0], pivot + rights[0][1]}
expRight := []int{pivot + rights[1][0], pivot + rights[1][1]}
var l, r []int
if len(lefts) > 0 {
l = []int{lefts[len(lefts)-1][0], lefts[len(lefts)-1][1]}
}
if len(rights) > 2 { r = []int{pivot + rights[2][0], pivot + rights[2][1]}
}
ret := strings.Builder{}
if len(l) != 0 {
ret.WriteString(in[:l[0]])
leftNum, err := strconv.Atoi(in[l[0]:l[1]])
if err != nil {
log.Panicln(err)
}
explodeLeftNum, err := strconv.Atoi(in[expLeft[0]:expLeft[1]])
if err != nil {
log.Panicln(err)
}
ret.WriteString(strconv.Itoa(leftNum + explodeLeftNum))
ret.WriteString(in[l[1] : expLeft[0]-1])
} else {
ret.WriteString(in[:expLeft[0]-1])
}
ret.WriteByte('0')
if len(r) != 0 {
ret.WriteString(in[expRight[1]+1 : r[0]])
rightNum, err := strconv.Atoi(in[r[0]:r[1]])
if err != nil {
log.Panicln(err)
}
explodeRightNum, err := strconv.Atoi(in[expRight[0]:expRight[1]])
if err != nil {
log.Panicln(err)
}
ret.WriteString(strconv.Itoa(rightNum + explodeRightNum))
ret.WriteString(in[r[1]:])
} else {
ret.WriteString(in[expRight[1]+1:])
}
return ret.String()
}
var twodigit = regexp.MustCompile(`\d\d+`)
func split(in string) string {
if split := twodigit.FindStringIndex(in); len(split) != 0 {
in = doSplit(in, split)
}
return in
}
func doSplit(in string, split []int) string {
ret := strings.Builder{}
ret.WriteString(in[:split[0]])
sno, err := strconv.Atoi(in[split[0]:split[1]])
if err != nil {
log.Panicln(err)
}
ret.WriteByte('[')
ret.WriteString(strconv.Itoa(sno / 2))
ret.WriteByte(',')
ret.WriteString(strconv.Itoa(int(math.Ceil(float64(sno) / 2))))
ret.WriteByte(']')
ret.WriteString(in[split[1]:])
return ret.String()
}
func parseInput(fileName string) ([]string, error) {
ret := []string{}
fd, err := os.Open(fileName)
if err != nil {
return ret, err
}
defer fd.Close()
buf := bufio.NewScanner(fd)
for buf.Scan() {
ret = append(ret, buf.Text())
}
return ret, nil
}