1
0

More than 1 year has passed since last update.

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

Last updated at Posted at 2023-04-22

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

問題の内容

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

 
具体例で考えてみよう

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

1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16

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

13 9 5 1
14 10 6 2
15 11 7 3
16 12 8 4

2次元 list で表現してみよう

まず最初の盤面を2次元 list で1マスずつ表示すると以下のようになります。
見比べやすいように最初の盤面を再度載せておきますので、必要に応じて表示させてください。

最初の盤面(クリックすると開きます)
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
### 最初の盤面を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度回転させた盤面を再度載せておきますので、必要に応じて表示させてください。

90度回転させた盤面(クリックすると開きます)
13 9 5 1
14 10 6 2
15 11 7 3
16 12 8 4
### 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 値 を表にまとめると、
以下のようになります。

数字 2次元 list の index 値
最初の盤面 90度回転した盤面
1 [0][0] [0][3]
2 [0][1] [1][3]
3 [0][2] [2][3]
4 [0][3] [3][3]
5 [1][0] [0][2]
6 [1][1] [1][2]
7 [1][2] [2][2]
8 [1][3] [3][2]
9 [2][0] [0][1]
10 [2][1] [1][1]
11 [2][2] [2][1]
12 [2][3] [3][1]
13 [3][0] [0][0]
14 [3][1] [1][0]
15 [3][2] [2][0]
16 [3][3] [3][0]

 
盤面の回転をコード化してみよう

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

コード化してみると、以下のようになります。

# 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)

出力結果はこちら

時計回りに90度回転させた結果
[[13, 9, 5, 1],
 [14, 10, 6, 2],
 [15, 11, 7, 3],
 [16, 12, 8, 4]]
90度回転させた盤面(クリックすると開きます)
13 9 5 1
14 10 6 2
15 11 7 3
16 12 8 4

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

180度、270度回転させた場合も考えてみよう

時計回りに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

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

数字 2次元 list の index 値
最初の盤面 90度回転した盤面 180度回転した盤面 270度回転した盤面
1 [0][0] [0][3] [3][3] [3][0]
2 [0][1] [1][3] [3][2] [2][0]
3 [0][2] [2][3] [3][1] [1][0]
4 [0][3] [3][3] [3][0] [0][0]
5 [1][0] [0][2] [2][3] [3][1]
6 [1][1] [1][2] [2][2] [2][1]
7 [1][2] [2][2] [2][1] [1][1]
8 [1][3] [3][2] [2][0] [0][1]
9 [2][0] [0][1] [1][3] [3][2]
10 [2][1] [1][1] [1][2] [2][2]
11 [2][2] [2][1] [1][1] [1][2]
12 [2][3] [3][1] [1][0] [0][2]
13 [3][0] [0][0] [0][3] [3][3]
14 [3][1] [1][0] [0][2] [2][3]
15 [3][2] [2][0] [0][1] [1][3]
16 [3][3] [3][0] [0][0] [0][3]

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 値))」と同じ

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

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)

出力結果は以下の通り。

時計回りに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]]
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

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

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

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)
1
0
11

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0