2009年01月25日

ナノピコ教室:2次元配列の回転

  
問題
9行9列の2次元配列aを左へ90度、180度, 270度回転したものを配列b,c,dとする。
配列e,f,g,hは、aを次のような軸の周りで、180度回転したものとする。
e: a(1,1) と a(9,9)を結ぶ線
f: a(1,9) と a(9,1)を結ぶ線
g: a(1,5) と a(9,5)を結ぶ線
h: a(5,1) と a(5,9)を結ぶ線
配列aをもとにして、b,c,d,e,f,g,hを適当な順序で書き出すプログラムを書け。
ただし、配列の要素を入れ替える時に値を一時的にしまっておく場所として使えるのは、1変数だけとする。
ーーーーーーー

1変数だけしか使えないという制約から考えると、
90度回転させる処理よりも、e,f,g,hを求める反転処理のほうが簡単そうです。
そこで、a -> eを求める処理(これを DiagRevolveとする)と、a -> g を求める処理(これを HorRevolveとする)を組み合わせることで、bからhまでの配列を求める方法を採用しました。

a.DiagRevolve

という記述を、「配列 aにDiagRevolve処理をする」と読むと、

a.DiagRevolve.HorRevolve

で、a を左に270度回転した配列bとなります。これを繰り返し、

a.DiagRevolve.HorRevolve.DiagRevolve.HorRevolve...

と DiagRevolveとHorRevolveを交互に変換処理を行うと、

a,e,b,h,c,f,d,g という順番で配列を求めることができます。

これをC#のコードに書いたのが次のコードです。「書き出せ」というプログラムなので、変換処理の最後に、配列の内容を書き出す処理を挟み込んであります。
C#3.0の拡張メソッドで書いてみました。

普段2次元配列とか使ったことがないので、縦軸をx軸とするのか、Y軸とするのか、どちらが普通なのかわかりません。
『ナノピコ教室』の解答編を見ると、縦軸をX軸としているようですが、僕は横軸をx軸としたので、解答と微妙に違っていましたが、考え方は全く同じでした。

 class Program {
static void Main(string[] args) {
// この初期化はいつもどちらがx軸とy軸がで混乱する....
int[,] array = {
{ 11,21,31,41,51,61,71,81,91 },
{ 12,22,32,42,52,62,72,82,92 },
{ 13,23,33,43,53,63,73,83,93 },
{ 14,24,34,44,54,64,74,84,94 },
{ 15,25,35,45,55,65,75,85,95 },
{ 16,26,36,46,56,66,76,86,96 },
{ 17,27,37,47,57,67,77,87,97 },
{ 18,28,38,48,58,68,78,88,98 },
{ 19,29,39,49,59,69,79,89,99 },
};
Console.WriteLine(array[1, 8]);
Execute(array);

}

static void Execute(int[,] array) {
array.Print();
array.HorRevolve().DiagRevolve().HorRevolve().DiagRevolve()
.HorRevolve().DiagRevolve().HorRevolve();
}
}

static class ArrayExtended {
static int temp;
public static int[,] HorRevolve(this int[,] array) {
int yLeng = array.GetLength(1);
for (int y = 0; y < yLeng / 2; y++) {
for (int x = 0; x < array.GetLength(0); x++) {
temp = array[x, y];
array[x, y] = array[x, yLeng - y - 1];
array[x, yLeng - y - 1] = temp;
}
}
array.Print();
return array;
}

public static int[,] DiagRevolve(this int[,] array) {
for (int y = 1; y < array.GetLength(1); y++) {
for (int x = 0; x < y; x++) {
temp = array[x, y];
array[x, y] = array[y, x];
array[y, x] = temp;
}
}
array.Print();
return array;
}

public static void Print(this int[,] array) {
for (int y = 0; y < array.GetLength(1); y++) {
for (int x = 0; x < array.GetLength(0); x++) {
Console.Write("{0,2} ", array[x, y]);
}
Console.WriteLine();
}
Console.WriteLine();
}
}




※当記事に掲載したコードは、『ナノピコ教室・プログラミング問題集』(駒木悠二+有澤誠 編 共立出版株式会社)に掲載されている問題をGushwellがC#で解いたものです。


追記
改めてコードを眺めてみると、やはり、for文で y変数が外側に来るのはやはり不自然かなと思いました。A(x,y)という配列を考えた場合、x軸が縦方向に下に向かって伸びて行くと考えたほうが、このような問題の場合は自然なのかな。
これって常識ですか? ここ十年以上まともに2次元配列を使ったコードを書いたことがないものですから...



 

この記事へのトラックバックURL