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  }