def test_apply_side(self): cube = Cube((2, 2, 2)) colors = [[Color.WHITE, Color.RED], [Color.ORANGE, Color.GREEN]] apply_side(cube, self.orientation, colors) actual_colors = [[ cube.get_side(self.orientation).colors[i, j] for j in [0, 1] ] for i in [0, 1]] assert colors == actual_colors
def test_orient_not_matching_side(): cube = Cube((3, 3, 3)) for action in parse_actions("RUR'U'"): action.perform(cube, Orientation()) match = cube.orient(Orientation(), front=Pattern([[Color.WHITE, Color.GREEN, None], [None, None, None], [None, None, None]])) assert match is None
def test_get_side(): orientation: Orientation = Orientation(Side.LEFT, Side.TOP) orientation.get_side_rotation = MagicMock() orientation.get_side_rotation.return_value = 0 cube = Cube((3, 3, 3)) side = cube.get_side(orientation) assert isinstance(side, CubeSide) assert side == cube.sides[Side.LEFT]
def test_orient_keep(): cube = Cube((3, 3, 3)) for action in parse_actions("RUR'U'"): action.perform(cube, Orientation()) match = cube.orient(Orientation(), keeping=Side.LEFT, bottom=Pattern([[Color.WHITE, None, None], [None, None, None], [None, None, None]])) assert Orientation(Side.FRONT, Side.TOP) == match
def test_orient_not_matching_groups(): cube = Cube((3, 3, 3)) for action in parse_actions("RUR'U'"): action.perform(cube, Orientation()) match = cube.orient(Orientation(), front=Pattern([["a", "a", "b"], [None, None, None], [None, None, None]]), right=Pattern([["a", None, None], [None, None, None], ["a", None, "b"]])) assert match is None
def test_iterate() -> None: def orient_to_str(side: Side, i: int, j: int) -> str: return f"{side.name[0].upper()}{i}:{j}" cube = Cube((3, 4, 4)) result = set(map(lambda x: orient_to_str(*x), cube.iterate_components())) assert result == { "F0:0", "F0:1", "F0:2", "F1:0", "F1:1", "F1:2", "F2:0", "F2:1", "F2:2", "F3:0", "F3:1", "F3:2", "R0:1", "R0:2", "R1:1", "R1:2", "R2:1", "R2:2", "R3:1", "R3:2", "B0:0", "B0:1", "B0:2", "B1:0", "B1:1", "B1:2", "B2:0", "B2:1", "B2:2", "B3:0", "B3:1", "B3:2", "L0:1", "L0:2", "L1:1", "L1:2", "L2:1", "L2:2", "L3:1", "L3:2", "T1:1", "T2:1", "B1:1", "B2:1" }
def test_data_rotation(sample_cube: Cube) -> None: orientation = Orientation(Side.FRONT, Side.TOP) sample_cube.set_data(orientation, 0, 2, "b") sample_cube.set_data(orientation, 1, 2, "a") sample_cube.turn_vertical(orientation, 3, 1) def get_side(orient: Orientation) -> str: return data_to_string(sample_cube.get_side(orient)) assert get_side( orientation) == "None None None/None None None/None None None" assert get_side( orientation.to_right) == "None a b/None None None/None None None" assert get_side( orientation.to_top) == "None None b/None None a/None None None"
def test_runtime_globals(): runtime = CubeRuntime(Cube((3, 3, 3)), Orientation(), lambda action: None, lambda: None) existing = set(runtime.functions.global_values.keys()) assert existing.issuperset(set(CubeRuntime.COLOR_NAMES.keys())) assert existing.issuperset(set(CubeRuntime.SIDE_NAMES.keys())) assert "push_orientation" in existing
def test_wrong_columns(self): cube = Cube((2, 2, 2)) colors = [[Color.WHITE, Color.RED, Color.BLUE], [Color.ORANGE, Color.GREEN, Color.BLUE]] with raises(argparse.ArgumentTypeError) as e: apply_side(cube, self.orientation, colors) assert str(e.value) == "Incorrect number of columns"
def from_arguments(args: Namespace, cube: Cube, parser: ArgumentParser) -> Optional["Label"]: if args.label_data is None: return None image, scale = args.label_data texture = Texture(image, GL_RGBA, flip=True, mipmap=True) if args.label_side is not None: side = args.label_side else: side = Side.TOP face = cube.get_side(Orientation.regular(side)) if args.label_position is not None: i, j = args.label_position if i < 0 or i >= face.rows: parser.error(f"invalid label row: it must be between 0 and {face.rows - 1}") return None if j < 0 or j >= face.columns: parser.error(f"invalid label column: it must be between 0 and {face.columns - 1}") return None else: i = face.rows // 2 j = face.columns // 2 return Label(scale, texture, side, i, j)
def test_flip_flops(): code = """ let count: int while top[1, 1] != top[2, 2] or count == 0 do RUR'U' count = count + 1 end out(count) """ out_fn = MagicMock() stack = Stack() finish_function = MagicMock() cube_runtime = CubeRuntime(Cube((3, 3, 3)), Orientation(), lambda action: None, finish_function) cube_runtime.functions.initialize_stack(stack) stdlib.initialize_stack(stack) stack.add_global("out", Function(([Integer], Void))) globals = {"out": out_fn, **stdlib.exec_globals, **cube_runtime.functions.exec_globals} executor = ExecutionContext(globals) executor.compile(parser.parse(code, stack)) executor.execute(MockTracebackWriter()) cube_runtime.finished() out_fn.assert_called_once_with(6) finish_function.assert_called_once()
def test_action_callback(): callback: Callable[[Action], None] = MagicMock() runtime = CubeRuntime(Cube((3, 3, 3)), Orientation(), callback, lambda: None) runtime.perform_turn(Side.LEFT, 2, [1]) callback: MagicMock action = callback.call_args_list[0][0][0] assert isinstance(action, Turn) assert action.type == TurningType.VERTICAL
def test_data_set(sample_cube: Cube) -> None: orientation = Orientation(Side.RIGHT, Side.BACK) sample_cube.set_data(orientation, 1, 1, "a") sample_cube.set_data(orientation, 0, 0, "b") sample_cube.set_data(orientation, 1, 2, "c") sample_cube.set_data(orientation, 2, 1, "d") def get_side(orient: Orientation) -> str: return data_to_string(sample_cube.get_side(orient)) orientation = Orientation(Side.FRONT, Side.TOP) assert get_side(orientation) == "None None None/None None d/None None None" assert get_side( orientation.to_top) == "None None b/None None None/None None None" assert get_side(orientation.to_right) == "None None b/d a None/None c None" assert get_side(orientation.to_right.to_right ) == "b None None/None None None/None None None" assert get_side( orientation.to_bottom) == "None None None/None None c/None None None"
def assert_solved(cube: Cube): for front in Side: face = cube.get_side(Orientation.regular(front)) color = None for row in range(face.rows): for column in range(face.columns): c = face.colors[row, column] if color is None: color = c else: assert c == color
def test_suspend_rotations(): actions = [] runtime = CubeRuntime(Cube((2, 2, 2)), Orientation(), actions.append, lambda: None) runtime.perform_turn(Side.FRONT, 1, [1]) runtime.perform_rotate(Side.TOP, False) runtime.suspend_rotations() for _ in range(3): runtime.perform_turn(Side.FRONT, 1, [1]) runtime.perform_rotate(Side.TOP, False) runtime.resume_rotations() assert "FYFRBY'" == "".join(map(str, actions))
def test_get_color(side, orientation): class Colors: def __getitem__(self, item): pass class Side: def __init__(self): self.colors = Colors() with patch.object(Cube, 'get_side', return_value=Side()) as mock_method: runtime = CubeRuntime(Cube((3, 3, 3)), Orientation(), lambda action: None, lambda: None) runtime.get_color(side, 0, 0) mock_method.assert_called_once_with(orientation)
def test_state_stack(): actions = [] runtime = CubeRuntime(Cube((2, 2, 2)), Orientation(), actions.append, lambda: None) runtime.perform_turn(Side.FRONT, 1, [1]) runtime.perform_rotate(Side.TOP, False) runtime.push_orientation() for _ in range(3): runtime.perform_turn(Side.FRONT, 1, [1]) runtime.perform_rotate(Side.TOP, False) runtime.pop_orientation() assert "FYFYFYFYY" == "".join(map(str, actions))
def test_orient_full(): cube = Cube((3, 3, 3)) for action in parse_actions("RUR'U'"): action.perform(cube, Orientation()) match = cube.orient(Orientation(), top=Pattern([[Color.WHITE, None, None], [None, "a", None], ["a", None, None]]), front=Pattern([[None, None, None], [None, None, Color.ORANGE], [None, None, None]]), right=Pattern([[None, None, None], [Color.YELLOW, None, None], ["a", None, None]]), back=Pattern([[None, None, None], [None, None, None], [Color.BLUE, None, None]]), left=Pattern([[None, Color.ORANGE, None], [None, None, None], [None, Color.GREEN, None]]), bottom=Pattern([[Color.BLUE, None, Color.RED], [None, None, None], [None, None, None]])) assert Orientation(Side.RIGHT, Side.BOTTOM) == match
def assert_cube(cube: Cube, front: str, right: str, back: str, left: str, top: str, bottom: str) -> None: orientation = Orientation() assert front == side_to_string(cube.get_side(orientation)) assert right == side_to_string(cube.get_side(orientation.to_right)) assert back == side_to_string(cube.get_side(orientation.to_right.to_right)) assert left == side_to_string(cube.get_side(orientation.to_left)) assert top == side_to_string(cube.get_side(orientation.to_top)) assert bottom == side_to_string(cube.get_side(orientation.to_bottom))
def test_cube_flip_flop(): cube = Cube((3, 3, 3)) assert_cube(cube, "RRR/RRR/RRR", "GGG/GGG/GGG", "OOO/OOO/OOO", "BBB/BBB/BBB", "YYY/YYY/YYY", "WWW/WWW/WWW") for action in parse_actions("RUR'U'"): action.perform(cube, Orientation()) assert_cube(cube, "RRW/RRY/RRR", "GGY/OGG/YGG", "OGG/OOO/OOO", "OBB/BBB/BBB", "YYB/YYR/YYR", "WWG/WWW/WWW") for _ in range(5): for action in parse_actions("RUR'U'"): action.perform(cube, Orientation()) assert_cube(cube, "RRR/RRR/RRR", "GGG/GGG/GGG", "OOO/OOO/OOO", "BBB/BBB/BBB", "YYY/YYY/YYY", "WWW/WWW/WWW")
def test_orientation_transform(orientation, turn): cube1 = Cube((3, 3, 3)) cube2 = Cube((3, 3, 3)) turn.perform(cube1, orientation) origin = Orientation() turn.from_orientation(orientation, origin).perform(cube2, origin) for side in Side: o = Orientation.regular(side) assert str(cube1.get_side(o).colors) == str(cube2.get_side(o).colors)
def run_test(seed, filename, dimension): scramble = subprocess.check_output( ["python", "-m", "cubelang.scrambler", "-d", str(dimension), "-s", str(seed)]) scramble = scramble.decode(stdout.encoding).strip() cube = Cube((dimension, dimension, dimension)) orientation = Orientation() for action in parse_actions(scramble): orientation = action.perform(cube, orientation) arguments = ["python", "-m", "cubelang", "-d", str(dimension), "-s", scramble, str(Path(__file__).parents[1] / "examples" / filename)] solution = subprocess.check_output(arguments).decode("utf-8") for action in parse_actions(solution): orientation = action.perform(cube, orientation) assert_solved(cube)
def sample_cube() -> Cube: cube = Cube((3, 3, 3)) orientation = Orientation() assert orientation.get_side_rotation() == 0 red = cube.get_side(orientation) _set_side_colors(red, [[Color.ORANGE, Color.RED, Color.GREEN], [Color.YELLOW, Color.RED, Color.GREEN], [Color.BLUE, Color.WHITE, Color.GREEN]]) green = cube.get_side(orientation.to_right) _set_side_colors(green, [[Color.RED, Color.ORANGE, Color.ORANGE], [Color.RED, Color.GREEN, Color.WHITE], [Color.RED, Color.GREEN, Color.WHITE]]) orange = cube.get_side(orientation.to_left.to_left) _set_side_colors(orange, [[Color.YELLOW, Color.YELLOW, Color.RED], [Color.ORANGE, Color.ORANGE, Color.WHITE], [Color.ORANGE, Color.ORANGE, Color.GREEN]]) blue = cube.get_side(orientation.to_left) _set_side_colors(blue, [[Color.YELLOW, Color.YELLOW, Color.YELLOW], [Color.BLUE, Color.BLUE, Color.RED], [Color.ORANGE, Color.WHITE, Color.WHITE]]) yellow = cube.get_side(orientation.to_top) _set_side_colors(yellow, [[Color.BLUE, Color.GREEN, Color.GREEN], [Color.BLUE, Color.YELLOW, Color.YELLOW], [Color.BLUE, Color.BLUE, Color.WHITE]]) white = cube.get_side(orientation.to_bottom) _set_side_colors(white, [[Color.RED, Color.GREEN, Color.YELLOW], [Color.RED, Color.WHITE, Color.ORANGE], [Color.WHITE, Color.BLUE, Color.BLUE]]) assert_cube(cube, "ORG/YRG/BWG", "ROO/RGW/RGW", "YYR/OOW/OOG", "YYY/BBR/OWW", "BGG/BYY/BBW", "RGY/RWO/WBB") return cube
def test_orient(): code = """ orient top: {G--/---/---}, bottom: {--Y/---/---} then out(red) else-orient top: {-W-/---/---}, right: {---/---/-O-} then out(top[1, 1]) end """ out_fn = MagicMock() stack = Stack() cube_runtime = CubeRuntime(Cube((3, 3, 3)), Orientation(), lambda action: None, lambda: None) cube_runtime.functions.initialize_stack(stack) stdlib.initialize_stack(stack) stack.add_global("out", Function(([Color], Void))) globals = {"out": out_fn, **stdlib.exec_globals, **cube_runtime.functions.exec_globals} executor = ExecutionContext(globals) executor.compile(parser.parse(code, stack)) executor.execute(MockTracebackWriter()) cube_runtime.finished() out_fn.assert_called_once_with(orientation.Color.WHITE)
def main(): arg_parser = ArgumentParser() arg_parser.add_argument("-d", dest="dimension", help="dimensions of a cube", default=3, metavar="N", type=integer_type(2)) arg_parser.add_argument("-n", dest="turns_num", help="number of turns", type=integer_type(1), default=20) arg_parser.add_argument( "-a", dest="output_args", action="store_true", help= "display the state of the cube after the turns instead of the formula") arg_parser.add_argument( "-s", dest="seed", help="the seed for the pseudorandom number generator") args = arg_parser.parse_args() dim = args.dimension if args.seed is not None: random.seed(args.seed) actions: List[Turn] = [] prev_side = None for i in range(args.turns_num): if prev_side is None: sides = SIDES else: sides = [x for x in SIDES if x != prev_side] prev_side = random.choice(sides) first_index = random.randint(1, dim // 2) last_index = random.randint(1, first_index) if first_index == last_index: indices = [first_index] else: indices = [last_index, ..., first_index] turn = Turn(prev_side, indices, random.randint(1, 3)) actions.append(turn) if not args.output_args: for action in actions: print(str(action), end="") print() else: cube = Cube((dim, ) * 3) orientation = Orientation() for action in actions: action.perform(cube, orientation) print("--front", repr(cube.get_side(orientation).colors)) print("--right", repr(cube.get_side(orientation.to_right).colors)) print("--left", repr(cube.get_side(orientation.to_left).colors)) print("--back", repr(cube.get_side(orientation.to_right.to_right).colors)) print("--top", repr(cube.get_side(orientation.to_top).colors)) print("--bottom", repr(cube.get_side(orientation.to_bottom).colors))
def test_rotation_horizontal(sample_cube: Cube) -> None: orientation = Orientation(Side.RIGHT, Side.FRONT) sample_cube.turn_horizontal(orientation, 1, 1) assert_cube(sample_cube, "GGG/RRW/OYB", "YOO/GGW/RGW", "YYR/OOW/OOG", "YYW/BBB/OWB", "BGG/BYY/RRR", "YRW/RWO/WBB")
def test_rotation_horizontal_last(sample_cube: Cube) -> None: orientation = Orientation(Side.BOTTOM, Side.LEFT) sample_cube.turn_horizontal(orientation, -1, 3) assert_cube(sample_cube, "ORG/YRY/BWW", "OWW/OGG/RRR", "BYR/OOW/YOG", "YYY/BBR/OWW", "BGO/BYO/BBY", "RGG/RWG/WBG")
def test_rotation_slice(sample_cube: Cube) -> None: orientation = Orientation(Side.RIGHT, Side.BACK) sample_cube.turn_slice(orientation, 1, 1) assert_cube(sample_cube, "ORY/YRO/BWB", "RRR/GGO/WWO", "WYR/YOW/GOG", "YYY/BBR/OWW", "BGG/BYG/BBG", "RGO/RWO/WBY")
def test_get_absolute_2(side, i, j, a, b, c) -> None: cube = Cube((2, 2, 2)) x, y, z = cube.get_absolute_coordinates(side, i, j) assert x == a assert y == b assert z == c
def test_wrong_lines(self): cube = Cube((2, 2, 2)) colors = [[Color.WHITE, Color.RED]] with raises(argparse.ArgumentTypeError) as e: apply_side(cube, self.orientation, colors) assert str(e.value) == "Incorrect number of lines"