Slash grid problem.

This commit is contained in:
Ivan Malison 2015-07-09 18:30:49 -07:00
parent fba727783c
commit cbc0427bc4

222
dotfiles/lib/python/slash_grid.py Executable file
View File

@ -0,0 +1,222 @@
#!/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 chr(65 + 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(20, in_between_searches=print_grid)