0
0

More than 1 year has passed since last update.

めちゃくちゃ簡易のビンゴゲームを作る #3

Posted at

はじめに

前回までの記事で見た目的にはビンゴゲームになってきたので、次の段階として、ビンゴゲームのリーチやビンゴの判定機能を作りたい。検索すれば答えがヒットするんだろうけど、自分で考え抜きたい意地が発現してしまったので、記事を書きながら頭を整理しつつ、作っていきたいと思う。

ふわっと作戦を考える

今ふわっと考えていることとしては、現状はカードに縦5マス並べたものを5列横に並べているのだが、これを二次元配列を使っての配置に変更すること。これで、縦横の判定はしやすくなるだろうと予想している。斜めに関しては、2パターンしかないし、個別に書き連ねるのが良いのかな?

まず二次元配列での配置で現状までの機能をつくる

コード

public class BingoGame extends JFrame implements ActionListener{
	JButton mkCardBtn;
	JPanel BingoCardPanel;
	JPanel p1;
	JPanel p2;
	JPanel p3;
	JPanel p4;
	JPanel p5;

	JLabel [] [] numLabel = new JLabel [5] [5];
	LineBorder border = new LineBorder(Color.LIGHT_GRAY,2,true);
	GridLayout gl = new GridLayout(5,1);
	Container c;
	JButton startBtn;
	Random random = new Random();
	JFrame gameFrame;
	JTextArea numLog;
	JButton spinBtn;
	int spinNum;
	ArrayList<Integer> numList1 = new ArrayList<Integer>();
	ArrayList<Integer> numList2 = new ArrayList<Integer>();
	ArrayList<Integer> numList3 = new ArrayList<Integer>();
	ArrayList<Integer> numList4 = new ArrayList<Integer>();
	ArrayList<Integer> numList5 = new ArrayList<Integer>();
	ArrayList<Integer> spinNumbersList = new ArrayList<Integer>();
	
	
	String reach = "リーチ";
	String bingoStr = "ビンゴ!";
	public static void main(String[] args) {
		BingoGame frame = new BingoGame();
		frame.setVisible(true);
	}
	
	public BingoGame() {
		setBounds(10,10,600,400);
		setLocationRelativeTo(null);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		mkCardBtn = new JButton("ビンゴカード作成");
		mkCardBtn.addActionListener(this);
		
		BingoCardPanel = new JPanel();
		BingoCardPanel.setLayout(new GridLayout(1,5));
		
		mkCard(p1,0,0,1);
		mkCard(p2,0,1,6);
		mkCard(p3,0,2,11);
		mkCard(p4,0,3,16);
		mkCard(p5,0,4,21);
		
		JPanel p1_1 = new JPanel();
		p1_1.setLayout(new GridLayout(1,2));
		p1_1.add(mkCardBtn);
		p1_1.add(BingoCardPanel);
		
		startBtn  =new JButton("ゲーム開始");
		startBtn.addActionListener(this);
		
		c = getContentPane();
		c.add(p1_1, BorderLayout.CENTER);
		c.add(startBtn, BorderLayout.SOUTH); 
	}
	
	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == mkCardBtn) {
			numList1.clear();
			numList2.clear();
			numList3.clear();
			numList4.clear();
			numList5.clear();
			mkRandomNum(numList1,0);
		}else if(e.getSource() == startBtn) {
			insertGameFrame();
		}
		else if(e.getSource() == spinBtn) {

			do {
				spinNum = random.nextInt(75) + 1;
			}while(spinNumbersList.indexOf(spinNum) != -1);

			spinNumbersList.add(spinNum);
			String spinNumber = Integer.toString(spinNum);
			numLog.append(spinNumber + ",");
		}
		
		punchHole();
	}
	
	public void mkRandomNum(ArrayList<Integer> al, int i) {
		int x = 0;
		int y = 0;
		
		for(y = 0; y < 5; y++) {
			
			switch(y) {
			case 0:
				al = numList1;
				i = 1;
				break;
			case 1:
				al = numList2;
				i = 16;
				break;
				
			case 2:
				al = numList3;
				i = 31;
				break;
			case 3:
				al = numList4;
				i = 46;
				break;
			case 4:
				al = numList5;
				i = 61;
				break;
			}
			
			while(al.size() < 5) {
				int num = random.nextInt(15) + i;
				if(al.indexOf(num) == -1) {
					al.add(num);
				}
			}
			
			for(x = 0; x < 5; x++) {
				String number = Integer.toString(al.get(x));
				numLabel[x][y].setText(number);
			}
		}
	}
	
	public void mkCard(JPanel p, int x, int y, int i) {
		p = new JPanel();
		p.setLayout(gl);
		
		for(x = 0; x < 5; x++) {
			String testNum = Integer.toString(x + i);
			numLabel[x][y] = new JLabel(testNum);
			numLabel[x][y].setBorder(border);
			numLabel[x][y].setOpaque(true);
			p.add(numLabel[x][y]);
		}
		BingoCardPanel.add(p);
	}
	
	public void insertGameFrame() {
		gameFrame = new JFrame();
		gameFrame.setBounds(100, 100, 600, 400);
		gameFrame.setLocationRelativeTo(null);
		gameFrame.setDefaultCloseOperation(EXIT_ON_CLOSE);
		
		numLog = new JTextArea(5,10);
		LineBorder black = new LineBorder(Color.black,2,true);
		numLog.setBorder(black);
		numLog.setEditable(false);
		numLog.setLineWrap(true);
		JPanel panel1 = new JPanel();
		GridLayout gridlayout = new GridLayout(1,2);
		gridlayout.setHgap(5);
		gridlayout.setVgap(5);
		panel1.setLayout(gridlayout);
		panel1.add(BingoCardPanel);
		panel1.add(numLog);
		spinBtn = new JButton("Spin");
		spinBtn.addActionListener(this);
		
		Container c2 = gameFrame.getContentPane();
		c2.add(panel1,BorderLayout.CENTER);
		c2.add(spinBtn, BorderLayout.SOUTH);
		
		gameFrame.setVisible(true);
	}
	
	public void punchHole() { //カードに穴あける。
		if(spinNum <= 15) {
			changeBackgroundColor(numList1, 0);
		}else if(spinNum <= 30) {
			changeBackgroundColor(numList2, 1);
		}else if(spinNum <= 45) {
			changeBackgroundColor(numList3, 2);
		}else if(spinNum <= 60) {
			changeBackgroundColor(numList4, 3);
		}else if(spinNum <= 75) {
			changeBackgroundColor(numList5, 4);
		}
	}
	
	public void changeBackgroundColor(ArrayList<Integer> al, int y) { //背景色を変える
		int x = al.indexOf(spinNum);
		if(x != -1) {
			numLabel[x][y].setBackground(Color.red);
		}
	}
	

}

ちょっと説明

変えたのは

  • mkCard()
  • mkRandomNum()
  • punchHole()
  • changeBackgroundColor()

の4つ。引数は書くのめんどくさかったので、省略。

まず1つ目のmkCard()について。
今までは5つのJLabel[]を使っていたところを、1つのJLabel[][]と二次元配列に変更した。なのでxとyを使ってやってみた。
二重にfor文を書いてxとyの値を変化させれば仮引数が要らなくなるかもしれない。。と後から思った。

次に2つ目のmkRandomNum()について。
これは大きいfor文でyの値を変化させつつ、中の小さいfor文でxとかの値を変えている。最初はswitch文でarraylistを切り替えるのではなく、配列にarrayListを入れようとしていたのだが、Eclipseに総称型ArrayListの配列は作れないと怒られてしまったので、switch文でyの値に応じてarrayListを切り替えられるようにした。

3つ目のpunchHole()は、changeBackgroundColor()に渡す引数を変更しただけ。

最後に4つ目のchangeBackgroundColor()について
これも最初のmkCard()と同じく、JLabel[]だったところをJLabel[][]に変えた。
透明非透明を設定するsetOpaque()はmkCard()内でtrueに設定している。

それともう一つだけ。spinBtnの処理を書いてるところのdo~while文の使い方を間違えていたので修正しました!これで本当に数字被りが無くなったはず。

リーチ&ビンゴ判定機能をつくる

いよいよ本命の機能作成にとりかかる。
追加したのはこちらのコード。

public void judge(int x, int y) {
		//たてスキャン
		
		int a = x;
		int b = y;
		String str = numLabel[a][b].getText();
		int jnum = Integer.parseInt(str);
		int c_count = 0;
		int r_count = 0;
		
		for(int i=0;i<5;i++) {
			//numLabelに載ってる数字とspinNumbersListの中身を比べる。
			str = numLabel[a][i].getText();
			jnum = Integer.parseInt(str);
			if(spinNumbersList.indexOf(jnum) != -1) {
				c_count++;
			}
			
		}
		
		if(c_count == 4) {
			numLog.append(reach);
		}else if(c_count == 5) {
			numLog.append(bingoStr);
		}
		
		
		//横スキャン
		for(int i=0;i<5;i++) {
			str = numLabel[i][b].getText();
			jnum = Integer.parseInt(str);
			if(spinNumbersList.indexOf(jnum) != -1) {
				r_count++;
			}
		}
		
		if(r_count == 4) {
			numLog.append(reach);
		}else if(r_count == 5) {
			numLog.append(bingoStr);
		}
		
	}
	
	public void crossJudge() {
		String str;
		int jnum;
		int count1 = 0;
		int count2 = 0;
		for(int i=0;i<5;i++) {//左上から右下
			str = numLabel[i][i].getText();
			jnum = Integer.parseInt(str);
			
			if(spinNumbersList.indexOf(jnum) != -1) {
				count1++;
			}
		}
		
		if(count1 == 4) {
			numLog.append(reach);
		}else if(count1 == 5) {
			numLog.append(bingoStr);
		}
		
		for(int i=0;i<5;i++) {//右上から左下
			int j = 4-i;
			
			str = numLabel[i][j].getText();
			jnum = Integer.parseInt(str);
			if(spinNumbersList.indexOf(jnum) != -1) {
				count2++;
			}
			
			if(count2 == 4) {
				numLog.append(reach);
			}else if(count2 == 5) {
				numLog.append(bingoStr);
			}
		}
	}

このふたつのメソッドを背景色変えるchangeBackgroundColor()の中に追加した。
縦横スキャンに関しては、穴開けたマスの座標を使って、x座標だけ増減させるなどして、縦横の列をスキャンして、spinNumbersListに入っている数字と各マスの数字が一致しているか調べてる。4つ一致でリーチ表示、5つ一致でビンゴ表示をnumLogに出している。
ただ、この方法だと、同じリーチやビンゴを複数回表示することがあること、ダブルリーチやダブルビンゴなどには対応していないことが問題点。
だけど、自分の力だけだとこれが限界そうです。

斜め列の判定について
左上から右下への斜めは、座標がxとyで等しいので、
numLabel[i][i]でiを位置ずつ増やしスキャンした。
反対の、右上から左下への斜めは、yの値を一次関数を使って表してみた。

実行結果

image.png

image.png

終わりに

完璧ではないけど、自分が当初作ろうとしていた昨日は作ることができた。良い達成感。
今後は自分のコードを改良したり、他の人のビンゴコードを見て勉強してみようと思う。自分はJavaで書いてるのに、オブジェクト指向の便利機能をほとんど使えてないから、ここも勉強。

0
0
2

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
0
0