陽だまりの中で

~香川フリーランスのぼやき~

HelloWorldからのC#入門!!重複しない乱数と妹の出産!

f:id:hidamarinonakade:20150307215525j:plain

はじめに

こんにちわかなたです。
今日は朝一に、妹から出産の連絡がありました。
残念ながら日をまたいでの出産だったようで私の予想とは5時間ほどズレてしまいましたが無事に生まれてきてよかったと思います♪
ひなたが今日も仕事だったため、この記事を書き終わったら出産祝いを持っていく予定です。
妹の出産でも自分のことのようにうれしいものですね♪
私の母もなんだかんだ言いつつもうれしい様子でした。
妹から送られてきた写メがこちら
f:id:hidamarinonakade:20150307180513j:plain
娘にもこんな時期があったなぁ・・・(笑)


重複しない乱数

話は変わりまして、C#のお話をしたいと思います。
以前は乱数を用いた表示を行いましたね。
www.hinakana.net
この中で最後にいつものように課題をだしていました。

課題:1~10までの数字を重複しないようにランダムに表示

これについて解説していきたいと思います。

発想の転換

乱数を重複させないためにはどうしたら良いでしょうか?

従来の1~10までの乱数について考えてみましょう。

Random ransu = new Random();
int random = ransu.Next(1,11);
これで1~10までの乱数がランダムで発生しますね。
しかし、ここで問題になってくるのは数字を呼び出すたびにランダムで数字を呼び出すため数字が重複するということです。

1~10までの数字を準備してみましょう。

まずは数字を入れる箱を10個用意します。

int [] number = new int [10];

整数型の「number」という配列を用意しました。

これに1~10を順番に格納していきます。
直接打ち込んでいく方法もありますが、今後大きな数字を格納することが出てきた時のためにfor文を用いた方法を紹介しておきます。

for (int i = 0; i < number.Length; i++ )
{
number[i] = i + 1;
}

以前説明したと思いますが、再度ここで軽く説明を入れておきます。
まず整数型の「i」に0を挿入して、「{ }」の中のプログラムを一回実行するごとに「i」に1を足していっています。
そして、注目してもらいたいのが「number.Length」です。
「number」の配列の箱の数(Length)を読み込んでいます。
なので、わざわざ10などと指定してやらなくても勝手に読み込んでいるので「i」がその数に追いついたら繰り返し動作を停止します。
この文を使うメリットは、「急遽number配列を増やすことになった・・・」
そういった時にわざわざプログラムを色々いじりなおす必要がなくなるということです。
次にfor文の中を見てみましょう。
「number[i]」の配列に「i+1」の数字を挿入しています。
つまり「i」が0の時は「number[0]」に「1」を挿入しているということです。
このfor文全体でnumber配列の中に1~10の数字を挿入することができました。

重複しないということ

まず、実際に水、牛乳、オレンジジュースなどを入れたコップを連想してください。
これまでに組んだプログラミングがこれに近い状態です。
あとはこれをシャッフルするのです。
もちろんコップの位置を変えたりはできません
コップ=箱、配列と同じです。
あなたでしたらどうやって中身を入れ替えますか?
勘の良いあなたならもう気付いたはずです。
それでは実際に形にしてみましょう。

中身だけシャッフルしてみよう

中身だけシャッフルするには必要なものがあります。
そうです、一時的に避難させる別のコップ(箱)がいります。
まずはそれを用意してあげましょう。
今回は整数を取り扱っているので、「int」型の、仮という意味の英語を略して「temp」とつけておきましょう。

int temp = 0;

これでコップの準備はオーケーです。

次にどのように入れ替えるかイメージしてみてください。
1番目のコップには牛乳が、2番目のコップには水が入っています。
これを入れ替える場合、どうしますか?
まずは1番目の牛乳を仮のコップに避難させて、そこに2番目のコップの水を流し込みます。
そして空になった2番目のコップに仮のコップの牛乳を入れれば入れ替えることができますね?
それと同様のことを配列でも行います。
ただし、1~10の数字を順番に入れ替えただけでは、「2,3,4,5,6,7,8,9,10、1」という1つずれただけの残念な並びになります。
そこで最初に用意した乱数を使用して箱をランダムに抽出します。
これを10回それぞれの箱に対して行ってやることでまんべんなくすべてがシャッフルされた状態となります。

for(int i = 0; i < number.Length; i++)
{
temp = number[i];
number[i] = number[random];
number[random] = temp;
}

これでシャッフルのプログラムの完成です。
重複のしない1~10の配列ができました。

これを表示させるプログラムはこうです。

for(int i = 0; i < number.Length; i++)
{
Console.Write(number[i] + " ");
}

今回は見やすさを考えてスペースを入れています。

いざ実行!

Random ransu = new Random();
int random = ransu.Next(1,11);
int [] number = new int [10];
for(int i = 0; i < number.Length; i++)
{
number[i] = i + 1;
}
for(int i = 0; i < number.Length; i++)
{
int temp = number[i];
number[i] = number[random];
number[random] = temp;
}
for(int i = 0; i < number.Length; i++)
{
Console.Write(number[i] + " ");
}

すべて合わせたプログラムがこれです。
実行してみましょう!
実行するとこうなります。
f:id:hidamarinonakade:20150307212725p:plain
どうですか?
これで1~10の重複しない乱数の完成です。
これをうまく使えばトランプカードが簡単に作れます。

次回までにやってもらいたいこと

例のごとく課題です。
今回は今まで学んだことすべてを活用して、トランプカードをJOKER含めて54枚表示させてください。
ランダムに表示させられればなおよしです。

課題:トランプ54枚をランダム表示

おわりに

どうだったでしょうか?
途中急ぎ足になってしまいましたが、要点はゆっくりお話ししたつもりです。

そうそう、勘の良い方ならお気づきになったかもしれませんが、for文が出るたびに私はiを整数型に宣言してきました。
本来であれば最初に整数型に宣言したものは再度宣言するとエラーが出るのに・・・です。
ではなぜ私はfor文の出る都度宣言したのでしょうか。
答えは実にシンプルでfor文の中で宣言されたものはfor文の中でしか認識されないためです。
要は、外で宣言していればfor文の中でも使えるけれども、for文の中で宣言したものは外には持ち出せないということです。
for文の中では必要だけど、外で使うことは無い・・・といった場合などにプログラムがごちゃごちゃしないようにこうやって切り分けて使用します。
他にもクラスの中で宣言したものはその中では使えるけどメソッドの中で宣言したものはクラスでは使えない(例外有)などもあります。
それは追々使用しながら覚えていってください。
これからも少しずつ私と一緒に成長していきましょう♪

今日もお付き合いありがとうございました!

追伸

記事を書いている途中でひなたにうながされて、妹の出産祝いに行ってきました。
かなり小さくて感動しました♪
やっぱり生まれたては怖くて抱けません(笑)
特に人の子供となるとなおさらです^^;
でもうちの娘はよしよししていました(笑)
まだ一才なのに最近自我が芽生えてかわいがったり、こわがったりいろんな表情を見せてくれます♪
一年前は娘もこんな赤ちゃんだったんだなと思うと感慨深かったのでした。
それと同時に私のこの体も早く蹴りをつけなければならないなと、家族にも申し訳ないなと思ったのでした。