def setUp(self): self.test_solver = solver.Solver() self.field1 = TriangleField([[1], [1, 0, 2], [3, 0, 3, 0, 2]]) self.field2 = TriangleField([[1], [1, 0, 2], [1, 0, 3, 0, 2], [3, 0, 0, 0, 4, 0, 4]]) self.field3 = TriangleField([[1], [1, 0, 2]]) self.graph = Graph(directed=False) self.graph.add_edge('a', 'b') self.graph.add_edge('a', 'c') self.graph.add_edge('c', 'b') self.graph.add_edge('b', 'd')
class TriangleFieldTest(unittest.TestCase): def setUp(self): self.field = TriangleField([[1], [1, 0, 2], [1, 0, 3, 0, 2], [3, 0, 0, 0, 4, 0, 4]]) self.simple_field = TriangleField([[1], [1, 0, 2], [3, 0, 3, 0, 2]]) def test_get_neighbours(self): expected = {(1, 1)} self.assert_neighbours(expected, (0, 0)) expected = {(0, 0), (1, 2), (1, 0)} self.assert_neighbours(expected, (1, 1)) expected = {(3, 1)} self.assert_neighbours(expected, (3, 0)) expected = {(3, 5)} self.assert_neighbours(expected, (3, 6)) expected = {(2, 1), (3, 3), (2, 3)} self.assert_neighbours(expected, (2, 2)) def assert_neighbours(self, expected, position): actual = set(self.field.get_neighbours(*position)) self.assertSetEqual(expected, actual) def test_check_field_when_ok(self): assert (self.field.field == TriangleField(self.field.field).field) def test_init_when_wrong(self): field = [[0, 0], [0, 0, 0], [0, 0, 0, 0, 0, 0]] self.assertRaises(ValueError, TriangleField, field) self.assertRaises(ValueError, TriangleField, None) def test_index_checker(self): assert not self.field.is_valid(0, 1) assert not self.field.is_valid(5, 0) assert not self.field.is_valid(0, 3) def test_get_targets(self): expected = dict(vertices={(0, 0), (1, 0), (2, 0), (1, 2), (2, 4), (2, 2)}, pairs={ frozenset({(0, 0), (1, 0)}), frozenset({(2, 2), (2, 0)}), frozenset({(1, 2), (2, 4)}) }) actual = self.simple_field.get_targets() self.assertDictEqual(expected, actual)
def get_field_from_solution(self, field: TriangleField, solution: List[list]) -> List[list]: result = TriangleField(Generator.generate_triangle_field(field.size)) for pair in field.get_targets()['pairs']: start, end = tuple(pair) number = field[start] while start != end: for edge in solution: if start in edge: result[start] = number start = self.opposite(start, edge) result[end] = number return result.field
def prepare_data_solve(field: TriangleField) -> str: solver = Solver() solutions = set( TriangleField(solver.get_field_from_solution(field, solution)) for solution in solver.solve(field)) if len(solutions) > 0: result = f'Count Solutions = {len(solutions)}\n' return result + str(solutions.pop())
def solve(self, instance: TriangleField): graph = instance.create_graph() targets = instance.get_targets() vertices = Segment(graph.vertices()) edges = graph.edges() root = Node(edges[0], {v: v for v in vertices.active}, 1) def get_node(node_edge: List[tuple], neighbors: dict, name: int) -> Node: if node_edge: return Node(node_edge, neighbors, name) return Node.second_link nodes = [root] while edges: edge = edges.pop(0) next_edge = edges[0] if edges else None self.update_vertices(vertices, edge, edges) new_nodes = [] for node in nodes: links = [] if self.is_first_inconsistent(node, targets, vertices): links.append(Node.first_second) else: new_neighbor = self.update_main_path( node.neighbor, vertices.active) links.append(get_node(next_edge, new_neighbor, 0)) if self.is_second_inconsistent(node, targets, vertices): links.append(Node.first_second) else: new_neighbor = self.update_main_path( self.update_neighbors(node), vertices.active) links.append(get_node(next_edge, new_neighbor, 1)) new_nodes.extend(n for n in links if not self.is_link(n)) node.add_link(*links) nodes = new_nodes return self.create_solutions(root)
def create(self) -> List[List]: while True: pair = self.try_get_path_start() if pair is not None: self.add_path(*pair) elif (self.covered_cells >= self.cells_amount and self.number <= MAX_NUMBER): return self.get_gaming_field() else: field = self.generate_triangle_field(self.field.size) self.__init__(TriangleField(field))
def __init__(self, field, parent): super().__init__(parent) self.solver = Solver() self._field = TriangleField(field) self.board_size = self._field.size self.cells = [] self.right_cell = 0 self.cell_length = 50 self.init_ui() self._current_number = 1 self.targets = self._field.get_targets()['vertices'] self.solutions = list( set( TriangleField( self.solver.get_field_from_solution(self._field, solution)) for solution in self.solver.solve(self._field))) self.when_solved = lambda x: None for cell in self.cells: if cell.position in self.targets: cell.is_static = True self.right_cell += 1
def setUp(self): self.field = TriangleField([[1], [1, 0, 2], [1, 0, 3, 0, 2], [3, 0, 0, 0, 4, 0, 4]]) self.simple_field = TriangleField([[1], [1, 0, 2], [3, 0, 3, 0, 2]])
def test_check_field_when_ok(self): assert (self.field.field == TriangleField(self.field.field).field)
def generate_field(size: int = 3) -> List[List]: size = max(DEFAULT_FIELD_HEIGHT, size) field = Generator.generate_triangle_field(size) constructor = Generator(TriangleField(field)) return constructor.create()
def setUp(self): field = generator.Generator.generate_triangle_field(5) self.constructor = Generator(TriangleField(field)) self.field = TriangleField(field)
def read_file(name: str): filename = Reader.search_file(name) reader = Reader(filename) field = TriangleField(reader.get_field_from_file(filename)) return field
def prepare_data_generate(size: int): field = TriangleField(generator.Generator.generate_field(size)) return field
class TriangleBoard(QWidget): def __init__(self, field, parent): super().__init__(parent) self.solver = Solver() self._field = TriangleField(field) self.board_size = self._field.size self.cells = [] self.right_cell = 0 self.cell_length = 50 self.init_ui() self._current_number = 1 self.targets = self._field.get_targets()['vertices'] self.solutions = list( set( TriangleField( self.solver.get_field_from_solution(self._field, solution)) for solution in self.solver.solve(self._field))) self.when_solved = lambda x: None for cell in self.cells: if cell.position in self.targets: cell.is_static = True self.right_cell += 1 def init_ui(self): vbox = QVBoxLayout(self) vbox.setAlignment(Qt.AlignCenter) for i, row in enumerate(self._field): hbox = QHBoxLayout(self) hbox.setAlignment(Qt.AlignCenter) for j, number in enumerate(row): cell = FieldButton((i, j), self, self.cell_length, int(self.cell_length * 2 / 3) if (j != 0 and j != len(row) - 1) and j % 2 != 0 else self.cell_length) cell.number = number cell.on_mouse_click = functools.partial(self.cell_click, cell) self.cells.append(cell) hbox.addWidget(cell, 0, Qt.AlignCenter) vbox.addLayout(hbox) self.setLayout(vbox) def cell_click(self, cell): if cell.position not in self.targets: condition = any(cell.number == path[cell.position] for path in self.solutions) if condition and self._field[cell.position] != cell.number: self.right_cell += 1 elif any(self._field[cell.position] == path[cell.position] for path in self.solutions) and not condition: self.right_cell -= 1 self._field[cell.position] = cell.number if self.check_solution(): self.when_solved('Головоломка решена!') def clear(self): for cell in self.cells: if cell.position not in self.targets: cell.number = 0 self._field[cell.position] = 0 def check_solution(self): return self.right_cell == self._field.count_cells @property def field(self): return self._field @field.setter def field(self, field): for i, row in enumerate(field): for j, cell in enumerate(row): self._field[i, j] = cell for cell in self.cells: cell.number = self._field[cell.position] @property def current_number(self): return self._current_number @current_number.setter def current_number(self, value: int): if 0 < value < MAX_COLORS: self._current_number = value