//CowBull.java   -- required haBull.java
/*** CowBull.c   -- 電腦猜人想的 Bull & Cow game
 *          @CopyLeft by tsaiwn@csie.nctu.edu.tw
****************************************/
import java.io.*;
import java.util.*;   // StringTokenizer in this package

class CowBull {
     public static void main(String xx[ ]) {
        new CowBull( );
     }
 CowBull( ) {   // 單機版的 constructor
     prepareIO( );   // 把鍵盤和螢幕 stream 準備好 
     play( );
 }
 CowBull(BufferedReader cin, PrintStream cout, Brother him) {
   this.cin = cin;
   this.cout = cout;
   this.sys = him;    // 指回去正在 run 我的 Brother 
   play( );
 }
      BufferedReader cin;
      PrintStream cout;
      Brother sys;  // who is running me
      String record = " ";
 void putRecord(int guess, int na, int nb) {
    record += " "+guess+"("+na+"A " +nb+"B), ";
 }
 void prepareIO( ) {
    cin = new BufferedReader( 
              new InputStreamReader( System.in ) );
    cout = new PrintStream( System.out);
 }
  ///
       int possible[ ] = new int[5040];    // global variable
       int npsible;    // global variable 記著有幾個可能答案 //
 int rand( ) { return (int) (Math.random( ) * 32767 ); }
// C 程式中原來的 main
int play( ){
       int n, tmp, nguess, nbull, ncow;
       int yn, myGuess;
       //long now= time(0);
       //srand( now &0xffff);    /* randomize, see "man srand" */
      record= " ** " + sys.name + ": ";
      boolean quit = false;    // 不離開, 要繼續玩 :-) 
    while( ! quit ) {
    //again:
       npsible = prepareAnswers( );   // 放在 possible[5040]
       nbull = ncow = nguess = 0;
       while(nbull != 4) {
          // 由所有可能答案中隨便挑一個當 myGuess, 並印出說猜該數 //
           n = rand( ) % npsible;    /* 0.. npsible -1 */
           tmp = possible[0]; possible[0] = possible[n]; possible[n] = tmp;
           myGuess = possible[0];   /* 永遠猜第 0 個比較好寫 */
           cout.printf( "I guess your number" +
                           " is %04d, ... ", myGuess);
           ++nguess;  // 猜的次數
           /// /// 由 user 取得幾A放 nbull, 幾 B 放 ncow
           cout.print("\r\n \t\t  幾 A  幾  B? ");
           nbull = getAB( );
           if(nbull >= 3000) {  // he keyin 2 answers
               nbull = nbull %100;
               ncow = nbull %10;
               nbull = nbull / 10;
           }else if(nbull != 4) {   // 只回答 幾 A, 且不是 4 A
             cout.print("\r \t\t  " + nbull + " A 以及 幾  B? ");
             ncow = getInt( );
           }
           //getAnswer(&nbull, &ncow);
           putRecord(myGuess, nbull, ncow); // proof
           if(nbull == 4){
               if(nguess<5)cout.printf( "才 %d 次", nguess);
               cout.printf("喔 Yeah 我猜到了!\n");
               if(nguess>6)cout.printf("這麼衰..猜了 %d 次!\n", nguess);
               sys.log(3, " -->got "+myGuess+" in "+nguess+" times "
                       + " with " + sys.name);
               break;
           }
           cout.printf("%04d : %d A %d B; ", myGuess, nbull, ncow); ///
           /* 還沒猜對, 把不可能的答案刪除並修正 npsible */
           npsible = reduceAnswers(myGuess, nbull, ncow);
           if(npsible <= 0){
               cout.printf( "You 欺騙我!\n");
               sys.log(5, " -->??? "+myGuess+" in "+nguess+" times "
                       + " cheating by " + sys.name);
               sys.log(5, "    ??? "+record); // proof
               cout.printf("\r 你看: " +record);
               break;
           }
       }
       cout.printf("\r\n\t 要不要繼續玩下一攤(yes, no)? ");
       record= " " + sys.name + ": ";  // reset record
       yn = askPlayAgain();
       if(yn == 0) quit = true;  //goto again;
    }//while(!quit
       cout.printf( "Thank you and Bye!\n");
    return 0;
} // play(
//function to check if the user want to play again
int
askPlayAgain(){    /* return 1 if he/she said YES */
    String tmp="no";  //static char tmp[99];
    try {
       tmp = cin.readLine( );  // readLine(tmp);
    }catch(Exception e) { }
    if(tmp.length( ) == 0) return 1;  // 只按 ENTER
    if(tmp.charAt(0) == 'Y' || tmp.charAt(0) == 'y') return 1;
    if(tmp.charAt(0) == 'N' || tmp.charAt(0) == 'n') return 0;
    // if(toupper(tmp[0]) == 'N') return 0;
    cout.printf( "Please type N or Y: ");
    return askPlayAgain();    /* recursively call myself */
}

/// function   prepareAnswers();
int
prepareAnswers(){
      //想辦法 (用四層 for loop ) 把所有可能答案 放在 possible[5040]
      //共有 5040 個, 最小 0123, 最大 9876
      //(因每位不能重複)
     //int * x = possible;    /* 之後 x[0] 就是 possible[0] */
    // 以下是原來給大家的例子
    int p=0, i,k,m,n;
    for(i=0; i<=9; i++){
        for(k=0; k<=9; k++){
            if(k==i) continue;   /* 第二位k與第一位數i相同的都不要 */
            for(m=0; m<=9; m++){
                if(m==k || m==i) continue;
                for(n=0; n<=9; n++){
                   if(n==m || n==k || n==i) continue;
                   possible[p++] = i*1000+k*100+m*10+n;
                }
            }//for m
        }//for k
    }//for i
    return p;
}
/// function reduceAnswers()
int
reduceAnswers(int myGuess, int nbull, int ncow) {
       // 刪除不可能之答案, 並將可能之答案放在 array 前端 //
       // 以下只做刪除不可能之答案 //
       /// 順便把可能答案往 array 前端移 : 留給大家想 ..
       int na=0, nb=0, i;
       int n= 0;  /* possible[0] 是第一個可以蓋掉的 */
             /* 所以由 possible[1] 開始看看有哪些是有可能的就留下來 */
       for(i=1; i< npsible; i++){
             //叫用以前的 checkAnswer(要稍微修正) 比較 myGuess 和 possible[i]
             //以便知道myGuess對於 possible[i]是幾A幾B //
             //若幾A幾B剛好與 nbull 和 ncow 完全相同表示為可能答案 //
             //否則都要消去 //

            int kkk = checkAnswer(myGuess, possible[i], na, nb, i);
            na = kkk/10;  nb = kkk%10;
            if(na == nbull && nb==ncow){
                possible[n] = possible[i];    /*可能的答案移到 array 較前面*/
                ++n;   /* n 指向下一個可蓋掉的元素 possible[n] */
            }
       }//for i
       npsible = n;
       return n;
}
/***
 ***要稍微修正checkAnswer
    因以前是比兩個 array
    現在是比兩個整數, 要先用 %10 的方法拆成四位數 //
 *************************************************/
 int  checkAnswer(int xx, int yy, int na, int nb, int item){
    int x[ ]= new int[4], y[ ] = new int[4], i, j;
    na = nb =0;
    /* 要先把整數拆解成四位個位數 */
    x[0] = xx % 10; y[0] = yy % 10;
    x[1] = (xx %100) /10; y[1] = (yy %100) /10;
    x[2] = (xx /100) %10; y[2] = (yy /100) %10;
    x[3] = xx /1000; y[3] = yy /1000;
    for(i=0; i<=3; i++){
        if(x[i] == y[i]) ++(na);
        for(j=0; j<=3; j++)
           if(i!=j && x[i] == y[j]) ++(nb);
    }//for i
    return na*10 + nb;
 }
 int getInt( ) {
    String s = "000";
    try {
       s = cin.readLine( );
       if(s.length( ) == 0) s = "0"; 
    }catch(Exception e) {  }
    int ans =0;
    //if(s.length( ) == 0) return 0;
    try {
       ans = Integer.parseInt(s);
    }catch(Exception e) { ans = 0; }
    return ans;

 }
 int getAB( ) {  // 問 player 幾 A 幾 B? 若回答 二者, +3000 做區別
    int na=0, nb=0;
    String s = "0";
    try {
       s = cin.readLine( );
       if(s.length( ) == 0 ) s= "0";  // 只有按 ENTER 當作 0
    }catch(Exception e) { s="0"; }
    StringTokenizer stk = new StringTokenizer(s, " ,\t");
    if( stk.hasMoreTokens( ) ) {
        try {
          na = Integer.parseInt( stk.nextToken( ) );
        }catch(Exception e) { na = 0; }
    }
    if( stk.hasMoreTokens( ) ) {  // nb
        try {
          nb = Integer.parseInt( stk.nextToken( ) );
        }catch(Exception e) { nb = 0; }
        na = na*10 + nb + 3000; // indicate 2 answers
    } // 
    return na;   // 若 >= 3000 表示有兩個答案 ?A ? B
 }//getAB(

} // class
