//cow00.c -- by tsaiwn@csie.nctu.edu.tw //#define DEBUG #include #include #include #include #include #include int possible[5040]; // global variable int npsible; // global variable 記著有幾個可能答案 // int reduceAnswers(int myGuess, int nbull, int ncow); int readLine(char*); void checkAnswer(int xx, int yy, int *na, int *nb, int item); int main(){ int n, tmp, nguess, nbull, ncow; int yn, myGuess; long now= time(0); srand( now &0xffff); /* randomize, see "man srand" */ again: npsible = prepare_all_possible_answer(); // 放在 possible[5040] nbull = ncow = nguess = 0; while(nbull != 4) { #ifdef DEBUG fprintf(stderr, "DEBUG: npsible = %d\n", npsible); #endif // 由所有可能答案中隨便挑一個當 myGuess, 並印出說猜該數 // n = rand() % npsible; /* 0.. npsible -1 */ tmp = possible[0]; possible[0] = possible[n]; possible[n] = tmp; myGuess = possible[0]; /* 永遠猜第 0 個比較好寫 */ fprintf(stderr, "I guess your number" " is %4.4d, 幾A 幾B? ", myGuess); ++nguess; // 猜的次數 // 由 user 取得幾A放 nbull, 幾 B 放 ncow getAnswer(&nbull, &ncow); if(nbull == 4){ if(nguess<5)fprintf(stderr, "才 %d 次", nguess); fprintf(stderr, "喔 Yeah 我猜到了!\n"); if(nguess>6)fprintf(stderr, "這麼衰..猜了 %d 次!\n", nguess); break; } /* 還沒猜對, 把不可能的答案刪除並修正 npsible */ npsible = reduceAnswers(myGuess, nbull, ncow); if(npsible <= 0){ fprintf(stderr, "You 欺騙我!\n"); break; } } fprintf(stderr, "\n要不要繼續玩下一攤(yes, no)? "); yn = askPlayAgain(); if(yn) goto again; fprintf(stderr, "Thank you and Bye!\n"); } //function to check if the user want to play again int askPlayAgain(){ /* return 1 if he/she said YES */ static char tmp[99]; readLine(tmp); if(tmp[0] == 'Y' || *tmp == 'y') return 1; if(toupper(tmp[0]) == 'N') return 0; fprintf(stderr, "Please type N or Y: "); return askPlayAgain(); /* recursively call myself */ } // function to get how many A + how many B from player int getAnswer(int *nbull, int *ncow){ static char tmp[99], i; char *pa, *pb; /* used to make the program more intelegent */ readLine(tmp); pa = strchr(tmp, 'A'); if(pa==0) pa=strchr(tmp, 'a'); pb = strchr(tmp, 'B'); if(pb==0) pb=strchr(tmp, 'b'); if(pa==0 && pb!=0) pa = pb+3; if(pb==0 && pa!=0) pb = pa+3; for(i=0; i< strlen(tmp); i++){ if(tmp[i] == 'A' || tmp[i] == 'a') tmp[i] = ' '; if(tmp[i] == 'B' || tmp[i] == 'b') tmp[i] = ' '; if(tmp[i] == ',' || tmp[i] == ';') tmp[i] = ' '; } *nbull = *ncow = 0; sscanf(tmp, "%d %d", nbull, ncow); /* 注意 nbull, ncow */ if(pa>pb) { i = *nbull; *nbull = *ncow; *ncow = i; } /*swap A, B*/ #ifdef DEBUG fprintf(stderr, "===%d A, %d B\n", *nbull, *ncow); #endif return *nbull; } /// function prepare_all_possible_answer(); int prepare_all_possible_answer(){ //想辦法 (用四層 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; x[p++] = i*1000+k*100+m*10+n; } } } } return p; } /// function reduceAnswers() int reduceAnswers(int myGuess, int nbull, int ncow){ // 刪除不可能之答案, 並將可能之答案放在 array 前端 // // 以下只做刪除不可能之答案 // /// 順便把可能答案往 array 前端移 : 留給大家想 .. int na, nb, 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 完全相同表示為可能答案 // //否則都要消去 // #ifdef DEBUG if(i==1 || i==npsible-1 || i%100 == 0) fprintf(stderr, "DEBUG: %4d) ", i); #endif checkAnswer(myGuess, possible[i], &na, &nb, i); if(na == nbull && nb==ncow){ possible[n] = possible[i]; /*可能的答案移到 array 較前面*/ ++n; /* n 指向下一個可蓋掉的元素 possible[n] */ } } npsible = n; return n; } int readLine(char* p) { int n=0; fgets(p, 88, stdin); while( (p[n] != '\n') && (p[n] != 0) ) ++n; return n; // 共讀到 n 個 char } void checkAnswer(int xx, int yy, int *na, int *nb, int item) { fprintf(stderr, "Not implemented yet !!!\n"); } /*** /// 要稍微修正checkAnswer 因以前是比兩個 array 現在是比兩個整數, 要先用 %10 的方法拆成四位數 // *************************************************/