Advent of Code 2023

This page covers all the solutions I wrote for Advent of Code 2023 problems; they are all in Go and should be self-contained, expecting the input to be in 'input'. Occasionally I do some input preprocessing; I try to note it in the file if possible.

Syntax highlighting courtesy of codehost.

2023 Day 1a
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	ttl := 0
	for s.Scan() {
		first := 0
		last := 0
		for _, c := range s.Text() {
			if c >= '0' && c <= '9' {
				if first == 0 {
					first = int(c - '0')
				}
				last = int(c - '0')
			}
		}
		ttl += first*10 + last
	}
	fmt.Println(ttl)
}
2023 Day 1b
package main

import (
	"bufio"
	"fmt"
	"os"
)

var (
	digits = map[string]int{"one": 1, "two": 2, "three": 3, "four": 4,
		"five": 5, "six": 6, "seven": 7, "eight": 8, "nine": 9}
)

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	ttl := 0
	for s.Scan() {
		first := 0
		last := 0
		buf := ""
		off := 0
		for _, c := range s.Text() {
			if c >= '0' && c <= '9' {
				if first == 0 {
					first = int(c - '0')
				}
				last = int(c - '0')
				buf = ""
				off = 0
			} else {
				buf += string(c)
				for i := off; i < len(buf); i++ {
					if v, ok := digits[buf[i:]]; ok {
						if first == 0 {
							first = v
						}
						last = v
						off = i
						break
					}
				}
			}
		}
		ttl += first*10 + last
	}
	fmt.Println(ttl)
}
2023 Day 2a
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	idx := 0
	ttl := 0
	for s.Scan() {
		idx++
		bad := false
		for _, game := range strings.Split(s.Text(), ";") {
			r := 0
			g := 0
			b := 0
			for _, v := range strings.Split(game, ",") {
				if s, f := cutSuffix(v, "red"); f {
					r += numberOrDie(s)
				} else if s, f := cutSuffix(v, "blue"); f {
					b += numberOrDie(s)
				} else if s, f := cutSuffix(v, "green"); f {
					g += numberOrDie(s)
				} else {
					panic(fmt.Errorf("bad string seg %q", v))
				}
			}
			if r > 12 || g > 13 || b > 14 {
				bad = true
				break
			}
		}
		if !bad {
			ttl += idx
		}
	}
	fmt.Println(ttl)
}

func numberOrDie(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

// added in go1.20, but i'm still running go 1.19
func cutSuffix(s string, suffix string) (string, bool) {
	if strings.HasSuffix(s, suffix) {
		return s[:len(s)-len(suffix)], true
	}
	return s, false
}
2023 Day 2b
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	ttl := 0
	for s.Scan() {
		rm := 0
		gm := 0
		bm := 0
		for _, game := range strings.Split(s.Text(), ";") {
			r := 0
			g := 0
			b := 0
			for _, v := range strings.Split(game, ",") {
				if s, f := cutSuffix(v, "red"); f {
					r += numberOrDie(s)
				} else if s, f := cutSuffix(v, "blue"); f {
					b += numberOrDie(s)
				} else if s, f := cutSuffix(v, "green"); f {
					g += numberOrDie(s)
				} else {
					panic(fmt.Errorf("bad string seg %q", v))
				}
			}
			if r > rm {
				rm = r
			}
			if g > gm {
				gm = g
			}
			if b > bm {
				bm = b
			}
		}
		ttl += rm*gm*bm
	}
	fmt.Println(ttl)
}

func numberOrDie(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

// added in go1.20, but i'm still running go 1.19
func cutSuffix(s string, suffix string) (string, bool) {
	if strings.HasSuffix(s, suffix) {
		return s[:len(s)-len(suffix)], true
	}
	return s, false
}
2023 Day 3a
// an additional column of period characters was added to the input.
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	ttl := 0
	npttl := 0
	num := ""
	schematic := []string{}
	for s.Scan() {
		schematic = append(schematic, s.Text())
	}
	for i, row := range schematic {
		for j, c := range row {
			if c >= '0' && c <= '9' {
				num += string(c)
			} else if num != "" {
				cv, err := strconv.Atoi(num)
				if err != nil {
					panic(err)
				}
				ttl += cv
				part := false
				for v := max(0, i-1); v <= min(len(schematic)-1, i+1); v++ {
					for w := max(0, j-len(num)-1); w <= min(len(row)-1, j); w++ {
						if (schematic[v][w] < '0' || schematic[v][w] > '9') && schematic[v][w] != '.' {
							part = true
						}
					}
				}
				if !part {
					npttl += cv
				}
				num = ""
			}
		}
	}
	fmt.Println(ttl - npttl)
}

// apparently with go1.21 these are no longer necessary!  maybe i really should
// upgrade.
func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}
2023 Day 3b
// an additional column of period characters was added to the input.
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

type id struct {
	x   int
	y   int
	val int
}

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	ttl := 0
	num := ""
	numfinder := map[int]map[int]*id{}
	gears := [][]int{}
	row := 0
	for s.Scan() {
		sy := row
		sx := 0
		numfinder[row] = map[int]*id{}
		gears = append(gears, []int{})
		for j, c := range s.Text() {
			if c >= '0' && c <= '9' {
				if num == "" {
					sx = j
				}
				num += string(c)
			} else if num != "" {
				cv, err := strconv.Atoi(num)
				if err != nil {
					panic(err)
				}
				nid := &id{
					x:   sx,
					y:   sy,
					val: cv,
				}
				for iv := sx; iv < j; iv++ {
					numfinder[row][iv] = nid
				}
				num = ""
			}
			if c == '*' {
				gears[row] = append(gears[row], j)
			}
		}
		row++
	}
	for i, r := range gears {
		for _, j := range r {
			gl := map[id]struct{}{}
			for v := max(i-1, 0); v <= min(i+1, len(gears)); v++ {
				for w := max(j-1, 0); w <= j+1; w++ {
					if nid, ok := numfinder[v][w]; ok {
						gl[*nid] = struct{}{}
					}
				}
			}
			if len(gl) == 2 {
				st := 1
				for v, _ := range gl {
					st *= v.val
				}
				ttl += st
			}
		}
	}
	fmt.Println(ttl)
}

// apparently with go1.21 these are no longer necessary!  maybe i really should
// upgrade.
func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}
2023 Day 4a
// "game ###" prefix removed.  duplicate spaces replaced with a single space.
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	ttl := 0
	for s.Scan() {
		winners := map[int]struct{}{}
		count := 0
		card := strings.Split(s.Text(), "|")
		if len(card) != 2 {
			panic(fmt.Errorf("couldn't parse card: %q", s.Text()))
		}
		for _, num := range strings.Split(strings.TrimSpace(card[0]), " ") {
			winners[numberOrDie(num)] = struct{}{}
		}
		for _, num := range strings.Split(strings.TrimSpace(card[1]), " ") {
			if _, ok := winners[numberOrDie(num)]; ok {
				count++
			}
		}
		if count > 0 {
			ttl += 1 << (count - 1)
		}
	}
	fmt.Println(ttl)
}

func numberOrDie(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}
2023 Day 4b
// "game ###" prefix removed.  duplicate spaces replaced with a single space.
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

type cc struct {
	winners int
	cards int
}

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	ttl := 0
	points := []*cc{}
	for s.Scan() {
		winners := map[int]struct{}{}
		count := 0
		card := strings.Split(s.Text(), "|")
		if len(card) != 2 {
			panic(fmt.Errorf("couldn't parse card: %q", s.Text()))
		}
		for _, num := range strings.Split(strings.TrimSpace(card[0]), " ") {
			winners[numberOrDie(num)] = struct{}{}
		}
		for _, num := range strings.Split(strings.TrimSpace(card[1]), " ") {
			if _, ok := winners[numberOrDie(num)]; ok {
				count++
			}
		}
		points = append(points, &cc{count, 1})
	}
	for i, v := range points {
		for j := 0; j < v.winners; j++ {
			points[i+j+1].cards += v.cards
		}
		ttl += v.cards
	}
	fmt.Println(ttl)
}

func numberOrDie(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}
2023 Day 5a
// all non-number text removed from file.
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

type rmap struct {
	drs int
	srs int
	rl int
}

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	minloc := 99999999999999999
	s.Scan()
	seeds := []int{}
	for _, s := range strings.Split(s.Text(), " ") {
		seeds = append(seeds, numberOrDie(s))
	}
	s.Scan()
	catmap := [][]*rmap{[]*rmap{}}
	i := 0
	j := 0
	for s.Scan() {
		if s.Text() == "" {
			catmap = append(catmap, []*rmap{})
			i++
			j = 0
			continue
		}
		data := strings.Split(s.Text(), " ")
		if len(data) != 3 {
			panic(fmt.Errorf("bad line %q", s.Text()))
		}
		catmap[i] = append(catmap[i], &rmap{
			drs: numberOrDie(data[0]),
			srs: numberOrDie(data[1]),
			rl: numberOrDie(data[2]),
		})
		j++
	}
	for _, s := range seeds {
		for _, ms := range catmap { 
			for _, m := range ms {
				if s >= m.srs && s < m.srs+m.rl {
					s = s - m.srs + m.drs
					break
				}
			}
		}
		if s < minloc {
			minloc = s
		}
	}
	fmt.Println(minloc)
}

func numberOrDie(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}
2023 Day 5b
// all non-number text removed from file.
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

type rng struct {
	start int
	ln int
}

type rmap struct {
	drs int
	srs int
	rl int
}

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	minloc := 99999999999999999
	s.Scan()
	seeds := []int{}
	for _, s := range strings.Split(s.Text(), " ") {
		seeds = append(seeds, numberOrDie(s))
	}
	seedRanges := []*rng{}
	for i := 0; i < len(seeds); i += 2 {
		seedRanges = append(seedRanges, &rng{seeds[i],seeds[i+1]})
	}
	s.Scan()
	catmap := [][]*rmap{[]*rmap{}}
	i := 0
	j := 0
	for s.Scan() {
		if s.Text() == "" {
			catmap = append(catmap, []*rmap{})
			i++
			j = 0
			continue
		}
		data := strings.Split(s.Text(), " ")
		if len(data) != 3 {
			panic(fmt.Errorf("bad line %q", s.Text()))
		}
		catmap[i] = append(catmap[i], &rmap{
			drs: numberOrDie(data[0]),
			srs: numberOrDie(data[1]),
			rl: numberOrDie(data[2]),
		})
		j++
	}
	for _, r := range seedRanges {
		ranges := []*rng{r}
		for _, ms := range catmap { 
			nr := []*rng{}
			for i := 0; i < len(ranges); i++ {
				rs := ranges[i]
				match := false
				for _, m := range ms {
					if rs.start < m.srs && rs.start+rs.ln > m.srs {
						match = true
						ranges = append(ranges, &rng{rs.start,m.srs-rs.start})
						fmt.Printf("presplit %+v\n", rs)
						rs = &rng{m.srs,rs.start+rs.ln-m.srs}
						fmt.Printf("presplit %v %v %v\n", m, ranges[len(ranges)-1],rs)
					}
					if rs.start >= m.srs && rs.start < m.srs+m.rl {
						match = true
						rm := rs.start-m.srs+m.drs
						rl := rs.ln
						if rs.start + rs.ln > m.srs+m.rl {
							rl = m.srs+m.rl-rs.start
							fmt.Printf("split %v %v %d %d\n", rs, m, rm, rl)
							ranges = append(ranges, &rng{m.srs+m.rl,rs.start+rs.ln-m.srs-m.rl})
							fmt.Printf("nr: %v\n", ranges[len(ranges)-1])
						} 
						nr = append(nr, &rng{rm,rl})
					}
					if match {
						break
					}
				}
				if !match {
					nr = append(nr, rs)
				}
			}
			ranges = nr
		}
		for _, r := range ranges {
			if r.start < minloc {
				minloc = r.start
			}
		}
	}
	fmt.Println(minloc)
}

func numberOrDie(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}
2023 Day 6a
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	dur := []int{}
	dist := []int{}
	ttl := 1
	s.Scan()
	for _, d := range strings.Split(s.Text(), " ") {
		dur = append(dur, numberOrDie(d))
	}
	s.Scan()
	for _, d := range strings.Split(s.Text(), " ") {
		dist = append(dist, numberOrDie(d))
	}
	for idx, d := range dur {
		poss := 0
		for i := 0; i < d; i++ {
			dc := i*(d-i)
			if dc > dist[idx] {
				poss++
			}
		}
		ttl *= poss
	}
	fmt.Println(ttl)
}

func numberOrDie(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}
2023 Day 6b
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	dur := []int{}
	dist := []int{}
	s.Scan()
	for _, d := range strings.Split(s.Text(), " ") {
		dur = append(dur, numberOrDie(d))
	}
	s.Scan()
	for _, d := range strings.Split(s.Text(), " ") {
		dist = append(dist, numberOrDie(d))
	}
	poss := 0
	for idx, d := range dur {
		for i := 0; i < d; i++ {
			dc := i*(d-i)
			if dc > dist[idx] {
				poss++
			}
		}
	}
	fmt.Println(poss)
}

func numberOrDie(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}
2023 Day 7a
package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"
)

var (
	order = map[string]int{
		"2": 2,
		"3": 3,
		"4": 4,
		"5": 5,
		"6": 6,
		"7": 7,
		"8": 8,
		"9": 9,
		"T": 10,
		"J": 11,
		"Q": 12,
		"K": 13,
		"A": 14,
	}
)

type hand struct {
	deal string
	bid int
	sorted map[string]int
}

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	ttl := 0
	s := bufio.NewScanner(f)
	hands := []*hand{}
	for s.Scan() {
		in := strings.Split(s.Text(), " ")
		if len(in) != 2 {
			panic(fmt.Errorf("bad input %q", in))
		}
		h := &hand{
			deal: in[0],
			bid: numberOrDie(in[1]),
			sorted: map[string]int{},
		}
		for _, c := range h.deal {
			h.sorted[string(c)]++
		}
		hands = append(hands, h)
	}
	sort.Slice(hands, func(i, j int) bool {
		is := score(hands[i])
		js := score(hands[j])
		if is != js {
			return is < js
		}
		for v := 0; v < 5; v++ {
			diff := order[string(hands[j].deal[v])] - order[string(hands[i].deal[v])]
			if diff != 0 {
				return diff > 0
			}
		}
		panic(fmt.Errorf("couldn't handle: %+v %+v", hands[i], hands[j]))
	})
	for i, h := range hands {
		ttl += (i+1)*h.bid
	}
	fmt.Println(ttl)
}

func numberOrDie(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

func score(h *hand) int {
	if len(h.sorted) == 1 {
		return 7;
	}
	if len(h.sorted) == 2 {
		for _, v := range h.sorted {
			if v == 4 {
				return 6;
			}
		}
		return 5;
	}
	if len(h.sorted) == 3 {
		for _, v := range h.sorted {
			if v == 3 {
				return 4;
			}
		}
		return 3;
	}
	if len(h.sorted) == 4 {
		return 2;
	}
	return 1;
}
2023 Day 7b
package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"
)

var (
	order = map[string]int{
		"2": 2,
		"3": 3,
		"4": 4,
		"5": 5,
		"6": 6,
		"7": 7,
		"8": 8,
		"9": 9,
		"T": 10,
		"J": 11,
		"Q": 12,
		"K": 13,
		"A": 14,
	}
)

type hand struct {
	deal string
	bid int
	sorted map[string]int
}

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	ttl := 0
	s := bufio.NewScanner(f)
	hands := []*hand{}
	for s.Scan() {
		in := strings.Split(s.Text(), " ")
		if len(in) != 2 {
			panic(fmt.Errorf("bad input %q", in))
		}
		h := &hand{
			deal: in[0],
			bid: numberOrDie(in[1]),
			sorted: map[string]int{},
		}
		for _, c := range h.deal {
			h.sorted[string(c)]++
		}
		hands = append(hands, h)
	}
	sort.Slice(hands, func(i, j int) bool {
		is := score(hands[i])
		js := score(hands[j])
		if is != js {
			return is < js
		}
		for v := 0; v < 5; v++ {
			diff := order[string(hands[j].deal[v])] - order[string(hands[i].deal[v])]
			if diff != 0 {
				return diff > 0
			}
		}
		panic(fmt.Errorf("couldn't handle: %+v %+v", hands[i], hands[j]))
	})
	for i, h := range hands {
		ttl += (i+1)*h.bid
	}
	fmt.Println(ttl)
}

func numberOrDie(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}

func score(h *hand) int {
	if len(h.sorted) == 1 {
		return 7;
	}
	if len(h.sorted) == 2 {
		for _, v := range h.sorted {
			if v == 4 {
				return 6;
			}
		}
		return 5;
	}
	if len(h.sorted) == 3 {
		for _, v := range h.sorted {
			if v == 3 {
				return 4;
			}
		}
		return 3;
	}
	if len(h.sorted) == 4 {
		return 2;
	}
	return 1;
}
2023 Day 8a
package main

import (
	"bufio"
	"fmt"
	"os"
)

type next struct {
	l string
	r string
}

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	steps := 0
	ways := map[string]*next{}
	pos := "AAA"
	idx := 0
	s.Scan()
	path := s.Text()
	s.Scan()
	for s.Scan() {
		ways[s.Text()[0:3]] = &next{s.Text()[7:10], s.Text()[12:15]}
	}
	for pos != "ZZZ" {
		next := path[idx]
		if next == 'L' {
			pos = ways[pos].l
		} else {
			pos = ways[pos].r
		}
		idx = (idx + 1) % len(path)
		steps++
	}
	fmt.Println(steps)
}
2023 Day 8b
// just cut the input off after 20 lines or so and find the LCM of each
// individual position cycle using wolfram alpha or something.
package main

import (
	"bufio"
	"fmt"
	"os"
)

type next struct {
	l string
	r string
}

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	steps := 0
	ways := map[string]*next{}
	pos := []string{}
	idx := 0
	s.Scan()
	path := s.Text()
	s.Scan()
	for s.Scan() {
		ways[s.Text()[0:3]] = &next{s.Text()[7:10], s.Text()[12:15]}
		if s.Text()[2] == 'A' {
			pos = append(pos, s.Text()[0:3])
		}
	}
	done := false
	for !done {
		done = true
		nxt := path[idx]
		for i := 0; i < len(pos); i++ {
			if nxt == 'L' {
				pos[i] = ways[pos[i]].l
			} else {
				pos[i] = ways[pos[i]].r
			}
			if pos[i][2] != 'Z' {
				done = false
			} else {
				fmt.Printf("%d done processing step %d.\n", i, steps+1)
			}
		}
		idx = (idx + 1) % len(path)
		steps++
	}
	fmt.Println(steps)
}
2023 Day 9a
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	ttl := 0
	for s.Scan() {
		oasis := [][]int{[]int{}}
		input := strings.Split(s.Text(), " ")
		for _, i := range input {
			oasis[0] = append(oasis[0], numberOrDie(i))
		}
		done := false
		for !done {
			done = true
			oasis = append(oasis, []int{})
			for i := 0; i < len(oasis[len(oasis)-2]) - 1; i++ {
				next := oasis[len(oasis)-2][i+1]-oasis[len(oasis)-2][i]
				if next != 0 {
					done = false
				}
				oasis[len(oasis)-1] = append(oasis[len(oasis)-1], next)
			}
		}
		oasis[len(oasis)-1] = append(oasis[len(oasis)-1], 0)
		for i := len(oasis)-2; i >= 0; i-- {
			oasis[i] = append(oasis[i], oasis[i][len(oasis[i])-1]+oasis[i+1][len(oasis[i+1])-1])
		}
		ttl += oasis[0][len(oasis[0])-1]
	}
	fmt.Println(ttl)
}

func numberOrDie(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}
2023 Day 9b
package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	f, err := os.Open("input")
	if err != nil {
		panic(err)
	}
	s := bufio.NewScanner(f)
	ttl := 0
	for s.Scan() {
		oasis := [][]int{[]int{}}
		input := strings.Split(s.Text(), " ")
		for _, i := range input {
			oasis[0] = append(oasis[0], numberOrDie(i))
		}
		done := false
		for !done {
			done = true
			oasis = append(oasis, []int{})
			for i := 0; i < len(oasis[len(oasis)-2]) - 1; i++ {
				next := oasis[len(oasis)-2][i+1]-oasis[len(oasis)-2][i]
				if next != 0 {
					done = false
				}
				oasis[len(oasis)-1] = append(oasis[len(oasis)-1], next)
			}
		}
		oasis[len(oasis)-1] = append([]int{0}, oasis[len(oasis)-1]...)
		for i := len(oasis)-2; i >= 0; i-- {
			oasis[i] = append([]int{oasis[i][0]-oasis[i+1][0]}, oasis[i]...)
		}
		ttl += oasis[0][0]
	}
	fmt.Println(ttl)
}

func numberOrDie(s string) int {
	n, err := strconv.Atoi(s)
	if err != nil {
		panic(err)
	}
	return n
}