情報学部 菅沼ホーム Java 目次 索引

8パズル

  1. ステップ1: ゲームの枠組み

      8パズルでは,3 × 3 のマス目に 1 ~ 8 の表示がある 8 つのコマが配置され,1 つのマス目にはコマが置かれていません.このとき,空白のマス目にコマを移動する操作を繰り返すことによって,初期状態から目標状態を,できるだけ少ないコマの移動によって達成するゲームです.例えば,下に示す左の状態を,コマの移動によって右の状態に持って行くことになります.
      基本的に,「ゲーム枠の作成」で説明した方法とほぼ同じ方法で作成します.ただし,パネルのサイズは変更しています.また,ゲームオーバーの画面は存在しません.以下,各クラスに対して,「ゲーム枠の作成」の場合との違いについて説明していきます.

    1. Game クラス

        「ゲーム枠の作成」における Game クラスと全く同じプログラムです( Game.java ).

      /*************************/
      /* 8パズル              */
      /*   coded by Y.Suganuma */
      /*************************/
      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;
      import main.*;
      
      public class Game {
      	public static void main (String[] args)
      	{
      		Win win = new Win("8パズル");
      	}
      }
      
      class Win extends JFrame
      {
      	/******************/
      	/* コンストラクタ */
      	/******************/
      	Win(String name)
      	{
      					// JFrameクラスのコンストラクタ(Windowのタイトルを引き渡す)
      		super(name);
      					// Windowの大きさ
      		setSize(230, 230);   // 40+20, 70+20
      					// MainPanel の大きさを決定
      		Dimension size = getSize();
      		size.width  -=60;
      		size.height -=90;
      					// ContentPain を取得し,設定
      		Container CP = getContentPane();   // ContentPane を取得
      		CP.setLayout(null);   // レイアウトマネージャを停止
      		CP.setBackground(new Color(220, 255, 220));   // 背景色
      					// MainPanel を追加し,設定
      		MainPanel pn = new MainPanel(size);   // MainPanel オブジェクトの生成
      		CP.add(pn);   // MainPanel オブジェクトを ContentPane に追加
      		pn.setSize(size.width, size.height);
      		pn.setLocation(10, 10);
      					// ウィンドウを表示
      		setVisible(true);
      					// イベントリスナ
      		addWindowListener(new WinEnd());
      	}
      
      	/******************************/
      	/* 上,左,下,右の余白の設定 */
      	/******************************/
      	public Insets getInsets()
      	{
      		return new Insets(50, 20, 20, 20);
      	}
      
      	/************/
      	/* 終了処理 */
      	/************/
      	class WinEnd extends WindowAdapter
      	{
      		public void windowClosing(WindowEvent e) {
      			System.exit(0);
      		}
      	}
      }
      				

    2. MainPanel クラス

        「ゲーム枠の作成」における MainPanel クラスとほぼ同じですが,ゲームオーバーの状態を無くしている部分だけが異なっています( MainPanel.java ).

      package main;
      
      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;
      import start.*;
      import game.*;
      import clear.*;
      
      public class MainPanel extends JPanel implements Runnable
      {
      	Dimension size;   // パネルの大きさ
      	boolean in_game = true;   // ゲーム実行中はtrue
      	public int state = 0;   // ゲーム状態(0:表紙,1:ゲーム,2:クリア,3:終了)
      	public int level = 1;   // ゲームレベル
      	int old_state = 0;   // 直前のゲーム状態
      	StartPanel sp;
      	GamePanel gp;
      	GameClearPanel gcp;
      	Thread td;
      			// コンストラクタ
      	public MainPanel(Dimension size1)
      	{
      		size = size1;
      					// グリッドレイアウト
      		setLayout(new GridLayout(1, 1, 0, 0));
      					// ゲームパネルの生成
      		sp = new StartPanel(size, this);   // スタート(タイトル)
      		add(sp);
      					// スレッドの生成
      		td = new Thread(this);
      		td.start();
      	}
      			// ゲームの状態を変更
      	public void run()
      	{
      		while (in_game) {
      			try {
      				td.sleep(100);   // 100 ms 毎の実施
      			}
      			catch (InterruptedException e) {}
      			if (state != old_state) {
      							// 前のパネルの削除
      				if (old_state == 0)
      					remove(sp);
      				else if (old_state == 1)
      					remove(gp);
      				else
      					remove(gcp);
      							// 新しいパネルの追加
      				if (state == 3)   // ゲーム終了
      					in_game = false;
      				else {
      					if (state == 0) {   // StartPanel
      						sp = new StartPanel(size, this);
      						add(sp);
      					}
      					else if (state == 1) {   // GamePanel
      						gp = new GamePanel(size, this);
      						add(gp);
      					}
      					else {   // GameClearPanel
      						gcp = new GameClearPanel(size, this);
      						add(gcp);
      					}
      					validate();
      					old_state = state;
      				}
      			}
      		}
      	}
      }
      				

    3. StartPanel クラス

        「ゲーム枠の作成」における StartPanel クラスでは,「 s 」キーを押すとゲームを開始するように設定していましたが,ここではマウスのダブルクリックによって開始するように変更してあります( 036 行目,077 行目~ 082 行目).当然のことながら,ゲームタイトル及び「遊び方」の内容を変更しています.また,画面の大きさが小さいので,表示内容や方法を多少変更しています( StartPanel.java ).

      001	package start;
      002	
      003	import java.awt.*;
      004	import java.awt.event.*;
      005	import javax.swing.*;
      006	import main.*;
      007	
      008	public class StartPanel extends JPanel implements ActionListener
      009	{
      010		boolean in_game = true;
      011		Dimension size;   // パネルの大きさ
      012		MainPanel mp;
      013		JButton bt;
      014				// コンストラクタ
      015		public StartPanel(Dimension size1, MainPanel mp1)
      016		{
      017			size = size1;
      018			mp   = mp1;
      019						// レイアウトマネージャの停止
      020			setLayout(null);
      021						// 背景色の設定
      022			setBackground(Color.white);
      023						// ボタンの配置
      024			Font f = new Font("SansSerif", Font.BOLD, 20);
      025			FontMetrics fm = getFontMetrics(f);
      026			String str = "遊び方";
      027			int w = fm.stringWidth(str) + 40;
      028			int h = fm.getHeight() + 10;
      029			bt = new JButton(str);
      030			bt.setFont(f);
      031			bt.addActionListener(this);
      032			bt.setSize(w, h);
      033			bt.setLocation(size.width/2-w/2, 5);
      034			add(bt);
      035						// マウスリスナの追加
      036			addMouseListener(new Mouse());
      037		}
      038				// 描画
      039		public void paintComponent(Graphics g)
      040		{
      041			super.paintComponent(g);   // 親クラスの描画
      042			FontMetrics fm;
      043			Font f;
      044			String str;
      045			int w, h;
      046	
      047			f   = new Font("SansSerif", Font.BOLD, 40);
      048			fm  = g.getFontMetrics(f);
      049			str = "8パズル";
      050			w   = fm.stringWidth(str);
      051			h   = fm.getHeight();
      052			g.setFont(f);
      053			g.drawString(str, size.width/2-w/2, size.height/2);
      054	
      055			f   = new Font("Serif", Font.PLAIN, 20);
      056			fm  = g.getFontMetrics(f);
      057			str = "ゲーム開始";
      058			w   = fm.stringWidth(str);
      059			h   = size.height - 2 * fm.getHeight();
      060			g.setFont(f);
      061			g.drawString(str, size.width/2-w/2, h);
      062			str = "ダブルクリック";
      063			w   = fm.stringWidth(str);
      064			h   = size.height - fm.getHeight();
      065			g.drawString(str, size.width/2-w/2, h);
      066		}
      067				// ボタンがクリックされたときの処理
      068		public void actionPerformed(ActionEvent e)
      069		{
      070			if (e.getSource() == bt) {
      071				Method db = new Method();
      072				db.setVisible(true);
      073				requestFocusInWindow();
      074			}
      075		}
      076				// ダブルクリックされたときの処理
      077		class Mouse extends MouseAdapter {
      078			public void mouseClicked(MouseEvent e) {
      079				if (e.getClickCount() == 2)
      080					mp.state = 1;
      081			}
      082		}
      083	}
      084	
      085	/******************/
      086	/* ゲームの遊び方 */
      087	/******************/
      088	class Method extends JDialog
      089	{
      090				// コンストラクタ
      091		Method()
      092		{
      093			setTitle("ゲームの遊び方");
      094					// ContetPain
      095			Container cp = getContentPane();
      096			cp.setLayout(new FlowLayout(FlowLayout.CENTER));
      097			cp.setBackground(new Color(220, 255, 220));   // 背景色
      098			Font f = new Font("MS 明朝", Font.PLAIN, 20);
      099			setSize(550, 160);
      100					// TextArea の追加
      101			JTextArea ta = new JTextArea(5, 50);
      102			ta.setFont(f);
      103			ta.setEditable(false);
      104			ta.setLineWrap(true);
      105			ta.setText("・ゲーム開始: 画面上でダブルクリック\n");
      106	
      107			ta.append("・コマの移動: 移動したいコマをクリック\n");
      108			JScrollPane scroll = new JScrollPane(ta);
      109			cp.add(scroll);
      110					// Window を閉じるため
      111			addWindowListener(new WinEnd());
      112		}
      113					// 終了処理
      114		class WinEnd extends WindowAdapter
      115		{
      116			public void windowClosing(WindowEvent e) {
      117				setVisible(false);
      118			}
      119		}
      120	}
      				

    4. GamePanel クラス

        GamePanel クラスは,実際のゲームを実現するクラスです.従って,「ゲーム枠の作成」における GamePanel クラスとは,ゲームの種類によってその内容は大きく異なります.今後,このクラスを完成させていくことになりますが,ここでは,必要なボタンを貼り付けています( GamePanel.java ).

      01	package game;
      02	
      03	import java.awt.*;
      04	import javax.swing.*;
      05	import main.*;
      06	
      07	public class GamePanel extends JPanel
      08	{
      09		JButton bt[][] = new JButton [3][3];
      10				// コンストラクタ
      11		public GamePanel(Dimension size, MainPanel mp)
      12		{
      13						// グリッドレイアウト
      14			setLayout(new GridLayout(3, 3, 10, 10));
      15						// 背景色の設定
      16			setBackground(Color.white);
      17						// ボタンの配置
      18			for (int i1 = 0; i1 < 3; i1++) {
      19				for (int i2 = 0; i2 < 3; i2++) {
      20					bt[i1][i2] = new JButton();
      21					bt[i1][i2].setBackground(Color.cyan);
      22					add(bt[i1][i2]);
      23				}
      24			}
      25		}
      26	}
      				
      14 行目

        GridLayout クラスを使用して,3 行 3 列のグリッドレイアウトに変更しています.その際,各領域間の間隔を 10 ピクセルに設定しています.

      18 行目~ 25 行目

        グリッドレイアウトの各領域にボタンを貼り付けています.レイアウトに合わせ,ボタンも 2 次元配列で定義しています.一般に,多次元配列は,配列の各要素を配列として定義することによって可能です.例えば,2 行 3 列の配列 x は,
      	int x[][] = new int [2][3];					
      または,
      	int x[][] = new int [2][];
      	x[0] = new int [3];   // 以下,繰り返し文を使用可能
      	x[1] = new int [3];					
      のような形で定義可能です.初期設定を行いたい場合は,
      	int x[][] = {{1, 2, 3}, {4, 5, 6}};   // 内側の括弧が各行に相当					
      または,
      	int x1[] = {1, 2, 3};
      	int x2[] = {4, 5, 6};
      	int x[][] = {x1, x2};					
      のような方法で行います.

    5. GameClearPanel クラス

        「ゲーム枠の作成」における GameClearPanel クラスと,ほぼ同じです.違いは,レベルが 2 までしか無い点と,画面の大きさが小さいので,表示内容や方法を多少変更している点です( GameClearPanel.java ).

      package clear;
      
      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;
      import main.*;
      
      public class GameClearPanel extends JPanel implements ActionListener
      {
      	Dimension size;   // パネルの大きさ
      	MainPanel mp;
      	JButton bt1, bt2;
      			// コンストラクタ
      	public GameClearPanel(Dimension size1, MainPanel mp1)
      	{
      		size = size1;
      		mp   = mp1;
      					// レイアウトマネージャの停止
      		setLayout(null);
      					// 背景色の設定
      		setBackground(Color.white);
      					// ボタンの配置
      		Font f = new Font("SansSerif", Font.BOLD, 15);
      		FontMetrics fm = getFontMetrics(f);
      		String str1 = "Finish";
      		int w1 = fm.stringWidth(str1) + 40;
      		int h1 = fm.getHeight() + 10;
      		bt1 = new JButton(str1);
      		bt1.setFont(f);
      		bt1.addActionListener(this);   // アクションリスナ
      		bt1.setSize(w1, h1);
      
      		String str2;
      		if (mp.level == 2)
      			str2 = "First";
      		else
      			str2 = "Next";
      		int w2 = fm.stringWidth(str2) + 40;
      		int h2 = fm.getHeight() + 10;
      		bt2 = new JButton(str2);
      		bt2.setFont(f);
      		bt2.addActionListener(this);   // アクションリスナ
      		bt2.setSize(w2, h2);
      
      		bt1.setLocation(size.width/2-(w1+w2+5)/2, size.height-h1-20);
      		add(bt1);
      		bt2.setLocation(size.width/2-(w1+w2+5)/2+w1+5, size.height-h2-20);
      		add(bt2);
      	}
      			// 描画
      	public void paintComponent(Graphics g)
      	{
      		super.paintComponent(g);   // 親クラスの描画
      		Font f = new Font("SansSerif", Font.BOLD, 40);
      		FontMetrics fm = g.getFontMetrics(f);
      		String str = "Clear!";
      		int w = fm.stringWidth(str);
      		g.setFont(f);
      		g.drawString(str, size.width/2-w/2, size.height/2);
      	}
      			// ボタンがクリックされたときの処理
      	public void actionPerformed(ActionEvent e)
      	{
      		if (e.getSource() == bt1) {
      			mp.state = 3;
      			bt1.setEnabled(false);
      			bt2.setEnabled(false);
      		}
      		else {
      			mp.level++;
      			if (mp.level > 2) {   // 最初からゲーム再開
      				mp.state = 0;
      				mp.level = 1;
      			}
      			else   // レベルアップ
      				mp.state = 1;
      		}
      	}
      }
      				

  2. ステップ2: 初期状態の生成

      ここでは,初期状態を生成し,その状態をボタンに表示しています.修正するプログラムは,game パッケージ内の GamePanel クラスです( GamePanel.java ).

    001	package game;
    002	
    003	import java.awt.*;
    004	import javax.swing.*;
    005	import java.util.Random;
    006	import main.*;
    007	
    008	public class GamePanel extends JPanel
    009	{
    010		MainPanel mp;
    011		JButton bt[][] = new JButton [3][3];
    012		Random rn;
    013		int i_state[][] = {{1, 2, 3}, {8, 0, 4}, {7, 6, 5}};
    014		int g_state[][] = {{1, 2, 3}, {8, 0, 4}, {7, 6, 5}};
    015				// コンストラクタ
    016		public GamePanel(Dimension size, MainPanel mp1)
    017		{
    018			mp = mp1;
    019						// グリッドレイアウト
    020			setLayout(new GridLayout(3, 3, 10, 10));
    021						// 背景色の設定
    022			setBackground(Color.white);
    023						// ボタンの配置
    024			Font f = new Font("SansSerif", Font.BOLD, 25);
    025			for (int i1 = 0; i1 < 3; i1++) {
    026				for (int i2 = 0; i2 < 3; i2++) {
    027					bt[i1][i2] = new JButton();
    028					bt[i1][i2].setBackground(Color.cyan);
    029					bt[i1][i2].setFont(f);
    030					add(bt[i1][i2]);
    031				}
    032			}
    033						// ランダム変数の初期化
    034			rn = new Random();
    035						// 初期状態の生成
    036			create();
    037						// ボタンへ名前を表示
    038			for (int i1 = 0; i1 < 3; i1++) {
    039				for (int i2 = 0; i2 < 3; i2++) {
    040					if (i_state[i1][i2] > 0)
    041						bt[i1][i2].setText(Integer.toString(i_state[i1][i2]));
    042				}
    043			}
    044		}
    045				// 初期状態の生成
    046		void create()
    047		{
    048			int ct = (mp.level == 1) ? 10 : 100;
    049			int dr, k1, k2, wk;
    050			boolean sw = true;
    051	
    052			while (sw) {
    053				k1 = 1;
    054				k2 = 1;
    055						// 移動
    056				for (int i1 = 0; i1 < ct; i1++) {
    057					dr = rn.nextInt(4);
    058					switch (dr) {
    059						case 0:   // 上
    060							if (k1 > 0) {
    061								wk                = i_state[k1-1][k2];
    062								i_state[k1-1][k2] = 0;
    063								i_state[k1][k2]   = wk;
    064								k1--;
    065							}
    066							break;
    067						case 1:   // 下
    068							if (k1 < 2) {
    069								wk                = i_state[k1+1][k2];
    070								i_state[k1+1][k2] = 0;
    071								i_state[k1][k2]   = wk;
    072								k1++;
    073							}
    074							break;
    075						case 2:   // 左
    076							if (k2 > 0) {
    077								wk                = i_state[k1][k2-1];
    078								i_state[k1][k2-1] = 0;
    079								i_state[k1][k2]   = wk;
    080								k2--;
    081							}
    082							break;
    083						default:   // 右
    084							if (k2 < 2) {
    085								wk                = i_state[k1][k2+1];
    086								i_state[k1][k2+1] = 0;
    087								i_state[k1][k2]   = wk;
    088								k2++;
    089							}
    090							break;
    091					}
    092				}
    093						// ゴールと同じか否かのチェック
    094				for (int i1 = 0; i1 < 3 && sw; i1++) {
    095					for (int i2 = 0; i2 < 3 && sw; i2++) {
    096						if (i_state[i1][i2] != g_state[i1][i2])
    097							sw = false;
    098					}
    099				}
    100			}
    101		}
    102	}
    			
    010,016,018 行目

      他のメソッドでも使用するため,引数で渡された mp1 を,フィールド mp を定義( 010 行目)し,そこに代入しています( 018 行目).

    013,014 行目

      ゲームの初期状態( i_state,コマの移動によって変化する)と目標状態( g_state )を入れる配列の定義と初期設定です.初期設定における内側の括弧は,配列の各行の値に相当し,この例では,いずれも 3 行 3 列の配列になり,その状態は目標状態です.

    024,029 行目

      各コマにラベルを表示するため,そのフォントを設定しています.

    005 行目,012 行目,034 行目

      初期状態をランダムに設定するため,Random クラスのオブジェクトを生成しています.

    036 行目

      初期状態を生成するためのメソッド create を呼んでいます.その内容は,046 行目~ 101 行目です.

    038 行目~ 043 行目

      各コマに対して,初期状態で決まったラベルを貼り付けています.数値を文字列に変換するため,Integer クラススタティックstatic )なメソッド toString を利用しています.この例に示すように,スタティックメソッドやスタティック変数は,「オブジェクト.メソッド名」「オブジェクト.変数名」ではなく,「クラス名.メソッド名」「クラス名.変数名」という形で参照することに注意してください.

    048 行目

       ? : は,条件演算子と呼ばれ,一般的には以下のように記述されます.論理式が評価され,その結果が真であれば,式1を評価した結果が変数に代入され,偽であれば,式2を評価した結果が変数に代入されます.
    	変数 = (論理式) ? 式1 : 式2 				
    従って,048 行目は,レベルが 1 であれば,ct の値を 10 とし,そうでなければ,100 とするという意味になります.

    056 行目~ 092 行目

      任意の初期状態から,コマの移動によって目標状態に到達できるとは限らないため,逆に,目標状態からランダムに ct 回コマを移動させ初期状態を生成しています.ただし,その結果が偶然目標状態と一致する可能性も存在するため,094 行目~ 099 行目において,生成された初期状態が目標状態と一致しないことを確認しています.これが,052 行目の while 文を使用している理由です.

      057 行目において,0 から 3 までの数値をランダムに決定し,得られた数値に基づき,switch 文( 058 行目~ 091 行目)によってコマを移動させています.switch 文の一般形式は以下の通りであり,式の値が定数式に一致した case 文以下が実行されます.いずれの定数式とも一致しなかった場合は,default 以下が実行されます.なお,break 文は,強制的に switch 文の外に出るための文であり,外へ出た後,switch 文の後の文から実行されます.
    	switch (式) {
    	[case 定数式1 : ]
    		[文1]
    	[case 定数式2 : ]
    		[文2]
    	 ・・・・・
    	[default : ]
    		[文n]
    }				

  3. ステップ3: 完成

      ここでは,ボタンに対して,クリックすると移動する機能を加え,ゲームを完成します.修正するプログラムは,game パッケージ内の GamePanel クラスです( GamePanel.java ).

    001	package game;
    002	
    003	import java.awt.*;
    004	import java.awt.event.*;
    005	import javax.swing.*;
    006	import java.util.Random;
    007	import main.*;
    008	
    009	public class GamePanel extends JPanel implements ActionListener
    010	{
    011		MainPanel mp;
    012		JButton bt[][] = new JButton [3][3];
    013		Random rn;
    014		int i_state[][] = {{1, 2, 3}, {8, 0, 4}, {7, 6, 5}};
    015		int g_state[][] = {{1, 2, 3}, {8, 0, 4}, {7, 6, 5}};
    016				// コンストラクタ
    017		public GamePanel(Dimension size, MainPanel mp1)
    018		{
    019			mp = mp1;
    020						// グリッドレイアウト
    021			setLayout(new GridLayout(3, 3, 10, 10));
    022						// 背景色の設定
    023			setBackground(Color.white);
    024						// ボタンの配置
    025			Font f = new Font("SansSerif", Font.BOLD, 25);
    026			for (int i1 = 0; i1 < 3; i1++) {
    027				for (int i2 = 0; i2 < 3; i2++) {
    028					bt[i1][i2] = new JButton();
    029					bt[i1][i2].setBackground(Color.cyan);
    030					bt[i1][i2].setFont(f);
    031					bt[i1][i2].addActionListener(this);   // アクションリスナ
    032					add(bt[i1][i2]);
    033				}
    034			}
    035						// ランダム変数の初期化
    036			rn = new Random();
    037						// 初期状態の生成
    038			create();
    039						// ボタンへ名前を表示
    040			for (int i1 = 0; i1 < 3; i1++) {
    041				for (int i2 = 0; i2 < 3; i2++) {
    042					if (i_state[i1][i2] > 0)
    043						bt[i1][i2].setText(Integer.toString(i_state[i1][i2]));
    044				}
    045			}
    046		}
    047				// 初期状態の生成
    048		void create()
    049		{
    050			int ct = (mp.level == 1) ? 10 : 100;
    051			int dr, k1, k2, wk;
    052			boolean sw = true;
    053	
    054			while (sw) {
    055				k1 = 1;
    056				k2 = 1;
    057						// 移動
    058				for (int i1 = 0; i1 < ct; i1++) {
    059					dr = rn.nextInt(4);
    060					switch (dr) {
    061						case 0:   // 上
    062							if (k1 > 0) {
    063								wk                = i_state[k1-1][k2];
    064								i_state[k1-1][k2] = 0;
    065								i_state[k1][k2]   = wk;
    066								k1--;
    067							}
    068							break;
    069						case 1:   // 下
    070							if (k1 < 2) {
    071								wk                = i_state[k1+1][k2];
    072								i_state[k1+1][k2] = 0;
    073								i_state[k1][k2]   = wk;
    074								k1++;
    075							}
    076							break;
    077						case 2:   // 左
    078							if (k2 > 0) {
    079								wk                = i_state[k1][k2-1];
    080								i_state[k1][k2-1] = 0;
    081								i_state[k1][k2]   = wk;
    082								k2--;
    083							}
    084							break;
    085						default:   // 右
    086							if (k2 < 2) {
    087								wk                = i_state[k1][k2+1];
    088								i_state[k1][k2+1] = 0;
    089								i_state[k1][k2]   = wk;
    090								k2++;
    091							}
    092							break;
    093					}
    094				}
    095						// ゴールと同じか否かのチェック
    096				for (int i1 = 0; i1 < 3 && sw; i1++) {
    097					for (int i2 = 0; i2 < 3 && sw; i2++) {
    098						if (i_state[i1][i2] != g_state[i1][i2])
    099							sw = false;
    100					}
    101				}
    102			}
    103		}
    104				// ボタンがクリックされたときの処理
    105		public void actionPerformed(ActionEvent e)
    106		{
    107			int sw = 0;
    108						// 移動
    109			for (int i1 = 0; i1 < 3 && sw == 0; i1++) {
    110				for (int i2 = 0; i2 < 3 && sw == 0; i2++) {
    111					if (e.getSource() == bt[i1][i2]) {
    112						sw = 1;
    113						if (i1 > 0 && i_state[i1-1][i2] == 0) {   // 上
    114							sw = 2;
    115							bt[i1][i2].setText("");
    116							bt[i1-1][i2].setText(Integer.toString(i_state[i1][i2]));
    117							i_state[i1-1][i2] = i_state[i1][i2];
    118							i_state[i1][i2]   = 0;
    119						}
    120						else if (i1 < 2 && i_state[i1+1][i2] == 0) {   // 下
    121							sw = 2;
    122							bt[i1][i2].setText("");
    123							bt[i1+1][i2].setText(Integer.toString(i_state[i1][i2]));
    124							i_state[i1+1][i2] = i_state[i1][i2];
    125							i_state[i1][i2]   = 0;
    126						}
    127						else if (i2 > 0 && i_state[i1][i2-1] == 0) {   // 左
    128							sw = 2;
    129							bt[i1][i2].setText("");
    130							bt[i1][i2-1].setText(Integer.toString(i_state[i1][i2]));
    131							i_state[i1][i2-1] = i_state[i1][i2];
    132							i_state[i1][i2]   = 0;
    133						}
    134						else if (i2 < 2 && i_state[i1][i2+1] == 0) {   // 右
    135							sw = 2;
    136							bt[i1][i2].setText("");
    137							bt[i1][i2+1].setText(Integer.toString(i_state[i1][i2]));
    138							i_state[i1][i2+1] = i_state[i1][i2];
    139							i_state[i1][i2]   = 0;
    140						}
    141					}
    142				}
    143			}
    144						// ゴールか?
    145			if (sw > 1) {
    146				for (int i1 = 0; i1 < 3 && sw > 1; i1++) {
    147					for (int i2 = 0; i2 < 3 && sw > 1; i2++) {
    148						if (i_state[i1][i2] != g_state[i1][i2])
    149							sw = 0;
    150					}
    151				}
    152				if (sw > 1)
    153					mp.state = 2;
    154			}
    155		}
    156	}
    			
    004 行目,009 行目

      アクションイベントを処理するため,ActionListener インタフェースを継承しています.

    031 行目

      各ボタンにアクションリスナを付加しています.

    105 行目~ 155 行目

      ボタンがクリックされたときの処理です.クリックされたボタンの上下左右に空白のマス目が存在するか否かを調べ( 113,120,127,134 行目),もし存在した場合はコマを移動します.移動後,目標状態に達した場合はゲームクリア状態に移行します( 145 行目~ 154 行目).

情報学部 菅沼ホーム Java 目次 索引