N × N マスの盤面を回転させよう

プログラミングの勉強をしている時に、以下のような問題に出会いました。

**問題の内容**
===
> N × N マスの盤面がある。
この盤面を90度単位で M 回回転させた後の盤面を出力せよ。

　
**具体例で考えてみよう**
===
具体的に以下のような「4 × 4 マス」で考えてみます。

<table>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
    </tr>
    <tr>
        <td>5</td>
        <td>6</td>
        <td>7</td>
        <td>8</td>
    </tr>
    <tr>
        <td>9</td>
        <td>10</td>
        <td>11</td>
        <td>12</td>
    </tr>
    <tr>
        <td>13</td>
        <td>14</td>
        <td>15</td>
        <td>16</td>
    </tr>
</table>

まず、この盤面が時計回りに90度回転して、
以下のようになることを考えてみます。

<table>
    <tr>
        <td>13</td>
        <td>9</td>
        <td>5</td>
        <td>1</td>
    </tr>
    <tr>
        <td>14</td>
        <td>10</td>
        <td>6</td>
        <td>2</td>
    </tr>
    <tr>
        <td>15</td>
        <td>11</td>
        <td>7</td>
        <td>3</td>
    </tr>
    <tr>
        <td>16</td>
        <td>12</td>
        <td>8</td>
        <td>4</td>
    </tr>
</table>


**2次元 list で表現してみよう**
===
まず最初の盤面を2次元 `list` で1マスずつ表示すると以下のようになります。
見比べやすいように最初の盤面を再度載せておきますので、必要に応じて表示させてください。
<details><summary>最初の盤面（クリックすると開きます）</summary>
<table>
    <tr>
        <td>1</td>
        <td>2</td>
        <td>3</td>
        <td>4</td>
    </tr>
    <tr>
        <td>5</td>
        <td>6</td>
        <td>7</td>
        <td>8</td>
    </tr>
    <tr>
        <td>9</td>
        <td>10</td>
        <td>11</td>
        <td>12</td>
    </tr>
    <tr>
        <td>13</td>
        <td>14</td>
        <td>15</td>
        <td>16</td>
    </tr>
</table>
</details>


```Python
### 最初の盤面を2次元 list で1マスずつ表示
# 1行目
example_list[0][0] = 1
example_list[0][1] = 2
example_list[0][2] = 3
example_list[0][3] = 4

# 2行目
example_list[1][0] = 5
example_list[1][1] = 6
example_list[1][2] = 7
example_list[1][3] = 8

# 3行目
example_list[2][0] = 9
example_list[2][1] = 10
example_list[2][2] = 11
example_list[2][3] = 12

# 4行目
example_list[3][0] = 13
example_list[3][1] = 14
example_list[3][2] = 15
example_list[3][3] = 16
```

同様に、時計回りに90度回転させた盤面を2次元 `list` で1マスずつ表現すると以下のようになります。
見比べやすいように90度回転させた盤面を再度載せておきますので、必要に応じて表示させてください。
<details><summary>90度回転させた盤面（クリックすると開きます）</summary>
<table>
    <tr>
        <td>13</td>
        <td>9</td>
        <td>5</td>
        <td>1</td>
    </tr>
    <tr>
        <td>14</td>
        <td>10</td>
        <td>6</td>
        <td>2</td>
    </tr>
    <tr>
        <td>15</td>
        <td>11</td>
        <td>7</td>
        <td>3</td>
    </tr>
    <tr>
        <td>16</td>
        <td>12</td>
        <td>8</td>
        <td>4</td>
    </tr>
</table>
</details>

```Python
### 90度回転させた盤面を2次元 list で1マスずつ表示
# 1行目
example_list[0][0] = 13
example_list[0][1] = 9
example_list[0][2] = 5
example_list[0][3] = 1

# 2行目
example_list[1][0] = 14
example_list[1][1] = 10
example_list[1][2] = 6
example_list[1][3] = 2

# 3行目
example_list[2][0] = 15
example_list[2][1] = 11
example_list[2][2] = 7
example_list[2][3] = 3

# 4行目
example_list[3][0] = 16
example_list[3][1] = 12
example_list[3][2] = 8
example_list[3][3] = 4
```

各数字と
それぞれの2次元 `list` の index 値 を表にまとめると、
以下のようになります。

<table>
    <tr>
        <th rowspan="2">数字</th>
        <th colspan="2" style="text-align: center;">2次元 list の index 値</th>
    </tr>
    <tr>
        <th>最初の盤面</th>
        <th>90度回転した盤面</th>
    </tr>
    <tr>
        <td style="text-align: center;">1</td>
        <td style="text-align: center;">[0][0]</td>
        <td style="text-align: center;">[0][3]</td>
    </tr>
    <tr>
        <td style="text-align: center;">2</td>
        <td style="text-align: center;">[0][1]</td>
        <td style="text-align: center;">[1][3]</td>
    </tr>
    <tr>
        <td style="text-align: center;">3</td>
        <td style="text-align: center;">[0][2]</td>
        <td style="text-align: center;">[2][3]</td>
    </tr>
    <tr>
        <td style="text-align: center;">4</td>
        <td style="text-align: center;">[0][3]</td>
        <td style="text-align: center;">[3][3]</td>
    </tr>
    <tr>
        <td style="text-align: center;">5</td>
        <td style="text-align: center;">[1][0]</td>
        <td style="text-align: center;">[0][2]</td>
    </tr>
    <tr>
        <td style="text-align: center;">6</td>
        <td style="text-align: center;">[1][1]</td>
        <td style="text-align: center;">[1][2]</td>
    </tr>
    <tr>
        <td style="text-align: center;">7</td>
        <td style="text-align: center;">[1][2]</td>
        <td style="text-align: center;">[2][2]</td>
    </tr>
    <tr>
        <td style="text-align: center;">8</td>
        <td style="text-align: center;">[1][3]</td>
        <td style="text-align: center;">[3][2]</td>
    </tr>
    <tr>
        <td style="text-align: center;">9</td>
        <td style="text-align: center;">[2][0]</td>
        <td style="text-align: center;">[0][1]</td>
    </tr>
    <tr>
        <td style="text-align: center;">10</td>
        <td style="text-align: center;">[2][1]</td>
        <td style="text-align: center;">[1][1]</td>
    </tr>
    <tr>
        <td style="text-align: center;">11</td>
        <td style="text-align: center;">[2][2]</td>
        <td style="text-align: center;">[2][1]</td>
    </tr>
    <tr>
        <td style="text-align: center;">12</td>
        <td style="text-align: center;">[2][3]</td>
        <td style="text-align: center;">[3][1]</td>
    </tr>
    <tr>
        <td style="text-align: center;">13</td>
        <td style="text-align: center;">[3][0]</td>
        <td style="text-align: center;">[0][0]</td>
    </tr>
    <tr>
        <td style="text-align: center;">14</td>
        <td style="text-align: center;">[3][1]</td>
        <td style="text-align: center;">[1][0]</td>
    </tr>
    <tr>
        <td style="text-align: center;">15</td>
        <td style="text-align: center;">[3][2]</td>
        <td style="text-align: center;">[2][0]</td>
    </tr>
    <tr>
        <td style="text-align: center;">16</td>
        <td style="text-align: center;">[3][3]</td>
        <td style="text-align: center;">[3][0]</td>
    </tr>
</table>



　
**盤面の回転をコード化してみよう**
===
90度回転した盤面の index 値は、
回転前の盤面の index 値を使って、以下のように表すことができます。
・X 座標（1つ目の index 値）は、「元の盤面の Y 座標（2つ目の index 値）」と同じ
・Y 座標（2つ目の index 値）は、「N（マスの大きさ）-元の盤面の X 座標（1つ目の index 値）-1 」

コード化してみると、以下のようになります。
```Python
# pprint モジュールをインポート
import pprint

# 盤面の大きさ（N × N マス）
N = 4

# 元の盤面
example_list = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]

# 結果保存用 list (N × N マスの "." 詰めで準備)
result_list = [["." for i in range(N)] for j in range(N)]

# 元の盤面を時計回りに90度回転させる
for Y in range(N):
    for X in range(N):
        result_list[Y][N -X -1] = example_list[X][Y]

# 結果を見やすく出力
print("時計回りに90度回転させた結果")
pprint.pprint(result_list, width = 20)
```

出力結果はこちら

```Python
時計回りに90度回転させた結果
[[13, 9, 5, 1],
 [14, 10, 6, 2],
 [15, 11, 7, 3],
 [16, 12, 8, 4]]
```

<details><summary>90度回転させた盤面（クリックすると開きます）</summary>
<table>
    <tr>
        <td>13</td>
        <td>9</td>
        <td>5</td>
        <td>1</td>
    </tr>
    <tr>
        <td>14</td>
        <td>10</td>
        <td>6</td>
        <td>2</td>
    </tr>
    <tr>
        <td>15</td>
        <td>11</td>
        <td>7</td>
        <td>3</td>
    </tr>
    <tr>
        <td>16</td>
        <td>12</td>
        <td>8</td>
        <td>4</td>
    </tr>
</table>
</details>

時計回りに90度回転させることができました。



**180度、270度回転させた場合も考えてみよう**
===
時計回りに180度回転した盤面は以下の通り。

<table>
    <tr>
        <td>16</td>
        <td>15</td>
        <td>14</td>
        <td>13</td>
    </tr>
    <tr>
        <td>12</td>
        <td>11</td>
        <td>10</td>
        <td>9</td>
    </tr>
    <tr>
        <td>8</td>
        <td>7</td>
        <td>6</td>
        <td>5</td>
    </tr>
    <tr>
        <td>4</td>
        <td>3</td>
        <td>2</td>
        <td>1</td>
    </tr>
</table>


同様に270度回転した盤面は以下の通り。

<table>
    <tr>
        <td>4</td>
        <td>8</td>
        <td>12</td>
        <td>16</td>
    </tr>
    <tr>
        <td>3</td>
        <td>7</td>
        <td>11</td>
        <td>15</td>
    </tr>
    <tr>
        <td>2</td>
        <td>6</td>
        <td>10</td>
        <td>14</td>
    </tr>
    <tr>
        <td>1</td>
        <td>5</td>
        <td>9</td>
        <td>13</td>
    </tr>
</table>


各数字と
それぞれを2次元 `list` にした場合の index 値を表にまとめると、
以下のようになります。

<table>
    <tr>
        <th rowspan="2">数字</td>
        <th colspan="4" style="text-align: center;">2次元 list の index 値</th>
    </tr>
    <tr>
        <th>最初の盤面</th>
        <th>90度回転した盤面</th>
        <th>180度回転した盤面</th>
        <th>270度回転した盤面</th>
    </tr>
    <tr>
        <td style="text-align: center;">1</td>
        <td style="text-align: center;">[0][0]</td>
        <td style="text-align: center;">[0][3]</td>
        <td style="text-align: center;">[3][3]</td>
        <td style="text-align: center;">[3][0]</td>
    </tr>
    <tr>
        <td style="text-align: center;">2</td>
        <td style="text-align: center;">[0][1]</td>
        <td style="text-align: center;">[1][3]</td>
        <td style="text-align: center;">[3][2]</td>
        <td style="text-align: center;">[2][0]</td>
    </tr>
    <tr>
        <td style="text-align: center;">3</td>
        <td style="text-align: center;">[0][2]</td>
        <td style="text-align: center;">[2][3]</td>
        <td style="text-align: center;">[3][1]</td>
        <td style="text-align: center;">[1][0]</td>
    </tr>
    <tr>
        <td style="text-align: center;">4</td>
        <td style="text-align: center;">[0][3]</td>
        <td style="text-align: center;">[3][3]</td>
        <td style="text-align: center;">[3][0]</td>
        <td style="text-align: center;">[0][0]</td>
    </tr>
    <tr>
        <td style="text-align: center;">5</td>
        <td style="text-align: center;">[1][0]</td>
        <td style="text-align: center;">[0][2]</td>
        <td style="text-align: center;">[2][3]</td>
        <td style="text-align: center;">[3][1]</td>
    </tr>
    <tr>
        <td style="text-align: center;">6</td>
        <td style="text-align: center;">[1][1]</td>
        <td style="text-align: center;">[1][2]</td>
        <td style="text-align: center;">[2][2]</td>
        <td style="text-align: center;">[2][1]</td>
    </tr>
    <tr>
        <td style="text-align: center;">7</td>
        <td style="text-align: center;">[1][2]</td>
        <td style="text-align: center;">[2][2]</td>
        <td style="text-align: center;">[2][1]</td>
        <td style="text-align: center;">[1][1]</td>
    </tr>
    <tr>
        <td style="text-align: center;">8</td>
        <td style="text-align: center;">[1][3]</td>
        <td style="text-align: center;">[3][2]</td>
        <td style="text-align: center;">[2][0]</td>
        <td style="text-align: center;">[0][1]</td>
    </tr>
    <tr>
        <td style="text-align: center;">9</td>
        <td style="text-align: center;">[2][0]</td>
        <td style="text-align: center;">[0][1]</td>
        <td style="text-align: center;">[1][3]</td>
        <td style="text-align: center;">[3][2]</td>
    </tr>
    <tr>
        <td style="text-align: center;">10</td>
        <td style="text-align: center;">[2][1]</td>
        <td style="text-align: center;">[1][1]</td>
        <td style="text-align: center;">[1][2]</td>
        <td style="text-align: center;">[2][2]</td>
    </tr>
    <tr>
        <td style="text-align: center;">11</td>
        <td style="text-align: center;">[2][2]</td>
        <td style="text-align: center;">[2][1]</td>
        <td style="text-align: center;">[1][1]</td>
        <td style="text-align: center;">[1][2]</td>
    </tr>
    <tr>
        <td style="text-align: center;">12</td>
        <td style="text-align: center;">[2][3]</td>
        <td style="text-align: center;">[3][1]</td>
        <td style="text-align: center;">[1][0]</td>
        <td style="text-align: center;">[0][2]</td>
    </tr>
    <tr>
        <td style="text-align: center;">13</td>
        <td style="text-align: center;">[3][0]</td>
        <td style="text-align: center;">[0][0]</td>
        <td style="text-align: center;">[0][3]</td>
        <td style="text-align: center;">[3][3]</td>
    </tr>
    <tr>
        <td style="text-align: center;">14</td>
        <td style="text-align: center;">[3][1]</td>
        <td style="text-align: center;">[1][0]</td>
        <td style="text-align: center;">[0][2]</td>
        <td style="text-align: center;">[2][3]</td>
    </tr>
    <tr>
        <td style="text-align: center;">15</td>
        <td style="text-align: center;">[3][2]</td>
        <td style="text-align: center;">[2][0]</td>
        <td style="text-align: center;">[0][1]</td>
        <td style="text-align: center;">[1][3]</td>
    </tr>
    <tr>
        <td style="text-align: center;">16</td>
        <td style="text-align: center;">[3][3]</td>
        <td style="text-align: center;">[3][0]</td>
        <td style="text-align: center;">[0][0]</td>
        <td style="text-align: center;">[0][3]</td>
    </tr>
</table>

2次元 `list` の index 値の比較において、
180度回転した盤面の index 値は以下のように表すことができます。
・X 座標（1つ目の index 値）は、「N（マスの大きさ）-元の盤面の X 座標（1つ目の index 値）-1 」
・Y 座標（2つ目の index 値）は、「N（マスの大きさ）-元の盤面の Y 座標（2つ目の index 値）-1 」


同様に270度回転した盤面の index 値は以下のように表すことができます。
・X 座標（1つ目の index 値）は、「N（マスの大きさ）-元の盤面の Y 座標（2つ目の index 値）-1 」
・Y 座標（2つ目の index 値）は、「元の盤面の X 座標（1つ目の index 値））」と同じ


回転する部分を関数化してコード化すると、以下のようになります。
```Python
import pprint

# 盤面を回転させる関数
def rotate_board(N, M, input_list, output_list):

    # 時計回りに90度回転した場合
    if M == 1:
        for Y in range(N):
            for X in range(N):
                output_list[Y][N -X -1] = input_list[X][Y]

    # 時計回りに180度回転した場合
    elif M == 2:
        for Y in range(N):
            for X in range(N):
                output_list[N-X -1][N -Y -1] = input_list[X][Y]

    # 時計回りに270度回転した場合
    elif M == 3:
        for Y in range(N):
            for X in range(N):
              output_list[N -Y -1][X] = input_list[X][Y]

    # 処理結果を返す
    return(output_list)



# 盤面の大きさ（N × N マス）
N = 4

# 元の盤面
example_list = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]

# 結果保存用 list (N × N マスの "." 詰めで準備)
result_list = [["." for i in range(N)] for j in range(N)]

# 回転数（1回で時計回りに90度回転）
M = 2
# 盤面を回転させる関数を呼び出し
result_list = rotate_board(N, M, example_list, result_list)
# 時計回りに180度回転させた結果出力
print("時計回りに180度回転させた結果")
pprint.pprint(result_list, width = 20)
print("")

# 回転数（1回で時計回りに90度回転）
M = 3
# 盤面を回転させる関数を呼び出し
result_list = rotate_board(N, M, example_list, result_list)
# 結果出力
print("時計回りに270度回転させた結果")
pprint.pprint(result_list, width = 20)
```

出力結果は以下の通り。

```Python
時計回りに180度回転させた結果
[[16, 15, 14, 13],
 [12, 11, 10, 9],
 [8, 7, 6, 5],
 [4, 3, 2, 1]]

時計回りに270度回転させた結果
[[4, 8, 12, 16],
 [3, 7, 11, 15],
 [2, 6, 10, 14],
 [1, 5, 9, 13]]
```

<details><summary>180度回転させた盤面（クリックすると開きます）</summary>
<table>
    <tr>
        <td>16</td>
        <td>15</td>
        <td>14</td>
        <td>13</td>
    </tr>
    <tr>
        <td>12</td>
        <td>11</td>
        <td>10</td>
        <td>9</td>
    </tr>
    <tr>
        <td>8</td>
        <td>7</td>
        <td>6</td>
        <td>5</td>
    </tr>
    <tr>
        <td>4</td>
        <td>3</td>
        <td>2</td>
        <td>1</td>
    </tr>
</table>
</details>

<details><summary>270度回転させた盤面（クリックすると開きます）</summary>
<table>
    <tr>
        <td>4</td>
        <td>8</td>
        <td>12</td>
        <td>16</td>
    </tr>
    <tr>
        <td>3</td>
        <td>7</td>
        <td>11</td>
        <td>15</td>
    </tr>
    <tr>
        <td>2</td>
        <td>6</td>
        <td>10</td>
        <td>14</td>
    </tr>
    <tr>
        <td>1</td>
        <td>5</td>
        <td>9</td>
        <td>13</td>
    </tr>
</table>
</details>



時計回りに180度、270度回転させることもできました。



【2023/04/25 追記】
@shiracamus さんにコメントで`zip`関数と内包表記を使った美しいコードを教えて頂きました。
各行の意味についても、コメントで丁寧に教えて頂いたので、興味のある方コメント欄をご覧ください。


```Python
from pprint import pprint

def rotate0(board: list) -> list:
    return board

def rotate90(board: list) -> list:
    return [[*row][::-1] for row in zip(*board)]

def rotate180(board: list) -> list:
    return [row[::-1] for row in board[::-1]]

def rotate270(board: list) -> list:
    return [[*row] for row in zip(*board)][::-1]

def rotate(board: list, m: int) -> list:
    return [rotate0, rotate90, rotate180, rotate270][m % 4](board)

# 元の盤面
example: list = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]

print("時計回りに90度回転させた結果")
result: list = rotate(example, 1)
pprint(result, width=20)
print()

print("時計回りに180度回転させた結果")
result: list = rotate(example, 2)
pprint(result, width=20)
print()

print("時計回りに270度回転させた結果")
result: list = rotate(example, 3)
pprint(result, width=20)
```