Files
@ 0145cf4869b6
Branch filter:
Location: Diana/src/diana/sgfparser/node.py - annotation
0145cf4869b6
3.2 KiB
text/x-python
SVG slightly better rendering in nomacs
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 | afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 966ee650fabf afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 966ee650fabf afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 afabea7d0e61 | 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
def copy(self):
"""Create a copy of the Node, with the same parent and deep copied properties, no copied children."""
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
def __str__(self):
"""Returns textual representation of the Node itself, but disregards its children."""
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)
|