#導入
友人(プログラミング経験者)「お前プログラミング始めたんだって?」
僕「うんそだよー」
友人「じゃあLoto6の数字を決めてくれるプログラミング作ってみてよ」
僕「余裕でしょ」
#始めに
ロト6は、1~43の数字の中から異なる6個の数字を選ぶ数字選択式宝くじです。
タイトルにもあるように僕はプログラミング初心者なので、超簡単にJavaでロト6の数字を選んでくれるコードを書こう!の記事です。
当然ながら過去当選番号等をスクレイピングして~なんてことはしません。というかスクレイピングってなに?
奮闘記のような形になってますので、初心者の頃を思い出して生暖かい目で見て頂ければと思います。
##案1(ゴリ押し)
早速だけどコードを書いていく。
僕「えーと、まずは6個の数字を格納する配列を作って・・・・・・」
僕「当然、1~43の数字をランダムで選ぶんだからRandomクラスは必須だよね~」
int[] numbers = new int[6];
for (int i = 0; i < numbers.length; i++) {
Random random = new Random();
numbers[i] = random.nextInt(43)+1;
}
僕「あれ、これで完成したんじゃ? プログラミングって簡単だな」
僕「実行、っと」
39
18
7
18
34
11
僕「あ・・・そっかあ・・・・・・」
当たり前だが、これでは数字が被ってしまう。上記にもあるが、ロト6は異なる6つ数字が選ばれるので、さすがにこれで完成とは言えない。
僕「じゃあ被った場合はもう一度選びなおしてもらうようにしないといけないな~どうしよう」
僕「ゴリ押すか」
do {
for (int i = 0; i < numbers.length; i++) {
Random random = new Random();
numbers[i] = random.nextInt(43)+1;
}
} while (numbers[0] == numbers[1] || numbers[0] == numbers[2] || numbers[0] == numbers[3] ||
numbers[0] == numbers[4] || numbers[0] == numbers[5] || numbers[1] == numbers[2] ||
numbers[1] == numbers[3] || numbers[1] == numbers[4] || numbers[1] == numbers[5] ||
numbers[2] == numbers[3] || numbers[2] == numbers[4] || numbers[2] == numbers[5] ||
numbers[3] == numbers[4] || numbers[3] == numbers[5] || numbers[4] == numbers[5]);
完成。
求めていたものはできた。数字は絶対に被らない。
僕「見て見て~できたよ~」
友人「お、割かし早かったな。どれどれ・・・・・・?」
友人「・・・・・・」
友人「お前・・・・・・」
僕「え、俺また何かやっちゃいました?」
友人「ば! か! や! ろ! う!」
友人「プログラミングってのはなぁ!動けばいいってもんじゃないんだよ!~~(説教)~~」
僕「」
##案2(メソッド・汎用化)
案1はボツになってしまった。
僕「なんかよく分からないけど怒られちゃったなあ」
僕「でも確かに書くとき面倒くさかったし、僕が思い描くプログラミングって感じじゃないな~」
僕「まずは流れを整理しよう。やりたいことはさっき書いたように配列の中の数字が被っているかどうかのチェック。被っていた場合は片方の数字をチェンジ。そしてまた最初からチェックのし直しをする」
僕「そうか。配列の0番目~4番目の数字を他の数字と被ってないかチェックするメソッドを作ればいいのか!?」
僕「とりあえず乱数を取得するメソッドを作成して、配列に入れる・・・っと」
int[] numbers = new int[6];
for (int i = 0; i < numbers.length; i++) {
numbers[i] = getNumbers();
}
private static int getNumber() {
Random random = new Random();
return random.nextInt(43)+1;
}
僕「そんでもってcheckメソッドを作ろう」
private static void checkNumber0(int numbers[]) {
for(int i = 1;i < numbers.length;i++) {
if(numbers[0] == numbers[i]) {
numbers[i] = getNumber();
checkNumber0(numbers);
}
}
checkNumber1(numbers);
}
private static void checkNumber1(int numbers[]) {
for(int i = 2;i < numbers.length;i++) {
if(numbers[1] == numbers[i]) {
numbers[i] = getNumber();
checkNumber0(numbers);
}
}
checkNumber2(numbers);
}
private static void checkNumber2(int numbers[]) {
for(int i = 3;i < numbers.length;i++) {
if(numbers[2] == numbers[i]) {
numbers[i] = getNumber();
checkNumber0(numbers);
}
}
checkNumber3(numbers);
}
private static void checkNumber3(int numbers[]) {
for(int i = 4;i < numbers.length;i++) {
if(numbers[3] == numbers[i]) {
numbers[i] = getNumber();
checkNumber0(numbers);
}
}
checkNumber4(numbers);
}
private static void checkNumber4(int numbers[]) {
for(int i = 5;i < numbers.length;i++) {
if(numbers[4] == numbers[i]) {
numbers[i] = getNumber();
checkNumber0(numbers);
}
}
}
僕「できた!」
僕「けどこれ、さっきより長くなってない・・・? これ見せたらまた怒られそう・・・」
僕「checkNumber〇()の中身って似たようなプログラミングだし、一つに纏められないかな」
ここで冷静に考える。別々のメソッドの中には共通点が多い。数字が違うところも共通項が抜き出せそうだ。
- 共通項
- for文の中の変数iはチェックしたい配列[index]の一つ上の数字で初期化されている。
- [index]番目の中身をチェックしたら一つ上の[index]番目をチェックしに行く。
僕「これをプログラミングすればいけそう!」
private static void checkNumbers(int index, int[] numbers) {
for (int i = index + 1; i < numbers.length; i++) {
if (numbers[index] == numbers[i]) {
numbers[i] = getNumbers();
checkNumbers(0, numbers);
}
}
index++;
if (index < numbers.length - 1) {
checkNumbers(index, numbers);
}
}
完成。さっきよりも断然すっきりした。ドラクエのレベルアップの音が脳内で再生される。
僕「渾身の出来だし、さっそく友人に見せに行こう~」
・
・
・
友人「ふむ。さっきとコード量自体はあまり変わっていないかもしれないが、これでかなり汎用的になったな。これで仕様変更があっても楽になるぞ」
僕「ということはこれで合格!?」
友人「まあ初心者にしては、という枕詞が付くがな。それに合格は合格でも【及第点】というところだ」
僕「え~~これでも結構頑張ったのに。それとももっと簡単に書けるの?」
友人「ああ、これよりもっと簡潔にかける。それも頑張って考えてみてくれ」
僕「」
##案3(完成版)
案2はボツにはならなかったが、友人は及第点しかくれなかった。
ここまできたら友人もアッと驚くようなプログラムを作りたい。
僕「とは言ってもどうすればいいんだろう」
ここで流れを整理すると
- 配列を宣言する
- 配列の中身に乱数を代入する
- 配列の中身が他の中身と被ってないかチェックする
- 被っていた場合、片方の配列の中身を書き換える
- 【3,4】を繰り返す
僕「うーん。確かに少し無駄があるかも」
僕「【2】で配列の中に変数を代入するときにそれまで入れていた数字と被っていないかチェックすればもっと簡潔にできるかな??」
for(int i = 0;i < numbers.length;i++) {
numbers[i] = getNumber();
for(int j = 0 ; j < i ;j++) {
if(numbers[j] == numbers[i]) {
numbers[i] = getNumber();
}
}
}
完成、、、ではない。当然ながら2回目の
numbers[i]=getNumber();
で、また数字が被ってしまう可能性があるからだ。
僕「うーん。案2みたいにこれをメソッド化してif(true)なら一からやり直すようにすればいけそうだけど・・・」
僕「一から・・・・・・? ! いや違う、一減らせばいいだけだ!!
for(int i = 0;i < numbers.length;i++) {
numbers[i] = getNumber();
for(int j = 0 ; j < i ;j++) {
if(numbers[j] == numbers[i]) {
i--;
break;
}
}
}
僕「デクリメント・・・! そういえばこういうのもあったなあ」
僕「とにかく、これで最終完成といっていいかな。我ながら無駄なく綺麗なコードが書けたぞ!」
public class Loto6{
public static void main(String[] args) {
int[] numbers = new int[6];
for(int i = 0;i < numbers.length;i++) {
numbers[i] = getNumber();
for(int j = 0 ; j < i ;j++) {
if(numbers[j] == numbers[i]) {
i--;
break;
}
}
}
for (int i : numbers) {
System.out.println(i);
}
}
private static int getNumber() {
Random random = new Random();
return random.nextInt(43)+1;
}
}
友人「お!かなりいいコードが書けたな」
僕「えへへ」
友人「どうだ? こういった考えるプロセスだったり、自分で考えたコードがきちんと動いたときの喜びはでかいだろう」
僕「うん! プログラミングって楽しいって思いながらできたよ」
友人「それはよかった。これからも頑張ってくれよ」
僕「もちろん。ところで友人だったらどういうプログラムを書くの?」
友人「俺か? 俺ならそうだな・・・」
public class Loto {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<Integer>();
for(int i = 1;i <= 43;i++) {
numbers.add(i);
}
Collections.shuffle(numbers);
for(int i = 0;i < 6;i++) {
System.out.println(numbers.get(i));
}
}
}
友人「ま、ListクラスとCollectionsクラスを使ってパパっと出すかな~」
僕「あ ほ く さ」
#結論
プログラミング楽しい!