Files @ e3e6dfbb44f6
Branch filter:

Location: Diana/src/diana/sgfParser/node.py

Laman
date property, minor tweaks
from collections import deque
import logging as log

from . import skipWhitespace, ParserWarning
from .property import Property, GAME_INFO


class Node:
	def __init__(self):
		self.properties=dict()
		self.parent=None
		self.children=[]

	@staticmethod
	def fits(s,i):
		return i<len(s) and s[i]==";"

	@staticmethod
	def create(s,start):
		assert Node.fits(s,start)
		res=Node()

		i=skipWhitespace(s,start+1)
		while Property.fits(s,i):
			i,x=Property.create(s,i)
			if x.name in res.properties:
				log.warning(ParserWarning('duplicate "{0}" property in a node. second value ignored'.format(x.name),s,i))
			else:
				res.properties[x.name]=x
			i=skipWhitespace(s,i)
		return (i,res)

	def listGINodes(self):
		if self.isGINode(): yield self
		empty=not self.isGINode()

		node=self
		while node.parent:
			node=node.parent
			if node.isGINode():
				empty=False
				yield node

		queue=deque(self.children)
		while len(queue)>0:
			node=queue.popleft()
			if node.isGINode():
				empty=False
				yield node
			queue.extend(node.children)
		if empty: yield self # always yield at least self, can work as GINode as well as any other

	def isGINode(self):
		return any(prop.type==GAME_INFO for prop in self.properties.values())

	def setProp(self,name,value):
		self.properties[name]=value
		# zkontrolovat typ value

	def setChildren(self,children):
		self.children=children
		for child in children: child.parent=self

	def addChild(self,node):
		if node in self.children: return node
		node.parent=self
		self.children.append(node)
		return node

	def removeChild(self,node):
		if node not in self.children:
			return None
		del self.children[self.children.index(node)]
		node.parent=None
		return node

	def removeChildAt(self,i):
		if -len(self.children)<i<len(self.children):
			res=self.children[i]
			del self.children[i]
			res.parent=None
			return res
		return None

	## Create a copy of the Node, with the same parent and deep copied properties, no copied children.
	def copy(self):
		res=Node()
		res.properties={k: v.copy() for (k,v) in self.properties.items()}
		res.parent=self.parent
		return res

	def getProp(self,name,default=None):
		if name in self.properties: return self.properties[name].value
		else: return default

	## Returns textual representation of the Node itself, but disregards its children.
	def __str__(self):
		return ";" + "".join(str(p) for p in self.properties.values())

	def export(self):
		# there is a beautiful recursive solution, which this stack is too narrow to contain
		stack=[(self,1,1)]
		output=[]

		while len(stack)>0:
			node,left,right=stack.pop()
			if left>0: output.append("("*left)
			output.append(str(node)+"\n")

			childCount=len(node.children)
			if childCount==0: # a leaf
				output.append(")"*right+"\n")
			elif childCount==1: # a line
				stack.append((node.children[0],0,right))
			else: # a branching node
				# first child pops first, last child closes parent's parentheses
				children=zip(node.children,[1]*childCount,[1]*(childCount-1)+[1+right])
				stack.extend(reversed(children))

		return "".join(output)