Added solutions for 18th day: snailfish arithmetic
This commit is contained in:
parent
3f49055c82
commit
1108812492
8 changed files with 487 additions and 0 deletions
5
2021/18/example
Normal file
5
2021/18/example
Normal file
|
@ -0,0 +1,5 @@
|
|||
[1,1]
|
||||
[2,2]
|
||||
[3,3]
|
||||
[4,4]
|
||||
[5,5]
|
10
2021/18/example2
Normal file
10
2021/18/example2
Normal file
|
@ -0,0 +1,10 @@
|
|||
[[[0,[4,5]],[0,0]],[[[4,5],[2,6]],[9,5]]]
|
||||
[7,[[[3,7],[4,3]],[[6,3],[8,8]]]]
|
||||
[[2,[[0,8],[3,4]]],[[[6,7],1],[7,[1,6]]]]
|
||||
[[[[2,4],7],[6,[0,5]]],[[[6,8],[2,8]],[[2,1],[4,5]]]]
|
||||
[7,[5,[[3,8],[1,4]]]]
|
||||
[[2,[2,2]],[8,[8,1]]]
|
||||
[2,9]
|
||||
[1,[[[9,3],9],[[9,0],[0,7]]]]
|
||||
[[[5,[7,4]],7],1]
|
||||
[[[[4,2],2],6],[8,7]]
|
10
2021/18/example3
Normal file
10
2021/18/example3
Normal file
|
@ -0,0 +1,10 @@
|
|||
[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]]
|
||||
[[[5,[2,8]],4],[5,[[9,9],0]]]
|
||||
[6,[[[6,2],[5,6]],[[7,6],[4,7]]]]
|
||||
[[[6,[0,7]],[0,9]],[4,[9,[9,0]]]]
|
||||
[[[7,[6,4]],[3,[1,3]]],[[[5,5],1],9]]
|
||||
[[6,[[7,3],[3,2]]],[[[3,8],[5,7]],4]]
|
||||
[[[[5,4],[7,7]],8],[[8,3],8]]
|
||||
[[9,3],[[9,9],[6,[4,9]]]]
|
||||
[[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]]
|
||||
[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]
|
28
2021/18/first.go
Normal file
28
2021/18/first.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"git.adyxax.org/aoc/2021/18/pairs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
parser := pairs.NewParser(os.Stdin)
|
||||
pair, err := parser.Parse()
|
||||
if err != nil {
|
||||
log.Fatalf("%w", err)
|
||||
}
|
||||
for {
|
||||
pair2, err := parser.Parse()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
pair = pair.Add(pair2)
|
||||
}
|
||||
fmt.Println(pair)
|
||||
pair.Reduce()
|
||||
fmt.Println(pair)
|
||||
fmt.Println(pair.Magnitude())
|
||||
}
|
3
2021/18/go.mod
Normal file
3
2021/18/go.mod
Normal file
|
@ -0,0 +1,3 @@
|
|||
module git.adyxax.org/aoc/2021/18
|
||||
|
||||
go 1.17
|
100
2021/18/input
Normal file
100
2021/18/input
Normal file
|
@ -0,0 +1,100 @@
|
|||
[[[[8,1],8],[[8,1],0]],[[8,[2,4]],[0,8]]]
|
||||
[[[[2,2],[7,4]],[[9,1],6]],8]
|
||||
[[[3,6],[[8,7],[2,9]]],[8,[[2,3],9]]]
|
||||
[[[[4,5],[1,4]],1],[[0,8],[2,[6,8]]]]
|
||||
[[7,[[4,6],[0,0]]],[[4,3],5]]
|
||||
[[[[8,4],4],[[4,4],[1,0]]],[[5,[5,5]],[[5,2],1]]]
|
||||
[[[0,[5,8]],[1,7]],[[[5,0],[1,3]],7]]
|
||||
[4,[[[6,2],[7,8]],[0,[4,4]]]]
|
||||
[[[3,[5,3]],8],[[[6,8],4],[8,9]]]
|
||||
[[[6,0],[9,[8,1]]],[[[9,7],3],0]]
|
||||
[[9,[[9,3],[0,8]]],[[[5,3],0],[[5,6],2]]]
|
||||
[[3,[[7,7],3]],[[7,[5,2]],[[6,9],0]]]
|
||||
[1,[4,[3,8]]]
|
||||
[[[[0,2],9],[[0,7],8]],[[5,4],[2,8]]]
|
||||
[[[[1,8],9],[1,7]],[[4,[8,5]],[[6,3],[1,0]]]]
|
||||
[[9,[[4,3],[3,3]]],[[[4,9],[0,9]],6]]
|
||||
[7,[[8,0],[5,6]]]
|
||||
[[[[3,2],1],[[4,9],6]],[[9,[1,1]],[[8,7],1]]]
|
||||
[[[[5,1],[3,3]],0],[1,[[3,2],2]]]
|
||||
[[7,9],[[9,9],[5,[9,5]]]]
|
||||
[[[[4,3],[1,7]],[4,[9,2]]],[[6,[1,7]],[[8,0],3]]]
|
||||
[[[5,[2,8]],[[1,2],7]],[[3,[0,5]],[[3,5],8]]]
|
||||
[[[[2,2],6],[[2,1],7]],[[[4,6],8],7]]
|
||||
[[2,[[3,0],[0,5]]],[[[3,4],[0,1]],0]]
|
||||
[[[[9,9],5],[[9,9],6]],[[[4,1],2],0]]
|
||||
[4,[[2,9],[6,2]]]
|
||||
[[[8,6],6],7]
|
||||
[[7,[8,2]],[[[5,5],6],[9,0]]]
|
||||
[5,[[2,5],[[4,9],[8,6]]]]
|
||||
[[4,[7,[9,6]]],7]
|
||||
[[[9,[3,3]],[[3,1],[8,7]]],[[6,[3,5]],[4,1]]]
|
||||
[[8,6],[8,[[0,2],[8,1]]]]
|
||||
[6,[8,[[7,7],0]]]
|
||||
[3,4]
|
||||
[[9,[8,0]],[[[7,8],3],1]]
|
||||
[5,[[3,[8,7]],[[5,0],[9,7]]]]
|
||||
[[[[4,2],9],[6,[0,2]]],6]
|
||||
[[4,[3,[4,9]]],[[4,[1,6]],1]]
|
||||
[[[6,3],[8,8]],[5,[[9,3],[6,3]]]]
|
||||
[[[9,9],[[7,1],6]],[[[1,0],[7,4]],[3,[2,0]]]]
|
||||
[[[[2,5],9],[3,[6,2]]],[4,7]]
|
||||
[[1,[7,8]],[[[0,1],8],[[1,1],9]]]
|
||||
[[[9,[6,4]],[[9,8],[0,2]]],[[[8,9],[2,3]],[3,[8,0]]]]
|
||||
[[[[6,8],2],3],[[2,2],5]]
|
||||
[[[4,[8,5]],[[4,3],1]],[[[2,4],[4,4]],[[4,1],[1,7]]]]
|
||||
[[[[2,6],6],[[9,2],4]],[[[9,9],[9,5]],5]]
|
||||
[[[[7,5],[4,9]],4],[[[0,7],[3,6]],[[6,5],[3,0]]]]
|
||||
[[[4,4],[[5,7],[8,5]]],[0,8]]
|
||||
[[3,[[1,3],[7,5]]],[6,[[8,1],0]]]
|
||||
[[[9,9],[5,[9,6]]],[[[4,0],[5,4]],6]]
|
||||
[0,[[[9,2],4],3]]
|
||||
[[[1,[8,5]],[0,[6,0]]],[[[6,5],[3,1]],[[6,2],[1,5]]]]
|
||||
[[[4,0],[4,7]],6]
|
||||
[1,[[[5,2],9],[[3,9],4]]]
|
||||
[[[[9,6],[4,1]],4],[2,[[0,2],6]]]
|
||||
[9,[[[1,5],[3,1]],1]]
|
||||
[5,0]
|
||||
[9,[[[7,5],[2,1]],[[2,3],[5,3]]]]
|
||||
[[5,[[0,5],[9,5]]],[[[2,7],3],[[2,9],[3,5]]]]
|
||||
[[[1,9],2],[[7,[1,7]],[8,[9,8]]]]
|
||||
[[8,9],[[5,[9,0]],[[6,8],[5,2]]]]
|
||||
[6,[[[1,3],[0,8]],4]]
|
||||
[[[[9,8],[0,9]],[[8,4],[3,5]]],[[[5,0],8],[[6,8],1]]]
|
||||
[[6,[[1,4],[7,0]]],[[3,4],[[2,1],[2,7]]]]
|
||||
[[[5,0],[3,[4,7]]],[[9,3],[[9,4],[9,6]]]]
|
||||
[[[[8,3],[8,0]],5],[[[5,5],[0,2]],[[0,1],9]]]
|
||||
[[[[6,4],[1,8]],[3,[0,2]]],[8,[[8,8],5]]]
|
||||
[2,[[2,1],[1,4]]]
|
||||
[8,[0,[3,5]]]
|
||||
[[[[0,2],3],[[4,9],[1,2]]],[[8,2],[6,[7,1]]]]
|
||||
[[[0,0],9],1]
|
||||
[8,[[4,1],[[1,3],9]]]
|
||||
[[[8,[5,9]],9],[[[5,7],[9,0]],3]]
|
||||
[[5,[2,9]],7]
|
||||
[5,6]
|
||||
[[[[7,5],[8,3]],[[4,3],8]],[[2,2],[[7,2],[4,2]]]]
|
||||
[[[9,5],[3,[1,5]]],6]
|
||||
[[[[7,4],[7,9]],[[3,1],[3,1]]],[[[6,4],[0,1]],1]]
|
||||
[[3,[[7,4],9]],[[[5,8],[2,7]],[[0,4],[3,6]]]]
|
||||
[[[3,[2,3]],[[6,0],[7,7]]],1]
|
||||
[[2,[[8,8],[2,3]]],[5,2]]
|
||||
[[[0,[5,5]],[8,1]],5]
|
||||
[[3,9],[6,[[0,5],[1,7]]]]
|
||||
[[[[3,0],9],[8,2]],[[[2,2],8],0]]
|
||||
[[[9,6],[[5,1],[4,9]]],[[[1,1],[0,3]],[[4,9],[7,5]]]]
|
||||
[[[2,[6,1]],[[5,7],[9,2]]],[[[4,2],8],9]]
|
||||
[[9,[7,1]],[[4,5],[9,1]]]
|
||||
[[9,[5,0]],[[1,7],[[9,6],[4,5]]]]
|
||||
[[[[1,1],[8,7]],4],[[0,4],[[1,7],[3,5]]]]
|
||||
[[5,[1,[8,4]]],[[[9,4],0],[1,[5,5]]]]
|
||||
[[[5,[1,6]],[6,0]],[[0,[9,7]],1]]
|
||||
[2,[9,[[0,3],[2,3]]]]
|
||||
[3,[4,[[0,9],8]]]
|
||||
[[5,6],[[[9,9],[4,0]],[7,[2,0]]]]
|
||||
[[[[5,1],6],[[1,0],[7,1]]],[[6,[1,0]],[[4,2],[0,0]]]]
|
||||
[[[4,[0,2]],6],[[[4,3],[8,0]],[[9,6],[1,5]]]]
|
||||
[[[[5,3],[2,2]],[8,[8,3]]],[[9,1],2]]
|
||||
[[3,4],[[[4,7],[2,3]],[9,[9,0]]]]
|
||||
[[[5,[6,2]],[[1,5],[9,2]]],[[[7,9],3],[[6,7],[6,2]]]]
|
||||
[[[5,3],9],[[2,[4,3]],[[5,3],1]]]
|
296
2021/18/pairs/parser.go
Normal file
296
2021/18/pairs/parser.go
Normal file
|
@ -0,0 +1,296 @@
|
|||
package pairs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Token represents a lexical token.
|
||||
type Token int
|
||||
|
||||
const (
|
||||
// Special tokens
|
||||
ILLEGAL Token = iota
|
||||
EOF
|
||||
WHITESPACE
|
||||
|
||||
// Literals
|
||||
INT // integers
|
||||
|
||||
// Misc characters
|
||||
COMMA // ,
|
||||
OPEN_BRACKET
|
||||
CLOSE_BRACKET
|
||||
)
|
||||
|
||||
type Pair struct {
|
||||
HasSubPairs bool
|
||||
Value int
|
||||
Left, Right *Pair
|
||||
}
|
||||
|
||||
func (p Pair) String() string {
|
||||
if p.HasSubPairs {
|
||||
return fmt.Sprintf("[%s, %s]", p.Left.String(), p.Right.String())
|
||||
}
|
||||
return fmt.Sprintf("%d", p.Value)
|
||||
}
|
||||
|
||||
func (p Pair) Magnitude() int {
|
||||
if p.HasSubPairs {
|
||||
return 3*p.Left.Magnitude() + 2*p.Right.Magnitude()
|
||||
}
|
||||
return p.Value
|
||||
}
|
||||
|
||||
func (p1 *Pair) Add(p2 *Pair) *Pair {
|
||||
p := &Pair{
|
||||
HasSubPairs: true,
|
||||
Left: p1,
|
||||
Right: p2,
|
||||
}
|
||||
p.Reduce()
|
||||
return p
|
||||
}
|
||||
|
||||
func (p Pair) DeepCopy() *Pair {
|
||||
if p.HasSubPairs {
|
||||
return &Pair{
|
||||
HasSubPairs: true,
|
||||
Left: p.Left.DeepCopy(),
|
||||
Right: p.Right.DeepCopy(),
|
||||
}
|
||||
}
|
||||
return &Pair{Value: p.Value}
|
||||
}
|
||||
|
||||
func (p *Pair) Reduce() {
|
||||
for {
|
||||
if exploded, _, _ := p.TryExplode(0); exploded {
|
||||
continue
|
||||
}
|
||||
if p.TrySplit() {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Pair) TrySplit() bool {
|
||||
if p.HasSubPairs {
|
||||
if p.Left.TrySplit() {
|
||||
return true
|
||||
}
|
||||
return p.Right.TrySplit()
|
||||
}
|
||||
if p.Value >= 10 {
|
||||
p.HasSubPairs = true
|
||||
p.Left = &Pair{Value: p.Value / 2}
|
||||
p.Right = &Pair{Value: p.Value/2 + p.Value%2}
|
||||
p.Value = 0
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Pair) TryExplode(depth int) (bool, *int, *int) {
|
||||
if !p.HasSubPairs {
|
||||
return false, nil, nil
|
||||
}
|
||||
if depth >= 4 {
|
||||
p.HasSubPairs = false
|
||||
p.Value = 0
|
||||
l := p.Left.Value
|
||||
r := p.Right.Value
|
||||
p.Left = nil
|
||||
p.Right = nil
|
||||
return true, &l, &r
|
||||
}
|
||||
depth++
|
||||
if exploded, l, r := p.Left.TryExplode(depth); exploded {
|
||||
if r != nil {
|
||||
r = p.Right.TryAddToLeftMostNumber(r)
|
||||
}
|
||||
return exploded, l, r
|
||||
}
|
||||
if exploded, l, r := p.Right.TryExplode(depth); exploded {
|
||||
if l != nil {
|
||||
l = p.Left.TryAddToRightMostNumber(l)
|
||||
}
|
||||
return exploded, l, r
|
||||
}
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
func (p *Pair) TryAddToLeftMostNumber(n *int) *int {
|
||||
if p.HasSubPairs {
|
||||
return p.Left.TryAddToLeftMostNumber(n)
|
||||
}
|
||||
p.Value += *n
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Pair) TryAddToRightMostNumber(n *int) *int {
|
||||
if p.HasSubPairs {
|
||||
return p.Right.TryAddToRightMostNumber(n)
|
||||
}
|
||||
p.Value += *n
|
||||
return nil
|
||||
}
|
||||
|
||||
func isWhitespace(ch rune) bool {
|
||||
return ch == ' ' || ch == '\t' || ch == '\n'
|
||||
}
|
||||
|
||||
func isDigit(ch rune) bool {
|
||||
return (ch >= '0' && ch <= '9')
|
||||
}
|
||||
|
||||
var eof = rune(0)
|
||||
|
||||
// Scanner represents a lexical scanner.
|
||||
type Scanner struct {
|
||||
r *bufio.Reader
|
||||
}
|
||||
|
||||
// NewScanner returns a new instance of Scanner.
|
||||
func NewScanner(r io.Reader) *Scanner {
|
||||
return &Scanner{r: bufio.NewReader(r)}
|
||||
}
|
||||
|
||||
// read reads the next rune from the bufferred reader.
|
||||
// Returns the rune(0) if an error occurs (or io.EOF is returned).
|
||||
func (s *Scanner) read() rune {
|
||||
ch, _, err := s.r.ReadRune()
|
||||
if err != nil {
|
||||
return eof
|
||||
}
|
||||
return ch
|
||||
}
|
||||
|
||||
// unread places the previously read rune back on the reader.
|
||||
func (s *Scanner) unread() { _ = s.r.UnreadRune() }
|
||||
|
||||
// Scan returns the next token and literal value.
|
||||
func (s *Scanner) Scan() (tok Token, lit string) {
|
||||
// Read the next rune.
|
||||
ch := s.read()
|
||||
|
||||
// If we see whitespace then consume all contiguous whitespace.
|
||||
for isWhitespace(ch) {
|
||||
ch = s.read()
|
||||
}
|
||||
|
||||
// If we see a digit then consume as an int.
|
||||
if isDigit(ch) {
|
||||
return s.scanInt(ch)
|
||||
}
|
||||
|
||||
// Otherwise read the individual character.
|
||||
switch ch {
|
||||
case eof:
|
||||
return EOF, ""
|
||||
case ',':
|
||||
return COMMA, string(ch)
|
||||
case '[':
|
||||
return OPEN_BRACKET, string(ch)
|
||||
case ']':
|
||||
return CLOSE_BRACKET, string(ch)
|
||||
}
|
||||
|
||||
return ILLEGAL, string(ch)
|
||||
}
|
||||
|
||||
// scanInt consumes the current rune and all contiguous digit runes.
|
||||
func (s *Scanner) scanInt(read rune) (tok Token, lit string) {
|
||||
// Create a buffer and read the current character into it.
|
||||
var buf bytes.Buffer
|
||||
buf.WriteRune(read)
|
||||
|
||||
// Read every subsequent ident character into the buffer.
|
||||
// Non-ident characters and EOF will cause the loop to exit.
|
||||
for {
|
||||
if ch := s.read(); ch == eof {
|
||||
break
|
||||
} else if !isDigit(ch) {
|
||||
s.unread()
|
||||
break
|
||||
} else {
|
||||
_, _ = buf.WriteRune(ch)
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise return as a regular identifier.
|
||||
return INT, buf.String()
|
||||
}
|
||||
|
||||
// Parser represents a parser.
|
||||
type Parser struct {
|
||||
s *Scanner
|
||||
buf struct {
|
||||
tok Token // last read token
|
||||
lit string // last read literal
|
||||
n int // buffer size (max=1)
|
||||
}
|
||||
}
|
||||
|
||||
// NewParser returns a new instance of Parser.
|
||||
func NewParser(r io.Reader) *Parser {
|
||||
return &Parser{s: NewScanner(r)}
|
||||
}
|
||||
|
||||
// scan returns the next token from the underlying scanner.
|
||||
// If a token has been unscanned then read that instead.
|
||||
func (p *Parser) scan() (tok Token, lit string) {
|
||||
// If we have a token on the buffer, then return it.
|
||||
if p.buf.n != 0 {
|
||||
p.buf.n = 0
|
||||
return p.buf.tok, p.buf.lit
|
||||
}
|
||||
|
||||
// Otherwise read the next token from the scanner.
|
||||
tok, lit = p.s.Scan()
|
||||
|
||||
// Save it to the buffer in case we unscan later.
|
||||
p.buf.tok, p.buf.lit = tok, lit
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// unscan pushes the previously read token back onto the buffer.
|
||||
func (p *Parser) unscan() { p.buf.n = 1 }
|
||||
|
||||
func (p *Parser) Parse() (pair *Pair, err error) {
|
||||
pair = &Pair{}
|
||||
tok, lit := p.scan()
|
||||
switch tok {
|
||||
case OPEN_BRACKET:
|
||||
pair.HasSubPairs = true
|
||||
pair.Left, err = p.Parse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tok, lit := p.scan(); tok != COMMA {
|
||||
return nil, fmt.Errorf("found %q, expected COMMA", lit)
|
||||
}
|
||||
pair.Right, err = p.Parse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tok, lit := p.scan(); tok != CLOSE_BRACKET {
|
||||
return nil, fmt.Errorf("found %q, expected CLOSE_BRACKET", lit)
|
||||
}
|
||||
case INT:
|
||||
if v, err := strconv.Atoi(lit); err != nil {
|
||||
return nil, fmt.Errorf("failed to atoi an INT %s : %w", lit, err)
|
||||
} else {
|
||||
pair.Value = v
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected %q, expected OPEN_BRACKER or INT", lit)
|
||||
}
|
||||
return pair, nil
|
||||
}
|
35
2021/18/second.go
Normal file
35
2021/18/second.go
Normal file
|
@ -0,0 +1,35 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"git.adyxax.org/aoc/2021/18/pairs"
|
||||
)
|
||||
|
||||
func main() {
|
||||
max := 0
|
||||
parser := pairs.NewParser(os.Stdin)
|
||||
pairs := make([]*pairs.Pair, 0)
|
||||
for {
|
||||
pair, err := parser.Parse()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
pairs = append(pairs, pair)
|
||||
}
|
||||
l := len(pairs)
|
||||
for i := 0; i < l; i++ {
|
||||
for j := 0; j < l; j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
p1 := pairs[i].DeepCopy()
|
||||
p2 := pairs[j].DeepCopy()
|
||||
if m := p1.Add(p2).Magnitude(); max < m {
|
||||
max = m
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println(max)
|
||||
}
|
Loading…
Add table
Reference in a new issue