abstract class Problem{ // 解答集合のサイズを得る abstract int size(); // 解答集合のindex番目を得る abstract String get(int index); // 入力が解答集合の中に含まれているかの判定 boolean isValid(String str){ for(int i=0;i< size();i++){ if(str.equals(get(i))) return true; } return false; } // 問題の最初で出力する文字列 abstract String welcomeMessage(); // 入力と正解との関係を返す文字列の配列 abstract String[] answerStrings(); // 入力と正解との関係を判定する // 0の時は正解 abstract int answerType(String str); // 正解がs1と仮定した時のs2の関係 abstract int answerType(String s1,String s2); }前回の問題にしたがって,Problemのサブクラスとしては,以下のようなもの(HighLowProblem.java)が作れる
// Randomクラスを使うため import java.util.*; // 問題を保持するためのクラス class HighLowProblem extends Problem{ // int n; // 正解の文字列を入れる変数 String answerString; // 解答集合の要素数 int size(){ return n; } // 解答集合のindex番目の要素 String get(int index){ return Integer.toString(index+1); } // コンストラクタ HighLowProblem(int maxN,int index){ n=maxN; if(index< 0){ // 乱数のタネを作る Random r=new Random(); // [0 .. size()-1]の乱数を作って,それを元に解を作る answerString=get(r.nextInt(n)); } else answerString=get(index); } HighLowProblem(int maxN){ this(maxN,-1); } // 判定結果のtype番目の文字列 String[] answerStrings(){ String answers[]={"Correct","VERY LOW","LOW","HIGH","VERY HIGH"}; return answers; } // 正解がaの時に文字列strと比較して,判定結果を返す int answerType(String a,String str){ int answer=Integer.parseInt(a); int x=Integer.parseInt(str); if(answer==x) return 0; else if(x*2<=answer) return 1; else if(x< answer) return 2; else if(answer*2<=x) return 4; else return 3; } // 文字列strと正解を比較して,判定結果を返す int answerType(String str){ return answerType(answerString,str); } // 最初のメッセージ String welcomeMessage(){ return "Guess a number(1-"+n+") "; } }これを使った数当てゲームを遊ぶためのプログラムGameMaster.javaは以下のようになる.
// 入出力をおこなうため import java.io.*; // 問題を出題するためのクラス class GameMaster{ static void master(Problem problem) throws IOException{ BufferedReader d=new BufferedReader(new InputStreamReader(System.in)); int count=1; System.out.println(problem.welcomeMessage()); for(;;){ // キーボードからの一行読み込み String s=d.readLine(); if(!problem.isValid(s)){ System.out.println("Illegal format. Input Again."); continue; } int type=problem.answerType(s); if(type==0)break; System.out.println(problem.answerStrings()[type]); count++; } System.out.println("Correct Answer in "+count); } static public void main(String[] args) throws IOException{ master(new HighLowProblem(10000,-1)); } }まずは,この3つのファイルを保存して,
javac GameMaster.javaを実行してコンパイルし(依存関係のあるファイルは自動的にコンパイルしてくれます).
java GameMasterで想定したように動くことを確認してください.
// Randomを使うため import java.util.*; // class GameSolver{ static int solve(Problem problem){ Random r=new Random(); // index 番目が解である可能性があることを保持 boolean canBeAnswer[]=new boolean[problem.size()]; // 最初はすべて解である可能性がある. for(int i=0;i< problem.size();i++)canBeAnswer[i]=true; for(int count=1;;count++){ int numCanBeAnswer=0; for(int j=0;j< problem.size();j++) if(canBeAnswer[j]) { // numCanBeAnswerを1増やす (1) ; } // kに[0 .. numCanBeAnswer-1]の乱数を入れる int k= (2) ; String nextQuestion=""; for(int j=0;j< problem.size();j++){ if(canBeAnswer[j]){ if(k==0) { // nextQuestionに問題の解集合のj番目を入れる nextQuestion= (3) ; break; } else k--; } } System.out.println(nextQuestion); // 正解と文字列nextQuestion を比較して,判定結果を得る. int type= (4); System.out.println(problem.answerStrings()[type]); if(type==0) return count; for(int j=0;j< problem.size();j++){ if(canBeAnswer[j] && problem.answerType(problem.get(j),nextQuestion)!=type){ // canBeAnswer[j]をfalseにする (5) ; } } } } static public void main(String[] args){ System.out.println(solve(new HighLowProblem(10000,-1))); } }
// Randomを使うため import java.util.*; class MooProblem extends Problem{ String answerString; String mooNumbers[]; int size(){ return 10*9*8*7; } String get(int index){ return mooNumbers[index]; } static void swap(char cs[],int i,int j){ char c=cs[i]; cs[i]=cs[j]; cs[j]=c; } MooProblem(int index){ mooNumbers=new String[size()]; char tmpDigits[]={'0','1','2','3','4','5','6','7','8','9'}; int count=0; for(int i0=0;i0< 10;i0++){ swap(tmpDigits,0,i0); for(int i1=1;i1< 10;i1++){ swap(tmpDigits,1,i1); for(int i2=2;i2< 10;i2++){ swap(tmpDigits,2,i2); for(int i3=3;i3< 10;i3++){ swap(tmpDigits,3,i3); mooNumbers[count]=new String(tmpDigits,0,4); count++; swap(tmpDigits,3,i3); } swap(tmpDigits,2,i2); } swap(tmpDigits,1,i1); } swap(tmpDigits,0,i0); } if(index>=0){ answerString=get(index); } else{ // 乱数のタネを作る Random r=new Random(); // [0 .. size()-1]の乱数を作って,それを元に解を作る answerString=get(r.nextInt(size())); } } MooProblem(){ this(-1); } String welcomeMessage(){ return "Input a MOO number"; } String[] answerStrings(){ String answers[]={"4B0C","","2B2C","1B3C","0B4C", "","3B0C","2B1C","1B2C","0B3C", "","","2B0C","1B1C","0B2C", "","","","1B0C","0B1C", "","","","","0B0C"}; return answers; } // 正解と入力との間のbullを数える int getBull(String a,String s){ int bull=0; for(int i=0;i< 4;i++) if(a.charAt(i)==s.charAt(i)) bull++; return bull; } // 別のMoo数との間のcowを数える int getCow(String a,String s){ int cow=0; for(int i=0;i< 4;i++) for(int j=0;j< 4;j++) if(i!=j && a.charAt(i)==s.charAt(j)){ cow++; break; } return cow; } int answerType(String a,String s){ int bull=getBull(a,s); int cow=getCow(a,s); return (4-(bull+cow))*5+(4-bull); } int answerType(String s){ return answerType(answerString,s); } }これは数当てゲーム MOO に対応したものである.
MOO は, Hit & Blow, Cow & Bull などさまざまな名で呼ばれ, 親しまれて きた数当てゲームである. ゲームのルールは以下のようになっている.