exercism/go/tree-building/tree_building.go

110 lines
2.0 KiB
Go

package tree
import (
"errors"
"fmt"
)
const testVersion = 3
type Record struct {
ID, Parent int
}
type Node struct {
ID int
Children []*Node
}
type Mismatch struct{}
func (m Mismatch) Error() string {
return "c"
}
func Build(records []Record) (*Node, error) {
if len(records) == 0 {
return nil, nil
}
root := &Node{}
todo := []*Node{root}
n := 1
for {
if len(todo) == 0 {
break
}
newTodo := []*Node(nil)
for _, c := range todo {
for _, r := range records {
if r.Parent == c.ID {
if r.ID < c.ID {
return nil, errors.New("a")
} else if r.ID == c.ID {
if r.ID != 0 {
return nil, fmt.Errorf("b")
}
} else {
n++
switch len(c.Children) {
case 0:
nn := &Node{ID: r.ID}
c.Children = []*Node{nn}
newTodo = append(newTodo, nn)
case 1:
nn := &Node{ID: r.ID}
if c.Children[0].ID < r.ID {
c.Children = []*Node{c.Children[0], nn}
newTodo = append(newTodo, nn)
} else {
c.Children = []*Node{nn, c.Children[0]}
newTodo = append(newTodo, nn)
}
default:
nn := &Node{ID: r.ID}
newTodo = append(newTodo, nn)
breakpoint:
for _ = range []bool{false} {
for i, cc := range c.Children {
if cc.ID > r.ID {
a := make([]*Node, len(c.Children)+1)
copy(a, c.Children[:i])
copy(a[i+1:], c.Children[i:])
copy(a[i:i+1], []*Node{nn})
c.Children = a
break breakpoint
}
}
c.Children = append(c.Children, nn)
}
}
}
}
}
}
todo = newTodo
}
if n != len(records) {
return nil, Mismatch{}
}
if err := chk(root, len(records)); err != nil {
return nil, err
}
return root, nil
}
func chk(n *Node, m int) (err error) {
if n.ID > m {
return fmt.Errorf("z")
} else if n.ID == m {
return fmt.Errorf("y")
} else {
for i := 0; i < len(n.Children); i++ {
err = chk(n.Children[i], m)
if err != nil {
return
}
}
return
}
}