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

オセロ

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

      対戦相手を人間またはコンピュータとするオセロを作成します.基本的に,「ゲーム枠の作成」で説明した方法とほぼ同じ方法で作成します.ただし,パネルのサイズは変更しています.また,ゲームオーバーやゲームクリアの画面は存在しません.以下,各クラスに対して,「ゲーム枠の作成」の場合との違いについて説明していきます.なお,作成手順としては,まず人間対人間のゲームを完成させ(ステップ4まで),その後,対戦相手をコンピュータにした場合に必要な機能を付加します(ステップ5).

    1. Game クラス

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

      /*************************/
      /* オセロ                */
      /*   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("オセロ");
      	}
      }
      
      class Win extends JFrame
      {
      	/******************/
      	/* コンストラクタ */
      	/******************/
      	Win(String name)
      	{
      					// JFrameクラスのコンストラクタ(Windowのタイトルを引き渡す)
      		super(name);
      					// Windowの大きさ
      		setSize(487, 617);   // 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 クラスとほぼ同じですが,ゲームオーバーやゲームクリアの状態,及び,ゲームレベルを無くし,ゲーム方法を示すフィールド method を追加しています( MainPanel.java ).

      package main;
      
      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;
      import start.*;
      import game.*;
      
      public class MainPanel extends JPanel implements Runnable
      {
      	Dimension size;   // パネルの大きさ
      	boolean in_game = true;   // ゲーム実行中はtrue
      	public int state = 0;   // ゲーム状態(0:表紙,1:ゲーム,2:終了)
      	public int method = 0;   // ゲーム方法(0:対人間,1:対PC(先手),2:対PC(後手))
      	int old_state = 0;   // 直前のゲーム状態
      	StartPanel sp;
      	GamePanel gp;
      	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
      					remove(gp);
      							// 新しいパネルの追加
      				if (state == 2)   // ゲーム終了
      					in_game = false;
      				else {
      					if (state == 0) {   // StartPanel
      						sp = new StartPanel(size, this);
      						add(sp);
      					}
      					else {   // GamePanel
      						gp = new GamePanel(size, this);
      						add(gp);
      					}
      					validate();
      					old_state = state;
      				}
      			}
      		}
      	}
      }
      				

    3. StartPanel クラス

        「ゲーム枠の作成」における StartPanel クラスでは,「 s 」キーを押すとゲームを開始するように設定していましたが,ここでは「開始」ボタンクリックによって開始するように変更してあります( 058 行目~ 064 行目,091 行目~ 092 行目).また,ラジオボタンによって,対戦方法を選択できるようにしてあります.当然のことながら,ゲームタイトル及び「遊び方」の内容を変更しています( 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, ItemListener
      009	{
      010		boolean in_game = true;
      011		Dimension size;   // パネルの大きさ
      012		MainPanel mp;
      013		JButton bt, start;
      014		Checkbox c1, c2, c3;
      015				// コンストラクタ
      016		public StartPanel(Dimension size1, MainPanel mp1)
      017		{
      018			size = size1;
      019			mp   = mp1;
      020						// レイアウトマネージャの停止
      021			setLayout(null);
      022						// 背景色の設定
      023			setBackground(Color.white);
      024						// 「遊び方」ボタンの配置
      025			Font f = new Font("SansSerif", Font.BOLD, 20);
      026			FontMetrics fm = getFontMetrics(f);
      027			String str = "遊び方";
      028			int w = fm.stringWidth(str) + 40;
      029			int h = fm.getHeight() + 10;
      030			bt = new JButton(str);
      031			bt.setFont(f);
      032			bt.addActionListener(this);
      033			bt.setSize(w, h);
      034			bt.setLocation(size.width/2-w/2, 5);
      035			add(bt);
      036						// ラジオボタンの追加
      037			setFont(f);
      038			CheckboxGroup cbg = new CheckboxGroup();
      039			c1 = new Checkbox("対人間", cbg, true);
      040			w = fm.stringWidth("対人間") + 40;
      041			c1.setSize(w, h);
      042			c1.setLocation(20, size.height-3*h);
      043			c1.addItemListener(this);
      044			add(c1);
      045			c2 = new Checkbox("対コンピュータ(人先手)", cbg, false);
      046			w = fm.stringWidth("対コンピュータ(人先手)") + 40;
      047			c2.setSize(w, h);
      048			c2.setLocation(20, size.height-2*h);
      049			c2.addItemListener(this);
      050			add(c2);
      051			c3 = new Checkbox("対コンピュータ(人後手)", cbg, false);
      052			w = fm.stringWidth("対コンピュータ(人後手)") + 40;
      053			c3.setSize(w, h);
      054			c3.setLocation(20, size.height-h);
      055			c3.addItemListener(this);
      056			add(c3);
      057						// 「開始」ボタンの配置
      058			w = fm.stringWidth("開始") + 40;
      059			start = new JButton("開始");
      060			start.setFont(f);
      061			start.addActionListener(this);
      062			start.setSize(w, h);
      063			start.setLocation(size.width-w-20, size.height-2*h);
      064			add(start);
      065		}
      066				// 描画
      067		public void paintComponent(Graphics g)
      068		{
      069			super.paintComponent(g);   // 親クラスの描画
      070			FontMetrics fm;
      071			Font f;
      072			String str;
      073			int w, h;
      074	
      075			f   = new Font("SansSerif", Font.BOLD, 40);
      076			fm  = g.getFontMetrics(f);
      077			str = "オセロ";
      078			w   = fm.stringWidth(str);
      079			h   = fm.getHeight();
      080			g.setFont(f);
      081			g.drawString(str, size.width/2-w/2, size.height/2);
      082		}
      083				// ボタンがクリックされたときの処理
      084		public void actionPerformed(ActionEvent e)
      085		{
      086			if (e.getSource() == bt) {
      087				Method db = new Method();
      088				db.setVisible(true);
      089				requestFocusInWindow();
      090			}
      091			else if (e.getSource() == start)
      092				mp.state = 1;
      093		}
      094				// チェックされたときの処理
      095		public void itemStateChanged(ItemEvent e)
      096		{
      097			if (e.getSource() == c1)
      098				mp.method = 0;
      099			else if(e.getSource() == c2)
      100				mp.method = 1;
      101			else if(e.getSource() == c3)
      102				mp.method = 2;
      103		}
      104	}
      105	
      106	/******************/
      107	/* ゲームの遊び方 */
      108	/******************/
      109	class Method extends JDialog
      110	{
      111				// コンストラクタ
      112		Method()
      113		{
      114			setTitle("ゲームの遊び方");
      115					// ContetPain
      116			Container cp = getContentPane();
      117			cp.setLayout(new FlowLayout(FlowLayout.CENTER));
      118			cp.setBackground(new Color(220, 255, 220));   // 背景色
      119			Font f = new Font("MS 明朝", Font.PLAIN, 20);
      120			setSize(550, 160);
      121					// TextArea の追加
      122			JTextArea ta = new JTextArea(5, 50);
      123			ta.setFont(f);
      124			ta.setEditable(false);
      125			ta.setLineWrap(true);
      126			ta.setText("・ゲーム開始: ゲーム方法を選択した後,「開始」ボタンをクリック\n");
      127	
      128			ta.append("・コマを置く: コマを置きたい場所をクリック\n");
      129			JScrollPane scroll = new JScrollPane(ta);
      130			cp.add(scroll);
      131					// Window を閉じるため
      132			addWindowListener(new WinEnd());
      133		}
      134					// 終了処理
      135		class WinEnd extends WindowAdapter
      136		{
      137			public void windowClosing(WindowEvent e) {
      138				setVisible(false);
      139			}
      140		}
      141	}
      				
      008 行目

        ラジオボタンに対するイベント処理を行うため,ItemListener インタフェースを継承しています.

      037 行目~ 056 行目

        ラジオボタンの設定です.「対人間」を選択すると人間同士,「対コンピュータ(人先手)」を選択すると先手が人間で後手がコンピュータ,また,「対コンピュータ(人後手)」を選択すると後手が人間で先手がコンピュータとして,ゲームを実行できます.ラジオボタンをクリックすると,そのボタンにより,MainPanel オブジェクトのフィールド method の値が設定されます( 095 行目~ 103 行目).

    4. GamePanel クラス

        GamePanel クラスは,実際のゲームを実現するクラスです.従って,「ゲーム枠の作成」における GamePanel クラスとは,ゲームの種類によってその内容は大きく異なります.今後,このクラス及びその関連を完成させていくことになりますが,ここでは,GamePanel クラス( GamePanel.java : 001 行目~ 063 行目)に,メッセージを出力するテキストエリア,及び,「終了」と「再開」ボタンを貼り付けると共に,オセロを実行する盤となる Bord クラス( Bord.java : 065 行目~ 093 行目)を貼り付けています.さらに,ボードクラスにはコマを表す Koma クラス( Koma.java : 095 行目~ 110 行目)を貼り付けています.

      001	package game;
      002	
      003	import java.awt.*;
      004	import java.awt.event.*;
      005	import javax.swing.*;
      006	import main.*;
      007	
      008	public class GamePanel extends JPanel implements ActionListener
      009	{
      010		MainPanel mp;
      011		JTextArea ta;
      012		JButton bt1, bt2;
      013				// コンストラクタ
      014		public GamePanel(Dimension size, MainPanel mp1)
      015		{
      016			mp = mp1;
      017						// レイアウトマネージャの停止
      018			setLayout(null);
      019						// 背景色の設定
      020			setBackground(Color.white);
      021						// ボタンの配置
      022			Font f = new Font("SansSerif", Font.BOLD, 20);
      023			FontMetrics fm = getFontMetrics(f);
      024			int w = fm.stringWidth("終了") + 40;
      025			int h = fm.getHeight() + 10;
      026	
      027			bt1 = new JButton("終了");
      028			bt1.setFont(f);
      029			bt1.setSize(w, h);
      030			bt1.setLocation(size.width-w-5, size.height-50-h);
      031			bt1.addActionListener(this);   // アクションリスナ
      032			add(bt1);
      033	
      034			bt2 = new JButton("再開");
      035			bt2.setFont(f);
      036			bt2.setSize(w, h);
      037			bt2.setLocation(size.width-w-5, size.height-40);
      038			bt2.addActionListener(this);   // アクションリスナ
      039			add(bt2);
      040						// テキストエリアの配置
      041			ta = new JTextArea("黒の番です.\n");
      042			ta.setFont(f);
      043			JScrollPane sp = new JScrollPane(ta);
      044			sp.setSize(size.width-w-10, 90);
      045			sp.setLocation(0, size.height-90);
      046			add(sp);
      047						// オセロ盤の配置
      048			Bord bd = new Bord(size, this);
      049			bd.setSize(size.width, size.width);
      050			bd.setLocation(0, 0);
      051			add(bd);
      052		}
      053				// ボタンがクリックされたときの処理
      054		public void actionPerformed(ActionEvent e)
      055		{
      056			bt1.setEnabled(false);
      057			bt2.setEnabled(false);
      058			if (e.getSource() == bt1)   // ゲーム終了
      059				mp.state = 2;
      060			else   // 最初から再開
      061				mp.state = 0;
      062		}
      063	}
      064	
      065	package game;
      066	
      067	import java.awt.*;
      068	import javax.swing.*;
      069	
      070	public class Bord extends JPanel
      071	{
      072		GamePanel gp;
      073		Koma km[][] = new Koma [8][8];
      074				// コンストラクタ
      075		public Bord(Dimension size, GamePanel gp1)
      076		{
      077			int width;   // ボタンの大きさ
      078			int gap = 3;   // ボタン間の隙間の幅
      079			gp = gp1;
      080						// グリッドレイアウト
      081			setLayout(new GridLayout(8, 8, gap, gap));
      082						// 背景色の設定
      083			setBackground(new Color(165, 42, 42));
      084						// ボタンの配置
      085			width = (size.width - 9 * gap) / 8;
      086			for (int i1 = 0; i1 < 8; i1++) {
      087				for (int i2 = 0; i2 < 8; i2++) {
      088					km[i1][i2] = new Koma(width);
      089					add(km[i1][i2]);
      090				}
      091			}
      092		}
      093	}
      094	
      095	package game;
      096	
      097	import java.awt.*;
      098	import javax.swing.*;
      099	
      100	class Koma extends JButton
      101	{
      102		int width;   // ボタンの幅
      103				// コンストラクタ
      104		Koma(int width1)
      105		{
      106			width = width1;
      107						// 背景色の設定
      108			setBackground(Color.green);
      109		}
      110	}
      				
      022 行目~ 039 行目

        「終了」を選択するとゲームの終了処理を,また,「再開」を選択するとゲームをもう一度行うことになります.具体的な処理は,054 行目~ 062 行目でおこなっています.

      041 行目~ 046 行目

        テキストエリアを作成しています.JTextArea クラスにはスクロールバーが存在しないため,JScrollPane クラスを利用しています.テキストエリアには,システムからメッセージが出力されます.

      048 行目~ 051 行目

        オセロ盤を貼り付けています.オセロ盤 Bord クラスは,別ファイルにクラスとして定義されています( 065 行目~ 093 行目).

      065 行目~ 093 行目

        Bord クラスの定義です.GridLayout クラスを使用しています( 081 行目).その際,要素間の間隔を gap ピクセルに設定し,オセロ盤の枠を表現しています.グリッドレイアウトの各領域には,他のファイルに定義してある Koma クラス(ボタン)のオブジェクトを貼り付けています( 085 行目~ 091 行目).なお,Koma クラスのオブジェクトは,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};					
      のような方法で行います.

      095 行目~ 110 行目

        Koma クラスの定義です.ここでは,単に,コマの背景色を設定しているだけです.

  2. ステップ2: 初期状態の表示

      ここでは,初期状態におけるコマの配置を表示しています.修正するプログラムは,game パッケージ内の Bord クラス( Bord.java )と Koma クラス( Koma.java )です.まず,Bord クラスのソースファイルは以下に示すとおりです.

    01	package game;
    02	
    03	import java.awt.*;
    04	import javax.swing.*;
    05	
    06	public class Bord extends JPanel
    07	{
    08		GamePanel gp;
    09		Koma km[][] = new Koma [8][8];
    10		int b_w = -1;   // -1:黒の手番,1:白の手番
    11		int st[][] = {{0, 0, 0, 0, 0, 0, 0, 0},
    12		              {0, 0, 0, 0, 0, 0, 0, 0},
    13		              {0, 0, 0, 0, 0, 0, 0, 0},
    14		              {0, 0, 0, 1, -1, 0, 0, 0},
    15		              {0, 0, 0, -1, 1, 0, 0, 0},
    16		              {0, 0, 0, 0, 0, 0, 0, 0},
    17		              {0, 0, 0, 0, 0, 0, 0, 0},
    18		              {0, 0, 0, 0, 0, 0, 0, 0}};   // 盤面の状態(0:コマが置かれてない,-1:黒,1:白)
    19				// コンストラクタ
    20		public Bord(Dimension size, GamePanel gp1)
    21		{
    22			int width;   // ボタンの大きさ
    23			int gap = 3;   // ボタン間の隙間の幅
    24			gp = gp1;
    25						// グリッドレイアウト
    26			setLayout(new GridLayout(8, 8, gap, gap));
    27						// 背景色の設定
    28			setBackground(new Color(165, 42, 42));
    29						// ボタンの配置
    30			width = (size.width - 9 * gap) / 8;
    31			for (int i1 = 0; i1 < 8; i1++) {
    32				for (int i2 = 0; i2 < 8; i2++) {
    33					km[i1][i2] = new Koma(width);
    34					if (st[i1][i2] != 0)
    35						km[i1][i2].st = st[i1][i2];
    36					add(km[i1][i2]);
    37				}
    38			}
    39		}
    40	}
    			
    10 行目

      次にどちらの番かを示すフィールド b_w を定義し,その初期設定を行っています.この値が -1 の場合は黒,また,1 の場合は白の番であることを示します.

    11 行目~ 18 行目

      オセロ盤の状態を示す 2 次元配列 st( 8 行 8 列) を定義し,その初期設定を行っています.初期設置の内側の括弧は,配列の行に対応しています.0 の場合はコマが置かれてない,-1 の場合は黒コマが置かれている,また,1 の場合は白コマが置かれていることを示します.

    34,35 行目

      コマが置かれている場合は,その情報を対応する Koma オブジェクトに設定しています.

      また,Koma クラスのソースプログラムは,以下に示すとおりです.

    01	package game;
    02	
    03	import java.awt.*;
    04	import javax.swing.*;
    05	
    06	class Koma extends JButton
    07	{
    08		int width;   // ボタンの大きさ
    09		int st = 0;   // ボタンの状態(0:コマが置かれてない,-1:黒,1:白)
    10				// コンストラクタ
    11		Koma(int width1)
    12		{
    13			width = width1;
    14						// 背景色の設定
    15			setBackground(Color.green);
    16		}
    17				// 描画
    18		public void paintComponent(Graphics g)
    19		{
    20			super.paintComponent(g);   // 親クラスの描画
    21			if (st != 0) {
    22				if (st < 0)
    23					g.setColor(Color.black);
    24				else
    25					g.setColor(Color.white);
    26				g.fillOval(2, 2, width-4, width-4);
    27			}
    28		}
    29	}
    			
    09 行目

      Bord オブジェクトのフィールド st に対応した,このボタンの状態を示す変数です.

    18 行目~ 28 行目

      コマが存在する場所に,対応するコマを描画しています.

  3. ステップ3: コマを置く

      ここでは,人間対人間の対戦において,コマを置く動作を実現しています.修正するプログラムは,game パッケージ内の Bord クラスです( Bord.java ).Bord クラスでは,コマを置く操作を実現します.その際,コマを置くことができるか否かのチェックや挟まれたコマを反転する操作が必要になり,多少面倒なプログラムになります.

    001	package game;
    002	
    003	import java.awt.*;
    004	import java.awt.event.*;
    005	import javax.swing.*;
    006	
    007	public class Bord extends JPanel implements ActionListener
    008	{
    009		GamePanel gp;
    010		Koma km[][] = new Koma [8][8];
    011		int b_w = -1;   // -1:黒の手番,1:白の手番
    012		int st[][] = {{0, 0, 0, 0, 0, 0, 0, 0},
    013		              {0, 0, 0, 0, 0, 0, 0, 0},
    014		              {0, 0, 0, 0, 0, 0, 0, 0},
    015		              {0, 0, 0, 1, -1, 0, 0, 0},
    016		              {0, 0, 0, -1, 1, 0, 0, 0},
    017		              {0, 0, 0, 0, 0, 0, 0, 0},
    018		              {0, 0, 0, 0, 0, 0, 0, 0},
    019		              {0, 0, 0, 0, 0, 0, 0, 0}};   // 盤面の状態(0:コマが置かれてない,-1:黒,1:白)
    020		int n[] = new int [9];   // 指定された位置の各方向に対する反転できるコマの数
    021		                         //    [0] : 上方向
    022		                         //    [1] : 斜め右上方向
    023		                         //    [2] : 右方向
    024		                         //    [3] : 斜め右下方向
    025		                         //    [4] : 下方向
    026		                         //    [5] : 斜め左下方向
    027		                         //    [6] : 左方向
    028		                         //    [7] : 斜め左上方向
    029		                         //    [8] : 全体
    030				// コンストラクタ
    031		public Bord(Dimension size, GamePanel gp1)
    032		{
    033			int width;   // ボタンの大きさ
    034			int gap = 3;   // ボタン間の隙間の幅
    035			gp = gp1;
    036						// グリッドレイアウト
    037			setLayout(new GridLayout(8, 8, gap, gap));
    038						// 背景色の設定
    039			setBackground(new Color(165, 42, 42));
    040						// ボタンの配置
    041			width = (size.width - 9 * gap) / 8;
    042			for (int i1 = 0; i1 < 8; i1++) {
    043				for (int i2 = 0; i2 < 8; i2++) {
    044					km[i1][i2] = new Koma(width);
    045					km[i1][i2].addActionListener(this);
    046					if (st[i1][i2] != 0)
    047						km[i1][i2].st = st[i1][i2];
    048					add(km[i1][i2]);
    049				}
    050			}
    051		}
    052				//
    053				// ボタンがクリックされたときの処理
    054				//
    055		public void actionPerformed(ActionEvent e)
    056		{
    057						// クリックされたボタンを特定
    058			int k[] = {-1, -1};
    059			for (int i1 = 0; i1 < 8 && k[0] < 0; i1++) {
    060				for (int i2 = 0; i2 < 8 && k[0] < 0; i2++) {
    061					if (e.getSource() == km[i1][i2]) {
    062						k[0] = i1;
    063						k[1] = i2;
    064					}
    065				}
    066			}
    067						// 反転できるコマを探す
    068			r_check(k);
    069								// 反転するコマがない場合
    070			if (n[8] <= 0) {
    071				gp.ta.setForeground(Color.red);
    072				if (b_w < 0)
    073					gp.ta.setText("黒の番ですが,\n");
    074				else
    075					gp.ta.setText("白の番ですが,\n");
    076				gp.ta.append("そこへはコマを置けません.\n");
    077			}
    078								// 反転するコマがある場合
    079			else
    080				set(k);
    081		}
    082				//
    083				// コマの操作
    084				//
    085		void set(int k[])
    086		{
    087						// 反転
    088			reverse(k);
    089			b_w = -b_w;
    090			gp.ta.setForeground(Color.black);
    091			if (b_w < 0)
    092				gp.ta.setText("黒の番です.\n");
    093			else
    094				gp.ta.setText("白の番です.\n");
    095		}
    096				//
    097				// k[0] 行 k[1] 列に黒または白( b_w )のコマを置いた場合,反転できるコマを探す
    098				//
    099		void r_check(int k[])
    100		{
    101			int d[][] = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}};
    102			n[8] = 0;
    103			if (st[k[0]][k[1]] == 0) {
    104				for (int i1 = 0; i1 < 8; i1++) {
    105					int m1 = k[0], m2 = k[1];
    106					n[i1]  = 0;
    107					int s  = 0;   // 0:開始,1:カウント,2:カウント終了,3:反転不可能
    108					int ct = 0;
    109					while (s < 2) {
    110						m1 += d[i1][0];
    111						m2 += d[i1][1];
    112						if (m1 >= 0 && m1 < 8 && m2 >= 0 && m2 < 8) {
    113							if (st[m1][m2] == 0)
    114								s = 3;
    115							else if (st[m1][m2] == b_w) {
    116								if (s == 1)
    117									s = 2;
    118								else
    119									s = 3;
    120							}
    121							else {
    122								s = 1;
    123								ct++;
    124							}
    125						}
    126						else
    127							s = 3;
    128					}
    129					if (s == 2) {
    130						n[8]  += ct;
    131						n[i1]  = ct;
    132					}
    133				}
    134			}
    135		}
    136				//
    137				// k[0] 行 k[1] 列に黒または白( b_w )のコマを置いた場合におけるコマの反転
    138				//
    139		void reverse(int k[])
    140		{
    141			int d[][] = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}};
    142			for (int i1 = 0; i1 < 8; i1++) {
    143				int m1 = k[0], m2 = k[1];
    144				for (int i2 = 0; i2 < n[i1]; i2++) {
    145					m1 += d[i1][0];
    146					m2 += d[i1][1];
    147					km[m1][m2].st = b_w;
    148					st[m1][m2]    = b_w;
    149				}
    150			}
    151			km[k[0]][k[1]].st = b_w;
    152			st[k[0]][k[1]]    = b_w;
    153						// 描画
    154			for (int i1 = 0; i1 < 8; i1++) {
    155				for (int i2 = 0; i2 < 8; i2++) {
    156					if (st[i1][i2] != 0)
    157						km[i1][i2].repaint();
    158				}
    159			}
    160		}
    161	}
    			
    004 行目,007 行目,045 行目

      ボタンをクリックした時の処理を行うため,ActionListener インタフェースを継承しています.また,045 行目に置いて,各ボタンに,アクションリスナを追加しています.

    020 行目

      指定されたボタンにコマを置いた場合,斜め右上,右,斜め右下,下,斜め左下,左,及び,斜め左上方向の挟んで反転できるコマの数を設定するためのフィールドです.n[8] にはそれらの数の和が設定されます.従って,n[8] が 0 となるような場所にはコマを置けないことになります.

    058 行目~ 066 行目

      055 行目~ 081 行目が,ボタンがクリックされた時の処理であり,ここでは,クリックされたボタンを特定し,その行番号を k[0],列番号を k[1] に代入しています.

    068 行目

      k[0] 行 k[1] 列にコマを置いた場合に反転できるコマを探すためのメソッド r_check を呼んでいます.その結果,n[0] ~ n[8] に値が設定されます.メソッドにおける処理内容は,099 行目~ 135 行目に記載されています.

    070 行目~ 077 行目

      上の処理の結果,反転するコマが存在しない場合は,テキストエリアにメッセージを出力しています.

    080 行目

      コマを反転し,その後の処理を行うメソッド set を呼んでいます.メソッドの内容は,085 行目~ 095 行目に記載されています.

    088 行目

      n[0] ~ n[8] に設定された内容に基づき,k[0] 行 k[1] 列にコマを置いた時の反転処理を行うメソッド reverse を呼んでいます.メソッドにおける処理内容は,139 行目~ 160 行目に記載されています.

    089 行目~ 094 行目

      手番を変更した( 089 行目)後,テキストエリアにメッセージを出力しています.

    101 行目

      反転できるコマを探す方向をセットしています.例えば,{-1, 0} は,行番号が 1 だけ減り列番号が同じ方向,つまり,上方向を表しています.

    104 行目~ 133 行目

      k[0] 行 k[1] 列 を基点とした 8 つの方向に対して,反転させることができるコマの数を数えています.

    142 行目~ 152 行目

      k[0] 行 k[1] 列にコマを置いた時,8 つの方向に対して,挟まれているコマを反転した後,151,152 行目において,置いたコマに対する処理を行っています.

    154 行目~ 159 行目

      コマが置かれたボタンを再描画しています.

  4. ステップ4: 勝敗とスキップ

      ここでは,勝敗を決定する操作,及び,コマを置く場所が存在しない場合スキップする操作を追加します.ここまでの処理によって,人間対人間の対戦は完成となります.修正するプログラムは,game パッケージ内の Bord クラス( Bord.java )のメソッド set だけです.Bord クラスのソースプログラムは以下に示すとおりです.

    001	package game;
    002	
    003	import java.awt.*;
    004	import java.awt.event.*;
    005	import javax.swing.*;
    006	
    007	public class Bord extends JPanel implements ActionListener
    008	{
    009		GamePanel gp;
    010		Koma km[][] = new Koma [8][8];
    011		int b_w = -1;   // -1:黒の手番,1:白の手番
    012		int st[][] = {{0, 0, 0, 0, 0, 0, 0, 0},
    013		              {0, 0, 0, 0, 0, 0, 0, 0},
    014		              {0, 0, 0, 0, 0, 0, 0, 0},
    015		              {0, 0, 0, 1, -1, 0, 0, 0},
    016		              {0, 0, 0, -1, 1, 0, 0, 0},
    017		              {0, 0, 0, 0, 0, 0, 0, 0},
    018		              {0, 0, 0, 0, 0, 0, 0, 0},
    019		              {0, 0, 0, 0, 0, 0, 0, 0}};   // 盤面の状態(0:コマが置かれてない,-1:黒,1:白)
    020		int n[] = new int [9];   // 指定された位置の各方向に対する反転できるコマの数
    021		                         //    [0] : 上方向
    022		                         //    [1] : 斜め右上方向
    023		                         //    [2] : 右方向
    024		                         //    [3] : 斜め右下方向
    025		                         //    [4] : 下方向
    026		                         //    [5] : 斜め左下方向
    027		                         //    [6] : 左方向
    028		                         //    [7] : 斜め左上方向
    029		                         //    [8] : 全体
    030				// コンストラクタ
    031		public Bord(Dimension size, GamePanel gp1)
    032		{
    033			int width;   // ボタンの大きさ
    034			int gap = 3;   // ボタン間の隙間の幅
    035			gp = gp1;
    036						// グリッドレイアウト
    037			setLayout(new GridLayout(8, 8, gap, gap));
    038						// 背景色の設定
    039			setBackground(new Color(165, 42, 42));
    040						// ボタンの配置
    041			width = (size.width - 9 * gap) / 8;
    042			for (int i1 = 0; i1 < 8; i1++) {
    043				for (int i2 = 0; i2 < 8; i2++) {
    044					km[i1][i2] = new Koma(width);
    045					km[i1][i2].addActionListener(this);
    046					if (st[i1][i2] != 0)
    047						km[i1][i2].st = st[i1][i2];
    048					add(km[i1][i2]);
    049				}
    050			}
    051		}
    052				//
    053				// ボタンがクリックされたときの処理
    054				//
    055		public void actionPerformed(ActionEvent e)
    056		{
    057						// クリックされたボタンを特定
    058			int k[] = {-1, -1};
    059			for (int i1 = 0; i1 < 8 && k[0] < 0; i1++) {
    060				for (int i2 = 0; i2 < 8 && k[0] < 0; i2++) {
    061					if (e.getSource() == km[i1][i2]) {
    062						k[0] = i1;
    063						k[1] = i2;
    064					}
    065				}
    066			}
    067						// 反転できるコマを探す
    068			r_check(k);
    069								// 反転するコマがない場合
    070			if (n[8] <= 0) {
    071				gp.ta.setForeground(Color.red);
    072				if (b_w < 0)
    073					gp.ta.setText("黒の番ですが,\n");
    074				else
    075					gp.ta.setText("白の番ですが,\n");
    076				gp.ta.append("そこへはコマを置けません.\n");
    077			}
    078								// 反転するコマがある場合
    079			else
    080				set(k);
    081		}
    082				//
    083				// コマの操作
    084				//
    085		void set(int k[])
    086		{
    087						// 反転
    088			reverse(k);
    089			b_w = -b_w;
    090						// コマの数を数え,勝敗決定のチェック
    091			int b = 0, w = 0, total = 0;
    092			for (int i1 = 0; i1 < 8; i1++) {
    093				for (int i2 = 0; i2 < 8; i2++) {
    094					if (st[i1][i2] != 0) {
    095						total++;
    096						if (st[i1][i2] < 0)
    097							b++;
    098						else
    099							w++;
    100					}
    101				}
    102			}
    103						// 勝敗決定
    104			if (total == 64) {
    105				gp.ta.setForeground(Color.black);
    106				gp.ta.setText("黒 " + b + " 個, 白 " + w + " 個\n");
    107				if (b > w)
    108					gp.ta.append("黒の勝ちです.\n");
    109				else if (b == w)
    110					gp.ta.append("引き分けです.\n");
    111				else
    112					gp.ta.append("白の勝ちです.\n");
    113				for (int i1 = 0; i1 < 8; i1++) {
    114					for (int i2 = 0; i2 < 8; i2++)
    115						km[i1][i2].setEnabled(false);
    116				}
    117			}
    118						// 勝負継続
    119			else {
    120				gp.ta.setForeground(Color.black);
    121				gp.ta.setText("黒 " + b + " 個, 白 " + w + " 個\n");
    122								// スキップのチェック
    123				boolean sw = false;
    124				for (int i1 = 0; i1 < 8 && !sw; i1++) {
    125					for (int i2 = 0; i2 < 8 && !sw; i2++) {
    126						k[0] = i1;
    127						k[1] = i2;
    128						r_check(k);
    129						if (n[8] > 0)
    130							sw = true;
    131					}
    132				}
    133								// スキップの場合
    134				if (!sw) {
    135					gp.ta.append("コマを置けないため,スキップし,\n");
    136					b_w = -b_w;
    137				}
    138								// 次の手
    139				if (b_w < 0)
    140					gp.ta.append("黒の番です.\n");
    141				else
    142					gp.ta.append("白の番です.\n");
    143			}
    144		}
    145				//
    146				// k[0] 行 k[1] 列に黒または白( b_w )のコマを置いた場合,反転できるコマを探す
    147				//
    148		void r_check(int k[])
    149		{
    150			int d[][] = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}};
    151			n[8] = 0;
    152			if (st[k[0]][k[1]] == 0) {
    153				for (int i1 = 0; i1 < 8; i1++) {
    154					int m1 = k[0], m2 = k[1];
    155					n[i1]  = 0;
    156					int s  = 0;   // 0:開始,1:カウント,2:カウント終了,3:反転不可能
    157					int ct = 0;
    158					while (s < 2) {
    159						m1 += d[i1][0];
    160						m2 += d[i1][1];
    161						if (m1 >= 0 && m1 < 8 && m2 >= 0 && m2 < 8) {
    162							if (st[m1][m2] == 0)
    163								s = 3;
    164							else if (st[m1][m2] == b_w) {
    165								if (s == 1)
    166									s = 2;
    167								else
    168									s = 3;
    169							}
    170							else {
    171								s = 1;
    172								ct++;
    173							}
    174						}
    175						else
    176							s = 3;
    177					}
    178					if (s == 2) {
    179						n[8]  += ct;
    180						n[i1]  = ct;
    181					}
    182				}
    183			}
    184		}
    185				//
    186				// k[0] 行 k[1] 列に黒または白( b_w )のコマを置いた場合におけるコマの反転
    187				//
    188		void reverse(int k[])
    189		{
    190			int d[][] = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}};
    191			for (int i1 = 0; i1 < 8; i1++) {
    192				int m1 = k[0], m2 = k[1];
    193				for (int i2 = 0; i2 < n[i1]; i2++) {
    194					m1 += d[i1][0];
    195					m2 += d[i1][1];
    196					km[m1][m2].st = b_w;
    197					st[m1][m2]    = b_w;
    198				}
    199			}
    200			km[k[0]][k[1]].st = b_w;
    201			st[k[0]][k[1]]    = b_w;
    202						// 描画
    203			for (int i1 = 0; i1 < 8; i1++) {
    204				for (int i2 = 0; i2 < 8; i2++) {
    205					if (st[i1][i2] != 0)
    206						km[i1][i2].repaint();
    207				}
    208			}
    209		}
    210	}
    			
    091 行目~ 102 行目

      黒及び白のコマを数えています.

    104 行目~ 117 行目

      勝敗が決定した場合の処理です.テキストエリアにメッセージを出力した後,オセロ盤上のボタンを押しても反応しないようにしています.

    120,121 行目

      テキストエリアに,現時点における黒及び白のコマの数を表示しています.

    123 行目~ 132 行目

      メソッド r_check を利用して,コマを置ける場所が存在するか否かを調べています.

    134 行目~ 137 行目

      コマを置ける場所が存在しない場合は,テキストエリアにメッセージを出力し,手番を変更しています(スキップ).

  5. ステップ5: 完成

      ここでは,コンピュータがコマを置く場所を決定する処理を加え,ゲームを完成します.コンピュータのアルゴリズムを強化すれば強いオセロになりますが,今回は,最も多くのコマを反転できる場所を選択するようにしています.修正するプログラムは,game パッケージ内の GamePanel クラス( GamePanel.java )と Bord クラス( Bord.java )です.GamePanel クラスにおける変更は,41 行目~ 48 行目に示すテキストエリアに対する出力の変更だけです.

    01	package game;
    02	
    03	import java.awt.*;
    04	import java.awt.event.*;
    05	import javax.swing.*;
    06	import main.*;
    07	
    08	public class GamePanel extends JPanel implements ActionListener
    09	{
    10		MainPanel mp;
    11		JTextArea ta;
    12		JButton bt1, bt2;
    13				// コンストラクタ
    14		public GamePanel(Dimension size, MainPanel mp1)
    15		{
    16			mp = mp1;
    17						// レイアウトマネージャの停止
    18			setLayout(null);
    19						// 背景色の設定
    20			setBackground(Color.white);
    21						// ボタンの配置
    22			Font f = new Font("SansSerif", Font.BOLD, 20);
    23			FontMetrics fm = getFontMetrics(f);
    24			int w = fm.stringWidth("終了") + 40;
    25			int h = fm.getHeight() + 10;
    26	
    27			bt1 = new JButton("終了");
    28			bt1.setFont(f);
    29			bt1.setSize(w, h);
    30			bt1.setLocation(size.width-w-5, size.height-50-h);
    31			bt1.addActionListener(this);   // アクションリスナ
    32			add(bt1);
    33	
    34			bt2 = new JButton("再開");
    35			bt2.setFont(f);
    36			bt2.setSize(w, h);
    37			bt2.setLocation(size.width-w-5, size.height-40);
    38			bt2.addActionListener(this);   // アクションリスナ
    39			add(bt2);
    40						// テキストエリアの配置
    41			String str;
    42			if (mp.method == 0)
    43				str = "黒の番です.\n";
    44			else if (mp.method == 1)
    45				str = "あなた(黒)の番です.\n";
    46			else
    47				str = "コンピュータの番です.\n";
    48			ta = new JTextArea(str);
    49			ta.setFont(f);
    50			JScrollPane sp = new JScrollPane(ta);
    51			sp.setSize(size.width-w-10, 90);
    52			sp.setLocation(0, size.height-90);
    53			add(sp);
    54						// オセロ盤の配置
    55			Bord bd = new Bord(size, this);
    56			bd.setSize(size.width, size.width);
    57			bd.setLocation(0, 0);
    58			add(bd);
    59		}
    60				// ボタンがクリックされたときの処理
    61		public void actionPerformed(ActionEvent e)
    62		{
    63			bt1.setEnabled(false);
    64			bt2.setEnabled(false);
    65			if (e.getSource() == bt1)   // ゲーム終了
    66				mp.state = 2;
    67			else   // 最初から再開
    68				mp.state = 0;
    69		}
    70	}
    			

      Bord クラスのソースプログラムは以下に示すとおりです.

    001	package game;
    002	
    003	import java.awt.*;
    004	import java.awt.event.*;
    005	import javax.swing.*;
    006	
    007	public class Bord extends JPanel implements ActionListener
    008	{
    009		GamePanel gp;
    010		Koma km[][] = new Koma [8][8];
    011		int b_w = -1;   // -1:黒の手番,1:白の手番
    012		int st[][] = {{0, 0, 0, 0, 0, 0, 0, 0},
    013		              {0, 0, 0, 0, 0, 0, 0, 0},
    014		              {0, 0, 0, 0, 0, 0, 0, 0},
    015		              {0, 0, 0, 1, -1, 0, 0, 0},
    016		              {0, 0, 0, -1, 1, 0, 0, 0},
    017		              {0, 0, 0, 0, 0, 0, 0, 0},
    018		              {0, 0, 0, 0, 0, 0, 0, 0},
    019		              {0, 0, 0, 0, 0, 0, 0, 0}};   // 盤面の状態(0:コマが置かれてない,-1:黒,1:白)
    020		int n[] = new int [9];   // 指定された位置の各方向に対する反転できるコマの数
    021		                         //    [0] : 上方向
    022		                         //    [1] : 斜め右上方向
    023		                         //    [2] : 右方向
    024		                         //    [3] : 斜め右下方向
    025		                         //    [4] : 下方向
    026		                         //    [5] : 斜め左下方向
    027		                         //    [6] : 左方向
    028		                         //    [7] : 斜め左上方向
    029		                         //    [8] : 全体
    030				// コンストラクタ
    031		public Bord(Dimension size, GamePanel gp1)
    032		{
    033			int width;   // ボタンの大きさ
    034			int gap = 3;   // ボタン間の隙間の幅
    035			gp = gp1;
    036						// グリッドレイアウト
    037			setLayout(new GridLayout(8, 8, gap, gap));
    038						// 背景色の設定
    039			setBackground(new Color(165, 42, 42));
    040						// ボタンの配置
    041			width = (size.width - 9 * gap) / 8;
    042			for (int i1 = 0; i1 < 8; i1++) {
    043				for (int i2 = 0; i2 < 8; i2++) {
    044					km[i1][i2] = new Koma(width);
    045					km[i1][i2].addActionListener(this);
    046					if (st[i1][i2] != 0)
    047						km[i1][i2].st = st[i1][i2];
    048					add(km[i1][i2]);
    049				}
    050			}
    051						// コンピュータの操作
    052			if (gp.mp.method == 2) {
    053				int k[] = computer();   // コマを置く場所の決定
    054				set(k);   // コマを置く
    055			}
    056		}
    057				//
    058				// ボタンがクリックされたときの処理
    059				//
    060		public void actionPerformed(ActionEvent e)
    061		{
    062						// クリックされたボタンを特定
    063			int k[] = {-1, -1};
    064			for (int i1 = 0; i1 < 8 && k[0] < 0; i1++) {
    065				for (int i2 = 0; i2 < 8 && k[0] < 0; i2++) {
    066					if (e.getSource() == km[i1][i2]) {
    067						k[0] = i1;
    068						k[1] = i2;
    069					}
    070				}
    071			}
    072						// 反転できるコマを探す
    073			r_check(k);
    074								// 反転するコマがない場合
    075			if (n[8] <= 0) {
    076				gp.ta.setForeground(Color.red);
    077				if (gp.mp.method > 0)
    078					gp.ta.setText("あなたの番ですが,\n");
    079				else {
    080					if (b_w < 0)
    081						gp.ta.setText("黒の番ですが,\n");
    082					else
    083						gp.ta.setText("白の番ですが,\n");
    084				}
    085				gp.ta.append("そこへはコマを置けません.\n");
    086			}
    087								// 反転するコマがある場合
    088			else
    089				set(k);
    090		}
    091				//
    092				// コマの操作
    093				//
    094		void set(int k[])
    095		{
    096						// 反転
    097			reverse(k);
    098			b_w = -b_w;
    099						// コマの数を数え,勝敗決定のチェック
    100			int b = 0, w = 0, total = 0;
    101			for (int i1 = 0; i1 < 8; i1++) {
    102				for (int i2 = 0; i2 < 8; i2++) {
    103					if (st[i1][i2] != 0) {
    104						total++;
    105						if (st[i1][i2] < 0)
    106							b++;
    107						else
    108							w++;
    109					}
    110				}
    111			}
    112						// 勝敗決定
    113			if (total == 64) {
    114				gp.ta.setForeground(Color.black);
    115				gp.ta.setText("黒 " + b + " 個, 白 " + w + " 個\n");
    116				if (gp.mp.method > 0) {
    117					if (b == w)
    118						gp.ta.append("引き分けです.\n");
    119					else if (b > w && gp.mp.method == 1 || b < w && gp.mp.method == 2)
    120						gp.ta.append("あなたの勝ちです.\n");
    121					else
    122						gp.ta.append("コンピュータの勝ちです.\n");
    123				}
    124				else {
    125					if (b > w)
    126						gp.ta.append("黒の勝ちです.\n");
    127					else if (b == w)
    128						gp.ta.append("引き分けです.\n");
    129					else
    130						gp.ta.append("白の勝ちです.\n");
    131				}
    132				for (int i1 = 0; i1 < 8; i1++) {
    133					for (int i2 = 0; i2 < 8; i2++)
    134						km[i1][i2].setEnabled(false);
    135				}
    136			}
    137						// 勝負継続
    138			else {
    139				gp.ta.setForeground(Color.black);
    140				gp.ta.setText("黒 " + b + " 個, 白 " + w + " 個\n");
    141								// スキップのチェック
    142				boolean sw = false;
    143				for (int i1 = 0; i1 < 8 && !sw; i1++) {
    144					for (int i2 = 0; i2 < 8 && !sw; i2++) {
    145						k[0] = i1;
    146						k[1] = i2;
    147						r_check(k);
    148						if (n[8] > 0)
    149							sw = true;
    150					}
    151				}
    152								// 対コンピュータ
    153				if (gp.mp.method > 0) {
    154										// スキップの場合
    155					if (!sw) {
    156						b_w = -b_w;
    157						gp.ta.append("コマを置けないため,スキップし,\n");
    158						if (gp.mp.method == 1 && b_w < 0)
    159							gp.ta.append("あなた(黒)の番です.\n");
    160						else if (gp.mp.method == 2 && b_w > 0)
    161							gp.ta.append("あなた(白)の番です.\n");
    162						else {
    163							gp.ta.append("コンピュータの番です.\n");
    164							k = computer();   // コマを置く場所の決定
    165							set(k);   // コマを置く
    166						}
    167					}
    168										// 次の手
    169					else {
    170						if (gp.mp.method == 1 && b_w < 0)
    171							gp.ta.append("あなた(黒)の番です.\n");
    172						else if (gp.mp.method == 2 && b_w > 0)
    173							gp.ta.append("あなた(白)の番です.\n");
    174						else {
    175							gp.ta.append("コンピュータの番です.\n");
    176							k = computer();   // コマを置く場所の決定
    177							set(k);   // コマを置く
    178						}
    179					}
    180				}
    181								// 対人間
    182				else {
    183										// スキップの場合
    184					if (!sw) {
    185						gp.ta.append("コマを置けないため,スキップし,\n");
    186						b_w = -b_w;
    187					}
    188										// 次の手
    189					if (b_w < 0)
    190						gp.ta.append("黒の番です.\n");
    191					else
    192						gp.ta.append("白の番です.\n");
    193				}
    194			}
    195		}
    196				//
    197				// k[0] 行 k[1] 列に黒または白( b_w )のコマを置いた場合,反転できるコマを探す
    198				//
    199		void r_check(int k[])
    200		{
    201			int d[][] = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}};
    202			n[8] = 0;
    203			if (st[k[0]][k[1]] == 0) {
    204				for (int i1 = 0; i1 < 8; i1++) {
    205					int m1 = k[0], m2 = k[1];
    206					n[i1]  = 0;
    207					int s  = 0;   // 0:開始,1:カウント,2:カウント終了,3:反転不可能
    208					int ct = 0;
    209					while (s < 2) {
    210						m1 += d[i1][0];
    211						m2 += d[i1][1];
    212						if (m1 >= 0 && m1 < 8 && m2 >= 0 && m2 < 8) {
    213							if (st[m1][m2] == 0)
    214								s = 3;
    215							else if (st[m1][m2] == b_w) {
    216								if (s == 1)
    217									s = 2;
    218								else
    219									s = 3;
    220							}
    221							else {
    222								s = 1;
    223								ct++;
    224							}
    225						}
    226						else
    227							s = 3;
    228					}
    229					if (s == 2) {
    230						n[8]  += ct;
    231						n[i1]  = ct;
    232					}
    233				}
    234			}
    235		}
    236				//
    237				// k[0] 行 k[1] 列に黒または白( b_w )のコマを置いた場合におけるコマの反転
    238				//
    239		void reverse(int k[])
    240		{
    241			int d[][] = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}};
    242			for (int i1 = 0; i1 < 8; i1++) {
    243				int m1 = k[0], m2 = k[1];
    244				for (int i2 = 0; i2 < n[i1]; i2++) {
    245					m1 += d[i1][0];
    246					m2 += d[i1][1];
    247					km[m1][m2].st = b_w;
    248					st[m1][m2]    = b_w;
    249				}
    250			}
    251			km[k[0]][k[1]].st = b_w;
    252			st[k[0]][k[1]]    = b_w;
    253						// 描画
    254			for (int i1 = 0; i1 < 8; i1++) {
    255				for (int i2 = 0; i2 < 8; i2++) {
    256					if (st[i1][i2] != 0)
    257						km[i1][i2].repaint();
    258				}
    259			}
    260		}
    261				//
    262				// コンピュータが置くコマの場所を決定
    263				//
    264		int [] computer()
    265		{
    266			int k[] = new int [2];
    267			int kk[] = new int [2];
    268			int mx[] = new int [9];
    269			mx[8] = 0;
    270			for (int i1 = 0; i1 < 8; i1++) {
    271				for (int i2 = 0; i2 < 8; i2++) {
    272					kk[0] = i1;
    273					kk[1] = i2;
    274					r_check(kk);
    275					if (n[8] > mx[8]) {
    276						k[0] = kk[0];
    277						k[1] = kk[1];
    278						for (int i3 = 0; i3 < 9; i3++)
    279							mx[i3] = n[i3];
    280					}
    281				}
    282			}
    283			for (int i1 = 0; i1 < 9; i1++)
    284				n[i1] = mx[i1];
    285			return k;
    286		}
    287	}
    			
    053,054 行目

      コンピュータが先手の場合,コンピュータがコマを置く場所を決定するメソッド computer を呼んだ( 053 行目)後,コマを置いた後の処理( 054 行目)を行っています.メソッド computer の内容は,264 行目~ 286 行目に記述してあります.

    077 行目~ 084 行目

      テキストエリアへ出力するメッセージを変更しています.

    116 行目~ 131 行目

      テキストエリアへ出力するメッセージを変更しています.

    153 行目~ 193 行目

      対戦相手がコンピュータの場合,テキストエリアへ出力するメッセージを変更すると共に,人間がスキップする場合(163 行目~ 165 行目),または,人間がコマを置いた場合はその処理を終了した後(175 行目~ 177 行目),コンピュータによる処理を行っています.

    264 行目~ 286 行目

      コンピュータがコマを置く場所を決定するための処理を行っています.ここでは,最も多くコマを反転できる場所を選択し,その位置を配列として返しています.

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