Ejemplo n.º 1
0
def test_get_next_with_last_child_returns_none():
    """
    Verifies that `get_next` on a point with its last possible child returns None.
    """
    grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1)))
    grid[1][1].child = grid[1][0]
    assert get_next(grid[1][1]) is None
Ejemplo n.º 2
0
def test_observability_with_point_mutations_notifies_observers():
    """Verifies that grids forward point mutation notifications to their observers"""
    grid = Grid(((-1, -1), (-1, -1)))
    point = grid[0][0]
    # Instantiate and register an incrementor as an example observer of the grid
    incrementor = Incrementor()
    grid.register(incrementor.increment)
    # Mutate a point on the grid an arbitrary number of times
    # Verify that the incrementor indeed increments in response to each point mutation
    assert incrementor.count == 0
    for i in range(1, 4):
        # Solely accessing the point's child field should not notify observers
        assert point.child is None
        # Mutating the point's child field should indeed notify observers
        point.child = None
        assert incrementor.count == i
Ejemplo n.º 3
0
def test_get_next_with_one_remaining_segment_skips_point_on_new_segment():
    """
    Verifies that `get_next`, on last allowed segment, skips points on new segments.
    """
    grid = Grid(((-1, -1, -1, -1), (1, -1, -1, 0)))
    grid[1][0].child = grid[1][1]
    assert get_next(grid[1][1]).location == (1, 2)
Ejemplo n.º 4
0
def test_is_option_with_new_segment_and_one_remaining_segment_returns_false():
    """Verifies that a point not on the last allowed segment is not an option."""
    grid = Grid(((1, -1, -1, 0), (-1, -1, -1, -1)))
    current = grid[0][1]
    # Set partial path to current
    grid[0][0].child = current
    assert not is_option(current, grid[1][1])
Ejemplo n.º 5
0
def test_remaining_segments_with_source_returns_type():
    """
    Verifies that the number of remaining segments of a source point is what was set.
    """
    grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1)))
    assert grid[0][0].remaining_segments == 3
    assert grid[1][1].remaining_segments == 2
Ejemplo n.º 6
0
def test_is_on_different_segment_with_same_segment_returns_false():
    """
    Verifies that `is_on_different_segment` is false for a point on the same segment.
    """
    grid = Grid(((2, -1, -1), (-1, -1, -1), (1, -1, 0)))
    grid[0][0].child = grid[0][1]
    assert not grid[0][2].is_on_different_segment(grid[0][1])
Ejemplo n.º 7
0
def test_is_on_different_segment_with_different_segment_returns_true():
    """
    Verifies that `is_on_different_segment` is true for a point on a new segment.
    """
    grid = Grid(((2, -1, -1), (-1, -1, -1), (1, -1, 0)))
    grid[0][0].child = grid[0][1]
    assert grid[1][1].is_on_different_segment(grid[0][1])
Ejemplo n.º 8
0
def test_parent_with_parent_returns_correct_point():
    """Verifies that parent property methods function for a point with a parent."""
    grid = Grid(((2, -1), (1, 0)))
    parent, child = grid[0][0], grid[0][1]
    parent.child = child
    assert child.has_parent()
    assert child.parent is parent
Ejemplo n.º 9
0
def test_get_next_with_first_of_multiple_children_returns_next_child():
    """
    Verifies that `get_next` on a point with a child returns the correct next point.
    """
    grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1)))
    grid[1][1].child = grid[0][1]
    assert get_next(grid[1][1]).location == (1, 2)
Ejemplo n.º 10
0
def test_algorithm_with_unsolvable_example_returns_false(strategy):
    """Verifies that each algorithm returns false for an unsolvable puzzle."""
    grid = Grid(((2, -1, -1), (-1, -1, -1), (-1, -1, -1)))
    assert not strategy(grid)
    # Test that grid is clear
    for row in grid:
        for point in row:
            assert point.is_source() or point.is_open()
Ejemplo n.º 11
0
def test_str_with_complete_board_returns_correct_string():
    """Verifies that the string representation of a solved grid is correct."""
    grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1)))
    # Set path from "3"
    draw_path(grid, ((0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (2, 1), (2, 0)))
    # Set path from "2"
    draw_path(grid, ((1, 1), (1, 0), (2, 0)))
    assert str(grid) == GRID_STRING_2
Ejemplo n.º 12
0
def test_is_on_different_segment_with_source_returns_false():
    """
    Verifies that `is_on_different_segment` always reports false against sources.
    """
    grid = Grid(((2, -1, -1), (-1, -1, -1), (1, -1, 0)))
    source = grid[0][0]
    assert not grid[0][1].is_on_different_segment(source)
    assert not grid[1][0].is_on_different_segment(source)
Ejemplo n.º 13
0
def test_parent_with_sink_returns_none():
    """Verifies that a sink point never reports that it has a parent."""
    grid = Grid(((2, -1), (1, 0)))
    source, pipe, sink = grid[0][0], grid[0][1], grid[1][1]
    source.child = pipe
    pipe.child = sink
    assert not sink.has_parent()
    assert sink.parent is None
Ejemplo n.º 14
0
def test_is_option_with_new_segment_sink_and_two_remaining_segments_returns_true(
):
    """Verifies that a sink not on the second to last allowed segment is an option."""
    grid = Grid(((2, -1, 0), (-1, 0, -1)))
    current = grid[0][1]
    # Set partial path to current
    grid[0][0].child = current
    assert is_option(current, grid[1][1])
Ejemplo n.º 15
0
def test_get_next_with_no_child_and_all_open_neighbors_returns_first_available(
):
    """
    Verifies that `get_next` returns the first available neighbor if all are open.
    """
    grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1)))
    assert get_next(grid[0][0]).location == (0, 1)
    assert get_next(grid[1][1]).location == (0, 1)
Ejemplo n.º 16
0
def test_is_option_with_same_segment_sink_and_one_remaining_segment_returns_true(
):
    """Verifies that a sink on the last allowed segment is an option."""
    grid = Grid(((1, -1, 0), (-1, 0, -1)))
    current = grid[0][1]
    # Set partial path to current
    grid[0][0].child = current
    assert is_option(current, grid[0][2])
Ejemplo n.º 17
0
def test_is_option_with_open_neighbor_returns_true():
    """Verifies that `is_option` correctly identifies when a point is an option."""
    grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1)))
    current = grid[1][1]
    assert is_option(current, grid[0][1])
    assert is_option(current, grid[1][2])
    assert is_option(current, grid[2][1])
    assert is_option(current, grid[1][0])
Ejemplo n.º 18
0
def test_get_next_with_no_child_and_some_open_neighbors_returns_first_available(
):
    """
    Verifies that `get_next` returns the first available neighbor if some are open.
    """
    grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1)))
    # Set partial path from "3"
    draw_path(grid, ((0, 0), (0, 1), (0, 2), (1, 2)))
    assert get_next(grid[1][1]).location == (2, 1)
Ejemplo n.º 19
0
def test_is_head_complete_puzzle_returns_no_heads():
    """Verifies that a completely solved puzzle has no remaining heads."""
    grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1)))
    # Set path from "3"
    draw_path(grid, ((0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (2, 1), (2, 0)))
    # Set path from "2"
    draw_path(grid, ((1, 1), (1, 0), (2, 0)))
    # Test that there are no heads anymore
    assert not [point for row in grid for point in row if point.is_head()]
Ejemplo n.º 20
0
def test_is_open_with_pipe_conditional_on_parent():
    """Verifies that a pipe reports being open if and only if it's parentless."""
    grid = Grid(((2, -1), (1, 0)))
    pipe = grid[0][1]
    # Test pipe without parent is open
    assert pipe.is_open()
    # Test pipe with parent is not open
    grid[0][0].child = pipe
    assert not pipe.is_open()
Ejemplo n.º 21
0
def test_get_head_with_complete_puzzle_returns_none():
    """Verifies that a completely solved puzzle reports having no heads."""
    grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1)))
    # Set path from "3"
    draw_path(grid, ((0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (2, 1), (2, 0)))
    # Set path from "2"
    draw_path(grid, ((1, 1), (1, 0), (2, 0)))
    assert not has_head(grid)
    assert get_head(grid) is None
Ejemplo n.º 22
0
def test_get_next_with_greater_than_two_remaining_segments_skips_sinks():
    """
    Verifies that `get_next` skips a sink not on the last allowed segment.
    """
    grid = Grid(((-1, 0, -1), (4, -1, 0), (-1, -1, -1)))
    current = grid[1][1]
    # Set partial path to current
    grid[1][0].child = current
    assert get_next(current).location == (2, 1)
Ejemplo n.º 23
0
def test_solve_with_real_strategies_solves_grid(strategy):
    """Verifies that `solve` using real strategies solves a real grid."""
    grid = Grid(((2, -1), (0, 0)))
    assert solve(grid, strategy=strategy)
    # Test all points in component-wise order
    assert grid[0][0].child.location == (0, 1)
    assert grid[0][1].child.location == (1, 1)
    assert grid[1][0].is_open()
    assert grid[1][1].is_open()
Ejemplo n.º 24
0
def test_get_neighbors_with_some_neighbors_returns_correct_points():
    """Verifies that the neighbor method functions for points with some neighbors."""
    grid = Grid(((-1, -1), (-1, -1)))
    point = grid[0][0]
    expected_neighbors = (grid[0][1], grid[1][0])
    actual_neighbors = point.get_neighbors()
    assert len(expected_neighbors) == len(actual_neighbors) == 2
    for expected_neighbor, actual_neighbor in zip(expected_neighbors, actual_neighbors):
        assert expected_neighbor is actual_neighbor
Ejemplo n.º 25
0
def test_reveal_with_complete_puzzle_prints_but_does_not_backtrack(capsys):
    """Verifies that `reveal` on a complete puzzle prints as expected."""
    grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1)))
    # Set path from "3"
    draw_path(grid, ((0, 0), (0, 1), (0, 2), (1, 2), (2, 2), (2, 1), (2, 0)))
    # Set path from "2"
    draw_path(grid, ((1, 1), (1, 0), (2, 0)))
    # Test reveal with no delay
    reveal(grid, delay=0)
    assert capsys.readouterr().out == f"\x1b[J{SOLVED_GRID_STRING}\n"
Ejemplo n.º 26
0
def test_get_neighbor_with_neighbor_present_returns_correct_point():
    """Verifies that the neighbor method functions for a point with neighbors."""
    grid = Grid(((-1, -1, -1), (-1, -1, -1), (-1, -1, -1)))
    point = grid[1][1]
    neighbors = (grid[0][1], grid[1][2], grid[2][1], grid[1][0])
    # Test that the correct neighbor exists in each direction
    for i, direction in enumerate(Direction):
        assert point.has_neighbor(direction)
        neighbor = point.get_neighbor(direction)
        assert neighbor is neighbors[i]
Ejemplo n.º 27
0
def test_is_option_with_unavailable_neighbor_returns_false():
    """
    Verifies that `is_option` correctly identifies when a point is not an option.
    """
    grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1)))
    # Set partial path from "3"
    draw_path(grid, ((0, 0), (0, 1), (0, 2), (1, 2)))
    # Test neighbors on partial path from "3"
    current = grid[1][1]
    assert not is_option(current, grid[0][1])
    assert not is_option(current, grid[1][2])
Ejemplo n.º 28
0
def test_remaining_segments_with_first_segment_returns_no_change():
    """
    Verifies that a source's child has an unchanged number of remaining segments.
    """
    grid = Grid(((3, -1, -1), (-1, 2, -1), (0, -1, -1)))
    # Test first point on first segment
    grid[0][0].child = grid[0][1]
    assert grid[0][1].remaining_segments == 3
    # Test second point on first segment
    grid[0][1].child = grid[0][2]
    assert grid[0][2].remaining_segments == 3
Ejemplo n.º 29
0
def test_solve_with_default_arguments_solves_grid_silently(capsys):
    """Verifies that `solve` using default arguments solves a real grid silently."""
    grid = Grid(((2, -1), (0, 0)))
    assert solve(grid)
    # Test all points in component-wise order
    assert grid[0][0].child.location == (0, 1)
    assert grid[0][1].child.location == (1, 1)
    assert grid[1][0].is_open()
    assert grid[1][1].is_open()
    # Verify that nothing was printed to the console
    assert capsys.readouterr().out == ""
Ejemplo n.º 30
0
def august_9_grid():
    """Test fixture that creates the August 9 Gas Lines puzzle."""
    # Real NYT Magazine Gas Lines puzzle from the August 9, 2020 issue
    return Grid((
        (2, -1, 0, -1, 2, -1, -1),
        (-1, 4, -1, -1, -1, -1, 4),
        (-1, -1, -1, -1, 2, -1, -1),
        (-1, 0, 1, -1, -1, 0, -1),
        (-1, -1, -1, -1, -1, -1, -1),
        (-1, 3, 0, -1, -1, 4, -1),
        (4, -1, -1, -1, -1, -1, -1),
    ), )