package pov const testVersion = 2 // A Graph just holds all nodes in the graph type Graph struct { nodes []Node } func New() *Graph { return new(Graph) } // A Node is a label and a slice of references to other nodes type Node struct { label string connections []Node } func (g *Graph) AddNode(lbl string) { if g.getNode(lbl) == nil { g.nodes = append(g.nodes, Node{label: lbl}) } } func (g *Graph) getNode(lbl string) *Node { for i := range g.nodes { if g.nodes[i].label == lbl { return &g.nodes[i] } } return nil } func (g *Graph) AddArc(fr, to string) { frN := g.getNode(fr) if frN == nil { g.AddNode(fr) frN = g.getNode(fr) } toN := g.getNode(to) if g.getNode(to) == nil { g.AddNode(to) toN = g.getNode(to) } frN.connections = append(frN.connections, *toN) } func (g *Graph) ArcList() []string { var ret []string for _, k := range g.nodes { for _, l := range k.connections { ret = append(ret, k.label+" -> "+l.label) } } return ret } // getPath returns the shortest path from 'fr' to 'to' func (g *Graph) getPath(fr, to string) []string { if fr == to { return []string{fr} } st := g.getNode(fr) if st == nil { // Couldn't find the starting node return []string{} } var valPaths [][]string for i := range st.connections { if st.connections[i].label == to { return []string{fr, to} } tst := g.getPath(st.connections[i].label, to) if len(tst) > 0 { tst = append([]string{fr}, tst...) valPaths = append(valPaths, tst) } } if len(valPaths) == 0 { // No valid paths found return []string{} } var ret []string for i := range valPaths { if len(valPaths[i]) < len(ret) || len(ret) == 0 { ret = valPaths[i] } } return ret } func (g *Graph) ChangeRoot(oldRoot, newRoot string) *Graph { pth := g.getPath(oldRoot, newRoot) if len(pth) == 0 { // No valid path return g } for oldRoot != newRoot { // We just keep swapping the first two in pth until we're done if len(pth) >= 2 { n := g.getNode(pth[1]) if n == nil { return g } p := g.getNode(pth[0]) if p == nil { return g } p.removeConnection(n.label) n.connections = append(n.connections, *p) oldRoot = n.label pth = g.getPath(oldRoot, newRoot) } } return g } func (n *Node) removeConnection(to string) { for i, k := range n.connections { if k.label == to { copy(n.connections[i:], n.connections[i+1:]) n.connections[len(n.connections)-1] = Node{} n.connections = n.connections[:len(n.connections)-1] } } }