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

Javaプログラミングの勉強をしていて、自身のモチベーション維持になるのはやはり成果が目に見えた時ではないでしょうか。
成果が目に見える、それはアプリケーション開発だと思います。
大小の違いはあれど、自分が思った通りの動きをするアプリの動作を見た時はやはり感慨深いものがあります。
そんなアプリの中でも、ゲームプログラミングですと更に意欲が沸くという人も多いのではないでしょうか。
ゲームはプレイするものですが、プログラミング学習を始めた方にとっては、作るものにもなり得ます。
ここでは、ゲームプログラミングを学ぶため、みなさんもご存じの「オセロ」ゲームをJavaアプレットで作成します。
対戦相手を人間またはコンピュータとするオセロを作成します。
なお,作成手順としては,まず人間対人間のゲームを完成させて、その後対戦相手をコンピュータにした場合に必要な機能を付加します
この流れを説明していくことで理解を深めていただければと思います。
プログラミングをゲームで学びたい方は下記の記事をお読みください。
Javaでどんなことができるか
JavaはOSに依存をしないことからどんな環境でもソフトを動かすことができます。
例えば、今はもう見なくなってきたガラパゴス携帯(ガラケー)でもJavaを使ったアプリケーションを組むことができます。
また、Javaはサーバーサイドでも活躍しています。
サーバーサイドとはサーバー側で動くアプリケーションのことで、Web上のアプリケーションなどが良い例だと思います。
そのような意味ではJavaはWebとも相性が良く、総じていえばどんなものにも搭載されているマルチな言語であるという事ができるでしょう。
そして、今回のメインであるゲームでも、最近だとAndroidOS搭載のスマートフォンでのアプリ開発が一番わかりやすいのではないでしょうか。
また、Oracleの公式サイトでも紹介されていますが、有名ゲームMinecraftもJavaによって作成されています。
「独学でのプログラミング学習に苦戦していませんか?」
独学でのプログラミング学習の挫折率は9割以上と言われています。
✔プログラミングを身につけて、年収をUPさせたい
✔ITエンジニアになって、働き方を変えたい
✔生活を変えたいけど、何からやればよいか分からない
と思っているあなたへ向けて、
挫折率9割に負けない「プログラミング学習必勝法」を無料でプレゼントします!
完全無料なので、悩む前に今すぐ下のバナーをクリックして資料を読んでみてください!
\簡単30秒/
下のバナーからLINE友だち追加をして、無料で限定資料をGET!

全体構造を把握する
ゲームを作成する際(他のプログラムでも同様ですが),クラスをほとんど使用せず,すべての動作を一つ又は少数のクラス内に記述することも可能です。
しかしながら,そのような方法で作成すると,プログラムは非常に長くなり,読みにくいものになってしまいます。
プログラムの一部だけを修正する際にも,プログラム全体を理解せざるを得ず,非常に困難な作業になってしまいます。
そこで,ここでは,似たような対象を一つのクラスにまとめ,それらを適当に組み合わせることによってゲームを
作成していきます。このようにすることによって,各クラスに対するプログラムは短く読みやすくなります。
また,ゲームによって共通するクラスは,他のゲームを作成する際にも利用可能になります。
ゲームプログラムのほとんどは,表紙,ゲーム実行画面,終了画面など,そこに描かれている内容は異なりますが
一般に複数の画面(パネル)から構成されています。ゲームの進行と共に,それらのパネルが切り替えられていきます。
この方式は,ほとんどのゲームで共通だと思います。
具体的には、以下に示すような方法で画面の切り替えを制御します。(今回使わない部分も含みます)
ゲームの枠組み
全体構造を把握した上で、各役割をもつ、枠となるクラスを作成します。
Game クラス ( Game.java )
ゲームの枠となる Game クラスを作成します。
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 を追加しています。
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 クラスでは,「開始」ボタンクリックによるゲーム開始や、ラジオボタンによって対戦方法を選択できるようにしてあります。
ゲームタイトル及び「遊び方」の内容も記載します。
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 行目)を貼り付けています。
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!

初期状態の表示
ここでは,初期状態におけるコマの配置を表示しています。
Bord.java
ボードを表すクラスです。
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
コマの情報を制御するクラスです。
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クラス
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クラス
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 クラス
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 クラス
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 行目
コンピュータがコマを置く場所を決定するための処理を行っています。
ここでは,最も多くコマを反転できる場所を選択し,その位置を配列として返しています。
まとめ
いかがでしたでしょうか。
オセロ自体はみなさんもルールをよく知っており、ゲームルールとしては簡単な部類に入るかと思います。
しかし、いざプログラミングするとなると、枠の準備から役割毎のクラス分割など、プログラミングの練習にはうってつけのような内容です。
ただ、オセロゲームという自身が良く理解しているものを実現するということもあり
問題点の解決などは思考も柔軟に働く利点があるかと思います。
オセロに限らず、身近なゲームから複雑なものまでぜひ設計から悩みながら挑戦してみてください。