226 lines
3.3 KiB
Go
226 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
func mustAtoi(line rune) int {
|
|
i, _ := strconv.Atoi(string(line))
|
|
return i
|
|
}
|
|
|
|
func main() {
|
|
start := time.Now()
|
|
partOne()
|
|
duration := time.Since(start)
|
|
partTwo()
|
|
duration2 := time.Since(start)
|
|
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
|
|
}
|
|
|
|
func makeScanner(test bool) *bufio.Scanner {
|
|
var f *os.File
|
|
if test {
|
|
f, _ = os.Open("inputs/testinput")
|
|
} else {
|
|
f, _ = os.Open("inputs/input")
|
|
}
|
|
reader := bufio.NewReader(f)
|
|
return bufio.NewScanner(reader)
|
|
}
|
|
|
|
type pair struct {
|
|
parent *pair
|
|
leftp *pair
|
|
left int
|
|
rightp *pair
|
|
right int
|
|
}
|
|
|
|
func Parse(raw string) *pair {
|
|
root := &pair{}
|
|
var current *pair
|
|
left := true
|
|
for _, v := range raw {
|
|
switch v {
|
|
case '[':
|
|
if current == nil {
|
|
current = root
|
|
} else {
|
|
p := &pair{parent: current}
|
|
if left {
|
|
current.leftp = p
|
|
} else {
|
|
current.rightp = p
|
|
}
|
|
current = p
|
|
}
|
|
left = true
|
|
case ']':
|
|
current = current.parent
|
|
case ',':
|
|
left = false
|
|
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
|
if left {
|
|
current.left = mustAtoi(v)
|
|
} else {
|
|
current.right = mustAtoi(v)
|
|
}
|
|
case ' ':
|
|
continue
|
|
default:
|
|
panic("what the: " + string(v))
|
|
}
|
|
}
|
|
return root
|
|
}
|
|
|
|
func (p *pair) String() string {
|
|
var left, right string
|
|
if p.leftp == nil {
|
|
left = fmt.Sprintf("%d", p.left)
|
|
} else {
|
|
left = p.leftp.String()
|
|
}
|
|
if p.rightp == nil {
|
|
right = fmt.Sprintf("%d", p.right)
|
|
} else {
|
|
right = p.rightp.String()
|
|
}
|
|
return fmt.Sprintf("[%s,%s]", left, right)
|
|
}
|
|
|
|
func (p *pair) Magnitude() int {
|
|
left := 0
|
|
right := 0
|
|
if p.leftp == nil {
|
|
left = p.left
|
|
} else {
|
|
left = p.leftp.Magnitude()
|
|
}
|
|
if p.rightp == nil {
|
|
right = p.right
|
|
} else {
|
|
right = p.rightp.Magnitude()
|
|
}
|
|
return left*3 + right*2
|
|
}
|
|
|
|
func Add(left, right *pair) *pair {
|
|
return &pair{
|
|
leftp: left,
|
|
rightp: right,
|
|
}
|
|
}
|
|
|
|
func Reduce(p *pair) {
|
|
for {
|
|
if MustExplode(0, p) {
|
|
Explode(p)
|
|
} else if MustSplit(p) {
|
|
Split(p)
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func Split(p *pair) bool {
|
|
if p.left > 9 {
|
|
p.leftp = &pair{
|
|
left: p.left / 2,
|
|
right: (p.left / 2) + (p.left % 2),
|
|
}
|
|
p.left = 0
|
|
return true
|
|
}
|
|
if p.leftp != nil {
|
|
m := Split(p.leftp)
|
|
if m {
|
|
return true
|
|
}
|
|
}
|
|
if p.right > 9 {
|
|
p.rightp = &pair{
|
|
left: p.right / 2,
|
|
right: (p.right / 2) + (p.right % 2),
|
|
}
|
|
p.right = 0
|
|
return true
|
|
}
|
|
if p.rightp != nil {
|
|
m := Split(p.rightp)
|
|
if m {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func MustSplit(p *pair) bool {
|
|
if p.left > 9 || p.right > 9 {
|
|
return true
|
|
}
|
|
if p.leftp != nil {
|
|
m := MustSplit(p.leftp)
|
|
if m {
|
|
return true
|
|
}
|
|
}
|
|
if p.rightp != nil {
|
|
m := MustSplit(p.rightp)
|
|
if m {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func MustExplode(depth int, p *pair) bool {
|
|
if depth >= 4 {
|
|
return true
|
|
}
|
|
if p.leftp != nil {
|
|
m := MustExplode(depth+1, p.leftp)
|
|
if m {
|
|
return true
|
|
}
|
|
}
|
|
if p.rightp != nil {
|
|
m := MustExplode(depth+1, p.rightp)
|
|
if m {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func Explode(p *pair) {
|
|
|
|
}
|
|
|
|
func partOne() {
|
|
scanner := makeScanner(false)
|
|
|
|
scanner.Scan()
|
|
line := scanner.Text()
|
|
total := Parse(line)
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
total = Add(total, Parse(line))
|
|
}
|
|
fmt.Println(total)
|
|
}
|
|
|
|
func partTwo() {
|
|
scanner := makeScanner(false)
|
|
|
|
for scanner.Scan() {
|
|
// line := scanner.Text()
|
|
}
|
|
}
|