Created
December 18, 2021 16:33
-
-
Save almendar/ce196d193994586d1a1d23e54b4d78a2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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