from .node import Node from . import skipWhitespace, ParserError class Collection: def __init__(self,s): self.gameTrees=[] i=skipWhitespace(s,0) if i>=len(s): return elif not GameTree.fits(s,i): raise ParserError("expected a GameTree starting with '('",s,i) while GameTree.fits(s,i): i,x=GameTree.create(s,i) self.gameTrees.append(x) if i<len(s): raise ParserError("expected EOF",s,i) def listGames(self): for tree in self.gameTrees: for game in tree.listGames(): yield game class GameTree: def __init__(self): self.nodes=[] self.branches=[] @staticmethod def fits(s,i): return i<len(s) and s[i]=="(" @staticmethod def create(s,start): assert GameTree.fits(s,start) res=GameTree() i=skipWhitespace(s,start+1) if not Node.fits(s,i): raise ParserError("expected a Node starting with ';'",s,i) y=None while Node.fits(s,i): i,x=Node.create(s,i) res.nodes.append(x) if y: y.addChild(x) x.setParent(y) y=x i=skipWhitespace(s,i) while GameTree.fits(s,i): i,x=GameTree.create(s,i) res.branches.append(x) subroot=x.getNode(0) subroot.setParent(y) if y: y.addChild(subroot) i=skipWhitespace(s,i) if i>=len(s) or s[i]!=")": raise ParserError("expected end of a GameTree marked by ')'",s,i) i=skipWhitespace(s,i+1) return (i,res) ## Expand multiple games into distinct GameTrees and yield each. def listGames(self): for node in self._listGINodes(): yield self._buildSubtree(node) def getNode(self,i): if 0<=i<len(self.nodes): return self.nodes[i] return None ## Create and return a new game tree containing the provided Node. # # Ancestor nodes are copied, descendants are shared. def _buildSubtree(self,seedNode): node=seedNode.copy() while node.parent: newNode=node.parent.copy() node.parent=newNode newNode.setChildren([node]) node=newNode return node ## Find and yield Game Info nodes. def _listGINodes(self): for node in self.nodes: if node.isGINode(): yield node for tree in self.branches: for node in tree._listGINodes(): yield node