Skip to content

Instantly share code, notes, and snippets.

@almendar
Created December 18, 2021 16:33
Show Gist options
  • Save almendar/ce196d193994586d1a1d23e54b4d78a2 to your computer and use it in GitHub Desktop.
Save almendar/ce196d193994586d1a1d23e54b4d78a2 to your computer and use it in GitHub Desktop.
type SnailNumber struct {
parent, left, right *SnailNumber
value int
}
func (n *SnailNumber) Equals(otherN *SnailNumber) bool {
return n == otherN
}
func (n *SnailNumber) isNumber() bool {
return n.left == nil && n.right == nil
}
func Add(left *SnailNumber, right *SnailNumber) *SnailNumber {
el := &SnailNumber{left: left, right: right}
return el
}
func (n SnailNumber) String() string {
if n.left != nil && n.right != nil {
return fmt.Sprintf("[%v,%v]", n.left, n.right)
} else {
return fmt.Sprintf("%d", n.value)
}
}
func (n *SnailNumber) explode() bool {
toExplode := n.findExploding()
if toExplode == nil {
return false
}
nearestLeft := toExplode.findLeft()
if nearestLeft != nil {
nearestLeft.value += toExplode.left.value
}
nearestRight := toExplode.findRight()
if nearestRight != nil {
nearestRight.value += toExplode.right.value
}
toExplode.left = nil
toExplode.right = nil
toExplode.value = 0
return true
}
func _findLeft(root *SnailNumber, val *SnailNumber) *SnailNumber {
if root == nil {
return nil
}
if root.left.Equals(val) {
//go up
return _findLeft(root.parent, root)
}
return root.left.lookForFirtstValueToRight()
}
func (n *SnailNumber) findLeft() *SnailNumber {
return _findLeft(n.parent, n)
}
func (n *SnailNumber) lookForFirtstValueToRight() *SnailNumber {
if n.isNumber() {
return n
} else if n == nil {
return nil
} else {
node := n.right.lookForFirtstValueToRight()
if node == nil {
node = n.left.lookForFirtstValueToRight()
}
return node
}
}
func _findRight(root *SnailNumber, val *SnailNumber) *SnailNumber {
if root == nil {
return nil
}
if root.right.Equals(val) {
//go up
return _findRight(root.parent, root)
}
return root.right.lookForFirtstValueToLeft()
}
func (n *SnailNumber) findRight() *SnailNumber {
return _findRight(n.parent, n)
}
func (n *SnailNumber) lookForFirtstValueToLeft() *SnailNumber {
if n.isNumber() {
return n
} else if n == nil {
return nil
} else {
node := n.left.lookForFirtstValueToLeft()
if node == nil {
node = n.right.lookForFirtstValueToLeft()
}
return node
}
}
func (n *SnailNumber) findExploding() *SnailNumber {
return _findExploding(n, 0)
}
func _findExploding(n *SnailNumber, level int) *SnailNumber {
if n.isNumber() {
return nil
}
if level < 4 {
found := _findExploding(n.left, level+1)
if found == nil {
found = _findExploding(n.right, level+1)
}
return found
}
return n
}
func _findSplit(n *SnailNumber) *SnailNumber {
if n.isNumber() {
if n.value >= 10 {
return n
} else {
return nil
}
}
//look left
other := _findSplit(n.left)
if other == nil {
other = _findSplit(n.right)
}
return other
}
func (n *SnailNumber) findSplit() *SnailNumber {
return _findSplit(n)
}
func (n *SnailNumber) Split() bool {
splitPoint := n.findSplit()
// fmt.Printf("splitPoint: %v\n", splitPoint)
if splitPoint == nil {
return false
} else {
newLeft := &SnailNumber{splitPoint, nil, nil, splitPoint.value / 2}
newRight := &SnailNumber{splitPoint, nil, nil, splitPoint.value - splitPoint.value/2}
splitPoint.left = newLeft
splitPoint.right = newRight
splitPoint.value = -1
return true
}
}
func (n *SnailNumber) Reduce() {
for {
explodede := n.explode()
_FixParrents(n)
if explodede {
continue
}
splitted := n.Split()
_FixParrents(n)
if !splitted {
break
}
}
}
func (n *SnailNumber) Magnitude() int {
if n.isNumber() {
return n.value
} else {
return 3*n.left.Magnitude() + 2*n.right.Magnitude()
}
}
func _FixParrents(n *SnailNumber) {
if n.isNumber() {
return
}
n.left.parent = n
n.right.parent = n
_FixParrents(n.left)
_FixParrents(n.right)
}
func p(str string) *SnailNumber {
sn, _ := parseRecursive(str, 0)
_FixParrents(sn)
return sn
}
func parseRecursive(str string, cnt int) (*SnailNumber, int) {
char := rune(str[cnt])
if char >= '0' && char <= '9' {
parsedNumber, _ := strconv.Atoi(string(char))
return &SnailNumber{value: parsedNumber}, cnt + 1
}
//trying to parse left
if char == '[' {
left, newCnt := parseRecursive(str, cnt+1)
right, end := parseRecursive(str, newCnt+1)
parent := &SnailNumber{nil, left, right, -1}
left.parent = parent
right.parent = parent
return parent, end + 1
}
if char == ',' {
return parseRecursive(str, cnt+1)
}
log.Fatal("This is error")
return &SnailNumber{}, -1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment