はじめに
一通りプログラムの文法を覚えたら、皆さんはどうしていますか? いきなり大掛かりなものには取り掛かれませんから、何かちょっとした物を作ろうとするのではないでしょうか? しかし、プログラミング経験が豊富な人ならともかく、ほとんど経験の無い人の場合、そもそも何を作ってよいのかが分からない、分からないから書けない、という無限ループになりがちです。そこで今回は、「CodeBreaker」という数当てゲームを題材にし、main
メソッドにべた書きの状態から、GUIを使ったアプリケーションにしていく過程を追ってみます。初心者の方のお役に立てば幸いです。
対象読者
一通りJavaの文法の基礎を習得した人。ちょっとしたプログラムを作ってみたいが、良い課題が見つからない人。
必要な環境
J2SE1.4以上。開発環境としてEclipseを使っていますが、他の開発環境でも構いません。
構想
何をするにも、まずは作るものを決めなければ話になりません。いろいろ作ってみたい物はあるでしょう。ただ、初めから大きな物を作ろうと張り切ると、途中で気力が尽きてしまいます。特に初めての方は「さぁ、すごいの作ってやる」と意気込みすぎてしまい、「もういいや」と投げ出してしまうようです。
今回は、そんな事にならないように小粒な課題を選びました。だからと言って、作って2度と触らないような物だと、それはそれでつまりません。いろいろ考えた結果、昔から好きだったミニゲーム、CodeBreakerを題材に選びました。
何を作るのか
今回作成するCodeBreakerは、3桁の数字を当てるだけの単純なゲームです。「Hit&Blow」とも呼ばれています。皆さんの中には、コンシューマRPGの中のミニゲームで遊んだ経験のある人もいるのではないでしょうか。
ルールは、
- 数字は3つ
- 1つの数字は1~6の範囲を持つ
- 数字はそれぞれ別であり、重複しない
- 入力した数字が答えの中にあり、場所もあっている場合にはヒットとして数える
- 入力した数字が答えの中にあるが、場所はあってない場合ブローとして数える
- 3つの数字すべてがヒットになったら、ゲームクリア
以上のようになっています。
どう作るのか
最終的には、GUIで遊べるようにします。しかし、最初からGUIで作っていくことは難しいため、次の5段階に分けて作成していきます。
main
メソッドに擬似コードでCUI版ゲームの流れを書く- 擬似コードを実際のコードに置き換える
main
メソッドにべた書きの状態だったコードを、「GameEngine」クラスとして抽出、再利用できるようにする- GUIの外装を作成
- 外装に「GameEngine」クラスをはめ込み、動くようにする
ここでのポイントは、1.の擬似コードです。ここで紙上デバッグなどを行い、ソフトの動作する流れをしっかり頭に入れる事が重要です。次にある「どんな動きをするか」「どんな機能が必要か」の項目は、流れを整理し、擬似コードを書くために必要な工程です。一人で取り掛かっても確実にできるように、しっかり考えてください。
どんな動きをするか
早速作ってみたいところですが、そこをぐっと我慢します。まず最初に、このソフトがどんな動きをするのか想像してみましょう。どんな表示をし、どんな入力が必要で、どんな反応を返すのかが思いつかない状態では、ソフトを作ることは難しいでしょう。
入出力 | 動作内容 |
出力 | 最初にタイトルとルール説明 |
入力 | 3つの数字の入力 |
出力 | 入力した数字に対する結果の表示 |
出力 | 3つともヒットならゲームクリア |
出力 | ゲームクリアでなかったら、次の数字の入力を促す |
どんな機能が必要か
次にどのような機能がこのCodeBreakerに必要なのか考えてみましょう。先ほどあげた動きを実現するには、どのような機能が必要でしょう?
- タイトルとルールの表示
- 答えの生成
- 入力した数字の保持
- ヒット、ブローの判定
- ゲームクリアの判定
大まかに考えて、上のような機能が必要となるのではないでしょうか。
べた書きしてみる
ようやく実装です。しかし、いきなりコードは書きません。まず擬似コードを書いてからです。サンプルソースコードzipファイルの中の「net.sougetu.zero」パッケージおよび、「first」パッケージのファイルを開きます。
擬似コードの作成
先に挙げた機能を、そのまま擬似コードにしています。擬似コードと言ってもただのコメントです。私の場合、次のようになりました。
package net.sougetu.zero; /** * CodeBreakerZero<br> * シンプルにmainメソッドだけでコードブレイカーを作成します。 * ここでは擬似コードだけ記されている状態です。 * @author ono */ public class CodeBreakerZero { /** * @param args */ public static void main(String[] args) { //変数の初期化。 /*必要な変数 * タイトル、ルール文、答えの格納される配列、 * 入力された数字の格納される配列。 * ヒット数、ブロー数、チャレンジの回数 */ //タイトルとルールの表示 //ランダムな答えを作成。 //ただし、仕様通り、同じ数字がないようにする。 //入力させる。数値のチェックを行う。 //答え判断 //終了判断 ヒットが3つになったら終了 } }
もちろん、これを実行しても何も起きません。
実装
それでは、擬似コードを実際のコードに置き換えていきましょう。
package net.sougetu.first; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * CodeBreakerFirst<br> * シンプルにmainメソッドだけでコードブレイカーを作成します。 * * @author ono */ public class CodeBreakerFirst { /** * @param args */ public static void main(String[] args) { //変数の初期化。 /*必要な変数 * タイトル、ルール文、答えの格納される配列、 * 入力された数字の格納される配列。 * ヒット数、ブロー数、チャレンジの回数 */ String title = "*** CodeBreaker ***";// タイトル String rule = "隠された3つの数字をあてます。\n" + "1つの数字は1から6の間です。\n" + "3つの答えの中に同じ数字はありません。\n" + "入力した数字の、" + "位置と数字が当たってたらヒット、\n" + "数字だけあってたらブローとカウントします。\n" + "全部当てたら(3つともヒットになったら)" + "終了です\n\n"; int[] answer = new int[3];// 答えが入る int[] input = new int[3];// 入力した答えが入る /* * hitはhitのカウント用、blowもblowのカウント用。 * countは何回目のチャレンジかを数えている。 */ int hit = 0, blow = 0, count = 0; //タイトルとルールの表示 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println(title); System.out.println(rule); //ランダムな答えを作成。 //ただし、仕様通り、同じ数字がないようにする。 for (int i = 0; i < answer.length; i++) { //自分より前の要素にかぶるやつがないか確かめる。 //あったらもう1回random boolean flag = false; answer[i] = (int) (Math.random() * 6 + 1); do { flag = false; for (int j = i - 1; j >= 0; j--) { if (answer[i] == answer[j]) { flag = true; answer[i] = (int) (Math.random() * 6 + 1); } } } while (flag == true); } //ゲーム部 while (true) { count++; System.out.println("*** "+count + "回目 ***"); //インプット for (int i = 0; i < answer.length; i++) { System.out.print( (i + 1) + "個目 : "); try { input[i] = Integer.parseInt(br.readLine()); } catch (NumberFormatException e) { System.err.println("数値を入力してください"); i--; } catch (IOException e) { System.err.println("もう一度入力してください"); i--; } } //答え判断 hit = 0; blow = 0; for (int i = 0; i < answer.length; i++) { for (int j = 0; j < answer.length; j++) { if (i == j && input[i] == answer[j]) { hit++; } else if (input[i] == answer[j]) { blow++; } } } //終了判断 ヒットが3つになったら終了 System.out.println("ヒット" + hit + " ブロー" + blow); if (hit == 3) { System.out.println("おめでとー"); break; }else{ System.out.println(); } } } }
非常に単純な形ではありますが、動く物ができました。できはともかく、まずは動いてる物があることは重要です。早速遊んでみましょう。
遊んでいくうちにいろいろと足りない部分が見えてくるとは思いますが、それはこの記事が終わったあと、皆さんの手で拡張してみてください。今回は、目的のGUIまで一直線に突き進んでいきます。