Rotate a diamond tiling

21

2

Any regular hexagon can be tiled with diamonds, for instance like so (stolen from this question):

   ______
  /_/_/\_\
 /_/\_\/\_\
/\_\/_/\/_/\
\/_/\_\/_/\/
 \_\/_/\_\/
  \_\_\/_/

We'll consider the above a tiling of size 1 (since the diamonds' sides are made of one / or \ each). The same tiling of size 2 would look like:

      ____________
     /   /   /\   \
    /___/___/  \___\
   /   /\   \  /\   \
  /___/  \___\/  \___\
 /\   \  /   /\  /   /\
/  \___\/___/  \/___/  \
\  /   /\   \  /   /\  /
 \/___/  \___\/___/  \/
  \   \  /   /\   \  /
   \___\/___/  \___\/
    \   \   \  /   /
     \___\___\/___/

Your task is to rotate diamond tilings by a multiple of 60 degrees. The diamond tiling in the input can be in any size (and the size is not explicitly specified in the input). But it would always be a valid tiling, and all sides of the hexagon would have the same length.

These are the above examples rotated by 60 degrees clockwise:

   ______
  /_/\_\_\
 /\_\/_/\_\
/\/_/\_\/_/\
\/\_\/_/_/\/
 \/_/\_\_\/
  \_\/_/_/

      ____________
     /   /\   \   \
    /___/  \___\___\
   /\   \  /   /\   \
  /  \___\/___/  \___\
 /\  /   /\   \  /   /\
/  \/___/  \___\/___/  \
\  /\   \  /   /   /\  /
 \/  \___\/___/___/  \/
  \  /   /\   \   \  /
   \/___/  \___\___\/
    \   \  /   /   /
     \___\/___/___/

The input is a non-negative integer and a diamond tiling. 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.

Related questions:

jimmy23013

Posted 2015-06-25T15:31:32.970

Reputation: 34 042

12Martin will be so jealous! – Optimizer – 2015-06-25T15:35:26.050

Answers

3

JavaScript (ES6), 452 356 315 bytes

Where \n represents the literal newline character. Edit: Saved 96 bytes by realising that my algorithm doesn't need to know the number and size of diamonds separately, plus a few minor golfs that I missed the first time around. Saved 41 bytes by rearranging the code so that the destination was always the same pair of characters, plus a minor golf that I missed when converting to my previous algorithm.

r=
(s,n)=>(z=s.search`_`,l=(f,n=z*2+1)=>[...Array(n)].map(f),a=s.split`\n`,l(_=>(o=a.map(s=>[...s].fill` `),l((_,r)=>l((_,c)=>(d=z+c*2-r,a[s=z+r-c]&&(a[s][r+c]=='/'?o[r][d]=o[r][d+1]='_':0,a[s][r+c-1]=='\\'?o[r][d]='/':0),a[--s]&&(a[s][r+c]==`_`||a[s][r+c-1]==`_`?o[r][d+1]=`\\`:0)))),a=o.map(a=>a.join``)),n),a.join`\n`)
;
<pre id=i1>
   ______
  /_/_/\_\
 /_/\_\/\_\
/\_\/_/\/_/\
\/_/\_\/_/\/
 \_\/_/\_\/
  \_\_\/_/
</pre>
<input type=button value="Rotate!" onclick="i1.textContent = r(i1.textContent, 1)">
<pre id=i2>
      ____________
     /   /   /\   \
    /___/___/  \___\
   /   /\   \  /\   \
  /___/  \___\/  \___\
 /\   \  /   /\  /   /\
/  \___\/___/  \/___/  \
\  /   /\   \  /   /\  /
 \/___/  \___\/___/  \/
  \   \  /   /\   \  /
   \___\/___/  \___\/
    \   \   \  /   /
     \___\___\/___/
</pre>
<input type=button value="Rotate!" onclick="i2.textContent = r(i2.textContent, 1)">

Explanation: Considers each pair of output characters, which could be __, /_, _\, / or \, checking for the appropriate characters in the input which map to those output characters. Ungolfed:

function rotate(str, num) {
  // Measure the size using the indent of the _ in the first row.
  var size = str.indexOf('_');
  var arr = str.split('\n');
  while (num--) {
    // We build a character array to represent the output by turning the
    // input into a nested array and replacing everything with spaces.
    // Note that the output will have any trailing spaces from the input.
    var res = arr.map(s => Array.from(s).fill(' '));
    // Loop over a diamond that encloses the hexagon.
    for (var destrow = 0; destrow <= size * 2; destrow++) {
      for (var col = 0; col <= size * 2; col++) {
        var destcol = size + col * 2 - destrow;
        var srcrow = size + destrow - col;
        var srccol = destrow + col;
        // Map / to __, \ to / and __ to \.
        // We write __ first in case it gets overwritten by / or \.
        if (arr[srcrow]) {
          if (arr[srcrow][srccol] == '/') {
            res[destrow][destcol] = res[destrow][destcol + 1] = '_';
          }
          if (arr[srcrow][srccol - 1] == '\\') {
            res[destrow][destcol] = '/';
          }
        }
        // Need to check both positions in case one was overwritten.
        if (arr[srcrow - 1] &&
            (arr[srcrow - 1][srccol] == '_' || arr[srcrow - 1][srccol - 1] == '_')) {
          res[destrow][destcol + 1] = '\\';
        }
      }
    }
    arr = res.map(a => a.join(''));
  }
  return arr.join('\n');
}

Neil

Posted 2015-06-25T15:31:32.970

Reputation: 95 035

3

Pyth, 81 bytes

ju.es.e.reh|@s.e.e[yYykZ)bGCa+LV,t-y+k*3Y*5J-+kY/lG2Jc2j406610 4K"_/\\_\\"dKbGQ.z

Try it online

Rotates counterclockwise.

Each 60° rotation is performed using the following algorithm. Suppose the input is a hexagon of order k, so it has 2⋅k + 1 rows and 4⋅k columns. To find the rotated character at row i column j, let

  • u = i + jk
  • v = j − 3⋅i + 5⋅k

Then the output character is

  • \, if the input has / at row (u + 1)/2 column (v + 1)/2; else
  • /, if the input has _ at row u/2 column v/2 or row u/2 column (v + 2)/2; else
  • _, if the input has \ at row (u + 2)/2 column v/2 or row (u + 1)/2 column (v − 1)/2; else
  • space.

(We do not count characters at half-integer indices.)

Anders Kaseorg

Posted 2015-06-25T15:31:32.970

Reputation: 29 242

I think you can guarantee which positions have \s, it's just the _s that you have to check in both places. – Neil – 2016-07-16T11:27:32.267

@Neil Yes, you know where the \s are, but you might have to draw two _s for each \. – Anders Kaseorg – 2016-07-16T14:18:17.300

Oh, you check each underscore separately? – Neil – 2016-07-16T16:09:52.567