LAB04  繼續做上週 + 練習用 Java Application 寫出身分證驗證程式 
     (可以拿以前寫過的 C/C++ 版本來改, 自己沒寫過則copy別人 C/C++版本來改也可!)
Due: 即日起兩週內(每超過一週打九折)
Purpose: 更熟悉把 C/C++ 程式改為 Java 的注意事項, 並複習身分證編碼規則
 請注意: 
     做好習題請 到 e3.nctu.edu.tw 的討論區 依照規定 post 繳交
且  Subject: LAB04 from 學號姓名 
內容是心得 + Running Script  + Line numbers程式碼
LAB04_05_06_07 身分證驗證程式各種寫法
  *** 本題共包括未來四週的練習題: Lab04, Lab05, Lab06, Lab07 (還有第八題網路版)
  請參考所給範例: 
     http://www.cs.nctu.edu.tw/~tsaiwn/oop/03_Labs/Lab04/  內有 idc.cpp 和 idcheck.c
       a. C++ 寫的身分證驗證程式 (其實只用到 C++ 的一些些功能)> idc.cpp 
       b. 純種 C 寫的身分證驗證程式 idcheck.c  (可印出 id 所有錯誤)

   * 參考上學期與身分證有關的習題說明:
      http://www.cs.nctu.edu.tw/~tsaiwn/introcs/story/idcheck.htm 
     或自行上網找身分證編碼資料, 了解如何判斷一個身分證號碼是合法的?

   * 仔細研究所給範例(C/C++範例與Java範例), 看懂各個檢查與計算的 statements

   * 範例中字母轉換為數字是採用 table look up (查表法)
     研究程式碼, 思考何以要這樣做?
      若不這樣做? 還有哪些不會像土法煉鋼的做法?

   * C++ 範例程式 idc.cpp 只會印出一種錯誤.. 思考若要對一個輸入 ID 印出
     所有可能的錯誤要怎麼修改?  (想不出就看C範例 idcheck.c)

(1)LAB04  繼續完成上週 + 練習用 Java Application 寫出身分證驗證程式
   (A)複習: 研究測試之前習題給的 MyFirstCoffee.java (與講義略不同)
      要當作Applet 也要當作 Application, 點按(click) Applet 畫面看看
      然後加入一些句子使得當作 Application時可以按窗右上角的 X 關掉程式
     Hint: 要用到 WindowListener 的 windowClosing; 參考我給的範例:
       http://www.cs.nctu.edu.tw/~tsaiwn/oop/  裡面子目錄 java
        java/03_sample_JavaPrograms/01_gigi/   裡面各個 GiGi*.java
   (B)練習用 Java Application 寫出身分證驗證程式 
      先寫出沒有  GUI 的版本即可, 就是 文字版本就好 
  這題很簡單:) 把 idcheck.c 拿來大約幾分鐘就可以改好 :-) (改好後要研究一下!) 
  建議主程式內只有 new 自己, 真正的檢查工作寫在別的 function如 testID():
  假設你的 class 是 class IDCheck { //...  主程式內: 
        IDCheck me = new IDCheck( );
        me.testID( );
     }// main(   // 這是 Java 的 main 喔!
     void testID( ) { //原來 C 的 int main( ); 其實名稱可仍用 int main()  
        //...
     } // testID(  
  若還是不太會, 參考本目錄下以子目錄 sample_BATNUM 裡面的 C 版與 Java版
  尤其是連 C 版也還不太會的更要仔細看裡面各範例 stepwise refinement過程!
  當然也要把 bat6ok.c 與 bat6ok.java 好好對照一下!  
以下先預告未來各週的練習: 
(2)LAB05 把 LAB04 的 Java 改為 GUI版本 (有 Frame, Button, TextField)
   可在 class 內用一個 Frame 或自己 extends java.awt.Frame

(3)LAB06 把 LAB05 的 Java 改為 Applet, 並寫一個簡單 HTML 與之配合
   注意改寫完的 Java 程式必須仍然可以當作 Java Application

(4)LAB07 練習用網頁(HTML) + JavaScript 寫出身分證驗證程式
   注意 JavaScript 不是 Java, 這版本整個就只有一個 HTML 檔
   多看一些網頁按檢視 ==> 原始碼 就可偷看到一些 JavaScript 
   此程式只要偷看幾個網頁就會, 不必看 JavaScript 的書, 這站看看就夠用: 
http://residence.educities.edu.tw/brencar/JsTeach/JsTeach_grammar.html
   或這裡有完整語法與教學:  http://www.w3schools.com/jS/
   再不然自己用 gogle.com 查看 JavaScript 教學
 
(5)LAB08 網路版的身分證驗證程式(用Java寫簡易的網路程式) 
    把 LAB04 的 Java application 改成網路版(用你寫版本來改),
     配合我給的 TCP Server 範例稍作修改, 搭配執行, 阿就變成網路版了!

(6)Extra credit:
   練習用網頁(HTML) + CGI 程式 寫出身分證驗證程式,
   即輸入 ID 後送到 Server 端由 CGI 程式判斷身分證號碼是否合法
   再把結果用網頁送回 Browser. 
   注意所謂 CGI 程式是指會在 Server 端執行任何語言寫的程式!
   可用 google.com 找 "FORM 與 CGI" 
     * 你的 CGI 程式可以用 C 或 PERL 或其它你喜歡的語言 
     * 也可用 PHP 或 其它類似如 ASP, JSP   
   注意這項對 ID 檢查的工作是在 Server 端, 不是在 client 端的 Browser  
參考: http://webdesign.about.com/od/cgi/ss/aa022299.htm
      http://www.ck.tp.edu.tw/~thyu/perl-cgi-faq/pcp_faq.html
     或自己用 gogle.com 找 "FORM CGI 教學"  相關文章
You are the Counter visitors to this page.


idc.cpp (建議程式還不是很熟的先進子目錄sample_BATNUM看看 寫batnum程式的過程)

     1	//idc.cpp -- @CopyLeft by tsaiwn@csie.nctu.edu.tw
     2	//g++ idc.cpp
     3	#include <iostream>
     4	using namespace std;
     5	#include <ctype.h>
     6	int checkID(char *p);
     7	main()    /*** Last upDate: Mon, 1 Feb 1999 ***/
     8	{ 
     9	  char what[][70]={ "對啦!!這是合法的身份證字號", //訊息0
    10	                    "ㄟ..第一個字必須是字母啦",   //訊息1
    11	                    "你是第三性嗎?",              //訊息2
    12	                    "太短了! 不足碼唷!!",         //訊息3
    13	                    "怎麼會有這麼多碼!!",         //訊息4
    14	                    "打錯啦!!應該是數字喔!!",     //訊息5
    15	                    "神秘數字算出來是錯的"};      //訊息6
    16	  cout << "*********************************" << endl;
    17	  cout << "*********身份證驗證程式**********" << endl;
    18	  cout << "*********************************" << endl;
    19	  char id[16];
    20	  while(38==38){
    21	        cout << "請輸入身分證號碼 : ";
    22	        cin.getline(id, sizeof(id));   // getline 尾巴不會有 NewLine!
    23	        if (cin.fail()) {
    24	                if (cin.eof())  {    //EOF encounted?
    25	                        cout << endl;   // print NewLine
    26	                        break;   // leave the while Loop
    27	                }// if EOF
    28	                cin.clear();  // clear Error Status
    29	                cin.ignore(0xffff, '\n'); //drop till '\n',最多65535 chars
    30	                cout << "輸入字串太長!\n";
    31	                continue;  // go back to while
    32	        }// if cin.fail
    33	        // got an ID in char id[ ] , starting check the ID
    34	        if (id[1] == 'U' || id[1] == 'u') break;  // qUit ?
    35	        if (id[0] == '.' && id[1] == 0) {   // first char is dot(.)
    36	                break;
    37	        }
    38	        cout << "*********輸入 '.' 結束***********" << endl;            
    39	        cout << "====>" << what[checkID(id)] << endl ;
    40	  }   //輸出訊息
    41	  cout << "***********bye! bye!************" << endl;
    42	  return 0;   // main should return 0 to indicate there is no error
    43	}  // main(
    44	int checkID(char *p) {
    45	     char y[26]={ 10,11,12,13,14,15,16,17, 34,  //ABCDEFGH I
    46	                  18,19,20,21,22, 35,           //JKLMN O
    47	                  23,24,25,26,27,28,            //PQRSTU
    48	                  29,32,30,31, 33 };            //VWXYZ 
    49	     int sum = 0;       //sum是為了計算身份證是否為正確的變數
    50	     if  (isalpha(p[0])) {
    51	         char ktmp= toupper( p[0] ); // see "man isalpha", 要用到 <ctype.h> 
    52	         ktmp= y[ ktmp - 'A' ];      // 轉為 table y[] 中數值, 仍存回 ktmp
    53	         sum += (ktmp / 10) + 9* ( ktmp % 10 ); // 注意 int/int 得到整數
    54	          // sum 等於 ktmp/10 取整數部分加上9乘以ktmp除以10的餘數
    55	     } else {
    56	         return 1;   //若第一碼p[0]皆不為英文.表示輸入錯誤;傳回錯誤碼 1
    57	     }//if..else..
    58	     if (p[1] != '1' && p[1] != '2')  return 2; 
    59	     //身份證第二碼為性別碼: 1為男.2為女, 若都不是則傳回錯誤碼2
    60	        int j;  //接下來的9碼身份證號碼當然都是數字
    61	                // 將剩下號碼分別乘以8.7.6.5.4.3.2.1
    62	        for (j = 1;j < 9; j++) {
    63	            if (p[j] == 0) return 3;   //出現 NULL, 表不足碼傳回錯誤碼5
    64	            if (isdigit(p[j]))  sum += (p[j]-'0') * (9-j) ; 
    65	            else  return 5;   // found non_digit
    66	        }//for
    67	        if(!isdigit(p[9])) return 5; // 別忘了最後一碼也須是數字
    68	        sum += p[9]-'0';   // 最後一碼(檢查碼) 比重也是 1
    69	        if (p[10] != 0) return 4; // 第11碼須NULL否則傳回錯誤碼 4=太長
    70	        if ( (sum %10) != 0) return 6;    //若加權和不是0, 傳回錯誤碼6 
    71	        return 0;
    72	 }// checkID(


idcheck.c (建議程式還不是很熟的先進子目錄sample_BATNUM看看 寫batnum程式的過程)

     1	//idcheck.c -- by tsaiwn@csie.nctu.edu.tw
     2	//gcc idcheck.c
     3	//寫個程式可以檢查身分證號碼是否正確
     4	//Extra credit: 輸入 999 則產生一個可用的合法身分證號碼
     5	////////////
     6	#include <stdio.h>
     7	#include <ctype.h>
     8	void generateID( ), squeeze(char*); // 宣告兩個 function 
     9	int testID(char*);  // 查驗身分證各種可能的錯誤 並傳回錯誤代碼
    10	void printError(int code); // print error message according code
    11	
    12	// 注意 Java 不需要宣告, 因為在 class 內沒有先後關係 
    13	
    14	int main( ) {
    15	   static char id[99];  // 夠'長吧 :-) 身分證才 10 碼啦 
    16	   int code = 0;   // 用來記住錯誤代碼 
    17	   while(38 == 38) {   // for( ;; ) {
    18	       printf("請輸入身分證號碼 Input ID: ");
    19	       fgets(id, sizeof(id), stdin); // 整列讀入 到 id
    20	       // check EOF 
    21	       if(feof(stdin)) break;  //EOF == ^D in Unix; ^Z on DOS/Window
    22	       squeeze(id); // 把所有空白都去掉  white space
    23	       //printf("strlen(id)=%d\n", strlen(id));
    24	       if(strcmp(id, "-1") == 0) break; //Java 用 id.equals("-1")
    25	       if(strcmp(id, ".") == 0) break; 
    26	       if(strcmp(id, "quit") == 0) break; 
    27	       if(id[1] == 'U') break;  // QUIT ?  // Java 用 id.charAt(1)==
    28	       if(strcmp(id, "999") == 0) {generateID( ); continue; }
    29	       code = testID(id);  // 取得錯誤代號, 0 表示無錯 :-)
    30	       printf(" ID %s is ", id);
    31	       if(code==0) printf(" OK.\n");   // 印出說這號碼正確 
    32	       else {
    33	          printf(" Error ID! Reason(s):\n");
    34	       }//if
    35	       printError(code); // 依據 code 印訊息 
    36	   }// while(
    37	   printf("\r\nThank you and bye bye!\n");
    38	   return 0;
    39	}//main(
    40	
    41	//關於  squeeze(char*) 這好用的 function, 因為 C 程式庫沒有,自己寫:
    42	//注意 NewLine 也算 white space, 所以這函數也會把尾巴的 '\n' 拿掉!
    43	// 因為 fgets 讀入的資料尾巴有 NewLine; C++ 的 getline 則沒有 NewLine!
    44	void squeeze(char*p) {    // 擠掉所有的 white space; Java 要如何做呢?
    45	   char*p2 = p;    
    46	   if(*p == 0)return;   // NULL terminated, 一開始就字串結束: 空字串
    47	   while(*p2 !=0) {  // white space 請看  K&R課本第二章與附錄 B
    48	      if(isspace(*p2)) { ++p2; continue; }  // 丟掉 white space
    49	      *p = *p2; 
    50	      p++; ++p2;   // advance one char
    51	   }//while
    52	   *p = *p2;  // 0 == '\0'   == NULL 
    53	}// squeeze(
    54	
    55	// 關於 int testID(char* id) : 依據身分證規則查看 id 傳回錯誤代碼
    56	int yy[ ]={ 10,11,12,13,14,15,16,17, 34,  //ABCDEFGH I
    57	            18,19,20,21,22,  35,   //JKLMN O
    58	            23,24,25,26,27,28,     //PQRSTU
    59	            29,32,30,31, 33 };     //VWXY Z 
    60	int checkSum(char * id){  // 幫忙算 checkSum 給 testID(id) 用 
    61	   int sum, i;    // 因編碼沒完全照字母順序, 用算的要很多 if(...
    62	   int ynum;
    63	   // 用查表法 table look up 查出字母對應的兩位數較簡單直覺 !
    64	   // 先建個表 int yy[ ] = { 10, 11, 12, 13, ...};  // 照規定 AB..
    65	   // 然後 Let i = id[0]字母減去 'A' 得到 0..25
    66	   // 再查出 yy[i] 拿來用: ynum = yy[i];  // 10..O是35..Z不是35 !!
    67	   i = id[0] - 'A';
    68	   ynum = yy[i];
    69	   sum = ynum/10 + 9* (ynum%10);  // weight 1, 9, [876543211]
    70	   for(i=1; i<=8; ++i) sum += (id[i] - '0') *(9-i);  // 87654321
    71	   sum += (id[9] - '0') ;  // *1   檢查碼 weight 也是  1
    72	   return sum;   // 我只負責算出 checksum
    73	}//checkSum(
    74	
    75	int testID(char* id) {   //傳回錯誤代碼, 可用 bitwise "&" 運算找出 
    76	   int i, ans = 0, sum=0;  // sum 用來算 weighted check sum
    77	   id[0] = toupper(id[0]); // 轉為大寫
    78	   if(!isalpha(id[0])) ans = ans + 1;  // 1 號錯  ans = ans | 1;
    79	   if(id[1] != '1'  && id[1] != '2') ans += 2; // 2 號錯 男生女生?
    80	   if(strlen(id) < 10) ans += 4;   // 太短
    81	   if(strlen(id) > 10) ans += 8;   // 太長
    82	   for(i=1; i<=9; ++i) if(!isdigit(id[i])) ans = ans | 16; // 非數字
    83	   if((ans&16) != 0) return ans;  // 有非數字不用再算 check sum 啦 
    84	   if(ans != 0) return ans;  // 有任何錯就..就不用再算 check sum 啦 
    85	   sum = checkSum(id);   // 假設沒有其他怪字就算出 check sum
    86	   if(sum%10 != 0) ans |= 32;   // 必須除以 10 除得盡才對 
    87	   return ans;
    88	}// testID(
    89	
    90	char what[ ][88]={ "對啦!!這是合法的身份證字號", //訊息0
    91	                "ㄟ..第一個字必須是字母啦!",    // 訊息1
    92	                "你是第三性嗎?",            // 訊息2
    93	              "太短了!不足碼唷!!",      // 訊息3
    94	              "怎麼會有這麼多碼!!",     // 訊息4
    95	            "打錯啦!!應該是數字喔!!",   // 訊息5     
    96	            "神秘數字算出來是錯的??"     // 訊息6
    97	                };  // do NOT forget the ";"
    98	// String what[ ] = { ... };  // in Java 
    99	void printError(int code) {  // print all errors found use bitwise and
   100	   int i, yy[ ] = {0, 1, 2, 4, 8, 16, 32, 64, 128};
   101	   if(code == 0) { printf("%s\n", what[0]); return; }
   102	   for(i=1; i <= 6; ++i)if((code&yy[i]) != 0)printf("%s\n", what[i]);
   103	}// printError(
   104	
   105	void generateID( ) {
   106	   char id[11]={ 0 };   // 會全放 0  (NULL)  ==  '\0'   == 0
   107	   int i;
   108	   id[0] = 'A' +  rand( ) % 26;  // 'A' .. 'Z'
   109	   id[1] = '1' + rand( ) % 2;   // '1' .. '2'
   110	   for(i=2; i<=8; ++i) {
   111	     // 用亂數生出 id[2] .. id[8]
   112	     id[i] = '0' + rand( )%10;   // '0' .. '9'
   113	   } //
   114	   /// id[9] 是檢查碼, 要算, 可先塞 '0' 偷叫 checkSum( )再調整 
   115	   id[9] = '0';
   116	   i = checkSum(id);   // 借用 i 來存  checkSum
   117	   i = i % 10;
   118	   if(i != 0) id[9] = '0' + (10-i);     // 更正檢查碼 
   119	   printf(" Good ID: %s\n", id);   // legal ID now
   120	}// generateID(


bat6ok.c (建議程式還不是很熟的先進子目錄sample_BATNUM看看 寫batnum程式的過程)
   1 //bat6ok.c  -- @CopyLeft by tsaiwn@csie.nctu.edu.tw
   2 //BATtle of NUMbers
   3 //modified by __學號__  _姓_名_  and  __學號__  _姓_名_ 
   4 ///
   5 // 若用 Java 則須用 class 包起來; class名稱須與檔案名稱相同 !
   6 // 且 main 必須 public static void main(String xxx[ ]) {
   7 #define repeat  do {
   8 #define until(x)   } while(! (x) )
   9 
  10 #include <stdio.h>
  11 #include <stdlib.h>
  12 #include <time.h>
  13 
  14 #define MAX_STONE 31
  15 #define MIN_STONE 18
  16 #define MAX_TAKE 9
  17 //Java 內以上須用這樣 public final static int MAX_TAKE = 9;
  18 
  19 #ifndef __cplusplus
  20   typedef enum {false=0, true } bool; // C 不認識 這些
  21 #endif
  22 
  23 // define some global variables for the Game
  24 int nStone; // number of Stone
  25 int maxTake; // max stone to take for some game
  26 
  27 bool lastToWin;  // Win or Lose if took last one stone?
  28 bool userFirst, playAgain;
  29 /// 
  30 enum player {USER, COMPUTER};  // 這樣寫後面可以用USER/COMPUTER
  31 enum player who; // who is taking the stone? 輪到誰?
  32   // Java 的 enum 請看本檔案最後的補充 ! 
  33 void hello( ), prepareGame( ), playGame( );
  34 bool askUserFirst( ), askPlayAgain( );
  35 void userTurn( ), computerTurn( );
  36 void randomize( ) { srand(time(0));  } // 抓時間來當作亂數種子
  37 
  38 int main( ) {
  39    hello( ); 
  40    randomize( );  // randomize; make it true random
  41    repeat
  42       prepareGame( );
  43       userFirst = askUserFirst( );
  44       playGame( );
  45       playAgain = askPlayAgain( );
  46    until( ! playAgain );
  47    printf("Thank you for your play.\r\n");
  48    return 0;
  49 }
  50 
  51 void hello( ) {  
  52    printf("Welcome to the BATNUM game ...\r\n");
  53 }
  54 
  55 void prepareGame( ) {
  56    char msg[ ][88]={"Lose the game.", "win the game."};
  57    nStone = MIN_STONE + rand( ) % (MAX_STONE-MIN_STONE+1);
  58    maxTake = 3 + rand( ) % (MAX_TAKE -3 +1);  // 3..
  59    lastToWin = rand( )%2 == 1;  // half chance 一半的機會
  60    printf("\r\nThere are %d stones.\r\n", nStone);
  61    printf("At least take 1, at most %d stones.\r\n", maxTake);
  62    printf("The one who take the last stone will ");
  63    printf("%s\r\n", msg[lastToWin]); // 拿最後一個輸還是贏?
  64 #ifdef DEBUG
  65    printf("lastToWin=%d\n", lastToWin);
  66 #endif
  67 } // prepareGame
  68 
  69 bool askUserFirst( ) {
  70    static char buf[99];
  71    fprintf(stderr, "Do you want to go first(Y, N)? ");
  72    fgets(buf, sizeof(buf), stdin);
  73    if(buf[0]=='N' || buf[0]=='n') return false; //no
  74    if(buf[0]==0) return false;  // no!  C不認識 true/false
  75    return true;  //  Yes otherwise
  76 }
  77 
  78 bool askPlayAgain( ) {
  79    static char buf[99];
  80    fprintf(stderr, " Play again(Y, N)? ");
  81    fgets(buf, sizeof(buf), stdin);
  82    if(buf[0]=='N' || buf[0]=='n') return false; //no
  83    if(feof(stdin)) return false;  // EOF encounted
  84    return true;  // Yes
  85 } // askPlayAgain
  86 
  87 void playGame( ) {
  88    bool userWin=true; // assume user win
  89    if(userFirst) userTurn( );
  90    else printf(" OK. I go first.\r\n");
  91    while(nStone > 0 ) {
  92       computerTurn( );
  93       if(nStone <= 0) break; // gameOver
  94       userTurn( );
  95    } // game Over when leave the while Loop
  96    userWin = true; // assume you win
  97    if(lastToWin && (who == COMPUTER) ) userWin = false; // user 輸!
  98    if( (!lastToWin) && (who == USER) ) userWin = false; // user 也是輸
  99    if(userWin) printf(" Congratulations! You win!\r\n");
 100    else printf(" Sorry, I won! Ha ha!\n");
 101 } // playGame
 102 
 103 void userTurn( ) { 
 104    int nTake, canTake;
 105    static char buf[99];
 106    who = USER;  // now USER 's turn  記住輪到 USER
 107    canTake = maxTake;  // 照規定最多只能拿取 maxTake
 108    if(nStone < maxTake) canTake = nStone;  // 沒那麼多了
 109    printf(" How many you want to take(1..%d)? ", canTake);
 110    fgets(buf, sizeof(buf), stdin);
 111    nTake = (int)atol(buf);  
 112    // check if the nTake is legal ?
 113    // .. 若不符規定則要求 USER 重新輸入
 114    // .. 也可寫成若輸入負數表示 give up, 就結束此 game :-(
 115    while(nTake < 1 || nTake > canTake) { // illegal
 116       printf("  ?? Error, please re-type(1..%d)? ", canTake);
 117       fgets(buf, sizeof(buf), stdin);
 118       nTake = (int)atol(buf);  
 119    }
 120    nStone -= nTake;
 121    if(nStone == 0) printf(" You just took the last stone.\r\n");
 122    else printf(" %d stone(s) left.\r\n", nStone);
 123    return;
 124 } // userTurn
 125 
 126 void computerTurn( ) {
 127    int nTake = 1;
 128    who = COMPUTER;  // now is COMPUTER 's turn 記住輪到 COMPUTER
 129    // 必贏的策略?  須考慮拿最後一個贏還是輸
 130    nTake = nStone;
 131    if(!lastToWin) nTake--;  // 拿最後一個是輸ㄝ, 留一個給對手
 132    nTake = nTake % (1+maxTake);
 133    if(nTake == 0) nTake = 1; // 電腦會輸, 先賴皮拿一個等對手拿錯:-)
 134    if(nTake > nStone) nTake = nStone; // 沒那麼多! (不可能發生)
 135   ///
 136    nStone -= nTake;  // 拿走啊
 137    printf(" I take %d stone", nTake);
 138    if(nTake > 1) printf("s");  // 複數
 139    printf(" this time.");
 140    if(nStone == 0) printf(" I just took the last stone.\r\n");
 141    else printf(" Now %d stone(s) left.\r\n", nStone);
 142 } // computerTurn
 143 ///   === === END of the program BATNUM === ===
 144 /*** 關於 Java 的 enum: 在 C/C++ 的 enum 其實是整數, 可 Java 不是!
 145   Java 的 enum 是會變成 class ! 請編譯完後看看目錄中多出的 class 檔!
 146   以下是個簡單範例, 可編譯並且執行:
 147   //gg.java  -- test enum in Java, by tsaiwn@csie.nctu.edu.tw
 148   //avac gg.java
 149   //java gg
 150   //javap gg$player
 151   class gg {
 152        enum player {USER, COMPUTER}; 
 153     public static void main(String xx[ ]) {
 154        player yy = player.USER;
 155        System.out.println("user="+yy);
 156        if(yy == player.USER) System.out.println("YES yy is player.USER");
 157        else System.out.println("NO hahaha!");
 158     }//main
 159   } // class gg
 160 *************************************************************/


bat6ok.java (建議程式還不是很熟的先進子目錄sample_BATNUM看看 寫batnum程式的過程)

     1	//bat6ok.java -- modified from bat6ok.c
     2	//javac bat6ok.java
     3	//java bat6ok
     4	///////////////////////////////////////////////////
     5	//bat6ok.c  -- @CopyLeft by tsaiwn@csie.nctu.edu.tw
     6	//BATtle of NUMbers
     7	//modified by __學號__  _姓_名_  and  __學號__  _姓_名_ 
     8	///
     9	// 若用 Java 則須用 class 包起來; class名稱須與檔案名稱相同 !
    10	// 且 main 必須 public static void main(String xxx[ ]) {
    11	import java.io.*;
    12	import java.util.*;
    13	
    14	class bat6ok {   //  filename should be the same as class name
    15	
    16	 public final static int MAX_STONE = 31;
    17	 public final static int MIN_STONE = 18;
    18	 public final static int MAX_TAKE = 9;
    19	
    20	 // define some global variables for the Game
    21	  int nStone; // number of Stone
    22	  int maxTake; // max stone to take for some game
    23	
    24	  boolean lastToWin;  // Win or Lose if took last one stone?
    25	  boolean userFirst, playAgain;
    26	  /// 
    27	enum player {USER, COMPUTER};  // 這樣寫後面可以用USER/COMPUTER
    28	 player who;  // who is taking the stone? 輪到誰? 注意 Java 寫法 !
    29	
    30	public static void main(String xxx[  ]) {
    31	    bat6ok ggyy = new bat6ok( );
    32	    ggyy.main( );
    33	}
    34	bat6ok( ) {   // constructor
    35	     prepareIO( );
    36	}
    37	BufferedReader cin=null;
    38	PrintStream cout=null;
    39	
    40	void prepareIO( ) {
    41	     try {
    42	        cin =  new BufferedReader(
    43	                     new InputStreamReader( System.in )  );
    44	        cout = System.out;
    45	     }catch(Exception e) {  }
    46	}
    47	
    48	int main( ) { // 原來的 main( ); Note that it has different prototype
    49	   hello( ); 
    50	   randomize( );  // randomize; make it true random
    51	   do {
    52	      prepareGame( );
    53	      userFirst = askUserFirst( );
    54	      playGame( );
    55	      playAgain = askPlayAgain( );
    56	   } while( playAgain );
    57	   cout.printf("Thank you for your play.\r\n");
    58	   return 0;
    59	}
    60	
    61	int rand( ) {
    62	     return (int) (32767* Math.random( ) );
    63	}
    64	void srand(int seed) {
    65	} // not necessary :-)
    66	void randomize( ) {
    67	     srand((int)System.currentTimeMillis( ) );
    68	}
    69	
    70	void hello( ) {  
    71	   cout.printf("Welcome to the BATNUM game ...\r\n");
    72	}
    73	
    74	void prepareGame( ) {
    75	   String msg[ ]={"Lose the game.", "win the game."};
    76	   nStone = MIN_STONE + rand( ) % (MAX_STONE-MIN_STONE+1);
    77	   maxTake = 3 + rand( ) % (MAX_TAKE -3 +1);  // 3..
    78	   lastToWin = rand( )%2 == 1;  // half chance 一半的機會
    79	   cout.printf("\r\nThere are %d stones.\r\n", nStone);
    80	   cout.printf("At least take 1, at most %d stones.\r\n", maxTake);
    81	   cout.printf("The one who take the last stone will ");
    82	   int kkk;   kkk = 0;
    83	   if(lastToWin) kkk = 1;
    84	   cout.printf("%s\r\n", msg[kkk]); // 拿最後一個輸還是贏?
    85	} // prepareGame
    86	
    87	boolean askUserFirst( ) {
    88	    cout.printf( "Do you want to go first(Y, N)? ");
    89	    String buf = null;
    90	    try {
    91	          buf = cin.readLine( );
    92	    } catch(Exception e) { }
    93	    if(buf == null) return false;
    94	    if(buf.length( )==0) buf = "n";
    95	    if(buf.charAt(0)=='N' || buf.charAt(0)=='n') return false; //no
    96	    if(buf.charAt(0)==0) return false;  // no! 
    97	    return true;  //  Yes otherwise
    98	}
    99	
   100	boolean askPlayAgain( ) {
   101	    cout.printf( "Do you want to go first(Y, N)? ");
   102	    String buf = null;
   103	    try {
   104	          buf = cin.readLine( );
   105	    } catch(Exception e) { }
   106	    if(buf == null) return false;
   107	    if(buf.length( )==0) buf = "n";
   108	    if(buf.charAt(0)=='N' || buf.charAt(0)=='n') return false; //no
   109	    if(buf.charAt(0)==0) return false;  // no! 
   110	    return true;  // Yes
   111	} // askPlayAgain
   112	
   113	void playGame( ) {
   114	   boolean userWin=true; // assume user win
   115	   if(userFirst) userTurn( );
   116	   else cout.printf(" OK. I go first.\r\n");
   117	   while(nStone > 0 ) {
   118	        computerTurn( );
   119	        if(nStone <= 0) break; // gameOver
   120	        userTurn( );
   121	   } // game Over when leave the while Loop
   122	   userWin = true; // assume you win
   123	   if(lastToWin && (who == player.COMPUTER) ) userWin = false; // user 輸!
   124	   if( (!lastToWin) && (who == player.USER) ) userWin = false; // user 也是輸
   125	   if(userWin) cout.printf(" Congratulations! You win!\r\n");
   126	   else cout.printf(" Sorry, I won! Ha ha!\n");
   127	} // playGame
   128	
   129	void userTurn( ) { 
   130	   int nTake, canTake;
   131	   String buf;
   132	   who = player.USER;  // now USER 's turn  記住輪到 USER
   133	   canTake = maxTake;  // 照規定最多只能拿取 maxTake
   134	   if(nStone < maxTake) canTake = nStone;  // 沒那麼多了
   135	   cout.printf(" How many you want to take(1..%d)? ", canTake);
   136	   try {
   137	        buf = cin.readLine( );
   138	        if(buf==null) buf="0";
   139	        nTake = Integer.parseInt(buf);
   140	   }catch(Exception e) { nTake = 0;  }
   141	   while(nTake < 1 || nTake > canTake) { // illegal
   142	      cout.printf("  ?? Error, please re-type(1..%d)? ", canTake);
   143	      try {
   144	           buf = cin.readLine( );
   145	           if(buf==null) buf="0";
   146	           if(buf.length( )==0) buf = "0";
   147	           nTake = Integer.parseInt(buf);
   148	      }catch(Exception e) {  nTake = 0; }
   149	   }
   150	   nStone -= nTake;
   151	   if(nStone == 0) cout.printf(" You just took the last stone.\r\n");
   152	   else cout.printf(" %d stone(s) left.\r\n", nStone);
   153	   return;
   154	} // userTurn
   155	
   156	void computerTurn( ) {
   157	   int nTake = 1;
   158	   who = player.COMPUTER;  // now is COMPUTER 's turn 記住輪到 COMPUTER
   159	   // 必贏的策略?  須考慮拿最後一個贏還是輸
   160	   nTake = nStone;
   161	   if(!lastToWin) nTake--;  // 拿最後一個是輸ㄝ, 留一個給對手
   162	   nTake = nTake % (1+maxTake);
   163	   if(nTake == 0) nTake = 1; // 電腦會輸, 先賴皮拿一個等對手拿錯:-)
   164	   if(nTake > nStone) nTake = nStone; // 沒那麼多! (不可能發生)
   165	  ///
   166	   nStone -= nTake;  // 拿走啊
   167	   cout.printf(" I take %d stone", nTake);
   168	   if(nTake > 1) cout.printf("s");  // 複數
   169	   cout.printf(" this time.");
   170	   if(nStone == 0) cout.printf(" I just took the last stone.\r\n");
   171	   else cout.printf(" Now %d stone(s) left.\r\n", nStone);
   172	} // computerTurn
   173	
   174	} // class bat6ok
   175	///   === === END of the program BATNUM === ===

抓這習題壓縮檔 LAB04.jar       More hints to translate C programs into Java programs

 抓 BATNUM 抓石頭遊戲 C 版本 bat6ok.c 原始檔    抓其 Java檔 bat6ok.java
      再參考 BATNUM Java 新簡易改法: bat7.java   +   c2java.java      

就看看./sample_BATNUM/ 子目錄內 從零開始寫 batnum 抓石頭 遊戲
(進入子目錄後按右鍵存檔抓回你的電腦)
      關於用 PERL 寫 CGI 的 FAQ(常問問題) ./for_Extra_credit/
回到這個作業目錄(LAB04)             回到作業目錄             回到課程目錄
You are the Counter visitors to this page.