Files
@ d57d0d4ede15
Branch filter:
Location: Diana/src/diana/sgfParser/node.py
d57d0d4ede15
3.2 KiB
text/x-python
changed the naming convention to follow standards
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | from collections import deque
import logging as log
from . import skip_whitespace, 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 = skip_whitespace(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 = skip_whitespace(s, i)
return (i, res)
def list_gi_nodes(self):
if self.is_gi_node():
yield self
empty = not self.is_gi_node()
node = self
while node.parent:
node = node.parent
if node.is_gi_node():
empty = False
yield node
queue = deque(self.children)
while len(queue) > 0:
node = queue.popleft()
if node.is_gi_node():
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 is_gi_node(self):
return any(prop.type == GAME_INFO for prop in self.properties.values())
def set_prop(self, name, value):
self.properties[name] = value
# check value type
def set_children(self, children):
self.children = children
for child in children:
child.parent = self
def add_child(self, node):
if node in self.children:
return node
node.parent = self
self.children.append(node)
return node
def remove_child(self, node):
if node not in self.children:
return None
del self.children[self.children.index(node)]
node.parent = None
return node
def remove_child_at(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 get_prop(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")
child_count = len(node.children)
if child_count == 0: # a leaf
output.append(")"*right+"\n")
elif child_count == 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]*child_count, [1]*(child_count-1)+[1+right])
stack.extend(reversed(list(children)))
return "".join(output)
|