Javaで作る三目並べゲーム【前編】
「Java」プログラミング入門 ゲーム作りで学ぶ基礎から応用まで
初心者がプログラミングを楽しみながら学ぶには、ゲームを題材にすることが有効だ。「Java」を使った「三目並べゲーム」の開発を通じて、Javaプログラミングを学ぼう。
プログラミングの学習はもどかしさを感じることもある。学習にゲームを取り入れて、気分を軽くしてみよう。取り入れる方法の一つとして、ゲームをプログラミングすることがある。プログラミングの教材としてよく使われるゲームには以下がある。
- 数当てゲーム
- じゃんけん
- スネークゲーム
- プレイヤーが成長する線(スネーク)を操作し、障害物や自身の体に衝突しないようにしながら、食べ物を食べてスコアを増やすことを目的としたゲーム。
- スペースインベーダー
- チェッカー
- チェス
本連載は、プログラミング言語・開発環境「Java」で「三目並べゲーム」を作ることを目指す。三目並べゲームのプログラミングは、難易度で言えば中間当たりに位置する。Javaで数当てゲームやじゃんけんゲームを作れる人ならば、難易度は上がるものの三目並べゲームも作れるはずだ。以下では、具体的なサンプルコードを示しながら、ステップに沿ってJavaで三目並べゲームを完成させる方法を解説する。
Javaで三目並べゲームを作ってみよう
ステップ1.「TicTacToe」クラスを作成する
最初に、プログラムのエントリーポイント(実行開始点)を作ろう。そのためには、まず「main」メソッド(処理)を持つ「TicTacToe」というクラスを作成する。クラスとは、メソッドとデータ(フィールド)をまとめた「オブジェクト」の設計図だ。
/* Javaでの三目並べ実装例 */
public class TicTacToe {
public static void main(String[] args)
{
}
}
これから示すソースコードは、TicTacToeクラスのmainメソッド内、またはTicTacToeクラスの一部として宣言されたメソッド内に記述することになる。
ステップ2.必要な変数の宣言
三目並べのゲーム盤にはマスが9個ある。このゲームでは、選択されていないマスそれぞれの番号を表示し、どのマスをマークするのかをプレイヤーに尋ねる。以下に示す配列(同じ型の一連の変数群)「board[]」の各要素は、ゲーム盤にある1つのマスを表す。
char[] board = { '1','2','3',
'4','5','6',
'7','8','9' };
プログラムでは、何個のマスが選択済みなのか、現在どちらのプレイヤーのターンなのかといった情報も継続的に記録する必要がある。9マス全てが選択され、勝者がいない場合は引き分けになる。以下の「numberOfSquaresPlayed」は選択されたマスの数(0~9)、「whoseTurnItIs」は現在ターンを迎えているプレイヤーの記号(1人目が「o」、2人目が「x」)を表す変数だ。
var numberOfSquaresPlayed = 0;
var whoseTurnItIs = 'x';
ステップ3.三目並べのゲーム盤を描画
プレイヤーがマスを選択するたびに、プログラムはゲーム盤を描写する。今回のゲームはコマンドベースのインタフェースで動くシンプルなゲームなので、ゲーム盤の表示は画面のようになり、それほど複雑ではない。
三目並べのゲーム盤を生成してCLIの画面描画するロジックを、以下のように「printTheBoard()」というメソッドに入力しよう。
private static void printTheBoard(char[] board)
{
System.out.println( board[0] + " | " + board[1] + " | " + board[2]);
System.out.println( " - + - + - " );
System.out.println( board[3] + " | " + board[4] + " | " + board[5]);
System.out.println( " - + - + - " );
System.out.println( board[6] + " | " + board[7] + " | " + board[8]);
}
ゲーム盤を最初に描画すると、以下のように数字のみが表示される。
1 | 2 | 3
- + - + -
4 | 5 | 6
- + - + -
7 | 8 | 9
ゲームが進行すると、xとoがボードに記入される。三目並べのJava対戦が終了すると以下のようになる。
x | o | x
- + - + -
x | 5 | o
- + - + -
x | o | 9
ステップ4.プレイヤーに入力させる
次に、numberOfSquaresPlayedが9未満の時は、ゲーム盤の現在の状況をプレイヤーに示してマスを選ばせるロジックを追加する。1行目の「while」は、9マス全てが埋まるまでゲームが続くようにするためのループだ。printTheBoard()で現在のゲーム盤を表示した後、プレイヤーに入力を促す。プレイヤーの入力を受け付ける変数「scanner」は、Javaの「Scanner」クラスのオブジェクト(クラスの実体)として定義する。その後、プレイヤーが選択したマスに、プレイヤーに対応する記号を記録する。
while (numberOfSquaresPlayed < 9)
{
printTheBoard(board);
System.out.printf("記号%sのプレイヤーの番ターンです。マスを選んでください:", whoseTurnItIs);
var scanner = new java.util.Scanner(System.in);
var input = scanner.nextInt();
board[input-1] = whoseTurnItIs;
}
注意点として、配列のインデックスは0から始まる点がある。プレイヤーが入力するのは1~9の数値のうち1つだが、配列のインデックスとして使用するには、その数値から1を引かなければならない。例えばプレイヤーが5番のマスを選択した場合、対応するマスの配列におけるインデックスは4になる。
ステップ5.勝者判定
プレイヤーがマスを選択するごとに、1つの列がそろってゲームの勝敗が決まったかどうかをチェックする。三目並べで勝つには、以下の8通りの方法がある。
- 横1列がそろうパターン×3種類
- 縦1列がそろうパターン×3種類
- 斜めがそろうパターン×2種類
この勝利パターンを判定するために、3つのマスの状態をチェックする「if」文を8回記述するソースコードは、複雑で読みづらい。例えば1段目の列がそろっているかどうかをチェックする条件文は次のようになる。ゲームで勝ったかどうかを判断するためには、こうしたチェックが8回必要になってしまう。
if ((board[0] == whoseTurnItIs) &&
(board[1] == whoseTurnItIs) &&
(board[2] == whoseTurnItIs))
{
System.out.println("あなたの勝ちです! おめでとう!");
break;
}
そこで別の選択肢として、文字を表すための「char」型を整数型として扱うJavaの仕様を使い、勝敗判定のロジックを実装してみよう。
整数型のcharとは
Javaのchar型は、実際には16bitの符号なし整数型だ。 「int」「double」「float」といった、数値型と同じような数学的操作を適用できる。
これを三目並べの勝敗判定に使うには、特定の行にある3つのマス内の文字に相当する文字コードを加算して、その結果がxを3回掛けた内容と等しいかどうかを確認する。もし等しければ、その行にはxが3つそろっていることになる。2人目のプレイヤーの番ターンの時は、同じ処理をoの文字について実行する。
以下は、charの整数型としての性質を利用して、特定の行、列、斜めのラインで1つの記号がそろっているかどうかを判別するロジックだ。
if ( (board[0] + board[1] + board[2] == (whoseTurnItIs * 3)) // 1行目
|| (board[3] + board[4] + board[5] == (whoseTurnItIs * 3)) // 2行目
|| (board[6] + board[7] + board[8] == (whoseTurnItIs * 3)) // 3行目
|| (board[0] + board[3] + board[6] == (whoseTurnItIs * 3)) // 1列目
|| (board[1] + board[4] + board[7] == (whoseTurnItIs * 3)) // 2列目
|| (board[2] + board[5] + board[8] == (whoseTurnItIs * 3)) // 3列目
|| (board[0] + board[4] + board[8] == (whoseTurnItIs * 3)) // 左上から右下への斜めライン
|| (board[2] + board[4] + board[6] == (whoseTurnItIs * 3)) // 右上から左下への斜めライン
)
{
printTheBoard(board);
System.out.println("あなたの勝ちです! おめでとう!");
break;
} else {
numberOfSquaresPlayed++;
whoseTurnItIs = (whoseTurnItIs == 'x') ? 'o' : 'x';
}
ステップ6.交代
勝敗判定で、1つの記号がラインを埋めていることが確認できた場合、そのプレイヤーをたたえてwhileループから脱出する。
printTheBoard(board);
System.out.println("あなたの勝ちです! おめでとう!");
break;
1つの記号がラインを埋めていない場合は、記入済みのマス数を数えるカウンターnumberOfSquaresPlayedを1増やして、プレイヤーを交代する。以下は「三項演算子」を使用して、プレイヤーを交代するロジックを実装した例だ。現在のプレイヤーがxの場合はoのターンに、oの場合はxのターンになる。
numberOfSquaresPlayed++;
whoseTurnItIs = (whoseTurnItIs == 'x') ? 'o' : 'x';
三項演算子は、条件文の結果に基づいて異なる数値を返す演算子だ。「条件式 ? 真の場合の値 : 偽の場合の値」という構文で利用し、if文を簡略化するのに役立つ。上記の三項演算子の用例をif文で記述すると、次のようになる。
if (whoseTurnItIs == 'x')
{
whoseTurnItIs = 'o';
} else {
whoseTurnItIs = 'x';
}
新人の開発者だった当時、私はずっと三項演算子の難解な構文が嫌いだった。Java開発者としての経験を積んだ今でも好きにはなれないが、以前よりも使いこなせていると感じる。
ステップ7.引き分けの処理
9ターン繰り返しても勝者が決まらない場合は、whileループを脱出する。今回は、引き分けを宣言して両者をたたえるようにした。
if (numberOfSquaresPlayed == 9)
{
printTheBoard(board);
System.out.println("引き分け! お疲れさまでした。");
}
ステップ8.プログラムを実行する
全てのソースコードを記入できたら変更を保存し、プログラムを実行する。入力した内容が正しければ、プログラムは問題なく実行される。
ここまでに紹介したソースコードによる三目並べゲームのJavaプログラムは以下の通りだ。なお1行目の「package com.mcnz.vector;」は、このプロジェクトの構造を定義す「パッケージ宣言」だ。ここではプロジェクトを手掛ける組織の種類、組織名、プロジェクト名を示している。
package com.mcnz.vector;
public class TicTacTest {
public static void main(String[] args)
{
char[] board = { '1', '2', '3',
'4', '5', '6',
'7', '8', '9' };
var numberOfSquaresPlayed = 0;
var whoseTurnItIs = 'x';
while (numberOfSquaresPlayed < 9)
{
printTheBoard(board);
System.out.printf("記号%sのプレイヤーの番ターンです。マスを選んでください:", whoseTurnItIs);
var scanner = new java.util.Scanner(System.in);
var input = scanner.nextInt();
board[input - 1] = whoseTurnItIs;
if ( (board[0] + board[1] + board[2] == (whoseTurnItIs * 3)) // 1行目
|| (board[3] + board[4] + board[5] == (whoseTurnItIs * 3)) // 2行目
|| (board[6] + board[7] + board[8] == (whoseTurnItIs * 3)) // 3行目
|| (board[0] + board[3] + board[6] == (whoseTurnItIs * 3)) // 1列目
|| (board[1] + board[4] + board[7] == (whoseTurnItIs * 3)) // 2列目
|| (board[2] + board[5] + board[8] == (whoseTurnItIs * 3)) // 3列目
|| (board[0] + board[4] + board[8] == (whoseTurnItIs * 3)) // 左上から右下への斜めライン
|| (board[2] + board[4] + board[6] == (whoseTurnItIs * 3)) // 右上から左下への斜めライン
)
{
printTheBoard(board);
System.out.println("あなたの勝ちです! おめでとう!");
break;
} else {
numberOfSquaresPlayed++;
whoseTurnItIs = (whoseTurnItIs == 'x') ? 'o' : 'x';
}
}
}
private static void printTheBoard(char[] board)
{
System.out.printf("%n %s | %s | %s %n", board[0], board[1], board[2]);
System.out.println(" - + - + - ");
System.out.printf(" %s | %s | %s %n", board[3], board[4], board[5]);
System.out.println(" - + - + - ");
System.out.printf(" %s | %s | %s %n%n", board[6], board[7], board[8]);
}
}
次回は、さらなる学習のために三目並べゲームの改良案を紹介する。
TechTarget発 エンジニア虎の巻
米国TechTargetの豊富な記事の中から、開発のノウハウや技術知識など、ITエンジニアの問題解決に役立つ情報を厳選してお届けします。
Copyright © ITmedia, Inc. All Rights Reserved.
TechTarget発 エンジニア虎の巻
米国TechTargetの豊富な記事の中から、開発のノウハウや技術知識など、ITエンジニアの問題解決に役立つ情報を厳選してお届けします。
この記事の著者
関連記事
新着ホワイトペーパー PR
-
技術文書・技術解説
[Jamf Japan 合同会社] MDMだけでモバイルセキュリティは十分? 不足する対策を16項目でチェック -
事例
[Wrike Japan 株式会社] 世界的な家電メーカーが実践する「クリエイティブプロセス効率化」の方法とは? -
事例
[Wrike Japan 株式会社] 世界的テクノロジー企業に学ぶ、プロセス標準化とプロジェクト納品自動化の秘訣 -
事例
[Wrike Japan 株式会社] ソニー・ピクチャーズ テレビジョンに学ぶ、次世代サービスデリバリーのヒント -
事例
[Wrike Japan 株式会社] ソミック石川に学ぶ、ICT浸透後に直面した「工数管理」の課題と解決策
こんなメディアも見られています
TechTargetジャパンに関連する情報をお探しであれば、こちらのメディアもお役に立てるかもしれません。
ベンダーコンテンツ PR
From Informa TechTarget
SpecialPR
アクセスランキング
-
1
「データストレージの活用方法」に関するアンケート
-
2
脱VMwareの前提が崩れる BroadcomのVDDK公開停止で確認すべき点
-
3
「Microsoft 365」が乗っ取られる 跡形もなくMFAを破る手口
-
4
AI全部入り「Microsoft 365 E7」に企業が二の足を踏む訳 移行意向はわずか4%
-
5
【基本情報技術者試験】「デュプレックスシステム」と「デュアルシステム」の違いは?
-
6
「VMware離れ」は本当か 3000社がVCF 9にかじを切った現実的な理由
-
7
100億円の「Linux更新」を回避 みずほ銀行が選んだ“おきて破り”のRHEL延命策
-
8
「Microsoft一択」で本当にいいのか 知らぬ間にライセンス費用が膨らむ真相
-
9
GitHubが指摘 AIが書いた「おそらく動くコード」が招くシステム崩壊
-
10
なぜOpenAIやAnthropicのAIは「脱走」したのか 情シスが迫られるエージェント統制
ホワイトペーパーランキング PR
-
1
生成AIのハルシネーションを防止 回答精度を高めるセマンティックレイヤーとは
-
2
5回聞くだけじゃ足りない? トヨタ式「なぜなぜ分析」の正しい実践方法
-
3
AIエージェントで多様な日常業務を効率化するための入門ガイド
-
4
インシデント対応工数を約3割削減、東京ガスの事例に学ぶ監視体制刷新のコツ
-
5
「脱Excel」か「Excel快適化」か? 現場にやさしい業務改善の進め方
-
6
マンガで解説:「ゼロトラスト」「SASE」の必要性とメリット
-
7
5分で分かる「セキュア大容量ファイル転送サービス」の機能とメリット
-
8
情報セキュリティ対策早分かりガイド:25の自社診断で弱点と解決策を理解
-
9
国税庁の次世代基幹システム「KSK2」稼働開始に向けて、対応すべき変更点とは?
-
10
AIが「わざわざ使うツール」になっていない? 業務で自然に使う導線にする秘訣
TechTargetジャパン SNS
インフォメーション
注目情報をチェック
TechTargetジャパンをフォロー