Expand a Rubik's Cube Commutator

Background

We will be using a 3x3 cube for this challenge.

Rubik's cubers have their own notation for movements on the cube:

• Each of the 6 faces has a clockwise turn notated with a single capital letter: UDLRFB. There are three additional letters MES denoting the three center slices.
• Counterclockwise rotations have a prime symbol appended: U => U'. The prime symbol for this challenge will be an ASCII apostrophe.
• A move rotated twice (either CW or CCW) has a 2 appended: U => U2.
• A move cannot be rotated twice and prime at the same time.
• Individual moves are separated by spaces: U F D' B2 E M' S2
• This challenge will not be using lowercase letters, which signify moving two layers at the same time.

Commutators, coming from group theory, is an operation of two elements $$\g,h\$$ such that $$\\left[g,h\right]=ghg^\prime h^\prime\$$, where $$\g^\prime\$$ is the inverse of $$\g\$$, e.g. R U F' => F U' R'

Rubik's cubers use a similar notation to describe commutators, used for swapping two or three pieces without disturbing any others.

Some examples of commutators:

[F U R, D B] = (F U R) (D B) | (R' U' F') (B' D')
[F' U2 R, D B2] = (F' U2 R) (D B2) | (R' U2 F) (B2 D') // note how B2 and U2 aren't primed


The Challenge

Given a Rubik's cube commutator, expand the commutator to list out all the moves performed in it.

Input

Input is a Rubik's cube commutator. Each side of the commutator are guaranteed to be at least 1 move long. Each part of the commutator can be a separate value. Each move in each commutator part can be separate values, as long as a CCW/prime or double move is within the value of the move (e.g. [[R2], ...] is valid, but [[R,2], ...] is not).

Output

Output is a list of moves of the commutator. All moves must be capital letters in the set UDLRFBMES, with an optional prime ' or double move 2.

Test Cases

[[F U R], [D B]] = F U R D B R' U' F' B' D'
[[F' U2 R], [D B2]] = F' U2 R D B2 R' U2 F B2 D'
[[U F' R2 F' R' F R F2 U' F R2], [F U2 F' U2 F2]] = U F' R2 F' R' F R F2 U' F R2 F U2 F' U2 F2 R2 F' U F2 R' F' R F R2 F U' F2 U2 F U2 F'
[[M2 E2 S2], [B2 D2 F2]] = M2 E2 S2 B2 D2 F2 S2 E2 M2 F2 D2 B2
[[F], [B]] = F B F' B'
[[U], [U]] = U U U' U'


• Relevant: Reverse a Rubik's Cube Algorithm Jan 13 at 5:37
• The 3rd test-case has 's near 2s, which seem to contradict the rules. Jan 13 at 7:40
• Did you mean 3x3x3 cube? Jan 13 at 13:06
• @Noodle9 To quote OP from the sandbox: The common names for Rubik's cubes are by the size of a face since they're usually cubes, so we just call them "3x3" for a 3x3x3 cube, etc. Only in cuboids like the 3x3x4 cuboid actually have the 3rd dimension. (Although I personally still usually call it 3x3x3 Cube tbh, despite having collected twisty puzzles in the past.) Jan 13 at 14:01
• Why do you not want to eliminate cancelling moves?? Jan 13 at 15:10

R, 85 82 bytes

Or R>=4.1, 68 bytes by replacing two function occurrences with \s.

function(g,h,[=gsub,!=function(s)rev("''"["","(\\D)\$"["\\1'",s]]))c(g,h,!g,!h)


Try it online!

Input as two vectors of strings.

05AB1E, 14 12 bytes

í''««˜ε¤ºK2£


Explanation:

í             # Reverse each inner list of the (implicit) input-pair
''«          # Append a "'" to each inner-most string
«         # Merge this modified list to the (implicit) input-list
˜        # Flatten it to a single list of strings
ε       # Map over each string:
¤      #  Push its last character (without popping the string)
º     #  'Double' it with a horizontal mirror
K    #  Remove all those substrings from the string
#  (which will only remove potential "''")
2£  #  Only leave (up to) the first two characters of the string
# (after which the result is output implicitly)


BQN, 20 bytesSBCS

∾⊢∾(¬∘≠↓·⍷∾⟜"'")¨∘⌽¨


Run online!

¬∘≠↓·⍷∾⟜"'" is a function that inverts a single move:
∾⟜"'" Append a prime symbol
⍷ Deduplicate, This removes one ' if the move already contained one.
¬∘≠ Complement (1-) of the length of the move. -1 for length 2 moves, 0 for length 1. ↓ Drop this many characters (from the end because the value is negative)

(⍷∾⟜"'")¨ "U"‿"U'"‿"U2"
# → U' U' U2'
¬∘≠¨ "U"‿"U'"‿"U2"
# → 0 ¯1 ¯1
(¬∘≠↓·⍷∾⟜"'")¨ "U"‿"U'"‿"U2"
# → U' U U2


⌽¨ Reverse each list
( ... )¨∘ Invert each move inside of each list
⊢∾ Prepend the input to the result of that
∾ Flatten by one level

Ruby, 65 bytes

->a{[a,a.map{|x|x.reverse.map{|m|(m+?').sub("''","")[0,2]}}]*" "}


Try it online!

Jelly,  15  14 bytes

ḟ;ċ?”'ḣ2)Ṛ)⁸;Ẏ


A monadic Link accepting a list of lists (parts) of lists of characters (moves) which yields a list of lists of characters (moves).

Try it online!

How?

ḟ;ċ?”'ḣ2)Ṛ)⁸;Ẏ - Link: list of lists of moves, A
)    - for each Part of A:
)      -   for each Move in that part:
”'         -     yield a quote character
?           -     if...
ċ            -     ...condition: count     (X' -> 1, X -> 0, X2 -> 0)
ḟ              -     ...then: filter discard (X' -> X)
;             -     ...else: concatenate    (X -> X', X2 -> X2')
ḣ2       -     head to index 2         (X -> X, X'-> X', X2' -> X2)
Ṛ     -   reverse (this Part)
⁸   - A
;  - concatenate (the reversed, altered Part)
Ẏ - tighten from a list of four parts to a list of all of the resulting moves


Pyth, 16 bytes

s+Qm_m+-k\'*\'hI


Try it online!

s+Qm_m+-k\'*\'hIkdQ
Q   parsed input (Q is implicit)
m                  take each sublist d:
m           d      map each move k inside the sublist d to (d is implicit)
-k\'               the move k without the prime symbol
+                   and append
hIk         1 if the move k contains only one symbol, 0 otherwise
(k is implicit, actually checks if taking
the first character is still the complete move,
alternatively !tk also works)
*\'            repeats of the prime symbol
_                   reverse the sublists
+Q                   prepend the complete input
s                     and merge everything into a single list of moves


Charcoal, 28 bytes

ＷＳ⊞υι⪫⁺υＥυ⪫Ｅ⮌⪪ι ⁺⁻λ'×'№αλ ¦


Try it online! Link is to verbose version of code. Takes input as a list of newline-terminated string of space-separated moves. Explanation:

ＷＳ⊞υι


Input the list of moves.

⪫⁺υＥυ⪫Ｅ⮌⪪ι ⁺⁻λ'×'№αλ ¦


Extend the list by taking the list of moves, splitting on spaces, reversing, inverting each move, and joining with spaces, then join the extended list with spaces and output the result. Moves are inverted by removing any ' but then adding a ' if the move was a single letter.

Python 3, 113107 83 bytes

lambda g,h:g+h+[r(r(m+"'","2'","2"),"''","")for m in g[::-1]+h[::-1]]
r=str.replace


Try it online!

Input is two lists of strings. Naive string operations.

• -6 bytes from @pajonk: alias str.replace to r
• -24 bytes from @Kevin Cruijssen: output a list instead of a string
• -6 bytes? Jan 14 at 13:52
• 83 bytes if you output as list as well. Jan 14 at 16:46