def test_turning_transform(side: Side, turn: Side, res_side: TurningType, res_sides: int, res_turns: int): action = Turn(side, [1], 1) transformed = action._transform(turn) assert transformed.type == res_side assert transformed.turns == res_turns assert transformed.indices[0] == res_sides
def test_formatting(): a1 = Turn(Side.LEFT, 1, 1) a2 = Turn(Side.TOP, 1, 1) fp = FormattingPostprocessor() fp.callback = MagicMock() fp.process(a1) fp.process(a2) fp.done() assert fp.callback.call_args_list == [call("L"), call("U")]
def test_turning_vertical(side: Side, func: str, out_sides: List[int], out_amount: int) -> None: cube: Cube = CubeMock() mock = MagicMock() setattr(cube, func, mock) orientation = Orientation() action = Turn(side, [1, 2], 1) assert action.perform(cube, orientation) == orientation assert len(mock.call_args_list) == len(out_sides) print(mock.call_args_list[0]) for args, side in zip(mock.call_args_list, out_sides): arg_orientation, arg_index, arg_turn = tuple(args)[0] assert arg_orientation == orientation assert arg_index == side assert arg_turn == out_amount
def test_normal(self): result: List[Turn] = [] ofp = OrientationFreezePostprocessor() ofp.callback = result.append ofp.process(Turn(Side.FRONT, 1)) ofp.process(Rotate(Side.TOP)) ofp.process(Turn(Side.FRONT, 1)) ofp.process(Rotate(Side.TOP)) ofp.process(Turn(Side.FRONT, 1)) ofp.process(Rotate(Side.TOP)) ofp.process(Turn(Side.FRONT, 1)) ofp.process(Rotate(Side.FRONT)) ofp.process(Turn(Side.TOP, 1)) actual = list(map(lambda x: (x.type, x.indices[0]), result)) assert actual == [ (TurningType.SLICE, 1), (TurningType.VERTICAL, -1), (TurningType.SLICE, -1), (TurningType.VERTICAL, 1), (TurningType.SLICE, -1) ]
def test_turning(type: TurningType, amount1: int, amount2: int, exp_amount: Optional[int]): a1 = Turn(type, [1], amount1) a2 = Turn(type, [1], amount2) actual = [] pp = OptimizingPostprocessor() pp.callback = actual.append pp.process(a1) pp.process(a2) pp.done() if exp_amount is None: assert len(actual) == 0 else: assert len(actual) == 1 actual = actual[0] assert isinstance(actual, Turn) assert actual.type == type assert actual.turns == exp_amount assert actual.indices == [1]
def _create_turn_animation(self, action: Turn) -> Animation: turns = action.turns if turns == 3: turns = -1 if action.type == TurningType.HORIZONTAL: turns = -turns angle = math.radians(90 * turns) if action.type == TurningType.SLICE: axis = "z" side = Side.FRONT elif action.type == TurningType.VERTICAL: axis = "x" side = Side.LEFT else: axis = "y" side = Side.TOP orientation = Orientation.regular(side) width = self.cube.cube.get_side(orientation).columns components = set() for index in Turn.normalize_indices(action.indices, width): index -= 1 if index == 0: components.update(self._get_parts_front(orientation)) elif index == width - 1: components.update( self._get_parts_front(orientation.to_right.to_right)) components.update( self._get_parts_slice(orientation.to_right, index)) def execution_callback(value: float) -> None: for component in components: component.set_temp_rotation(**{axis: value}) def completion_callback() -> None: for component in components: component.apply_temp_rotation() self._run_animation() self.completed_count += 1 return FloatAnimation(0.0, angle, execution_callback, ease_in_out_quad, completion_callback, fraction_callback=self._fraction_callback)
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_normalize_indices(indices, expected): assert expected == Turn.normalize_indices(indices, 5)
def test_orientation_changes(orientation: Side, action: Turn, type: TurningType, indices: int): new_action = action.from_orientation(orientation) assert new_action.type == type assert new_action.indices[0] == indices
(Side.FRONT, Side.TOP, TurningType.VERTICAL, 1, 3), (Side.FRONT, Side.RIGHT, TurningType.HORIZONTAL, 1, 3), (Side.TOP, Side.RIGHT, TurningType.SLICE, -1, 3), ]) def test_turning_transform(side: Side, turn: Side, res_side: TurningType, res_sides: int, res_turns: int): action = Turn(side, [1], 1) transformed = action._transform(turn) assert transformed.type == res_side assert transformed.turns == res_turns assert transformed.indices[0] == res_sides @pytest.mark.parametrize("orientation, action, type, indices", [(Orientation(Side.BACK, Side.LEFT), Turn(Side.RIGHT, 1, 3), TurningType.HORIZONTAL, -1), (Orientation(Side.TOP, Side.BACK), Turn(Side.TOP, 1, 1), TurningType.SLICE, -1), (Orientation(Side.RIGHT, Side.BOTTOM), Turn(Side.FRONT, 1, 1), TurningType.VERTICAL, -1)]) def test_orientation_changes(orientation: Side, action: Turn, type: TurningType, indices: int): new_action = action.from_orientation(orientation) assert new_action.type == type assert new_action.indices[0] == indices @pytest.mark.parametrize("indices, expected", [([2], {2}), ([2, 4], {2, 4}), ([2, ..., 4], {2, 3, 4}), ([1, ..., 3, 5], {1, 2, 3, 5}),
pp.process(a2) pp.done() if res is None: assert len(actual) == 0 else: assert len(actual) == 1 actual = actual[0] assert isinstance(actual, Rotate) assert actual.axis_side == res assert actual.twice == res_double @pytest.mark.parametrize("a1, a2", [ (Rotate(Side.LEFT, True), Rotate(Side.TOP, False)), (Rotate(Side.LEFT, True), Turn(Side.TOP, 1)), (Turn(TurningType.HORIZONTAL, [1], 1), Turn(TurningType.VERTICAL, [1], 1)), (Turn(TurningType.HORIZONTAL, [1], 1), Turn(TurningType.HORIZONTAL, [2], 1)) ]) def test_rotations_do_nothing(a1, a2): actual = [] pp = OptimizingPostprocessor() pp.callback = actual.append pp.process(a1) pp.process(a2) pp.done() for x, y in zip_longest(actual, [a1, a2]): assert repr(x) == repr(y)
def test_rotation(): actions = list(parse_actions("X X' Y' Z2")) expected_sides = [Side.RIGHT, Side.LEFT, Side.BOTTOM, Side.FRONT] expected_twice = [False, False, False, True] assert len(actions) == len(expected_sides) for action, side, twice in zip(actions, expected_sides, expected_twice): assert isinstance(action, Rotate) assert action.twice == twice assert action.axis_side == side @pytest.mark.parametrize("action, expected", [(Turn(Side.FRONT, 1, 1), "F"), (Turn(Side.FRONT, 1, 2), "F2"), (Turn(Side.FRONT, 1, 3), "F'"), (Turn(Side.LEFT, 1, 1), "L"), (Turn(Side.RIGHT, 1, 2), "R2"), (Turn(Side.BACK, 1, 3), "B'"), (Turn(Side.TOP, 1, 1), "U"), (Turn(Side.BOTTOM, 1, 2), "D2"), (Rotate(Side.FRONT, False), "Z"), (Rotate(Side.BACK, False), "Z'"), (Rotate(Side.BACK, True), "Z2"), (Rotate(Side.FRONT, True), "Z2"), (Rotate(Side.RIGHT, False), "X"), (Rotate(Side.BOTTOM, False), "Y'")]) def test_representation(action: Action, expected: str): actual = str(action)