# Rotate a Chinese checkerboard

A Chinese checkerboard looks like this (based on this question, but this time it has a fixed size):

            G
. G
G G G
G G . G
B B B B . . Y G . Y . Y Y
B B B . . G . . . Y Y Y
B . B . . . . . Y . Y
B . . . . . . . . Y
. . . . . . . . .
. P . . . . . O O .
P P . . . . . . . O O
P P P . . . R . . O O .
P P P P . . R . . O O O O
R . R R
R R R
R .
R


Each non-space character in this example can be replaced by any non-space printable ASCII character in the input, while spaces are never changed. Note that it isn't guaranteed to be a valid arrangement in Chinese checker (such as it may not have exactly 7 different kind of characters).

Your task is to rotate it by a multiple of 60 degrees.

This is the above example rotated by 60 degrees clockwise:

            B
B B
B B B
B . B B
P P P . . . B . . G G . G
P P P P . . . . . G G G
P P . . . . . G Y . G
P . . . . . . . G G
. . . . . . . . .
R . . . . . . . . Y
R . R R . . . . Y Y .
R R R . . . O . . . Y Y
R . R R . . . O . Y Y Y Y
O O O .
O O O
O .
O


The input is a non-negative integer and a Chinese checkerboard. Your program (or function) should rotate it by the integer * 60 degrees. You decide whether to rotate clockwise or counterclockwise, as long as it is consistent. Both the input and output shouldn't have extra leading or trailing spaces.

This is code-golf. Shortest code wins.

# CJam, 6159434038 36 bytes

{{_N/eeSf.*:sW%zsS-\{_' >{;(}&+}/}*}


This is an anonymous function that expects a string and an integer on the stack.

Thanks to @jimmy23013 for golfing off 19 bytes.

Try it online in the CJam interpreter.

### Idea

We can assign an order to the printable characters of the checkerboards by reading them eastwards, then southwards.

This way, the original and rotated checkerboard

            G                                  B
. G                                B B
G G G                              B B B
G G . G                            B . B B
B B B B . . Y G . Y . Y Y          P P P . . . B . . G G . G
B B B . . G . . . Y Y Y            P P P P . . . . . G G G
B . B . . . . . Y . Y              P P . . . . . G Y . G
B . . . . . . . . Y                P . . . . . . . G G
. . . . . . . . .                  . . . . . . . . .
. P . . . . . O O .                R . . . . . . . . Y
P P . . . . . . . O O              R . R R . . . . Y Y .
P P P . . . R . . O O .            R R R . . . O . . . Y Y
P P P P . . R . . O O O O          R . R R . . . O . Y Y Y Y
R . R R                            O O O .
R R R                              O O O
R .                                O .
R                                  O


become

G.GGGGGG.GBBBB..YG.Y.YYBBB..G...YYYB.B.....Y.YB........Y..........P.....OO.PP.......OOPPP...R..OO.PPPP..R..OOOOR.RRRRRR.R


and

BBBBBBB.BBPPP...B..GG.GPPPP.....GGGPP.....GY.GP.......GG.........R........YR.RR....YY.RRR...O...YYR.RR...O.YYYYOOO.OOOO.O


respectively.

We can find the second sequence in the first checkerboard by reading its characters northeastwards, then southeastwards.

To achieve this in code, we start by prepending n - 1 spaces to the nth row of the checkerboard (shown on the left). Then, we reverse the order of the rows (shown on the right).

            G                                                       R
. G                                                   R .
G G G                                               R R R
G G . G                                           R . R R
B B B B . . Y G . Y . Y Y                       P P P P . . R . . O O O O
B B B . . G . . . Y Y Y                       P P P . . . R . . O O .
B . B . . . . . Y . Y                       P P . . . . . . . O O
B . . . . . . . . Y                       . P . . . . . O O .
. . . . . . . . .                       . . . . . . . . .
. P . . . . . O O .                   B . . . . . . . . Y
P P . . . . . . . O O               B . B . . . . . Y . Y
P P P . . . R . . O O .           B B B . . G . . . Y Y Y
P P P P . . R . . O O O O       B B B B . . Y G . Y . Y Y
R . R R                       G G . G
R R R                       G G G
R .                       . G
R                       G


Finally, we transpose rows with columns:

                 ​

B

BB

BBB

B.BB

PPP...B..GG.G

PPPP.....GGG

PP.....GY.G

P.......GG

.........

R........Y

R.RR....YY.

RRR...O...YY

R.RR...O.YYYY

OOO.

OOO

O.

O


The whitespace is all over the place, but the printable characters are in the correct order if we read them eastwards, then southwards.

All that's left to do is replacing the nth printable character of the original checkerboard by the nth printable character of the last modification.

### Code

                                   e# Stack: String B, Integer A
{                               }* e# Repeat A times:
_N/                               e#   Push a copy of B and split it at linefeeds.
ee                             e#   Enumerate the lines of B.
Sf.*:s                       e#   Execute S.*s for each line:
e#     [4 "abc"] -> "    abc"
W%                     e#   Reverse the order of line lines.
z                    e#   Zip; transpose rows with columns.
s                   e#   Flatten the arrays of strings.
S-                 e#   Remove spaces.
e#   This pushes a string L.
\{          }/   e#   For each character C in the unmodified B:
_' >           e#     Check if C is bigger than ' '.
{  }&      e#     If it is:
;(        e#      Discard C and shift out a char from L.
+     e#     Append a char (C or from L) to L.
e#  L is B rotated by 60 degrees. Set L := B.

• _,,Sf*\.+W%ze_. – jimmy23013 Jun 21 '15 at 15:27
• @jimmy23013: Much better than my sorting approach. Thanks! – Dennis Jun 21 '15 at 15:42
• liq{_N/eeSf.*W%:szsS-\{_' >{;(}&\}/;]}@*, but I was thinking of rotating by 60 degrees, not 45 degrees when I was writing this challenge... – jimmy23013 Jun 21 '15 at 16:00
• @jimmy23013: Wow, thanks! I was try a different approach, but qN/(i{_eeSf.*W%:szSf-{},.{' f+sW<\,' e[}}*N* is even longer than what I had before... – Dennis Jun 21 '15 at 17:36

# Python 2, 171 bytes

def f(S,n):
o="";E=enumerate;B=S.splitlines(1)
for r,l in E(B):
for c,q in E(l):z=r-8;y=6-(z+c)/2;x=-y-z;exec"x,y,z=-y,-z,-x;"*n;o+=q*(q<"!")or B[z+8][12-y+x]
print o


This is perhaps the only time I've ever found str.splitlines useful — for all other times, .split("\n") is shorter.

Use like f(S,10).

## Explanation

For each char in the input, we either:

• Keep it if it's a space or newline, or
• Replace it with the correct char otherwise

To figure out which char to replace with, we convert the grid to cube coordinates (x, y, z), rotate n times by transforming (x, y, z) -> (-y, -z, -x), then convert back.