2010年5月6日 星期四

猜數字遊戲 (幾A幾B) C語言短碼程式範例


相信應該大部分的人都玩過幾A幾B的遊戲
話說我在國中、高中都有不少同學都會玩這遊戲
可是我卻不會...也沒興趣去問...直到大一,老師出了一個幾A幾B的程式作業要我們寫
我才知道遊戲怎玩...= =+


到現在大四了,就突然想到這個遊戲
因為資工系也讀了快四年了,對程式概念與邏輯判斷都比大一清楚很多
再加上因為有稍微看了《Short Coding》這本書
所以突然想再重寫一次幾A幾B遊戲程式
而且是盡可能用最短程式碼與最佳執行效率去寫
於是這簡單的小程式竟然花了我一天多的時間才完成
主要原因是在縮短程式碼與執行效率,所以才會寫了一天多的時間
不然只單純完成這程式,其實10幾分鐘就寫出來了

前提:
因為重點在寫出短碼、有效率、能正確執行的方向
所以程式功能我沒去設計太複雜的東西跟錯誤的例外處理
也就是假設使用者輸入時都會乖乖的輸入四位數字,不會亂輸入其他東西等等


程式功能:
純粹叫電腦產生四位不重複的數字(例如2178)
讓玩家去猜出電腦所產生的數字而已
然後限定只能猜10次,每猜一次皆會提示幾A幾B跟剩餘的次數
只要猜對或猜超過次數,直接顯示「猜對了」或者「失敗」的訊息,不再顯示是幾A幾B


所以功能上算很單純,因此有興趣的人可以參考看看小弟寫出來的短碼版程式囉
雖然說是短碼,不過應該還是有更精簡的空間吧...

p.s初學程式的人看我的程式碼可能會有很多地方看不太懂,如有興趣,推薦各位看看《Short Coding》這本書,中文書名是「寫出簡捷好程式-短碼達人的心得技法」,這本比較建議有程式基礎的人看才看得懂唷,這本會讓你對程式技巧更提昇(前提當然是要有足夠的程式基礎)

/*
=== 猜數字遊戲 (幾A幾B) ===
程式作者:Neil
網誌:http://neilchennc.blogspot.tw
日期:2010.05.07
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void)
{
    char cn[5]="",un[5]=""; //cn:電腦數字, un:玩家猜的數字
    int i,j,na,nb,times=10;
    srand(time(NULL));

    puts("===猜數字遊戲===\n程式作者:Neil\n網誌:http://neilchennc.blogspot.com \n\n請輸入四位數字:(例如2178)");
    for(i=0;i<4&&(cn[i]=rand()%10+48);i++) //產生電腦數字
        for(j=0;j<i;j++) cn[j]==cn[i]&&i--; //檢查重複
    do{
        na=nb=i=scanf("%4s",un)&0; fflush(stdin);
        for(;i<4;i++) for(j=0;j<4;j++) un[i]==cn[j]&&(i==j?na++:nb++); //計算幾A幾B
        na-4&&--times&&printf("結果:%dA%dB,還有%d次機會...\n", na,nb,times);
    }while(na-4&&times); //迴圈猜times次
    na==4?puts("您猜對了!"):printf("失敗,猜超過10次,答案是%s\n",cn);
    return system("pause");
}


程式碼與執行檔下載:點我

19 則留言:

  1. 不好意思 可以問一下為什麼 rand()%10 <-(我知道這樣取亂數的範圍是0~9) 為什麼還要+48呢? 然後不加會錯? (而且加其他數也會錯)

    我是新手 如果太笨 請不要笑太大聲~"~

    回覆刪除
  2. 因為rand()%10產生出來的是0~9的數字型態(int)
    而+48是因為對應到ASCII表的字元型態(char)
    48~57分別對應到0~9的字元

    您可以去google查「ASCII」看看囉~

    回覆刪除
  3. 嗯 我知道了謝謝Neil大的指導

    回覆刪除
  4. cn[j]==cn[i]&&i--
    這句實在寫得太妙了!!

    回覆刪除
  5. 大一新生,學C語言2個禮拜(也是要寫這個作業)
    想問問您的想法是不是這樣:
    1.
    cn[j]==cn[i]&&i--; //檢查重複
    把目前的電腦數字全部檢查,若相同且i不是0
    則i減1重新產生

    2.
    for(;i<4;i++) for(j=0;j<4;j++) un[i]==cn[j]&&(i==j?na++:nb++); //計算幾A幾B

    把目前的電腦數字全部檢查,若相同看i和j是不是同個位子
    是: A+1 否: B+1

    3.
    na-4&&--times&&printf("結果:%dA%dB,還有%d次機會...\n", na,nb,times);
    na是4時不會印,其他照印
    且na是4時打破do while roop

    4.
    na==4?puts("您猜對了!"):printf("失敗,猜超過10次,答案是%s\n",cn);
    印出解果

    是這樣嗎?
    如果不是還請指教,畢竟我是新手.....0.0

    回覆刪除
  6. To 5樓:

    沒錯,基本上你講得都對
    因為程式有由左至右判斷的特性
    所以以這行來說
    na-4&&--times&&printf("結果:%dA%dB,還有%d次機會...\n", na,nb,times);
    如果na-4不成立(意思就是na=4),則--times跟printf不會執行
    如果na-4成立,--times不成立,則printf不會執行
    依此類推

    還有要注意的就是--times這是先減1在判斷times是多少
    如果是times--則是先判斷times然後再減1

    回覆刪除
  7. 謝謝版大,不過如果亂排法cn[j]==cn[i]&&i--
    改成4bit型式1234,1235,.....會跑很久
    因為會一直改.............

    #include
    #include
    #include
    #include
    #include
    #define SIZE 4
    using namespace std;

    bool insert(char d[3024][4], char n[9], int c ,int rnd)
    {
    for(int i = 0 ; i<4 ; ++i)
    d[c][i] = n[rnd];
    return true;
    }

    bool modifyNum(char d[3024][4], int count, int check)
    {
    //與自己相同
    bool selfSame = (d[count][0]==d[count][1] ||
    d[count][0]==d[count][2] ||
    d[count][0]==d[count][3] ||
    d[count][1]==d[count][2] ||
    d[count][1]==d[count][3] ||
    d[count][2]==d[count][3]);
    //與別人相同
    bool otherSame = (d[count][0]==d[check][0] &&
    d[count][1]==d[check][1] &&
    d[count][2]==d[check][2] &&
    d[count][3]==d[check][3]);

    if( selfSame || otherSame){
    cout << 1 << endl;
    return true;
    }
    else{
    cout << 0 << endl;
    return false;
    }
    }

    void initialDate(char data[3024][4])
    {
    char num[] = {'1','2','3','4','5','6','7','8','9'};
    int randNum[SIZE] = {-1};


    for(int count = 0 ; count < 9 && insert(data, num, count,rand()%9) ;++count)
    for(int check = 0 ; check < count ; ++check)
    modifyNum(data, count, check) && count--;

    }

    void outPutData(char data[3024][4])
    {
    for(int i=0;i<9;i++){
    for(int j=0;j<4;j++)
    cout << data[i][j];
    cout << endl;
    }
    }

    int main()
    {
    char Memory[3024][4] = {'\0'};
    srand(time(0));
    initialDate(Memory);
    outPutData(Memory);
    system("pause");
    return 0;
    }
    不知道要如何判斷呢?

    回覆刪除
  8. 等等......
    我居然insert一樣的rand()%9

    回覆刪除
  9. 改成這樣OK了,不過有點久@@
    #include
    #include
    #include
    #include
    #include
    #define SIZE 4
    using namespace std;

    bool insert(char d[3024][4], char n[9], int c)
    {
    for(int i = 0 ; i<4 ; ++i)
    d[c][i] = n[rand()%9];
    return true;
    }

    bool modifyNum(char d[3024][4], int count, int check)
    {
    //與自己相同
    bool selfSame = (d[count][0]==d[count][1] ||
    d[count][0]==d[count][2] ||
    d[count][0]==d[count][3] ||
    d[count][1]==d[count][2] ||
    d[count][1]==d[count][3] ||
    d[count][2]==d[count][3]);
    //與別人相同
    bool otherSame = (d[count][0]==d[check][0] &&
    d[count][1]==d[check][1] &&
    d[count][2]==d[check][2] &&
    d[count][3]==d[check][3]);

    if( selfSame || otherSame){
    //cout << 1 << endl;
    return true;
    }
    else{
    //cout << 0 << endl;
    return false;
    }
    }

    void initialData(char data[3024][4])
    {
    char num[] = {'1','2','3','4','5','6','7','8','9'};
    int randNum[SIZE] = {-1};


    for(int count = 0 ; count < 3024 && insert(data, num, count) ;++count)
    for(int check = 0 ; check < count ; ++check)
    modifyNum(data, count, check) && count--;

    }

    void outPutData(char data[3024][4])
    {
    for(int i=0;i<3024;i++){
    for(int j=0;j<4;j++)
    cout << data[i][j];
    cout << endl;
    }
    }

    int main()
    {
    char Memory[3024][4] = {'\0'};
    srand(time(0));
    initialData(Memory);
    outPutData(Memory);
    system("pause");
    return 0;
    }

    回覆刪除
  10. 請問na=nb=i=scanf("%4s",un)&0; fflush(stdin);

    這句話是甚麼意思?

    回覆刪除
  11. #include
    #include
    #include
    stdio.h 和 stdlib.h
    是啥意思

    回覆刪除
  12. C++ 的warning\246 是什麼

    回覆刪除
  13. 大四了~應該是讓電腦去猜別人的數字
    且在5~7次之內猜出來

    回覆刪除
  14. 請問如果內定答案為4801的話要怎麼改?

    回覆刪除
  15. 稍微這樣改如何?
    g:na=nb=i=scanf("%4s",un)&0;
    fflush(stdin);
    for(;i<4;i++) for(j=0;j<4;j++)
    if(un[i]==un[j]&&i!=j) {printf("不合法數字!請重新輸入!\n");goto g;}
    for(i=0;i<4;i++) for(j=0;j<4;j++) un[i]==cn[j]&&(i==j?na++:nb++); //計算幾A幾B

    回覆刪除
  16. 請問如何讓輸入的數字 出現在冒號後面

    回覆刪除
    回覆
    1. 想請問怎麼轉寫成流程圖?謝謝你

      刪除
    2. 想請問怎麼轉寫成流程圖?謝謝你

      刪除