Skip to content

Instantly share code, notes, and snippets.

@grandstaish
Created April 4, 2017 09:42
Show Gist options
  • Save grandstaish/89a073194885b53228d120e561ca4df2 to your computer and use it in GitHub Desktop.
Save grandstaish/89a073194885b53228d120e561ca4df2 to your computer and use it in GitHub Desktop.
fun Node.format(): String {
return formatInternal().lines.joinToString(separator = "\n")
}
fun max(a: Int, b: Int, c: Int): Int {
return Math.max(Math.max(a, b), c)
}
fun String.center(width: Int, fillChar: Char = ' ') : String {
var s = this
var left = true
while (s.length < width) {
if (left) {
s = fillChar + s
} else {
s += fillChar
}
left = !left
}
return s
}
fun Node.formatInternal() : FormatParts {
var label = value.toString()
val (leftLines, leftPos, leftWidth) = left?.formatInternal() ?: FormatParts(mutableListOf(), 0, 0)
val (rightLines, rightPos, rightWidth) = right?.formatInternal() ?: FormatParts(mutableListOf(), 0, 0)
// Ensure left and right lines are the same size by appending whitespace.
while (leftLines.size < rightLines.size) {
leftLines.add(" ".repeat(leftWidth))
}
while (rightLines.size < leftLines.size) {
rightLines.add(" ".repeat(rightWidth))
}
val middle = max(rightPos + leftWidth - leftPos + 1, label.length, 2)
val pos = leftPos + (middle / 2)
val width = leftPos + middle + rightWidth - rightPos
val lines = mutableListOf<String>()
// Pad the label with '.'s to match middle length
if ((middle - label.length) % 2 == 1
&& parent != null
&& this != parent.left
&& label.length < middle) {
label += '.'
}
label = label.center(middle, '.')
if (label[0] == '.') {
label = ' ' + label.substring(1)
}
if (label[label.length - 1] == '.') {
label = label.substring(0, label.length - 1) + ' '
}
// Add the value
var valueLine = ""
valueLine += " ".repeat(leftPos)
valueLine += label
valueLine += " ".repeat(rightWidth - rightPos)
lines.add(valueLine)
// Add arrows when children exist.
var slashLine = ""
slashLine += " ".repeat(leftPos)
slashLine += if (left != null) "/" else " "
slashLine += " ".repeat(middle - 2)
slashLine += if (right != null) "\\" else " "
slashLine += " ".repeat(rightWidth - rightPos)
lines.add(slashLine)
// Add rest of the lines from the left and right children
(0 until leftLines.size).mapTo(lines) {
var result = leftLines[it]
result += " ".repeat(width - leftWidth - rightWidth)
result += rightLines[it]
result
}
return FormatParts(lines, pos, width)
}
data class FormatParts(val lines: MutableList<String>, val pos: Int, val width: Int)
@grandstaish
Copy link
Author

Draws something that looks like this:

         ...38..         
        /       \        
      ..30.     46       
     /     \   /  \      
    .12    35 42  99     
   /   \          / \    
  .1   15        57 116  
 /  \   \             \  
-10 5   20            122

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment