#include //#define TRUE_RANDOM #define xor ^ #define bool int #define MIN_PILE 2 #define MAX_PILE 7 #define MIN_STONE 7 #define MAX_STONE 30 int myrandom(int lower, int upper); void hello(), byebye(); void playNIM(); int main(){ static char yesNo[99]; hello(); while(38){ playNIM(); fprintf(stderr, "Play again (Y,N): "); fgets(yesNo, 99, stdin); if( toupper(yesNo[0]) == 'N') break; } byebye(); } int nPile,takeP,takeN; int pile[MAX_PILE+2]; int userFirst; int lastWin; char tmp99[99]; void prepareStones(); void tellStatus(); bool gameOver(); void userTurn(); void computerTurn(); void playNIM(){ static char yesNo[99]; prepareStones(); tellStatus(); fprintf(stderr, "take last one to "); if(lastWin) fprintf(stderr, "Win!\n"); else fprintf(stderr, "Lose!\n"); userFirst = 1; fprintf(stderr, "Want to go first(Y,N)? "); fgets(yesNo, 99, stdin); if( toupper(yesNo[0]) == 'N') userFirst = 0; if(userFirst) userTurn(); while(49){ if(gameOver()){ /* user takes the last one */ if(lastWin) printf("Congratulations! You win!\n"); else printf("Ahh Ha! I win!\n"); break; } computerTurn(); if(gameOver()){ if(lastWin) printf("Ahh Ha! I win!\n"); else printf("Congratulations! You win!\n"); break; } userTurn(); } /* while(49) */ } /* playNIM */ bool gameOver( ){ int i; int sum = 0; for(i=1; i<= nPile; i++){ sum += pile[i]; } return sum == 0; /* no stones left */ } /*****************/ void prepareStones(){ int i; nPile = myrandom(MIN_PILE, MAX_PILE); for(i=1; i<= nPile; ++i){ pile[i] = myrandom(MIN_STONE, MAX_STONE); } lastWin = 0; if( myrandom(0, 100) > 50) lastWin = 1; /*** sound(400); delay(200); nosound; ***/ } /******/ bool leagleMove(int p, int n){ if(p<1 || p > nPile) return 0; if(n<1 || n > pile[p]) return 0; return 1; } void tellStatus(){ int i, ktemp; printf("There are %d piles of each has ", nPile); for(i=1; i<= nPile; ++i){ printf( " %d", pile[i]); } printf(" stones.\n"); } void userTurn(){ /** make sure the player makes a legal move **/ int i, ktemp; tellStatus(); do { /** sound(400); delay(200); nosound; /*** ***/ printf("Which Pile? "); gets(tmp99); takeP = atoi(tmp99); ktemp = 0; if(leagleMove(takeP, 1) ) ktemp= pile[takeP]; printf("How many stones in this pile?(1..%d) ", ktemp); gets(tmp99); takeN = atoi(tmp99); } while( ! leagleMove(takeP, takeN) ); pile[takeP] -= takeN; return; } /* userTurn */ /***************************/ void computerTurn(){ /* try to win if possible */ int i; takeN = pile[1]; /* assume All stones in 1st pile is OK */ /* first of all, calculate how many stones will the xor result be? */ for(i=2; i<= nPile; ++i) takeN = takeN ^ pile[i]; /* xor */ if( takeN == 0) { /* I can Not win :-< */ /* I am supposed to lose so far. So just take one stone. */ takeP = 1; takeN = pile[takeP]; /* takeN 暫時記住最多幾個stone */ for(i=2; i<=nPile; ++i){ if( pile[i] > takeN){ takeP=i; takeN= pile[takeP]; } } takeN = 1; }else{ /* now decide which pile we can remove some stones to win*/ for(i = nPile; i>=1; --i){ if ( (takeN xor pile[i]) < pile[i] ) takeP=i; } /* now calculate 真正該拿之石頭數 */ takeN = pile[takeP] - (pile[takeP] xor takeN); /***重要***/ } /* if( takeN ==0 ... */ pile[takeP] = pile[takeP] - takeN; fprintf(stderr, "Computer takes %d from pile %d\n", takeN, takeP); return; } void hello(){ fprintf(stderr, "This is an old game of NIM.\n"); fprintf(stderr, "You should pick up at least one stone.\n"); fprintf(stderr, "And you can take at most all stones in one pile.\n"); } void byebye(){ fprintf(stderr, "\nThank you for playing NIM :-)\n"); } int myrandom(int lower, int upper){ static int firstFlag = 0; #ifdef TRUE_RANDOM if(firstFlag == 0){ srand( time(0) & 0xffff ); ++firstFLAG; } #endif int ans = rand() % (upper-lower+1); ans += lower; return ans; }