This Kata is the first in the [Rubiks Cube collection](https://www.codewars.com/collections/rubiks-party).

[This](https://ruwix.com/the-rubiks-cube/notation/) or [this](https://ruwix.com/the-rubiks-cube/notation/advanced/) websites will be very usefull for this kata, if there will be some lack of understanding after the description. There are plenty of examples and a 3D model that can perform all needed rotations.

In this Kata you will give the cube the ability to rotate.

The Rubik's Cube is made of six faces. F(ront), L(eft), R(ight), B(ack), U(p), D(own)

Below a two dimensional representation of the cube.
```
      +-----+
      |     |
      |  U  |
      |     |
+-----+-----+-----+-----+
|     |     |     |     |
|  L  |  F  |  R  |  B  |
|     |     |     |     |
+-----+-----+-----+-----+
      |     |
      |  D  |
      |     |
      +-----+
```

On every face you can see nine stickers. Every sticker can be one of the six colors: Yellow, Blue, Red, Green, Orange, White. In this Kata they are represented with according small letters (y, b, r, g, o, w,).

A solved cube has on every face only one color:
```
      +-----+
      |y y y|
      |y y y|
      |y y y|
+-----+-----+-----+-----+
|b b b|r r r|g g g|o o o|
|b b b|r r r|g g g|o o o|
|b b b|r r r|g g g|o o o|
+-----+-----+-----+-----+
      |w w w|
      |w w w|
      |w w w|
      +-----+
```
Every sticker on a face in this Kata has a positional number
```
+-----+
|1 2 3|
|4 5 6|
|7 8 9|
+-----+
```
So the state of the face could be represented in a 9 character string consisting of the possible colors.
```
+-----+
|y r b|
|o o w|   state == "yrboowygb"
|y g b|
+-----+
```
So a state of the cube is a 54 character long string consisting of the state of every face in this order: U L F R B D
```
      +-----+
      |y y y|
      |y y y|      state == "yyyyyyyyybbbbbbbbbrrrrrrrrrgggggggggooooooooowwwwwwwww"
      |y y y|
+-----+-----+-----+-----+
|b b b|r r r|g g g|o o o|
|b b b|r r r|g g g|o o o|
|b b b|r r r|g g g|o o o|
+-----+-----+-----+-----+
      |w w w|
      |w w w|
      |w w w|
      +-----+
```

# Rotations
To make things easier I have preloded the `state_representation(state)` function that can visialise a state.

## basic rotations
Every face can rotate.

- The direction of a rotation is always defined on your "axis of sight" when your looking at a face of the cube.
- A rotation of a face is written with an uppercase letter: `F`, `B`, ...
- Clockwise and counterclockwise rotations are distinguished by an apostroph, added to the letter for the counterclockwise rotations.

Examples:
- `F` rotates the front face clockwise.
- `F'` rotates the front face conterclockwise.

You can rotate a face twice with a `2` after the letter. E.g. `F2` rotates the front face clockwise twice.


## slice rotations
There is a possibility to rotate only a middle layer of the cube. These are called slice turns. There are three: `M, E, S`. There is no obvious clockwise or counterclockwise directions, so the are some special standarts:

`M`(idle) the layer between `L` and `R`, turn direction as `L`

`E`(quator) the layer between `D` and `U`, turn direction as `D`

`S`(tanding) the layer between `F` and `B`, turn direction as `F`

```
After a "M" turn
      +-----+
      |y o y|
      |y o y|      state == "yoyyoyyoybbbbbbbbbryrryrryrgggggggggowoowoowowrwwrwwrw"
      |y o y|
+-----+-----+-----+-----+
|b b b|r y r|g g g|o w o|
|b b b|r y r|g g g|o w o|
|b b b|r y r|g g g|o w o|
+-----+-----+-----+-----+
      |w r w|
      |w r w|
      |w r w|
      +-----+
```

## whole cube rotations

There are three more letters you should consider: `X, Y, Z`. This are basically rotating the whole cube along one of the 3D axis.

## double layer rotations

This are some kind of combined rotations. There are 6: `f, r, u, l, d, b`. Yes, like the 'basic rotations' but lowercase. A `f` means that you rotate the `F` face and the next slice layer with it IN THE SAME DIRECTION (in the F case its `S`). 

This is the whole list of possible rotations that the cube should perform:
```
F R U L D B F' R' U' L' D' B' F2 R2 U2 L2 D2 B2
M E S M' E' S' M2 E2 S2
f r u l d b f' r' u' l' d' b' f2 r2 u2 l2 d2 b2
X Y Z X' Y' Z' X2 Y2 Z2
```
I have preloded a dictionary `single_rotations` that includes every single state to mentioned rotations.
`single_rotations["F2"] == "yyyyyywwwbbgbbgbbgrrrrrrrrrbggbggbggoooooooooyyywwwwww"`

# Task
implement the `perform(sequence)` function that takes a string with space separeted values witha sequence of rotations. 
E.g. `F R2 f X M2 L' U2 d' Z M' B`
The cube always starts in a solved state ("yyyyyyyyybbbbbbbbbrrrrrrrrrgggggggggooooooooowwwwwwwww")

The function should return the changed state of the cube after the sequence.
```
perform("F U") == "byybyybyyrrrbbwbbwyggrrrrrroooyggyggbbwoooooogggwwwwww"
```



Enjoy ^_^

Source: codewars | Difficulty: EASY
Tags: Geometry

Ad-hoc

Starter code: def ROTF(U,L,F,R,B,D):
	

Solutions:
(f, g) = (lambda X: [list(x) for x in zip(*X[::-1])], lambda X: [list(x) for x in zip(*X)][::-1])

def ROTF(U, L, F, R, B, D):
	(U[2], (L[0][2], L[1][2], L[2][2]), (R[0][0], R[1][0], R[2][0]), D[0]) = ([L[0][2], L[1][2], L[2][2]][::-1], list(D[0]), list(U[2]), [R[0][0], R[1][0], R[2][0]][::-1])
	return (U, L, f(F), R, B, D)

def ROTS(U, L, F, R, B, D):
	(U[1], (L[0][1], L[1][1], L[2][1]), (R[0][1], R[1][1], R[2][1]), D[1]) = ([L[0][1], L[1][1], L[2][1]][::-1], list(D[1]), list(U[1]), [R[0][1], R[1][1], R[2][1]][::-1])
	return (U, L, F, R, B, D)

def perform(a):
	c = 'yyyyyyyyybbbbbbbbbrrrrrrrrrgggggggggooooooooowwwwwwwww'
	(U, L, F, R, B, D) = ([list(c[9 * i:9 * i + 9][j * 3:j * 3 + 3]) for j in range(3)] for i in range(6))
	A = []
	for x in a.replace("'", '3').split():
		A += [x[0]] * int(x[1]) if len(x) == 2 else [x]
	T = []
	W = 'FS YYYFY YYYFSY YFYYY YFSYYY YYFYY YYFSYY XFXXX XFSXXX XXXFX XXXFSX YYYSY XSXXX'
	for x in A:
		T += {k: list(v) for (k, v) in zip('fLlRrBbDdUuME', W.split())}.get(x, x)
	for X in T:
		if X == 'X':
			(U, L, F, R, B, D) = (F, g(L), D, f(R), g(g(U)), g(g(B)))
		if X == 'Y':
			(U, L, F, R, B, D) = (f(U), F, R, B, L, g(D))
		if X == 'Z':
			(U, L, F, R, B, D) = (f(L), f(D), f(F), f(U), g(B), f(R))
		if X == 'F':
			(U, L, F, R, B, D) = ROTF(U, L, F, R, B, D)
		if X == 'S':
			(U, L, F, R, B, D) = ROTS(U, L, F, R, B, D)
	return ''.join((''.join((''.join(y) for y in x)) for x in (U, L, F, R, B, D)))


def ROTF(U, L, F, R, B, D):
	F = [list(x) for x in zip(*F[::-1])]
	u = list(U[2])
	l = [L[0][2], L[1][2], L[2][2]]
	r = [R[0][0], R[1][0], R[2][0]]
	d = list(D[0])
	U[2] = l[::-1]
	(L[0][2], L[1][2], L[2][2]) = d
	(R[0][0], R[1][0], R[2][0]) = u
	D[0] = r[::-1]
	return (U, L, F, R, B, D)

def ROTS(U, L, F, R, B, D):
	u = list(U[1])
	l = [L[0][1], L[1][1], L[2][1]]
	r = [R[0][1], R[1][1], R[2][1]]
	d = list(D[1])
	U[1] = l[::-1]
	(L[0][1], L[1][1], L[2][1]) = d
	(R[0][1], R[1][1], R[2][1]) = u
	D[1] = r[::-1]
	return (U, L, F, R, B, D)

def perform(a):
	c = 'yyyyyyyyybbbbbbbbbrrrrrrrrrgggggggggooooooooowwwwwwwww'
	(U, L, F, R, B, D) = ([list(c[9 * i:9 * i + 9][j * 3:j * 3 + 3]) for j in range(3)] for i in range(6))
	A = []
	for x in a.replace("'", '3').split():
		if len(x) == 2:
			A += [x[0]] * int(x[1])
		else:
			A += [x]
	TMP = []
	for x in A:
		if x == 'L':
			TMP += list('YYYFY')
		if x == 'l':
			TMP += list('YYYFSY')
		if x == 'R':
			TMP += list('YFYYY')
		if x == 'r':
			TMP += list('YFSYYY')
		if x == 'B':
			TMP += list('YYFYY')
		if x == 'b':
			TMP += list('YYFSYY')
		if x == 'D':
			TMP += list('XFXXX')
		if x == 'd':
			TMP += list('XFSXXX')
		if x == 'U':
			TMP += list('XXXFX')
		if x == 'u':
			TMP += list('XXXFSX')
		if x == 'M':
			TMP += list('YYYSY')
		if x == 'E':
			TMP += list('XSXXX')
		else:
			TMP += [x]
	A = TMP[:]
	for X in A:
		if X == 'F':
			(U, L, F, R, B, D) = ROTF(U, L, F, R, B, D)
		if X == 'S':
			(U, L, F, R, B, D) = ROTS(U, L, F, R, B, D)
		if X == 'f':
			(U, L, F, R, B, D) = ROTF(U, L, F, R, B, D)
			(U, L, F, R, B, D) = ROTS(U, L, F, R, B, D)
		if X == 'Z':
			(U, L, D, R) = (L, D, R, U)
			F = [list(x) for x in zip(*F[::-1])]
			B = [list(x) for x in zip(*B)][::-1]
			U = [list(x) for x in zip(*U[::-1])]
			L = [list(x) for x in zip(*L[::-1])]
			R = [list(x) for x in zip(*R[::-1])]
			D = [list(x) for x in zip(*D[::-1])]
		if X == 'X':
			(U, F, D, B) = (F, D, B, U)
			L = [list(x) for x in zip(*L)][::-1]
			R = [list(x) for x in zip(*R[::-1])]
			B = [list(x) for x in zip(*B)][::-1]
			B = [list(x) for x in zip(*B)][::-1]
			D = [list(x) for x in zip(*D)][::-1]
			D = [list(x) for x in zip(*D)][::-1]
		if X == 'Y':
			(L, F, R, B) = (F, R, B, L)
			U = [list(x) for x in zip(*U[::-1])]
			D = [list(x) for x in zip(*D)][::-1]
		z = ''.join((''.join((''.join(y) for y in x)) for x in (U, L, F, R, B, D)))
	return z