1.プログラミング
前回の内部設計を基に、プログラミングします。
・ModelBS.java
・ViewBS.java
・ControllerBS.java
の3ファイルを作ってみたので、下記に貼り付けます。文字色が黒のみなので見にくいと思いますが、ご了承ください。
----------------------- ModelBS.java ------------------------------
import java.util.*;
public class ModelBS {
//-----------
// メンバ変数
private long lGold = 10; // 所持Gold
private int iPlayTimes = 0; // 挑戦回数
private int iWinningStreak = 0; // 連勝
private long[] lOdds =
{0,2,4,8,16,32,64,128}; // 賭け率(倍率)
private ArrayList<String[]> arrayTop5; // ランキング
//---------------
// コンストラクタ
public ModelBS() {
// ランキングを初期化
ArrayList<String[]> ranking = new ArrayList();
for(int i=0; i<5; i++) {
String[] strPlayerInfo = {"","0"}; // [0]:プレイヤー名、[1]:Gold
ranking.add(strPlayerInfo);
}
// 初期状態のランキングをメンバ変数に設定
this.arrayTop5 = ranking;
}
//-----------------
// 所持Goldのgetter
public long getGold() {
return this.lGold;
}
//-----------------
// 挑戦回数のgetter
public int getPlayTimes() {
return this.iPlayTimes;
}
//-----------------
// 挑戦回数のsetter
public void setPlayTimes(int times) {
this.iPlayTimes = times;
}
//-------------------
// ランキングのgetter
public ArrayList<String[]> getTop5() {
return this.arrayTop5;
}
//-----------
// 乱数を生成
//-----------
// 戻り値
// int[0] : 最初に提示する乱数
// int[1] : 勝負に使う乱数
public int[] getRandomNumber() {
int[] retNum = {0, 0};
Random r = new Random();
// 引数に13を指定すると0~12で乱数生成されるため、+1する
int iFirstNum = r.nextInt(13) + 1;
int iSecondNum;
while((iSecondNum = r.nextInt(13) + 1) == iFirstNum) {
}
retNum[0] = iFirstNum;
retNum[1] = iSecondNum;
return retNum;
}
//-------------------------------------------
// 勝負の判定結果によってGoldの計算などを行う
//-------------------------------------------
// パラメータ
// iRandomNum : 乱数
// strBetGold : betしたGold
// strBS : 入力した大小
// 戻り値
// true : プレイヤーの勝ち
// false : プレイヤーの負け
public boolean calcGold(int[] iRandomNum, String strBetGold, String strBS) {
Integer betGold = new Integer(strBetGold);
boolean retIsWin = isWin(iRandomNum, strBS);
// betした分のGoldを所持Goldから減らす
this.lGold = this.lGold - betGold.longValue();
if(retIsWin) {
// 勝ちの場合は、連勝記録を+1する
this.iWinningStreak++;
this.lGold = this.lGold + betGold.longValue() * lOdds[iWinningStreak];
} else {
// 負けの場合は連勝を0に戻す
this.iWinningStreak = 0;
}
return retIsWin;
}
//-----------------
// 勝負の判定をする
//-----------------
// パラメータ
// iRandomNum : 乱数
// strBS : 入力した大小
// 戻り値
// true : プレイヤーの勝ち
// false : プレイヤーの負け
public boolean isWin(int[] iRandomNum, String strBS) {
boolean retIsWin = false;
boolean isBig = false;
// 最初の乱数と次の乱数を大小比較
if(iRandomNum[0] < iRandomNum[1]) {
isBig = true;
}
if(isBig && strBS.equals("b")) {
// Bigでbを予想したので勝ち
retIsWin = true;
} else if(!isBig && strBS.equals("s")) {
// Smallでsを予想したので勝ち
retIsWin = true;
}
return retIsWin;
}
//---------------------------------
// ランキング入りしたかチェックする
//---------------------------------
public boolean checkRanking() {
boolean isRanking = false;
for(int i=0; i<this.arrayTop5.size(); i++) {
String[] strPlayerInfo = this.arrayTop5.get(i);
Integer rank5Gold = new Integer(strPlayerInfo[1]);
if(this.lGold > rank5Gold.longValue()) {
isRanking = true;
break;
}
}
return isRanking;
}
//---------------------
// ランキングを更新する
//---------------------
public void updateRanking(String strPlayerName) {
boolean isRanking = false;
for(int i=0; i<this.arrayTop5.size(); i++) {
String[] strPlayerInfo = this.arrayTop5.get(i);
Integer rank5Gold = new Integer(strPlayerInfo[1]);
if(this.lGold > rank5Gold.longValue()) {
String[] strNewPlayerInfo = {strPlayerName, String.valueOf(this.lGold)};
// ランキングのリストに追加
this.arrayTop5.add(i, strNewPlayerInfo);
break;
}
}
if(this.arrayTop5.size() == 6) {
// 追加すればリストのサイズは6になっているので、6個目を削除
this.arrayTop5.remove(5);
}
}
//-------------------
// データを初期化する
//-------------------
public void clearData() {
this.lGold = 10;
this.iWinningStreak = 0;
}
}
-------------------------------------------------------------------------
------------------------ ViewBS.java ------------------------------
import java.util.*;
import java.text.*;
public class ViewBS {
//-------------------------
// ゲームタイトルを表示する
public void displayTitle() {
System.out.println("####################");
System.out.println("# Big or Small #");
System.out.println("####################");
}
//---------------------
// ランキングを表示する
public void displayRanking(ModelBS model) {
NumberFormat nFormat = NumberFormat.getNumberInstance();
ArrayList<String[]> list = model.getTop5();
System.out.println("ランキング");
for(int i=0; i<list.size(); i++) {
String[] strPlayerInfo = (String[])list.get(i);
Integer gold = new Integer(strPlayerInfo[1]);
StringBuffer strLine = new StringBuffer();
strLine.append(String.valueOf(i+1)).append("位 ");
strLine.append(strPlayerInfo[0]).append(" ");
// 3桁毎にカンマを入れて数字を表示する
strLine.append(nFormat.format(gold.longValue()));
System.out.println(strLine.toString());
}
}
//-------------------
// 所持Goldを表示する
public void displayGold(ModelBS model) {
NumberFormat nFormat = NumberFormat.getNumberInstance();
long lGold = model.getGold();
System.out.println("--------------------");
System.out.print("Gold : ");
System.out.println(nFormat.format(lGold));
System.out.println("--------------------");
}
//---------------------------------
// ゲーム開始のメッセージを表示する
public void displayStartMessage() {
System.out.println("ゲームを始めます。");
}
//---------------------------------
// ゲーム終了のメッセージを表示する
public void displayEndMessage() {
System.out.println("ゲーム終了です。");
}
//--------------------------------------------------------
// 所持Goldが0になったのでゲーム終了のメッセージを表示する
public void displayZeroEndMessage() {
System.out.println("Goldが0になりました。ゲーム終了です。");
}
//-------------------------------
// 最初のランダムな数字を表示する
public void displayFirstNumber(int times, int randomNum) {
System.out.print(times);
System.out.print("回目の挑戦です。数字は");
System.out.print(randomNum);
System.out.println("です。");
}
//--------------------------------------------
// betするGoldを入力させるメッセージを表示する
public void displayBetMessage() {
System.out.print("betするGoldを入力してください : ");
}
//-----------------------------------
// Big or Smallのメッセージを表示する
public void displayBSMessage() {
System.out.print("次に出てくる数字はBig or Small?(bかsを入力) : ");
}
//---------------------
// 勝負の結果を表示する
public void displayResult(boolean isWin, int iSecondNum) {
System.out.print(iSecondNum);
System.out.println("が出ました。");
if(isWin) {
System.out.println("おめでとうございます。あなたの勝ちです。");
} else {
System.out.println("残念。あなたの負けです。");
}
System.out.println("");
}
//-----------------------------
// 再挑戦のメッセージを表示する
public void displayRetryMessage() {
System.out.print("再挑戦しますか?(yかnを入力) : ");
}
//---------------------------------------------
// ランキング入りしたときのメッセージを表示する
public void displayRankinMessage() {
System.out.println("おめでとうございます。ランキング入りしました。");
System.out.print("プレイヤーの名前を入力してください : ");
}
//--------------------------------------------
// betするGoldの入力で数字以外を入力された場合
public void displayWarningNumber() {
System.out.println("数字を入力してください。");
}
//---------------------------------
// 所持Goldよりも多く入力された場合
public void displayWarningGold() {
System.out.println("所持しているGoldを超えています。");
}
//-------------------------
// b, s以外を入力された場合
public void displayWarningBS() {
System.out.println("bかsを入力してください。");
}
//-------------------------
// y, n以外を入力された場合
public void displayWarningYesNo() {
System.out.println("yかnを入力してください。");
}
}
-------------------------------------------------------------------------
------------------ ControllerBS.java ------------------------------
import java.util.*;
public class ControllerBS {
public static void main(String args[]) {
try {
int iMaxTimes = 7; // 7回挑戦する
int iCurrentTimes = 1; // 現在の挑戦回数
Scanner scan = new Scanner(System.in);
ViewBS view = new ViewBS();
ModelBS model = new ModelBS();
view.displayTitle();
view.displayRanking(model);
view.displayGold(model);
view.displayStartMessage();
while(true) {
model.setPlayTimes(iCurrentTimes);
// 乱数を生成
int[] iRandomNum = model.getRandomNumber();
// 最初の数字を表示
view.displayFirstNumber(iCurrentTimes, iRandomNum[0]);
view.displayBetMessage();
// betするGoldを入力
String strBetGold = inputBetGold(model, view, scan);
view.displayBSMessage();
// Big or Smallを入力
String strBS = inputBS(view, scan);
// 勝負の結果を判定してGoldを計算
boolean isWin = model.calcGold(iRandomNum, strBetGold, strBS);
// 勝負の結果を表示
view.displayResult(isWin, iRandomNum[1]);
view.displayGold(model);
iCurrentTimes++;
// 7回の挑戦が終了
if(iCurrentTimes > iMaxTimes) {
view.displayEndMessage();
// ランキングを更新
updateRanking(model, view, scan);
if(isRetry(view, scan)) {
// 1回目から再挑戦
iCurrentTimes = 1;
prepareRetry(model, view);
} else {
// 終了
return;
}
} else if(model.getGold() == 0) {
// 所持Goldが0になったのでゲーム終了
view.displayZeroEndMessage();
if(isRetry(view, scan)) {
// 1回目から再挑戦
iCurrentTimes = 1;
prepareRetry(model, view);
} else {
// 終了
return;
}
}
}
} catch(Exception e) {
System.out.println(e);
}
}
//-----------------------------
// 再挑戦するかどうかを入力する
private static boolean isRetry(ViewBS view, Scanner scan) {
boolean ret = false;
String strRetry;
view.displayRetryMessage();
while(true) {
strRetry = scan.nextLine(); // yかnを入力
if(strRetry.equals("y")) {
// 再挑戦
ret = true;
break;
} else if(strRetry.equals("n")) {
// 終了
break;
} else {
// yとn以外の文字は入力しない
view.displayWarningYesNo();
}
}
return ret;
}
//---------------------------------
// ランキング入りした場合は更新する
private static void updateRanking(ModelBS model, ViewBS view, Scanner scan) {
if(model.checkRanking()) {
view.displayRankinMessage();
// プレイヤーの名前を入力
String strPlayerName = scan.nextLine();
// ランキングを更新
if(strPlayerName.length() > 10) {
model.updateRanking(strPlayerName.substring(0,10));
} else {
model.updateRanking(strPlayerName);
}
view.displayRanking(model);
}
}
//-------------------------
// 再挑戦するので初期化する
private static void prepareRetry(ModelBS model, ViewBS view) {
model.clearData();
view.displayGold(model);
}
//------------------
// betするGoldを入力
private static String inputBetGold(ModelBS model, ViewBS view, Scanner scan) {
String strBetGold;
while(true) {
strBetGold = scan.nextLine();
if(checkGold(model, view, strBetGold)) {
break;
}
}
return strBetGold;
}
//-------------------
// Big or Smallを入力
private static String inputBS(ViewBS view, Scanner scan) {
String strBS;
while(true) {
strBS = scan.nextLine();
if(strBS.equals("b") || strBS.equals("s")) {
break;
} else {
// bとs以外を入力されたので警告
view.displayWarningBS();
}
}
return strBS;
}
//-------------
// 数値チェック
private static boolean isNumber(String strBetGold) {
boolean ret = true;
try {
Integer.parseInt(strBetGold);
} catch(NumberFormatException e) {
ret = false;
}
return ret;
}
//------------------------
// betされたGoldをチェック
private static boolean checkGold(ModelBS model, ViewBS view, String strBetGold) {
boolean ret = true;
if(isNumber(strBetGold)) {
Integer betGold = new Integer(strBetGold);
if(betGold.longValue() > model.getGold()) {
// 所持Goldよりも多いので警告
view.displayWarningGold();
ret = false;
}
} else {
// 数字以外が入力されたので警告
view.displayWarningNumber();
ret = false;
}
return ret;
}
}
-------------------------------------------------------------------------
貼り付けてみると途中で改行されたりで、やっぱり見にくいですね。。。
続いて、プログラムの解説をします。
2.解説
①ModelBSクラス
ランキングの情報や所持Goldなどのデータを管理しています。また、データを利用して大小の予想を判定したり、Goldの計算処理も行っています。
②ViewBSクラス
コマンドプロンプトにメッセージを表示します。System.out.print処理は全てこのクラスで行います。
③ControllerBSクラス
このクラスからゲームの処理が始まります。標準入力から受け取った文字のチェックや、ModelBSやViewBSに処理を指示します。
実際に動かしてみた画像がこちらです。
ランキングもちゃんと表示されています。数回やってみて、最高で200万Gold超えでした。乱数で1や13が出ると勝ったようなものなので、所持Goldを全betして増やすのが当たり前になっていました(笑)また、12が出て次は間違いなくSmallだろうと予想したら13が出たり、2が出て次はBigを予想したら1が出たりしましたので、数字はしっかりランダムに作られているようです。毎回全betして全勝すれば、計算上は20億を超えるはずですので、達成したら感動するかもしれないですね。
次回はこのゲーム作りを振り返ります。