# Intend to replace the original Step
import re
from operator import itemgetter


MOVE_RE = re.compile("([ULFRBD]w?|[MSEulfrbdxyz])(\'|i|2|2\'|)")

CLOCKWISE = 1
HALFTURN = 2
COUNTER = 3


class Move(tuple):

    __slots__ = ()

    def __new__(cls, representation):
        if isinstance(representation, Move):
            symbol = representation.symbol
            sign = representation.sign

        elif isinstance(representation, tuple) and len(representation) == 2:
            symbol, sign = representation
            assert symbol in "ULFRBDMSEulfrbdxyz" and sign in (1, 2, 3), \
                "Invalid Move initialisation: {}".format(representation)

        elif isinstance(representation, str):
            match = MOVE_RE.match(representation.strip())
            if match is None:
                raise ValueError("Invalid move: {}".format(representation))
            symbol, sign = match.groups()
            if "w" in symbol:
                symbol = symbol[0].lower()
            if sign == "2'":
                sign = "2"
            if sign == "i":
                sign = "'"
            sign = [None, "", "2", "'"].index(sign)

        else:
            raise ValueError("Can only accept Move, str, or 2-element tuple")

        return super().__new__(cls, (symbol, sign))

    symbol = property(itemgetter(0))
    sign = property(itemgetter(1))

    def __repr__(self):
        return self.symbol + [None, "", "2", "'"][self.sign]

    def __hash__(self):
        return hash(str(self))

    def __eq__(self, move):
        if not isinstance(move, Move):
            move = Move(move)
        return self.symbol == move.symbol and self.sign == move.sign

    def __ne__(self, move):
        return not self.__eq__(move)

    def __add__(self, move):
        if not isinstance(move, Move):
            move = Move(move)
        assert self.symbol == move.symbol, "Can't operate addition on two " \
                                           "Moves with different symbols"
        sign = (self.sign + move.sign) % 4
        if sign == 0:
            return 0
        return Move((self.symbol, sign))

    def __mul__(self, i):
        assert isinstance(i, int), "Can only multiply with an integer"
        sign = (self.sign * i) % 4
        if sign == 0:
            return 0
        return Move((self.symbol, sign))

    def inverse(self):
        return Move((self.symbol, 4 - self.sign))


if __name__ == "__main__":
    m = Move("R")
    assert m * 3 == m.inverse() == Move("R'")
    assert m + Move("R'") == 0
    assert m + Move("R") == Move("R2")
    assert Move("l'") == Move("li") == Move(("l", 3)) == Move(Move("l'"))

@@ -75,16 +75,24 @@
 etter%0A%0A%0A
+GENERIC_
 MOVE_RE 
@@ -104,17 +104,103 @@
 compile(
-%22
+%0A    %22(%5B1-9%5D%5B0-9%5D*%7C)(%5BULFRBD%5Dw?%7C%5BMSEulfrbdxyz%5D)(%5C'%7Ci%7C2%7C2%5C'%7C)%22)%0AMOVE_RE = re.compile(%22()
 (%5BULFRBD
@@ -282,16 +282,28 @@
 %0A%0Aclass 
+GenericCubic
 Move(tup
@@ -326,16 +326,48 @@
 s__ = ()
+%0A    __regex__ = GENERIC_MOVE_RE
 %0A%0A    de
@@ -520,24 +520,65 @@
 ntation.sign
+%0A            level = representation.level
 %0A%0A        el
@@ -641,17 +641,17 @@
 ion) == 
-2
+3
 :%0A      
@@ -647,32 +647,39 @@
 = 3:%0A           
+ level,
  symbol, sign = 
@@ -712,16 +712,75 @@
  assert 
+isinstance(level, int) and level %3E 0 and %5C%0A                
 symbol i
@@ -967,23 +967,29 @@
 match = 
-MOVE_RE
+cls.__regex__
 .match(r
@@ -1124,24 +1124,31 @@
 %0A           
+ level,
  symbol, sig
@@ -1166,16 +1166,103 @@
 roups()%0A
+            if level == %22%22:%0A                level = %221%22%0A            level = int(level)%0A
         
@@ -1620,16 +1620,23 @@
 _(cls, (
+level, 
 symbol, 
@@ -1639,24 +1639,60 @@
 ol, sign))%0A%0A
+    level = property(itemgetter(0))%0A
     symbol =
@@ -1704,33 +1704,33 @@
 erty(itemgetter(
-0
+1
 ))%0A    sign = pr
@@ -1747,17 +1747,17 @@
 mgetter(
-1
+2
 ))%0A%0A    
@@ -3032,8 +3032,46 @@
 (%22l'%22))%0A
+    assert %7BMove(%22M'%22): 4%7D%5B%22M'%22%5D == 4%0A

Create GenericCubicMove class