#!/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)