撰寫一Java程式可與Server連線, 自動進行猜四位數字的遊戲. 這四個數字皆為0-9, 且不重覆. 假設Server手中的數字是X, 你的程式猜的是G, 則Server會告訴你 結果為nm, 其中n表示在n個位置上有相同的數字, m表示有m個數字相同但位置不同. 我們以#來代表此運算. 如X=1234, G=3456, 則X # G = 02; 又如X=1234, G=1243, 則X # G = 22.
  1. Guess Server的寫法參見程設網站範例區
  2. 連線後先送出八個byte的學號. 新紀元學院同學請於學號前加一個0
  3. 進行猜數字100次
  4. 每次猜數字時先送出四個byte的數字, 然後Server會送回兩個byte的結果, 當結果為40時則表示猜中. 猜中後立刻進行下一組數字.
  5. 你可以用消去法把不可能數字去掉. 假設集合S為所有可能的解答, x屬於S, 當猜x時所得的答案為a, 則對所有可能的解答y屬於S, 我們可得 x # y = a, 由此你可以消去所有不可能的解答.
  6. 分數高低除程式之內容外, 所猜次數的多寡也會列入考量.

該如何去想這個問題呢? 第一眼的想法是建立一個決策樹, 根節點是某數字, 每個 分支代表電腦回答此數字的可能答案, 每一個子樹則要決定在該位置要猜哪個數字好. 不過若你這樣去思考, 會發覺此決策樹非常大而複雜, 要找張夠大的紙, 花個幾天的 時間在上面推演, 然後再寫個幾千行的程式來完成.

另一種思考方式, 則是消去法. 若大家還記得歸納法的話, 若要證明某定理對所有的 N>=1都成立, (1)先證明N=1成立, (2)若N成立可推得N+1也成立, 由(1)(2)該定理成立. 這方法的 原理是, 只要問題是可數的(如自然數), 我們可從1一路數下去, 總有一天會數到N. 消去法也是差不多的意思, 只要該問題的可能解是有限個, 那我們只要每次 (想到迴圈了嗎?)都至少消去一組不可能的解, 那麼總有一天會消去所有不可能的解, 留下的自然就是正確的解答了. 在猜四位數字的問題裡, 可能的解有10*9*8*7種, 剩下的問題就是如何消去不可能的解了. 我們猜G, 電腦回答nm, 則電腦手中的數字X 有甚麼性質? G # X = nm !!! 也就是說目前還沒有被消去的任意可能解答Y, 必定要 符合 G # Y = nm, 否則 Y 就不可能是 X. 當然有個小地方要注意的是, 若nm = 40, 則G就是X, 否則G一定不是X.

此作業解答的範例如下
    byte[] studentID = {8,7,3,2,1,0,0,6};
    Socket s = new Socket("163.22.20.114",1234);
    InputStream in = s.getInputStream();
    OutputStream out = s.getOutputStream();
    byte ans = new byte[2];
    try {
        out.write(studentID);
        for (int i=0; i<100; i++) {
            while (true) {
                byte[] guess = guess(); // your guess method
                out.write(guess);
                in.read(ans);
                if (ans[0]==4 && ans[1]==0) {
                    break;
                }
                eliminate(guess, ans); // 消去所有不可能的解答
            }
        }
        in.close();
        out.close();
        s.close();
    } catch(Exception ex) {
        System.out.println(ex);
    }