github.com/gorgonia/agogo@v0.1.1/mcts/graph.go (about) 1 package mcts 2 3 import ( 4 "bytes" 5 "fmt" 6 "sort" 7 "text/template" 8 9 "github.com/awalterschulze/gographviz" 10 "github.com/gorgonia/agogo/game" 11 ) 12 13 type statefulNode struct { 14 *Node 15 Player game.Colour 16 board []game.Colour 17 stride int 18 } 19 20 func (s *statefulNode) State() string { 21 var buf bytes.Buffer 22 for i, c := range s.board { 23 if i%s.stride == 0 { 24 fmt.Fprint(&buf, "⎢ ") 25 } 26 fmt.Fprintf(&buf, "%s ", c) 27 if (i+1)%s.stride == 0 && i != 0 { 28 fmt.Fprint(&buf, "⎥<BR />") 29 } 30 } 31 return buf.String() 32 } 33 34 func (t *MCTS) ToDot() string { 35 g := gographviz.NewGraph() 36 if err := g.SetName("G"); err != nil { 37 panic(err) 38 } 39 g.SetDir(true) 40 41 var states []*statefulNode 42 for i := range t.nodes { 43 n := &t.nodes[i] 44 s := &statefulNode{ 45 Node: n, 46 board: make([]game.Colour, t.M*t.N), 47 stride: t.M, 48 } 49 states = append(states, s) 50 } 51 52 var buf bytes.Buffer 53 for i, kids := range t.children { 54 n := states[i] 55 if !n.IsActive() { 56 continue 57 } 58 if n.Player == game.None { 59 n.Player = game.Black 60 } 61 move := n.Move() 62 if !move.IsPass() && !move.IsResignation() { 63 n.board[move] = n.Player 64 } 65 66 tmpl.Execute(&buf, n) 67 attrs := map[string]string{ 68 "fontname": "Monaco", 69 "shape": "none", 70 "label": buf.String(), 71 } 72 g.AddNode("G", fmt.Sprintf("%v", n.id), attrs) 73 buf.Reset() 74 sort.Sort(byMove{l: kids, t: t}) 75 76 for _, kid := range kids { 77 child := t.nodeFromNaughty(kid) 78 if !child.IsActive() { 79 continue 80 } 81 s := states[child.id] 82 copy(s.board, n.board) 83 s.Player = game.Colour(opponent(game.Player(n.Player))) 84 85 g.AddEdge(fmt.Sprintf("%v", n.id), fmt.Sprintf("%v", kid), true, nil) 86 } 87 88 } 89 return g.String() 90 } 91 92 const tmplRaw = `< 93 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0"> 94 <TR><TD>Node ID</TD><TD>xx{{.ID}}</TD></TR> 95 <TR><TD>Move</TD><TD>{{.Move}}</TD></TR> 96 <TR><TD>Player</TD><TD>{{.Player}}</TD></TR> 97 <TR><TD>Visits</TD><TD>{{.Visits}}</TD></TR> 98 <TR><TD>Score</TD><TD>{{.Score}}</TD></TR> 99 <TR><TD>Value</TD><TD>{{.Value}}</TD></TR> 100 <TR><TD>State</TD><TD>{{.State}}</TD></TR> 101 </TABLE> 102 > 103 ` 104 105 var tmpl *template.Template 106 107 func init() { 108 tmpl = template.Must(template.New("name").Parse(tmplRaw)) 109 }