前回は3行3列のビンゴゲームを作成したが、それを拡張して任意の大きさで遊べるようにしてみよう!
実行例
今回は幅と最低ビンゴライン数を入力するとその当たりが何回目に出たかをシミュレーションするアプリを作成する。
1
幅>3 最低Bingoライン数>8 444 444 444 30281251回
上の結果は3*3のビンゴですべてが同じ数字になるのに今回30281251回かかったことを表す。
2
幅>5 最低Bingoライン数>2 55782 46512 22222 17552 27312 112383回
上記の例は5*5のビンゴにおいて2列以上ビンゴが出るまでに要した回数だ。
作成
メソッド
まずはいつものように処理に必要そうなメソッドを作成していく
static int[][] makeCard(int width){
Random rand=new Random();
int[][] card=new int[width][width];
for(int i=0;i<width;i++){
for(int j=0;j<width;j++){
card[i][j]=rand.nextInt(9)+1;
}
}
return card;
}
指定された幅のビンゴカードを作成するメソッドだ。2次元配列を作成しその中に1~9の値をランダムに入れている。
static void showCard(int[][] card){
for(int[] line:card){
for(int n:line){
System.out.print(n);
}
System.out.println();
}
}
引数に2次元配列を受け取りそれを1行ずつ出力する処理だ。今回は拡張for文を使用している。特に問題となるところはないだろう。
static boolean isSame(int[] line){
int first=line[0];
for(int i=1;i<line.length;i++){
if(first != line[i]){
return false;
}
}
return true;
}
引数に1次元配列を受け取り、その要素がすべて同じ場合にはtrueをそうでない場合はfalseを返却するメソッドだ。最初の一つと違うのを見つけた段階でfalseを返却している。もしfalseにならなかったということは全部同じということになる。
static int countLine(int[][] temp){
int count=0;
for(int[] line:temp){
if(isSame(line)){count++;}
}
return count;
}
2次元配列を引数に受け取り、その行がすべて同じ場合だった場合にcountを1増やしている。
例)
{ {2,2,2}, {3,1,5}, {4,4,4} }
上記の2次元配列の場合は2を返す。
static int horizontalMatchLine(int[][] card){
return countLine(card);
}
横のラインの判定は簡単だ。最初に作った2次元配列をそのままcountLineにわたしてあげれば何列揃ったのかがわかる。
static int verticalMatchLine(int[][] card){
int[][] lines=new int[card.length][card.length];
for(int i=0;i<card.length;i++){
for(int j=0;j<card.length;j++){
lines[i][j]=card[j][i];
}
}
return countLine(lines);
}
もともとのビンゴカード配列を引数に受け取り、それを元に縦の組み合わせを取得している。
元となる配列 { {2,2,2}, {3,1,5}, {4,4,4} } 新たに作成される配列 { {2,3,4}, {2,1,4}, {2,5,4} }
コードのなかにあるiとjを入れ替える処理はこういったときの常套手段だ。
処理の流れを目で追って上の図になることを確認してもらいたい。
この配列ができればあとはcountLineに渡せば縦のラインが何列そろっているかがわかる。
static int crossMatchLine(int[][] card){
int[][] lines=new int[2][card.length];
for(int i=0;i<lines.length;i++){
for(int j=0;j<card.length;j++){
if(i==0){
lines[i][j]=card[j][j];
}else{
lines[i][j]=card[j][card.length-1-j];
}
}
}
return countLine(lines);
}
最後に斜めのラインを調べるメソッドを作成する。
斜めのラインは2つあるので要素数2の2次元配列を作成する。
最初の要素は{0,0}{1,1}{2,2}といった要素を取得していけばよいので[j][j]となる。
次の要素は{0,2},{1,1},{2,0}といった要素なので[j][card.length-1-j]となる。card.lengthが3と仮定して組み合わせが取得できることを確認してもらいたい。
これで斜めの2つを要素にもつ2次元配列ができたのであとはcountLineに渡すだけだ。これで斜めのラインが何列そろったのかがわかる。
メインメソッド
上記で必要な処理が全て揃った。後はメインメソッドで実行例のようになるようにしていこう。
全ソースコード
import java.util.*;
public class BingoApp{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
System.out.print("幅>");
int width=sc.nextInt();
System.out.print("最低Bingoライン数>");
int matchLine=sc.nextInt();
long total=0;
while(true){
total++;
int[][] card=makeCard(width);
int count=0;
count+=horizontalMatchLine(card);
count+=verticalMatchLine(card);
count+=crossMatchLine(card);
if(count >= matchLine){
showCard(card);
System.out.println(total+"回");
break;
}
}
}
static int[][] makeCard(int width){
Random rand=new Random();
int[][] card=new int[width][width];
for(int i=0;i<width;i++){
for(int j=0;j<width;j++){
card[i][j]=rand.nextInt(9)+1;
}
}
return card;
}
static void showCard(int[][] card){
for(int[] line:card){
for(int n:line){
System.out.print(n);
}
System.out.println();
}
}
static boolean isSame(int[] line){
int first=line[0];
for(int i=1;i<line.length;i++){
if(first != line[i]){
return false;
}
}
return true;
}
static int horizontalMatchLine(int[][] card){
return countLine(card);
}
static int verticalMatchLine(int[][] card){
int[][] lines=new int[card.length][card.length];
for(int i=0;i<card.length;i++){
for(int j=0;j<card.length;j++){
lines[i][j]=card[j][i];
}
}
return countLine(lines);
}
static int crossMatchLine(int[][] card){
int[][] lines=new int[2][card.length];
for(int i=0;i<lines.length;i++){
for(int j=0;j<card.length;j++){
if(i==0){
lines[i][j]=card[j][j];
}else{
lines[i][j]=card[j][card.length-1-j];
}
}
}
return countLine(lines);
}
static int countLine(int[][] temp){
int count=0;
for(int[] line:temp){
if(isSame(line)){count++;}
}
return count;
}
}
以上で終了だ。実行を行う際には10*10で5列とかあまり無理な組み合わせは入れないほうがいい。生きている間に計算が完了しない可能性がある。
コメント