【初心者向け】Javaでゲームを作るための5つのステップ

2023.01.28
Javaでゲームを作るための5つのステップ

Javaプログラミングの勉強をしていて、自身のモチベーション維持になるのはやはり成果が目に見えた時ではないでしょうか。
成果が目に見える、それはアプリケーション開発だと思います。
大小の違いはあれど、自分が思った通りの動きをするアプリの動作を見た時はやはり感慨深いものがあります。

そんなアプリの中でも、ゲームプログラミングですと更に意欲が沸くという人も多いのではないでしょうか。
ゲームはプレイするものですが、プログラミング学習を始めた方にとっては、作るものにもなり得ます。

ここでは、ゲームプログラミングを学ぶため、みなさんもご存じの「オセロ」ゲームをJavaアプレットで作成します。

対戦相手を人間またはコンピュータとするオセロを作成します。
なお,作成手順としては,まず人間対人間のゲームを完成させて、その後対戦相手をコンピュータにした場合に必要な機能を付加します

この流れを説明していくことで理解を深めていただければと思います。

プログラミングをゲームで学びたい方は下記の記事をお読みください。

プログラミングをゲーム感覚で学べる学習サイト7選【ゲーム作成したい方も】

Javaでどんなことができるか

タブレットでJavaを使う人

JavaはOSに依存をしないことからどんな環境でもソフトを動かすことができます。

例えば、今はもう見なくなってきたガラパゴス携帯(ガラケー)でもJavaを使ったアプリケーションを組むことができます。

また、Javaはサーバーサイドでも活躍しています。
サーバーサイドとはサーバー側で動くアプリケーションのことで、Web上のアプリケーションなどが良い例だと思います。
そのような意味ではJavaはWebとも相性が良く、総じていえばどんなものにも搭載されているマルチな言語であるという事ができるでしょう。

そして、今回のメインであるゲームでも、最近だとAndroidOS搭載のスマートフォンでのアプリ開発が一番わかりやすいのではないでしょうか。
また、Oracleの公式サイトでも紹介されていますが、有名ゲームMinecraftもJavaによって作成されています。


「独学でのプログラミング学習に苦戦していませんか?」

独学でのプログラミング学習の挫折率は9割以上と言われています。

プログラミングを身につけて、年収をUPさせたい
ITエンジニアになって、働き方を変えたい
✔生活を変えたいけど、何からやればよいか分からない

と思っているあなたへ向けて、
挫折率9割に負けない「プログラミング学習必勝法」を無料でプレゼントします!

完全無料なので、悩む前に今すぐ下のバナーをクリックして資料を読んでみてください!

\簡単30秒/

下のバナーからLINE友だち追加をして、無料で限定資料をGET!

全体構造を把握する

ゲームを作成する際(他のプログラムでも同様ですが),クラスをほとんど使用せず,すべての動作を一つ又は少数のクラス内に記述することも可能です。
しかしながら,そのような方法で作成すると,プログラムは非常に長くなり,読みにくいものになってしまいます。
プログラムの一部だけを修正する際にも,プログラム全体を理解せざるを得ず,非常に困難な作業になってしまいます。

そこで,ここでは,似たような対象を一つのクラスにまとめ,それらを適当に組み合わせることによってゲームを
作成していきます。このようにすることによって,各クラスに対するプログラムは短く読みやすくなります。

また,ゲームによって共通するクラスは,他のゲームを作成する際にも利用可能になります。
ゲームプログラムのほとんどは,表紙,ゲーム実行画面,終了画面など,そこに描かれている内容は異なりますが
一般に複数の画面(パネル)から構成されています。ゲームの進行と共に,それらのパネルが切り替えられていきます。

この方式は,ほとんどのゲームで共通だと思います。
具体的には、以下に示すような方法で画面の切り替えを制御します。(今回使わない部分も含みます)

画面の切り替え制御

ゲームの枠組み

全体構造を把握した上で、各役割をもつ、枠となるクラスを作成します。

Game クラス ( Game.java )

ゲームの枠となる Game クラスを作成します。

JavaScript
import java.awt.*;
import javax.swing.*;
import java.applet.*;
import java.net.*;
import main.*;

public class Game extends JApplet
{
	// 初期設定
	public void init()
	{
		Dimension size = getSize();   // アプレットの大きさの取得
		size.width  -=10;
		size.height -=10;
		Container CP = getContentPane();   // ContentPane を取得
		CP.setLayout(null); // レイアウトマネージャを停止
		CP.setBackground(new Color(220, 255, 220));   // 背景色
		AppletContext AC = getAppletContext();   // アプレットのコンテキストを取得
		URL CB = getCodeBase();   // HTML ファイルが存在する URL
		MainPanel pn = new MainPanel(AC, CB, size);   // MainPanel オブジェクトの生成
		CP.add(pn);   // MainPanel オブジェクトを ContentPane に追加
		pn.setSize(size.width, size.height);
		pn.setLocation(5, 5);
	}
}

MainPanel クラス ( MainPanel.java )

ゲームの基本画面です。

ゲーム方法を示すフィールド method を追加しています。

JavaScript
package main;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.applet.*;
import java.net.*;
import start.*;
import game.*;

public class MainPanel extends JPanel implements Runnable
{
	AppletContext ac;   // アプレットのコンテキスト
	URL cb;   // HTML ファイルが存在する URL
	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(AppletContext ac1, URL cb1, Dimension size1)
	{
		ac   = ac1;
		cb   = cb1;
		size = size1;
		// グリッドレイアウト
		setLayout(new GridLayout(1, 1, 0, 0));
		// スタートパネルの生成
		sp = new StartPanel(ac, cb, size, this);   // スタート(タイトル)
		add(sp);
		// スレッドの生成
		td = new Thread(this);
		td.start();
	}

	// ゲームの状態を変更
	public void run()
	{
		while (in_game) {
			try {
				td.sleep(1);   // 1 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(ac, cb, size, this);
						add(sp);
					}
					else {   // GamePanel
						gp = new GamePanel(ac, cb, size, this);
						add(gp);
					}
					validate();
					old_state = state;
				}
			}
		}
	}
}

StartPanel クラス (StartPanel.java)

StartPanel クラスでは,「開始」ボタンクリックによるゲーム開始や、ラジオボタンによって対戦方法を選択できるようにしてあります。

ゲームタイトル及び「遊び方」の内容も記載します。

JavaScript
package start;
	
	import java.awt.*;<span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start"></span>
	import java.awt.event.*;
	import javax.swing.*;
	import java.applet.*;
	import java.net.*;
	import main.*;
	
	public class StartPanel extends JPanel implements ActionListener, ItemListener
	{
		boolean in_game = true;
		AppletContext ac;   // アプレットのコンテキスト
		URL cb;   // HTML ファイルが存在する URL
		Dimension size;   // アプレットの大きさ
		MainPanel mp;
		JButton bt, start;
		Checkbox c1, c2, c3;
		// コンストラクタ
		public StartPanel(AppletContext ac1, URL cb1, Dimension size1, MainPanel mp1)
		{
			ac   = ac1;
			cb   = cb1;
			size = size1;
			mp   = mp1;
			// レイアウトマネージャの停止
			setLayout(null);
			// 背景色の設定
			setBackground(Color.white);
			// 「遊び方」ボタンの配置
			Font f = new Font("SansSerif", Font.BOLD, 20);
			FontMetrics fm = getFontMetrics(f);
			String str = "遊び方";
			int w = fm.stringWidth(str) + 40;
			int h = fm.getHeight() + 10;
			bt = new JButton(str);
			bt.setFont(f);
			bt.addActionListener(this);
			bt.setSize(w, h);
			bt.setLocation(size.width/2-w/2, 5);
			add(bt);
			// ラジオボタンの追加
			setFont(f);
			CheckboxGroup cbg = new CheckboxGroup();
			c1 = new Checkbox("対人間", cbg, true);
			w = fm.stringWidth("対人間") + 40;
			c1.setSize(w, h);
			c1.setLocation(20, size.height-3*h);
			c1.addItemListener(this);
			add(c1);
			c2 = new Checkbox("対コンピュータ(人先手)", cbg, false);
			w = fm.stringWidth("対コンピュータ(人先手)") + 40;
			c2.setSize(w, h);
			c2.setLocation(20, size.height-2*h);
			c2.addItemListener(this);
			add(c2);
			c3 = new Checkbox("対コンピュータ(人後手)", cbg, false);
			w = fm.stringWidth("対コンピュータ(人後手)") + 40;
			c3.setSize(w, h);
			c3.setLocation(20, size.height-h);
			c3.addItemListener(this);
			add(c3);
			// 「開始」ボタンの配置
			w = fm.stringWidth("開始") + 40;
			start = new JButton("開始");
			start.setFont(f);
			start.addActionListener(this);
			start.setSize(w, h);
			start.setLocation(size.width-w-20, size.height-2*h);
			add(start);
		}
		// 描画
		public void paintComponent(Graphics g)
		{
			super.paintComponent(g);   // 親クラスの描画
			FontMetrics fm;
			Font f;
			String str;
			int w, h;
	
			f   = new Font("SansSerif", Font.BOLD, 40);
			fm  = g.getFontMetrics(f);
			str = "オセロ";
			w   = fm.stringWidth(str);
			h   = fm.getHeight();
			g.setFont(f);
			g.drawString(str, size.width/2-w/2, size.height/2);
		}
		// ボタンがクリックされたときの処理
		public void actionPerformed(ActionEvent e)
		{
			URL url;
			if (e.getSource() == bt) {
				try {
					url = new URL(cb+"start/method.htm");
					ac.showDocument(url, "method");
					requestFocusInWindow();
				}
				catch (MalformedURLException me)
				{
					System.out.println("Bad URL: method.htm");
				}
			}
			else if (e.getSource() == start)
				mp.state = 1;
		}
		// チェックされたときの処理
		public void itemStateChanged(ItemEvent e)
		{
			if (e.getSource() == c1)
				mp.method = 0;
			else if(e.getSource() == c2)
				mp.method = 1;
			else if(e.getSource() == c3)
				mp.method = 2;
		}
	}

010 行目

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

043 行目~ 062 行目

ラジオボタンの設定です。

「対人間」を選択すると人間同士,「対コンピュータ(人先手)」を選択すると先手が人間で後手がコンピュータ,また,「対コンピュータ(人後手)」を選択すると後手が人間で先手がコンピュータとして,ゲームを実行できます。

ラジオボタンをクリックすると,そのボタンにより,MainPanel のフィールド method の値が設定されます( 108 行目~ 116 行目)。

GamePanel クラス

GamePanel クラスは,実際のゲームを実現するクラスです。

メッセージを出力するテキストエリア,及び,「終了」と「再開」ボタンと共に,オセロを実行する盤となる Bord クラス( Bord.java : 067 行目~ 095 行目)を貼り付けています。

さらに,ボードクラスにはコマを表す Koma クラス( Koma.java : 097 行目~ 112 行目)を貼り付けています。

JavaScript
001       package game;

002

003       import java.awt.*;

004       import java.awt.event.*;

005       import javax.swing.*;

006       import java.applet.*;

007       import java.net.*;

008       import main.*;

009

010       public class GamePanel extends JPanel implements ActionListener

011       {

012                MainPanel mp;

013                JTextArea ta;

014                JButton bt1, bt2;

015                // コンストラクタ

016                public GamePanel(AppletContext ac, URL cb, Dimension size, MainPanel mp1)

017                {

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                          int w = fm.stringWidth("終了<span>") + 40;</span>

027                          int h = fm.getHeight() + 10;

028

029                          bt1 = new JButton("終了<span>");</span>

030                          bt1.setFont(f);

031                          bt1.setSize(w, h);

032                          bt1.setLocation(size.width-w-5, size.height-50-h);

033                          bt1.addActionListener(this);   // アクションリスナ

034                          add(bt1);

035

036                          bt2 = new JButton("再開<span>");</span>

037                          bt2.setFont(f);

038                          bt2.setSize(w, h);

039                          bt2.setLocation(size.width-w-5, size.height-40);

040                          bt2.addActionListener(this);   // アクションリスナ

041                          add(bt2);

042                          // テキストエリアの配置

043                          ta = new JTextArea("黒の番です。<span>\n");</span>

044                          ta.setFont(f);

045                          JScrollPane sp = new JScrollPane(ta);

046                          sp.setSize(size.width-w-10, 90);

047                          sp.setLocation(0, size.height-90);

048                          add(sp);

049                          // オセロ盤の配置

050                          Bord bd = new Bord(size, this);

051                          bd.setSize(size.width, size.width);

052                          bd.setLocation(0, 0);

053                          add(bd);

054                }

055                // ボタンがクリックされたときの処理

056                public void actionPerformed(ActionEvent e)

057                {

058                          bt1.setEnabled(false);

059                          bt2.setEnabled(false);

060                          if (e.getSource() == bt1)   // ゲーム終了

061                                   mp.state = 2;

062                          else   // 最初から再開

063                                   mp.state = 0;

064                }

065       }

066

067       package game;

068

069       import java.awt.*;

070       import javax.swing.*;

071

072       public class Bord extends JPanel

073       {

074                GamePanel gp;

075                Koma km[][] = new Koma [8][8];

076                // コンストラクタ

077                public Bord(Dimension size, GamePanel gp1)

078                {

079                          int width;   // ボタンの大きさ

080                          int gap = 3;   // ボタン間の隙間の幅

081                          gp = gp1;

082                          // グリッドレイアウト

083                          setLayout(new GridLayout(8, 8, gap, gap));

084                          // 背景色の設定

085                          setBackground(new Color(165, 42, 42));

086                          // ボタンの配置

087                          width = (size.width - 9 * gap) / 8;

088                          for (int i1 = 0; i1 < 8; i1++) {

089                                   for (int i2 = 0; i2 < 8; i2++) {

090                                             km[i1][i2] = new Koma(width);

091                                             add(km[i1][i2]);

092                                   }

093                          }

094                }

095       }

096

097       package game;

098

099       import java.awt.*;

100       import javax.swing.*;

101

102       class Koma extends JButton

103       {

104                int width;   // ボタンの幅

105                // コンストラクタ

106                Koma(int width1)

107                {

108                          width = width1;

109                          // 背景色の設定

110                          setBackground(Color.green);

111                }

112       }

024 行目~ 041 行目

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

043 行目~ 048 行目

テキストエリアを作成しています。

JTextArea クラスにはスクロールバーが存在しないため,JScrollPane クラスを利用しています。

テキストエリアには,システムからメッセージが出力されます。

050 行目~ 053 行目

オセロ盤を貼り付けています。

オセロ盤 Bord クラスは,別ファイルにクラスとして定義されています( 067 行目~ 095 行目)。

067 行目~ 095 行目

Bord クラスの定義です。

GridLayout クラスを使用しています( 083 行目)。

その際,要素間の間隔を gap ピクセルに設定し,オセロ盤の枠を表現しています。

グリッドレイアウトの各領域には,他のファイルに定義してある Koma クラス(ボタン)のオブジェクトを

貼り付けています( 087 行目~ 093 行目)。

なお,Koma クラスのオブジェクトは 2 次元配列を使用して表現しています。

097 行目~ 112 行目

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


「プログラミング学習に苦戦しているあなたへ」

独学でのプログラミング学習の挫折率は9割以上と言われています。

プログラミングを身につけて、年収をUPさせたい
ITエンジニアになって、働き方を変えたい
✔生活を変えたいけど、何からやればよいか分からない

と思っているあなたへ向けて、
挫折率9割に負けない「プログラミング学習必勝法」を無料でプレゼントします!

完全無料なので、悩む前に今すぐ下のバナーをクリックして資料をGETしましょう!

\簡単30秒/

下のバナーからLINE友だち追加をして、無料で限定資料をGET!

画像に alt 属性が指定されていません。ファイル名: d77f61a7bf823616a12faf1f70fa44e6-735x300.png

初期状態の表示

ここでは,初期状態におけるコマの配置を表示しています。

Bord.java

ボードを表すクラスです。

JavaScript
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:黒の手番,<span>1:</span>白の手番

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}};   // 盤面の状態(<span>0:</span>コマが置かれてない,<span>-1:</span>黒,<span>1:</span>白)

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.java

コマの情報を制御するクラスです。

JavaScript
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;   // ボタンの状態(<span>0:</span>コマが置かれてない,<span>-1:</span>黒,<span>1:</span>白)

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 行目

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

コマを置く

ここでは,人間対人間の対戦において,コマを置く動作を実現しています。

Bord クラスでは,コマを置く操作を実現します。

その際,コマを置くことができるか否かのチェックや挟まれたコマを反転する操作が必要になります。

Bordクラス

JavaScript
1       package game;

2

3       import java.awt.*;

4       import java.awt.event.*;

5       import javax.swing.*;

6

7       public class Bord extends JPanel implements ActionListener

8       {

9                GamePanel gp;

010                Koma km[][] = new Koma [8][8];

011                int b_w = -1;   // -1:黒の手番,<span>1:</span>白の手番

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}};   // 盤面の状態(<span>0:</span>コマが置かれてない,<span>-1:</span>黒,<span>1:</span>白)

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("黒の番ですが,<span>\n");</span>

074                                   else

075                                             gp.ta.setText("白の番ですが,<span>\n");</span>

076                                   gp.ta.append("そこへはコマを置けません。<span>\n");</span>

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("黒の番です。<span>\n");</span>

093                          else

094                                   gp.ta.setText("白の番です。<span>\n");</span>

095                }

096                //

097                // k[0] 行<span> k[1] </span>列に黒または白(<span> b_w </span>)のコマを置いた場合,反転できるコマを探す

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:開始,<span>1:</span>カウント,<span>2:</span>カウント終了,<span>3:</span>反転不可能

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] 行<span> k[1] </span>列に黒または白(<span> b_w </span>)のコマを置いた場合におけるコマの反転

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       }

7 行目

ボタンをクリックした時の処理を行うため,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 行目

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

勝敗とスキップ

ここでは,勝敗を決定する操作,及び,コマを置く場所が存在しない場合スキップする操作を追加します。

ここまでの処理によって,人間対人間の対戦は完成となります。

修正するプログラムは,Bord クラス( Bord.java )のメソッド set です。

Bordクラス

JavaScript
1       package game;

2

3       import java.awt.*;

4       import java.awt.event.*;

5       import javax.swing.*;

6

7       public class Bord extends JPanel implements ActionListener

8       {

9                GamePanel gp;

010                Koma km[][] = new Koma [8][8];

011                int b_w = -1;   // -1:黒の手番,<span>1:</span>白の手番

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}};   // 盤面の状態(<span>0:</span>コマが置かれてない,<span>-1:</span>黒,<span>1:</span>白)

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("黒の番ですが,<span>\n");</span>

074                                   else

075                                             gp.ta.setText("白の番ですが,<span>\n");</span>

076                                   gp.ta.append("そこへはコマを置けません。<span>\n");</span>

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("黒<span> " + b + " </span>個, 白<span> " + w + " </span>個<span>\n");</span>

107                                   if (b > w)

108                                             gp.ta.append("黒の勝ちです。<span>\n");</span>

109                                   else if (b == w)

110                                             gp.ta.append("引き分けです。<span>\n");</span>

111                                   else

112                                             gp.ta.append("白の勝ちです。<span>\n");</span>

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("黒<span> " + b + " </span>個, 白<span> " + w + " </span>個<span>\n");</span>

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("コマを置けないため,スキップし,<span>\n");</span>

136                                             b_w = -b_w;

137                                   }

138                                    // 次の手

139                                   if (b_w < 0)

140                                             gp.ta.append("黒の番です。<span>\n");</span>

141                                   else

142                                             gp.ta.append("白の番です。<span>\n");</span>

143                          }

144                }

145                //

146                // k[0] 行<span> k[1] </span>列に黒または白(<span> b_w </span>)のコマを置いた場合,反転できるコマを探す

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:開始,<span>1:</span>カウント,<span>2:</span>カウント終了,<span>3:</span>反転不可能

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] 行<span> k[1] </span>列に黒または白(<span> b_w </span>)のコマを置いた場合におけるコマの反転

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       }

088 行目~ 102 行目

コマを反転し( 088 合目),手番を変更した( 089 行目)後,黒及び白のコマを数えています。

104 行目~ 117 行目

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

120,121 行目

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

123 行目~ 132 行目

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

134 行目~ 137 行目

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

完成

ここでは,コンピュータがコマを置く場所を決定する処理を加え,ゲームを完成します。
コンピュータのアルゴリズムを強化すれば強いオセロになりますが,今回は,最も多くのコマを反転できる場所を選択するようにしています。

修正するプログラムは,GamePanel クラス( GamePanel.java )と Bord クラス( Bord.java )です。
GamePanel クラスにおける変更は,43 行目~ 49 行目に示すテキストエリアに対する出力の変更だけです。

GamePanel クラス

JavaScript
01        package game;

02

03        import java.awt.*;

04        import java.awt.event.*;

05        import javax.swing.*;

06        import java.applet.*;

07        import java.net.*;

08        import main.*;

09

10        public class GamePanel extends JPanel implements ActionListener

11        {

12                 MainPanel mp;

13                 JTextArea ta;

14                 JButton bt1, bt2;

15                 // コンストラクタ

16                 public GamePanel(AppletContext ac, URL cb, Dimension size, MainPanel mp1)

17                 {

18                           mp = mp1;

19                           // レイアウトマネージャの停止

20                           setLayout(null);

21                           // 背景色の設定

22                           setBackground(Color.white);

23                           // ボタンの配置

24                           Font f = new Font("SansSerif", Font.BOLD, 20);

25                           FontMetrics fm = getFontMetrics(f);

26                           int w = fm.stringWidth("終了<span>") + 40;</span>

27                           int h = fm.getHeight() + 10;

28

29                           bt1 = new JButton("終了<span>");</span>

30                           bt1.setFont(f);

31                           bt1.setSize(w, h);

32                           bt1.setLocation(size.width-w-5, size.height-50-h);

33                           bt1.addActionListener(this);   // アクションリスナ

34                           add(bt1);

35

36                           bt2 = new JButton("再開<span>");</span>

37                           bt2.setFont(f);

38                           bt2.setSize(w, h);

39                           bt2.setLocation(size.width-w-5, size.height-40);

40                           bt2.addActionListener(this);   // アクションリスナ

41                           add(bt2);

42                           // テキストエリアの配置

43                           String str;

44                           if (mp.method == 0)

45                                    str = "黒の番です。<span>\n";</span>

46                           else if (mp.method == 1)

47                                    str = "あなた(黒)の番です。<span>\n";</span>

48                           else

49                                    str = "コンピュータの番です。<span>\n";</span>

50                           ta = new JTextArea(str);

51                           ta.setFont(f);

52                           JScrollPane sp = new JScrollPane(ta);

53                           sp.setSize(size.width-w-10, 90);

54                           sp.setLocation(0, size.height-90);

55                           add(sp);

56                           // オセロ盤の配置

57                           Bord bd = new Bord(size, this);

58                           bd.setSize(size.width, size.width);

59                           bd.setLocation(0, 0);

60                           add(bd);

61                 }

62                 // ボタンがクリックされたときの処理

63                 public void actionPerformed(ActionEvent e)

64                 {

65                           bt1.setEnabled(false);

66                           bt2.setEnabled(false);

67                           if (e.getSource() == bt1)   // ゲーム終了

68                                    mp.state = 2;

69                           else   // 最初から再開

70                                    mp.state = 0;

71                 }

72        }

Bord クラス

JavaScript
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:黒の手番,<span>1:</span>白の手番

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}};   // 盤面の状態(<span>0:</span>コマが置かれてない,<span>-1:</span>黒,<span>1:</span>白)

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("あなたの番ですが,<span>\n");</span>

079                                   else {

080                                             if (b_w < 0)

081                                                       gp.ta.setText("黒の番ですが,<span>\n");</span>

082                                             else

083                                                       gp.ta.setText("白の番ですが,<span>\n");</span>

084                                   }

085                                   gp.ta.append("そこへはコマを置けません。<span>\n");</span>

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("黒<span> " + b + " </span>個, 白<span> " + w + " </span>個<span>\n");</span>

116                                   if (gp.mp.method > 0) {

117                                             if (b == w)

118                                                       gp.ta.append("引き分けです。<span>\n");</span>

119                                             else if (b > w && gp.mp.method == 1 || b < w && gp.mp.method == 2)

120                                                       gp.ta.append("あなたの勝ちです。<span>\n");</span>

121                                             else

122                                                       gp.ta.append("コンピュータの勝ちです。<span>\n");</span>

123                                   }

124                                   else {

125                                             if (b > w)

126                                                       gp.ta.append("黒の勝ちです。<span>\n");</span>

127                                             else if (b == w)

128                                                       gp.ta.append("引き分けです。<span>\n");</span>

129                                             else

130                                                       gp.ta.append("白の勝ちです。<span>\n");</span>

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("黒<span> " + b + " </span>個, 白<span> " + w + " </span>個<span>\n");</span>

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("コマを置けないため,スキップし,<span>\n");</span>

158                                                       if (gp.mp.method == 1 && b_w < 0)

159                                                                gp.ta.append("あなた(黒)の番です。<span>\n");</span>

160                                                       else if (gp.mp.method == 2 && b_w > 0)

161                                                                gp.ta.append("あなた(白)の番です。<span>\n");</span>

162                                                       else {

163                                                                gp.ta.append("コンピュータの番です。<span>\n");</span>

164                                                                k = computer();   // コマを置く場所の決定

165                                                                set(k);   // コマを置く

166                                                       }

167                                             }

168                                             // 次の手

169                                             else {

170                                                       if (gp.mp.method == 1 && b_w < 0)

171                                                                gp.ta.append("あなた(黒)の番です。<span>\n");</span>

172                                                       else if (gp.mp.method == 2 && b_w > 0)

173                                                                gp.ta.append("あなた(白)の番です。<span>\n");</span>

174                                                       else {

175                                                                gp.ta.append("コンピュータの番です。<span>\n");</span>

176                                                                k = computer();   // コマを置く場所の決定

177                                                                set(k);   // コマを置く

178                                                       }

179                                             }

180                                   }

181                                   // 対人間

182                                   else {

183                                             // スキップの場合

184                                             if (!sw) {

185                                                       gp.ta.append("コマを置けないため,スキップし,<span>\n");</span>

186                                                       b_w = -b_w;

187                                             }

188                                             // 次の手

189                                             if (b_w < 0)

190                                                       gp.ta.append("黒の番です。<span>\n");</span>

191                                             else

192                                                       gp.ta.append("白の番です。<span>\n");</span>

193                                   }

194                          }

195                }

196                //

197                // k[0] 行<span> k[1] </span>列に黒または白(<span> b_w </span>)のコマを置いた場合,反転できるコマを探す

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:開始,<span>1:</span>カウント,<span>2:</span>カウント終了,<span>3:</span>反転不可能

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] 行<span> k[1] </span>列に黒または白(<span> b_w </span>)のコマを置いた場合におけるコマの反転

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 行目に記述してあります。

076 行目~ 086 行目

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

116 行目~ 131 行目

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

155 行目~ 179 行目

対戦相手がコンピュータの場合,テキストエリアへ出力するメッセージを変更すると共に,人間がスキップする場合(163 行目~ 165 行目)

または,人間がコマを置いた場合はその処理を終了した後(175 行目~ 177 行目),コンピュータによる処理を行っています。

264 行目~ 286 行目

コンピュータがコマを置く場所を決定するための処理を行っています。

ここでは,最も多くコマを反転できる場所を選択し,その位置を配列として返しています。

まとめ

いかがでしたでしょうか。
オセロ自体はみなさんもルールをよく知っており、ゲームルールとしては簡単な部類に入るかと思います。
しかし、いざプログラミングするとなると、枠の準備から役割毎のクラス分割など、プログラミングの練習にはうってつけのような内容です。
ただ、オセロゲームという自身が良く理解しているものを実現するということもあり
問題点の解決などは思考も柔軟に働く利点があるかと思います。

オセロに限らず、身近なゲームから複雑なものまでぜひ設計から悩みながら挑戦してみてください。

関連記事

資料請求

  • 短期集中で最速エンジニア転職を実現-転職成功者インタビュー一覧

    DMM WEBCAMPでは転職成功率98%を実現しています。本資料では、元警察官や元ラーメン屋など様々なバックグラウンドを持つ卒業生の声をお届けします。

    資料をダウンロードする
  • IT技術がもたらす3つの変化と身につけるべきスキル

    IT技術の発展により、今後10~20年程度で47%の仕事がなくなると言われています。どのような変化が訪れ、私達はどのようなスキルを身につけるべきかを解説します。

    資料をダウンロードする
  • 未経験がフリーランスエンジニアになる方法-年収アップで自由な働き方を手に入れる

    働き方改革やリモートワークの影響でフリーランスという働き方の人気は高まりつつあります。フリーランスエンジニアとして活躍するために必要な情報をお届けします。

    資料をダウンロードする

© 2023 WEBCAMP MEDIA Powered by AFFINGER5