Rotate a Chinese checkerboard

19

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.

jimmy23013

Posted 2015-06-21T11:25:08.253

Reputation: 34 042

Answers

16

CJam, 61 59 43 40 38 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.

Dennis

Posted 2015-06-21T11:25:08.253

Reputation: 196 637

_,,Sf*\.+W%ze_. – jimmy23013 – 2015-06-21T15:27:32.447

@jimmy23013: Much better than my sorting approach. Thanks! – Dennis – 2015-06-21T15:42:54.267

liq{_N/eeSf.*W%:szsS-\{_' >{;(}&\}/;]}@*, but I was thinking of rotating by 60 degrees, not 45 degrees when I was writing this challenge... – jimmy23013 – 2015-06-21T16:00:09.547

@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 – 2015-06-21T17:36:59.930

11

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.

Sp3000

Posted 2015-06-21T11:25:08.253

Reputation: 58 729