forked from colonelpanic/dotfiles
223 lines
6.4 KiB
Python
Executable File
223 lines
6.4 KiB
Python
Executable File
#!/usr/bin/env python
|
|
class SlashGrid(object):
|
|
|
|
def __init__(self, slash_array):
|
|
self.slash_array = slash_array
|
|
self.nodes = [
|
|
[Node(row_index, column_index, self) for column_index, value in enumerate(row)]
|
|
for row_index, row in enumerate(slash_array)
|
|
]
|
|
|
|
@property
|
|
def width(self):
|
|
return len(self.nodes[0])
|
|
|
|
@property
|
|
def height(self):
|
|
return len(self.nodes)
|
|
|
|
def run(self, in_between_searches=lambda x: x):
|
|
count = 0
|
|
for node_row in self.nodes:
|
|
for node in node_row:
|
|
if not node.top_visited:
|
|
in_between_searches(self)
|
|
count += 1
|
|
node.search('top', tag=count)
|
|
if not node.bottom_visited:
|
|
in_between_searches(self)
|
|
count += 1
|
|
node.search('bottom', tag=count)
|
|
in_between_searches(self)
|
|
return count
|
|
|
|
def __str__(self):
|
|
return '\n'.join(self.grid_row_string(row) for row in self.nodes)
|
|
|
|
def grid_row_string(self, row):
|
|
node_strings = [
|
|
node.string_lines for node in row
|
|
]
|
|
return '\n'.join(''.join(string_collection) for string_collection in zip(*node_strings))
|
|
|
|
|
|
class OutOfBoundsError(Exception):
|
|
pass
|
|
|
|
|
|
class Node(object):
|
|
|
|
_right_top = ('right', 'top')
|
|
_right_bottom = ('right', 'bottom')
|
|
_left_top = ('left', 'top')
|
|
_left_bottom = ('left', 'bottom')
|
|
|
|
_directions_map = {
|
|
True: (_left_top, _right_bottom),
|
|
False: (_left_bottom, _right_top)
|
|
}
|
|
|
|
_opposites = {
|
|
'left': 'right',
|
|
'right': 'left',
|
|
'top': 'bottom',
|
|
'bottom': 'top'
|
|
}
|
|
|
|
def __init__(self, row_index, column_index, grid):
|
|
self.row_index = row_index
|
|
self.column_index = column_index
|
|
self.grid = grid
|
|
self.top_visited = False
|
|
self.bottom_visited = False
|
|
|
|
@property
|
|
def string_lines(self):
|
|
if self.forward:
|
|
return [''.join([self.string_for_visited(self.top_visited), '/']),
|
|
''.join(['/', self.string_for_visited(self.bottom_visited)])]
|
|
else:
|
|
return [''.join(['\\', self.string_for_visited(self.top_visited)]),
|
|
''.join([self.string_for_visited(self.bottom_visited), '\\'])]
|
|
|
|
@staticmethod
|
|
def string_for_visited(visited):
|
|
if visited is True:
|
|
return 'X'
|
|
elif visited is False:
|
|
return ' '
|
|
else:
|
|
string = str(visited)
|
|
if isinstance(visited, int):
|
|
return str(visited)
|
|
if len(string) > 1:
|
|
return '`'
|
|
else:
|
|
return string
|
|
|
|
@property
|
|
def forward(self):
|
|
return self.grid.slash_array[self.row_index][self.column_index]
|
|
|
|
def directions_from(self, edge):
|
|
for direction_pair in self._directions_map[self.forward]:
|
|
if edge in direction_pair:
|
|
return direction_pair
|
|
else:
|
|
raise Exception()
|
|
|
|
def opposite(self, edge):
|
|
return self._opposites[edge]
|
|
|
|
def edge_visited(self, edge):
|
|
return getattr(self, self.edge_visited_string(edge))
|
|
|
|
def edge_visited_string(self, edge):
|
|
return '{0}_visited'.format(edge)
|
|
|
|
def visit_edge(self, edge, tag):
|
|
was_unvisited = not self.edge_visited(edge)
|
|
if was_unvisited:
|
|
setattr(self, self.edge_visited_string(edge), tag)
|
|
return was_unvisited
|
|
|
|
def search(self, edge, tag=True):
|
|
was_unvisited = self.visit_edge(edge, tag)
|
|
if not was_unvisited:
|
|
return
|
|
directions = self.directions_from(edge)
|
|
for travel_edge in directions:
|
|
try:
|
|
getattr(self, travel_edge).search(self.opposite(travel_edge), tag=tag)
|
|
except OutOfBoundsError:
|
|
pass
|
|
|
|
@property
|
|
def left_visited(self):
|
|
if self.forward:
|
|
return self.top_visited
|
|
else:
|
|
return self.bottom_visited
|
|
|
|
@property
|
|
def right_visited(self):
|
|
if self.forward:
|
|
return self.bottom_visited
|
|
else:
|
|
return self.top_visited
|
|
|
|
@right_visited.setter
|
|
def right_visited(self, value):
|
|
if self.forward:
|
|
self.bottom_visited = value
|
|
else:
|
|
self.top_visited = value
|
|
|
|
|
|
@left_visited.setter
|
|
def left_visited(self, value):
|
|
if self.forward:
|
|
self.top_visited = value
|
|
else:
|
|
self.bottom_visited = value
|
|
|
|
@property
|
|
def left(self):
|
|
if self.column_index <= 0:
|
|
raise OutOfBoundsError()
|
|
return self.grid.nodes[self.row_index][self.column_index-1]
|
|
|
|
@property
|
|
def right(self):
|
|
if self.column_index > self.grid.width - 2:
|
|
raise OutOfBoundsError()
|
|
return self.grid.nodes[self.row_index][self.column_index + 1]
|
|
|
|
@property
|
|
def top(self):
|
|
if self.row_index <= 0:
|
|
raise OutOfBoundsError()
|
|
return self.grid.nodes[self.row_index - 1][self.column_index]
|
|
|
|
@property
|
|
def bottom(self):
|
|
if self.row_index > self.grid.height-2:
|
|
raise OutOfBoundsError()
|
|
return self.grid.nodes[self.row_index + 1][self.column_index]
|
|
|
|
|
|
if __name__ == '__main__':
|
|
def print_grid(grid):
|
|
print "X"*100
|
|
print grid
|
|
|
|
def square(size, in_between_searches=lambda x: x):
|
|
import random
|
|
sg = SlashGrid([[bool(random.randint(0, 1)) for _ in range(size)] for _ in range(size)])
|
|
size = sg.run(in_between_searches)
|
|
return size
|
|
# SlashGrid([
|
|
# [True, False, True],
|
|
# [False, True, True]
|
|
# ]).run(print_grid)
|
|
# SlashGrid([
|
|
# [True, True, True],
|
|
# [False, False, False],
|
|
# [True, False, True]
|
|
# ]).run(print_grid)
|
|
# SlashGrid([
|
|
# [True, True, True, False, True],
|
|
# [False, False, False, True, False],
|
|
# [True, False, True, False, False],
|
|
# [True, True, True, False, True],
|
|
# ]).run(print_grid)
|
|
# SlashGrid([
|
|
# [True, True, True, False, True, False],
|
|
# [False, False, True, False, False, False],
|
|
# [True, True, True, False, False, False],
|
|
# [True, False, False, True, True, True],
|
|
# [True, False, False, True, False, False],
|
|
# [True, True, True, False, True, False]
|
|
# ]).run(print_grid)
|
|
print square(5, in_between_searches=print_grid)
|