// AddAProp adds a property to a node. // AddAProp changes a BlackMoveNode or a WhiteMoveNode into an InteriorNode, // when a property is added, making the B or W property the first in the list. func (gamT *GameTree) AddAProp(n TreeNodeIdx, pv PropertyValue) (err ah.ErrorList) { mov := gamT.treeNodes[n].propListOrNodeLoc if gamT.treeNodes[n].TNodType == BlackMoveNode { var movPV *PropertyValue = new(PropertyValue) movPV.StrValue = SGFCoords(ah.NodeLoc(mov), gamT.IsFF4()) movPV.NextProp = nilPropIdx movPV.PropType = B_idx movPV.ValType = Move gamT.treeNodes[n].TNodType = InteriorNode gamT.treeNodes[n].propListOrNodeLoc = nilPropIdx err := gamT.addProperty(*movPV, n) if len(err) != 0 { err.Add(ah.NoPos, "adding B property "+err.Error()) } } else if gamT.treeNodes[n].TNodType == WhiteMoveNode { var movPV *PropertyValue = new(PropertyValue) movPV.StrValue = SGFCoords(ah.NodeLoc(mov), gamT.IsFF4()) movPV.NextProp = nilPropIdx movPV.PropType = W_idx movPV.ValType = Move gamT.treeNodes[n].TNodType = InteriorNode gamT.treeNodes[n].propListOrNodeLoc = nilPropIdx err := gamT.addProperty(*movPV, n) if len(err) != 0 { err.Add(ah.NoPos, "adding W property "+err.Error()) } } err = gamT.addProperty(pv, n) if len(err) != 0 { err.Add(ah.NoPos, "adding property "+err.Error()) } return err }
// writeTree writes a .sgf tree from the treeNodes array // w is a buffered I/O writer // n is the TreeNodeIdx of the root of this tree // needs is a bool that is true when a \n is needed // nMov keeps a count of moves per line. // writeTree first writes one node, then recursively calls writeTree // writeTree is only called from writeGame, which has one active call, and one that is never reached (&& false) func (p *GameTree) writeTree(w *bufio.Writer, n TreeNodeIdx, needs bool, nMov int, nMovPerLine int) (err error) { defer u(tr("writeTree")) if needs == true { if nMov > 0 { err = w.WriteByte('\n') nMov = 0 } err = w.WriteByte('(') } if err == nil { if nMov == nMovPerLine { err = w.WriteByte('\n') nMov = 0 } err = w.WriteByte(';') // write the node typ := p.treeNodes[n].TNodType switch typ { case GameInfoNode: // fmt.Println("writing GameInfoNode\n") err = p.writeProperties(w, n, true) case InteriorNode: // fmt.Println("writing InteriorNode\n") err = p.writeProperties(w, n, false) case BlackMoveNode: _, err = w.WriteString("B[") _, err = w.Write(SGFCoords(ah.NodeLoc(p.treeNodes[n].propListOrNodeLoc), p.IsFF4())) err = w.WriteByte(']') nMov += 1 case WhiteMoveNode: _, err = w.WriteString("W[") _, err = w.Write(SGFCoords(ah.NodeLoc(p.treeNodes[n].propListOrNodeLoc), p.IsFF4())) err = w.WriteByte(']') nMov += 1 default: fmt.Println("*** unsupported TreeNodeType in writeTree") err = errors.New("writeTree: unsupported TreeNodeType" + strconv.FormatInt(int64(typ), 10)) return err } if err == nil { // write the children lastCh := p.treeNodes[n].Children if lastCh != nilTreeNodeIdx && err == nil { ch := p.treeNodes[lastCh].NextSib chNeeds := (lastCh != ch) err = p.writeTree(w, ch, chNeeds, nMov, nMovPerLine) for ch != lastCh && err == nil { ch = p.treeNodes[ch].NextSib // nMov += 1 err = p.writeTree(w, ch, chNeeds, nMov, nMovPerLine) } } if (err == nil) && (needs == true) { err = w.WriteByte(')') } } } return err }
// GetMove returns the move at a node func (gamT *GameTree) GetMove(n TreeNode) (nl ah.NodeLoc, c ah.PointStatus, err ah.ErrorList) { if n.TNodType == BlackMoveNode { nl, c = ah.NodeLoc(n.propListOrNodeLoc), ah.Black } else if n.TNodType == WhiteMoveNode { nl, c = ah.NodeLoc(n.propListOrNodeLoc), ah.White } else if n.TNodType == InteriorNode { OK := false lastProp := n.propListOrNodeLoc if lastProp != nilPropIdx { pl := gamT.propertyValues[lastProp].NextProp prop := gamT.propertyValues[pl] process := func(prop PropertyValue) { if prop.PropType == B_idx { OK = true c = ah.Black nl, err = SGFPoint(prop.StrValue) } else if prop.PropType == W_idx { OK = true c = ah.White nl, err = SGFPoint(prop.StrValue) } else { pl = prop.NextProp } } // pprocess first prop. process(prop) if !OK { for (pl != lastProp) && (err == nil) { pl := gamT.propertyValues[pl].NextProp prop := gamT.propertyValues[pl] // pprocess next prop. process(prop) if OK { break } } } } if !OK { err.Add(ah.NoPos, "sgf/GetMove: move property not found in interior node") } } else { // TODO: support moves with other properties nl = ah.IllegalNodeLoc c = ah.Unocc err.Add(ah.NoPos, "sgf/GetMove: not a move node or interior node") } return nl, c, err }
// FindChild returns the index of a child of with a move at mov func (gamT *GameTree) FindChild(par TreeNodeIdx, mov ah.NodeLoc) (found TreeNodeIdx) { found = nilTreeNodeIdx var ch TreeNodeIdx = nilTreeNodeIdx var p_idx PropIdx = nilPropIdx checkMov := func() { if gamT.propertyValues[p_idx].PropType == B_idx || gamT.propertyValues[p_idx].PropType == W_idx { mv, err := SGFPoint(gamT.propertyValues[p_idx].StrValue) if len(err) != 0 { return } if mv == mov { found = ch // set found to the child index } } } lookFor := func() { typ := gamT.treeNodes[ch].TNodType switch typ { case InteriorNode: var tail_p PropIdx = gamT.treeNodes[ch].propListOrNodeLoc if tail_p != nilPropIdx { p_idx = tail_p // check for mov checkMov() for p_idx != tail_p && found == nilTreeNodeIdx { p_idx = gamT.propertyValues[p_idx].NextProp // check for mov checkMov() } } case BlackMoveNode, WhiteMoveNode: // TODO: need to check the mov color? currently, no if ah.NodeLoc(gamT.treeNodes[ch].propListOrNodeLoc) == mov { found = ch } default: } } tail := gamT.treeNodes[par].Children if tail != nilTreeNodeIdx { // check if any children ch = gamT.treeNodes[tail].NextSib // get the first child // look for a move at mov lookFor() for ch != tail && found == nilTreeNodeIdx { ch = gamT.treeNodes[ch].NextSib // get the next child // look for a move at mov lookFor() } } return found }
func DoAddLabels(gamT *GameTree, nodIdx TreeNodeIdx) { lastCh := gamT.treeNodes[nodIdx].Children if lastCh != nilTreeNodeIdx { ch := gamT.treeNodes[lastCh].NextSib i := 1 for ch != lastCh { nodLoc, _, _ := gamT.GetMove(gamT.treeNodes[ch]) if nodLoc != ah.PassNodeLoc { i += 1 } ch = gamT.treeNodes[ch].NextSib } if i > 1 { Labels := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" //Labels := [26]byte{'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'} var sep = make([]byte, 2) var colon = make([]byte, 1) sep[0] = ']' sep[1] = '[' colon[0] = ':' // fmt.Println("i =", i) needsLabel := false if gamT.treeNodes[nodIdx].TNodType == BlackMoveNode { // change to InteriorNode and Add B_idx property nodLoc := ah.NodeLoc(gamT.treeNodes[nodIdx].propListOrNodeLoc) if nodLoc != ah.PassNodeLoc { pv := PropertyValue{StrValue: SGFCoords(nodLoc, gamT.IsFF4()), NextProp: nilPropIdx, PropType: B_idx, ValType: Move} gamT.treeNodes[nodIdx].TNodType = InteriorNode gamT.treeNodes[nodIdx].propListOrNodeLoc = nilPropIdx _ = gamT.addProperty(pv, nodIdx) needsLabel = true } } else if gamT.treeNodes[nodIdx].TNodType == WhiteMoveNode { // change to InteriorNode and Add W_idx property nodLoc := ah.NodeLoc(gamT.treeNodes[nodIdx].propListOrNodeLoc) if nodLoc != ah.PassNodeLoc { pv := PropertyValue{StrValue: SGFCoords(nodLoc, gamT.IsFF4()), NextProp: nilPropIdx, PropType: W_idx, ValType: Move} gamT.treeNodes[nodIdx].TNodType = InteriorNode gamT.treeNodes[nodIdx].propListOrNodeLoc = nilPropIdx _ = gamT.addProperty(pv, nodIdx) needsLabel = true } } else { needsLabel = true } if needsLabel { // Build the LB property pv := PropertyValue{StrValue: nil, NextProp: nilPropIdx, PropType: LB_idx, ValType: ListOfCompPoint_simpTest} lastCh = gamT.treeNodes[nodIdx].Children ch = gamT.treeNodes[lastCh].NextSib j := 0 for ch != lastCh { nodLoc, _, _ := gamT.GetMove(gamT.treeNodes[ch]) if nodLoc != ah.PassNodeLoc { // fmt.Printf(" StrValue = %s\n", string(pv.StrValue)) pv.StrValue = append(pv.StrValue, SGFCoords(nodLoc, gamT.IsFF4())...) // fmt.Printf(" StrValue = %s\n", string(pv.StrValue)) pv.StrValue = append(pv.StrValue, colon[0]) // fmt.Printf(" StrValue = %s\n", string(pv.StrValue)) pv.StrValue = append(pv.StrValue, Labels[j]) // fmt.Printf(" StrValue = %s\n", string(pv.StrValue)) j += 1 if j < i { pv.StrValue = append(pv.StrValue, sep...) // fmt.Printf(" StrValue = %s\n", string(pv.StrValue)) } } ch = gamT.treeNodes[ch].NextSib } nodLoc, _, _ := gamT.GetMove(gamT.treeNodes[ch]) if nodLoc != ah.PassNodeLoc { pv.StrValue = append(pv.StrValue, SGFCoords(nodLoc, gamT.IsFF4())...) pv.StrValue = append(pv.StrValue, colon[0]) pv.StrValue = append(pv.StrValue, Labels[j]) // fmt.Printf(" StrValue = %s\n", string(pv.StrValue)) } //add the LB property _ = gamT.addProperty(pv, nodIdx) NumberOfAddedLabels += 1 } } } }