2016 Update

This commit is contained in:
Tina Müller 2016-12-05 22:15:40 +01:00
parent 948b86eafa
commit dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions

View file

@ -1,3 +1,18 @@
A tree structure (i.e. a rooted, connected acyclic graph) is often used in programming. It's often helpful to visually examine such a structure. There are many ways to represent trees to a reader, such as indented text (à la unix <code>tree</code> command), nested HTML tables, hierarchical GUI widgets, 2D or 3D images, etc.
A tree structure &nbsp; (i.e. a rooted, connected acyclic graph) &nbsp; is often used in programming.
'''Task''': Write a program to produce a visual representation of some tree. The content of the tree doesn't matter, nor does the output format, the only requirement being that the output is human friendly. Make do with the vague term "friendly" the best you can.
It's often helpful to visually examine such a structure.
There are many ways to represent trees to a reader, such as:
:::* &nbsp; indented text &nbsp; (à la unix <code> tree </code> command)
:::* &nbsp; nested HTML tables
:::* &nbsp; hierarchical GUI widgets
:::* &nbsp; 2D &nbsp; or &nbsp; 3D &nbsp; images
:::* &nbsp; etc.
;Task:
Write a program to produce a visual representation of some tree.
The content of the tree doesn't matter, nor does the output format, the only requirement being that the output is human friendly.
Make do with the vague term "friendly" the best you can.
<br><br>

View file

@ -0,0 +1,103 @@
# outputs nested html tables to visualise a tree #
# mode representing nodes of the tree #
MODE NODE = STRUCT( STRING value, REF NODE child, REF NODE sibling );
REF NODE nil node = NIL;
# tags etc. #
STRING table = "<table border=""1"" cellspacing=""4"">"
, elbat = "</table>"
, tr = "<tr>"
, rt = "</tr>"
, td = "<td style=""text-align: center; vertical-align: top; """
, dt = "</td>"
, nbsp = "&nbsp;"
;
CHAR nl = REPR 10;
# returns the number of child elements of tree #
OP CHILDCOUNT = ( REF NODE tree )INT:
BEGIN
INT result := 0;
REF NODE child := child OF tree;
WHILE REF NODE( child ) ISNT nil node
DO
result +:= 1;
child := sibling OF child
OD;
result
END # CHILDCOUNT # ;
# generates nested HTML tables from the tree #
OP TOHTML = ( REF NODE tree )STRING:
IF tree IS nil node
THEN
# no node #
""
ELSE
# hae at least one node #
STRING result := "";
INT child count = CHILDCOUNT tree;
result +:= table + nl
+ tr + nl
+ td + " colspan="""
+ whole( IF child count < 1 THEN 1 ELSE child count FI, 0 )
+ """>" + nbsp + value OF tree + nbsp
+ dt + nl
+ rt + nl
;
IF child count > 0
THEN
# the node has branches #
REF NODE child := child OF tree;
INT child number := 1;
INT mid child = ( child count + 1 ) OVER 2;
child := child OF tree;
result +:= tr + nl;
WHILE child ISNT nil node
DO
result +:= td + ">" + nl
+ IF CHILDCOUNT child < 1 THEN nbsp + value OF child + nbsp ELSE TOHTML child FI
+ dt + nl;
child := sibling OF child
OD;
result +:= rt + nl
FI;
result +:= elbat + nl
FI # TOHTML # ;
# test the tree visualisation #
# returns a new node with the specified value and no child or siblings #
PROC new node = ( STRING value )REF NODE: HEAP NODE := NODE( value, nil node, nil node );
# appends a sibling node to the node n, returns the sibling #
OP +:= = ( REF NODE n, REF NODE sibling node )REF NODE:
BEGIN
REF NODE sibling := n;
WHILE REF NODE( sibling OF sibling ) ISNT nil node
DO
sibling := sibling OF sibling
OD;
sibling OF sibling := sibling node
END # +:= # ;
# appends a new sibling node to the node n, returns the sibling #
OP +:= = ( REF NODE n, STRING sibling value )REF NODE: n +:= new node( sibling value );
# adds a child node to the node n, returns the child #
OP /:= = ( REF NODE n, REF NODE child node )REF NODE: child OF n := child node;
# adda a new child node to the node n, returns the child #
OP /:= = ( REF NODE n, STRING child value )REF NODE: n /:= new node( child value );
NODE animals := new node( "animals" );
NODE fish := new node( "fish" );
NODE reptiles := new node( "reptiles" );
NODE mammals := new node( "mammals" );
NODE primates := new node( "primates" );
NODE sharks := new node( "sharks" );
sharks /:= "great-white" +:= "hammer-head";
fish /:= "cod" +:= sharks +:= "piranha";
reptiles /:= "iguana" +:= "brontosaurus";
primates /:= "gorilla" +:= "lemur";
mammals /:= "sloth" +:= "horse" +:= "bison" +:= primates;
animals /:= fish +:= reptiles +:= mammals;
print( ( TOHTML animals ) )

View file

@ -0,0 +1,62 @@
#import system.
#import system'routines.
#import extensions.
#class Node
{
#field theValue.
#field theChildren.
#constructor new : value &children:children
[
theValue := value.
theChildren := children toArray.
]
#constructor new : value
<= new:value &children:nil.
#constructor new &children:children
<= new:emptyLiteralValue &children:children.
#constructor new : value &child:child
<= new:value &children:(Array new &object:child).
#method get = theValue.
#method children = theChildren.
}
#class(extension)treeOp
{
#method writeTree:node:prefix &subject:childrenProp
[
#var children := node::childrenProp get.
#var length := children length.
children zip:(RangeEnumerator new &from:1 &to:length) &eachPair:(:child:index)
[
self writeLine:prefix:"|".
self writeLine:prefix:"+---":(child get).
#var nodeLine := prefix + (index==length)iif:" ":"| ".
self writeTree:child:nodeLine &subject:childrenProp.
].
^ self.
]
#method writeTree:node &subject:childrenProp
= self writeTree:node:"" &subject:childrenProp.
}
#symbol program =
[
#var tree := Node new &children:
(
Node new:"a" &children:
(
Node new:"c" &child:(Node new:"d"),
Node new:"d"
),
Node new:"b").
console writeTree:tree &subject:%children.
].

View file

@ -20,4 +20,4 @@ sub visualize-tree($tree, &label, &children,
# example tree built up of pairs
my $tree = root=>[a=>[a1=>[a11=>[]]],b=>[b1=>[b11=>[]],b2=>[],b3=>[]]];
.say for visualize-tree($tree, *.key, *.value.list);
.map({.join("\n")}).join("\n").say for visualize-tree($tree, *.key, *.value.list);

View file

@ -0,0 +1,166 @@
extern crate rustc_serialize;
extern crate term_painter;
use rustc_serialize::json;
use std::fmt::{Debug, Display, Formatter, Result};
use term_painter::ToStyle;
use term_painter::Color::*;
type NodePtr = Option<usize>;
#[derive(Debug, PartialEq, Clone, Copy)]
enum Side {
Left,
Right,
Up,
}
#[derive(Debug, PartialEq, Clone, Copy)]
enum DisplayElement {
TrunkSpace,
SpaceLeft,
SpaceRight,
SpaceSpace,
Root,
}
impl DisplayElement {
fn string(&self) -> String {
match *self {
DisplayElement::TrunkSpace => " │ ".to_string(),
DisplayElement::SpaceRight => " ┌───".to_string(),
DisplayElement::SpaceLeft => " └───".to_string(),
DisplayElement::SpaceSpace => " ".to_string(),
DisplayElement::Root => "├──".to_string(),
}
}
}
#[derive(Debug, Clone, Copy, RustcDecodable, RustcEncodable)]
struct Node<K, V> {
key: K,
value: V,
left: NodePtr,
right: NodePtr,
up: NodePtr,
}
impl<K: Ord + Copy, V: Copy> Node<K, V> {
pub fn get_ptr(&self, side: Side) -> NodePtr {
match side {
Side::Up => self.up,
Side::Left => self.left,
_ => self.right,
}
}
}
#[derive(Debug, RustcDecodable, RustcEncodable)]
struct Tree<K, V> {
root: NodePtr,
store: Vec<Node<K, V>>,
}
impl<K: Ord + Copy + Debug + Display, V: Debug + Copy + Display> Tree<K, V> {
pub fn get_node(&self, np: NodePtr) -> Node<K, V> {
assert!(np.is_some());
self.store[np.unwrap()]
}
pub fn get_pointer(&self, np: NodePtr, side: Side) -> NodePtr {
assert!(np.is_some());
self.store[np.unwrap()].get_ptr(side)
}
// Prints the tree with root p. The idea is to do an in-order traversal
// (reverse in-order in this case, where right is on top), and print nodes as they
// are visited, one per line. Each invocation of display() gets its own copy
// of the display element vector e, which is grown with either whitespace or
// a trunk element, then modified in its last and possibly second-to-last
// characters in context.
fn display(&self, p: NodePtr, side: Side, e: &Vec<DisplayElement>, f: &mut Formatter) {
if p.is_none() {
return;
}
let mut elems = e.clone();
let node = self.get_node(p);
let mut tail = DisplayElement::SpaceSpace;
if node.up != self.root {
// If the direction is switching, I need the trunk element to appear in the lines
// printed before that node is visited.
if side == Side::Left && node.right.is_some() {
elems.push(DisplayElement::TrunkSpace);
} else {
elems.push(DisplayElement::SpaceSpace);
}
}
let hindex = elems.len() - 1;
self.display(node.right, Side::Right, &elems, f);
if p == self.root {
elems[hindex] = DisplayElement::Root;
tail = DisplayElement::TrunkSpace;
} else if side == Side::Right {
// Right subtree finished
elems[hindex] = DisplayElement::SpaceRight;
// Prepare trunk element in case there is a left subtree
tail = DisplayElement::TrunkSpace;
} else if side == Side::Left {
elems[hindex] = DisplayElement::SpaceLeft;
let parent = self.get_node(node.up);
if parent.up.is_some() && self.get_pointer(parent.up, Side::Right) == node.up {
// Direction switched, need trunk element starting with this node/line
elems[hindex - 1] = DisplayElement::TrunkSpace;
}
}
// Visit node => print accumulated elements. Each node gets a line and each line gets a
// node.
for e in elems.clone() {
let _ = write!(f, "{}", e.string());
}
let _ = write!(f,
"{key:>width$} ",
key = Green.bold().paint(node.key),
width = 2);
let _ = write!(f,
"{value:>width$}\n",
value = Blue.bold().paint(format!("{:.*}", 2, node.value)),
width = 4);
// Overwrite last element before continuing traversal
elems[hindex] = tail;
self.display(node.left, Side::Left, &elems, f);
}
}
impl<K: Ord + Copy + Debug + Display, V: Debug + Copy + Display> Display for Tree<K, V> {
fn fmt(&self, f: &mut Formatter) -> Result {
if self.root.is_none() {
write!(f, "[empty]")
} else {
let mut v: Vec<DisplayElement> = Vec::new();
self.display(self.root, Side::Up, &mut v, f);
Ok(())
}
}
}
/// Decodes and prints a previously generated tree.
fn main() {
let encoded = r#"{"root":0,"store":[{"key":0,"value":0.45,"left":1,"right":3,
"up":null},{"key":-8,"value":-0.94,"left":7,"right":2,"up":0}, {"key":-1,
"value":0.15,"left":8,"right":null,"up":1},{"key":7, "value":-0.29,"left":4,
"right":9,"up":0},{"key":5,"value":0.80,"left":5,"right":null,"up":3},
{"key":4,"value":-0.85,"left":6,"right":null,"up":4},{"key":3,"value":-0.46,
"left":null,"right":null,"up":5},{"key":-10,"value":-0.85,"left":null,
"right":13,"up":1},{"key":-6,"value":-0.42,"left":null,"right":10,"up":2},
{"key":9,"value":0.63,"left":12,"right":null,"up":3},{"key":-3,"value":-0.83,
"left":null,"right":11,"up":8},{"key":-2,"value":0.75,"left":null,"right":null,
"up":10},{"key":8,"value":-0.48,"left":null,"right":null,"up":9},{"key":-9,
"value":0.53,"left":null,"right":null,"up":7}]}"#;
let tree: Tree<i32, f32> = json::decode(&encoded).unwrap();
println!("{}", tree);
}