2019年1月26日 星期六

Sudoku 獨數

關於 Sudoku 的玩法可以參考 wikipedia
https://zh.wikipedia.org/wiki/%E6%95%B8%E7%8D%A8

規則滿簡單的,但是玩起來說實在滿花時間的,這東西大概1998年,我還在當兵時流行了一陣子,現在還是會在一些報紙、雜誌中看到,在1998年時,就寫了一個簡單的 C code來計算答案。

最近公司導入新的制度,面試要考類似 leetcode 的coding題目,由於要出題,左想右想,覺得Sudoku 這是個不錯的好題目,規則簡單,實作上會用到些程式的觀念,也是現實生活中會看到的題目,而不是為了 coding 而 coding 的題目。

說實在二十年前的程式想法,早就已經忘光了,只好重新構思解法,年紀與經驗增長,同時加上 google 的威力,其實很快就大概有了方向。

  1. 首先看來需要一個 "檢查" 規則的 function
  2. 然後就是需要一個產生 1~9 的 function,產生後就把數字填入試試看,符合規則的話,就再試下一個空格的數字。

好像還差了什麼?Yes,如果目前的位置所有的數字都不合規則的話,就必需再回頭改一下上一次位置的數字,這樣子的話才可以把所有的狀況都試完,用 recursive 的 function 來說就是要做到 Recursive backtracking 回溯的功能。

想法有了就是寫 code 了,之前用 C,現在學習 AI 都用 Python,改用 Python 來試試好了。感謝google的威力,網路上就是現成的 Python code了。
https://stackoverflow.com/questions/1697334/algorithm-for-solving-sudoku

只是要做為 interview 的解答,希望要求再高一些,程式可讀再高一些,stackoverflow 上面的,還有些改善的空間。
  1. isValid function : 可讀可以再加強些,稍微改成 check row, check colum and check grid 看來就完美多了
  2. findNextCellToFill function : 這個只是找出下一個要填的位置,功用不大,其實可以不用這個 function
  3. solveSudoku function : 這個 recursive function,傳入 i, j 當作位置,要解決的位置,其實可以整合成 position 一個變數就好,上面的 findNextCellToFill 就可以變成簡單的 position + 1
  4. 最後加上些 test case,看看輸出是否正確就完成了
以下就是修正完的 code,看來比之前的好一些,思路變清楚,結構也易讀,以下是source code 的部分。


# -*- coding: utf-8 -*-
"""
Created on Thu Dec  6 11:26:29 2018

@author: Robin_Chiu
"""

# A standard Sudoku puzzle consists of a grid of 9 blocks. Each block contains 9 boxes arranged in 3 rows and 3 columns.
# · Each column must contain all of the numbers 1 through 9 and no two numbers in the same column of a Sudoku puzzle can be the same.
# · Each row must contain all of the numbers 1 through 9 and no two numbers in the same row of a Sudoku puzzle can be the same.
# · Each block must contain all of the numbers 1 through 9 and no two numbers in the same block of a Sudoku puzzle can be the same.
 
def isValid(grid, i, j, e):
    # check the row
    rowOk = all([e != grid[i][x] for x in range(9)])
    if not rowOk:
        return False
    
    # check the column
    columnOk = all([e != grid[x][j] for x in range(9)])
    if not columnOk:
        return False
    
    # check the grid
    # finding the top left x,y co-ordinates of the section containing the i,j cell
    secTopX, secTopY = 3 *(i//3), 3 *(j//3) #floored quotient should be used here. 
    for x in range(secTopX, secTopX+3):
        for y in range(secTopY, secTopY+3):
            if grid[x][y] == e:
                return False
            
    # pass all the check return True
    return True

def solveSudoku(grid, pos=0):
    # calculate the i, j position
    i = pos//9
    j = pos%9
    
    # if it's the end stop the recursive 
    if pos == 81:
        for each in grid:
            print(each)        
    # if there is number in it, check the next one
    elif grid[i][j] != 0:
        solveSudoku(grid, pos+1)
    # find the valid number in i, j
    else:
        for e in range(1,10):
            if isValid(grid,i,j,e):
                grid[i][j] = e
                solveSudoku(grid, pos+1)
                # Undo the current cell for backtracking
                grid[i][j] = 0
                

def main():
    puzzle1 = [[5, 1, 7, 6, 0, 0, 0, 3, 4], 
             [2, 8, 9, 0, 0, 4, 0, 0, 0], 
             [3, 4, 6, 2, 0, 5, 0, 9, 0], 
             [6, 0, 2, 0, 0, 0, 0, 1, 0], 
             [0, 3, 8, 0, 0, 6, 0, 4, 7], 
             [0, 0, 0, 0, 0, 0, 0, 0, 0], 
             [0, 9, 0, 0, 0, 0, 0, 7, 8], 
             [7, 0, 3, 4, 0, 0, 5, 6, 0], 
             [0, 0, 0, 0, 0, 0, 0, 0, 0]]
 
    puzzle2 = [[5, 3, 0, 0, 7, 0, 0, 0, 0],
              [6, 0, 0, 1, 9, 5, 0, 0, 0],
              [0, 9, 8, 0, 0, 0, 0, 6, 0],
              [8, 0, 0, 0, 6, 0, 0, 0, 3],
              [4, 0, 0, 8, 0, 3, 0, 0, 1],
              [7, 0, 0, 0, 2, 0, 0, 0, 6],
              [0, 6, 0, 0, 0, 0, 2, 8, 0],
              [0, 0, 0, 4, 1, 9, 0, 0, 5],
              [0, 0, 0, 0, 8, 0, 0, 7, 9]]
    
    solveSudoku(puzzle1)
    print()
    solveSudoku(puzzle2)

if __name__ == '__main__':
    main()





 




2019年1月11日 星期五

奇雞連連

奇雞連連 是一款小朋友的桌遊,有關於詳細的玩法介紹可以參考以下網址 https://www.youtube.com/watch?v=h7tnUZACSA8

   其實這已經是2017 一月的事了,小朋友學校老師鼓勵同學玩些桌遊,也買了幾套桌遊供小朋友在學校玩耍,有天回來跟我說他玩了"奇雞連連"打敗了不少同學,我上網看了一下這不是 "井字遊戲" 嗎?但是深入了解後,發現玩法不太一樣,還有記憶力的考驗。上Play store想找下相關的APP download 來玩玩看,結果竟然找不到,雖然說可以用不同大小的紙張 or 杯子之類的來代替,但覺得還是不太方便,之前有開發 "井字遊戲" 的經驗,就想說這個應該介面稍微改一下就OK了,於是就出現了這一個 APP。

   用電腦就是方便增加了 "反悔" 功能,可以一步一步退回,方便人類重下分析不同的狀況,使用APP再更深入研究這個遊戲之後,發現其實先手下的人是一定獲勝的, 改天再整理必勝的技巧來分享下,先手必勝的話,這個遊戲算是有設計上的缺陷的,但就一款訓練小朋友分析、記憶的遊戲來說,還是一款不錯的遊戲,至於勝負, 所謂 "勝敗乃兵家常事" ,就不用太計較了。

    以下是 Play Store 的連結 和 截圖,有興趣的人可以download玩玩看,也有加入AI對戰的功能,但這個AI的設計比 "井字遊戲" 難,因為棋子可以移動,所以decision tree的展開會有問題,尚未想到比較好的做法,有任何建議也歡迎提出。

https://play.google.com/store/apps/details?id=com.robin.gobblet


2014年8月18日 星期一

TicTacToe 井字遊戲




  • 由來

    最近看到小朋友在玩 OOXX 也就是井字遊戲,很簡單,很耐玩的小小遊戲,就想說來implement一下這個東西。

  • 井字遊戲

    規則很簡單,九宮格,一人畫一個輪流,三個連成線就贏了!誰先手的話,贏面比較大。

  • AI

    在AI的書中,OOXX幾乎是標準的教材,在wikipedia上面查詢TicTacToe 也有分析的步驟  http://en.wikipedia.org/wiki/Tic-tac-toe ,所以就加上AI 的功能,這個 AI 很容易就可以走完所有的走法,從中選出最好的,所以 AI 是不敗的,反而人類一不小心就會犯錯!
    AI 的方法就是標準的Game tree search 進化成 Minmax ( http://en.wikipedia.org/wiki/Minmax )
,再簡化成 Negamax ( http://en.wikipedia.org/wiki/Negamax ),後面還有 Alpha Beta Pruning 的方式來加快運算的速度,不過因為只有九宮格,很容易就運算完畢,這部分就省下了!實際上implement 時第一步需要記下來走法和分數,用來決定下一步怎麼走,也是就 rootsearch function。
    後面有加上random 來選出相同分數的走法,以免AI 都是走同一步,但是因為都是選最高分,所以 AI 還是不敗的,呵呵!


package com.robin.tictactoe;

import java.util.ArrayList;
import java.util.Date;


public class AI {
 char marker;
 char opponentmarker;
 long initTime = 0;
 long nowTime = 0;
 int number = 0;
 char type = 'C';
 
 
 public AI(char marker) {
  this.marker = marker;
  if(marker == 'X')
   opponentmarker = 'O';
  else
   opponentmarker = 'X';
 }
 
 void move(Game game) {
  initTime = new Date().getTime();
  number = 0;
  int move = rootsearch(game, 1);
  game.move(marker, move);
 }
 
 int get_score(Game game) {
  number++;
  if(game.is_gameover()) {
   if(game.winner==marker)
    return 1;
   else if(game.winner==opponentmarker)
    return -1;
  }
  return 0;
 }
 
 int rootsearch(Game game, int color) {
    int bestmove = -999;
    int bestscore = -999;

    // get the possible move
    ArrayList moves = game.get_move();
    ArrayList candidate = new ArrayList();
    
    for(int i=0; i bestscore) {
        bestscore = score;
        bestmove = moves.get(i);
        candidate.clear();        
        candidate.add(moves.get(i));
      } else if(score == bestscore) {
        candidate.add(moves.get(i));
      }
    }
    bestmove = candidate.get((int)Math.floor(Math.random()*candidate.size()));
    return bestmove;
 }
 
 int negamax(Game game, int color) {
  int bestscore = -999;
  // get the score
  if(game.is_gameover()) {
   bestscore = color * get_score(game);
  } else {
   //get the possible moves
   ArrayList moves = game.get_move();
   for(int i=0; i bestscore) {
     bestscore = score;
    }
   }
  }
  return bestscore;
 }
}



  • Html5

    最近 html5 滿紅的,抓來的code原本是 python 寫的,想來改寫成 javascript,順便熟悉一下html5的新功能!




// Robin Chiu : hcchiu63@gmail.com
// 2014/06/20 the first version

var context;
var width, height;

var output = output || {};

output.paintBoard = function(){
   var board = document.getElementById('board');
  
   width = board.width;
   height = board.height;
   context = board.getContext('2d');
   context.clearRect (0, 0, width , height);

   context.beginPath();
   context.strokeStyle = '#000'; 
   context.lineWidth   = 4;

   context.moveTo((width / 3), 0);
   context.lineTo((width / 3), height);

   context.moveTo((width / 3) * 2, 0);
   context.lineTo((width / 3) * 2, height);

   context.moveTo(0, (height / 3));
   context.lineTo(width, (height / 3));

   context.moveTo(0, (height / 3) * 2);
   context.lineTo(width, (height / 3) * 2);

   context.stroke();
   context.closePath();
}

output.paintAIinfo = function() {
  var moveInfo = document.getElementById('moveInfo');
  moveInfo.innerHTML = '<h3> AI result:</h3>' +
                       '<br />Time:' + (AI.nowTime-AI.initTime) + 'ms' +
                       '<br />Calculate number:' + AI.number;

}

output.paintX = function(x, y) {

   context.beginPath();

   context.strokeStyle = '#ff0000'; 
   context.lineWidth   = 4;

   var offsetX = (width / 3) * 0.1;
   var offsetY = (height / 3) * 0.1;

   var beginX = x * (width / 3) + offsetX;
   var beginY = y * (height / 3) + offsetY;

   var endX = (x + 1) * (width / 3) - offsetX * 2;
   var endY = (y + 1) * (height / 3) - offsetY * 2;

   context.moveTo(beginX, beginY);
   context.lineTo(endX, endY); 

   context.moveTo(beginX, endY);
   context.lineTo(endX, beginY);  

   context.stroke();
   context.closePath(); 
}

output.paintO = function(x, y) {
  
   context.beginPath();

   context.strokeStyle = '#0000ff'; 
   context.lineWidth   = 4;

   var offsetX = (width / 3) * 0.1;
   var offsetY = (height / 3) * 0.1;

   var beginX = x * (width / 3) + offsetX;
   var beginY = y * (height / 3) + offsetY;

   var endX = (x + 1) * (width / 3) - offsetX * 2;
   var endY = (y + 1) * (height / 3) - offsetY * 2;

   context.arc(beginX + ((endX - beginX) / 2), beginY + ((endY - beginY) / 2), (endX - beginX) / 2 , 0, Math.PI * 2, true);

   context.stroke();
   context.closePath();
}


var game = game || {};

// game init function
game.init = function() {
  game.board = ['-','-','-','-','-','-','-','-','-'];
  game.moves = [];
  game.winner = "-";
}

// print the current status of game
game.print = function() {
  // print the board
  output.paintBoard();
  // print the O and X
  for(var i=0; i<9; i++) {
    var x = i%3;
    var y = Math.floor(i/3);
    if(game.board[i]=="O")
      output.paintO(x, y);
    else if(game.board[i]=="X")
      output.paintX(x, y);
  }

  // AI information 
  output.paintAIinfo();

  // console debug
  for(var i=0; i<9; i=i+3) {
    console.info(game.board[i] + ", " + game.board[i+1] + ", " + game.board[i+2]);
  }
}

// get the next move array
game.get_move = function() {
  var empty = [];
  for(var i=0; i<game.board.length; i++) {
    if(game.board[i] == "-")
      empty.push(i);
  }
  return empty;
}

// put some item to the position
game.move = function(marker, pos) {
  game.board[pos] = marker;
  game.moves.push(pos);
}

game.is_gameover = function() {
  var win_position = [[0,1,2], [3,4,5], [6,7,8], [0,3,6], [1,4,7], [2,5,8], [0,4,8], [2,4,6]];
  // check the patten
  for(var i=0; i<win_position.length; i++) {
    var p = win_position[i];
    if(game.board[p[0]]==game.board[p[1]] && game.board[p[0]]==game.board[p[2]] && game.board[p[0]] != '-') {
      game.winner = game.board[p[0]];
      return true;
    }
  }
  
  // check the if it's full
  for(var i=0; i<game.board.length; i++) {
    if(game.board[i] == "-") {
      game.winner = "-";
      return false;
    }
  }

  return true;
}

// revert last move
game.revert = function() {
  var pos = game.moves.pop();
  game.board[pos] = '-';
  game.winner = "-";
}


var AI = AI || {};

AI.init = function(marker) {
  AI.marker = marker;
  AI.initTime = 0;
  AI.nowTime = 0;
  AI.number = 0;
  AI.type = "C";
  if(AI.marker == "X") 
    AI.opponentmarker = "O";
  else
    AI.opponentmarker = "X";
}

AI.move = function(gameinstance) {
  AI.initTime = new Date().getTime();
  AI.number = 0;
  var move = AI.rootsearch(gameinstance, 1);
  AI.nowTime = new Date().getTime();
  //var move_position = 4;
  gameinstance.move(AI.marker, move);
}

AI.get_score = function(gameinstance) {
  AI.number++;
  if(gameinstance.is_gameover()) {
    if(gameinstance.winner == AI.marker)
      return 1;
    else if(gameinstance.winner == AI.opponentmarker)
      return -1;
  }
  return 0;
}

AI.rootsearch = function(gameinstance, color) {
  var bestmove = -999;
  var bestscore = -999;

  // get the possiable move
  var moves = gameinstance.get_move();
  var candidate = [];

  for(var i=0; i<moves.length; i++) {
    // set the move
    if(color == 1)
      gameinstance.move(AI.marker, moves[i]);
    else
      gameinstance.move(AI.opponentmarker, moves[i]);
    // get the score
    var score = -1 * AI.negamax(gameinstance, -color);

    // revert the move
    gameinstance.revert();
    // get the max score
    if(score > bestscore) {
      bestscore = score;
      bestmove = moves[i];
      candidate=[];
      candidate.push(moves[i])
    } else if(score == bestscore) {
      candidate.push(moves[i]);
    }
  }
  bestmove = candidate[Math.floor(Math.random()*candidate.length)];
  return bestmove;
}

AI.negamax = function(gameinstance, color) {
  var bestscore = -999;

  //get the score
  if(gameinstance.is_gameover()) {
    return color * AI.get_score(gameinstance);
  } else {
    // get the possiable move
    var moves = gameinstance.get_move();

    for(var i=0; i<moves.length; i++) {
      // set the move
      if(color == 1)
        gameinstance.move(AI.marker, moves[i]);
      else
        gameinstance.move(AI.opponentmarker, moves[i]);
      // get the score
      var score = -1 * AI.negamax(gameinstance, -color);

      // revert the move
      gameinstance.revert();
      // get the max score
      if(score > bestscore) {
        bestscore = score;
      }
    }
    return bestscore;
  }
}


var Human = Human || {};

Human.init = function(marker) {
  Human.marker = marker;
  Human.type = 'H';
}

Human.move = function(gameinstance, pos) {
  gameinstance.move(Human.marker, pos);
}

function clickHandler(e) {
    var y = Math.floor(e.clientY / (height / 3));    
    var x =  Math.floor(e.clientX / (width/ 3)); 
    var pos =  x + ( y * 3 );

    if(game.board[pos]!="-") {
      alert("invalid position...");
      return;
    }
    // Human move
    Human.move(game, pos);
    game.print();
    check();

    // AI move
    AI.move(game);
    game.print();
    check();
}

function check() {
  if(game.is_gameover()) {
    if(game.winner == AI.marker) 
      alert("AI win...");
    else if(game.winner == Human.marker)
      alert("You win...");
    else
      alert("Nobody win...");
    game.init();
    game.print();
  }
}


function Play() {
  game.init();
  game.print();
  Human.init("X");
  AI.init("O");
}


  • Android

    有時間再將 html5 改寫成 Android,說實在Android上面的 TicTacToe 實在太多了,但是我下載了幾個,玩起來總覺得沒有畫在紙上好玩的感覺,後來覺得是在紙上畫上格子玩,把整張紙畫的滿滿的趣味不見了,所以Android的方向就改成接近原本在紙上的玩法!





想玩的話,可以上google play download,網址如下:

2013年11月17日 星期日

libgdx

最近有空看了一下libgdx,還滿有趣的跟大家分享一下心得。
  • What's the libgdx?

 什麼是libgdx,在 http://libgdx.badlogicgames.com/ 下方是這個寫的 "Desktop/Android/HTML5 Java game development framework",也是一個在桌機上、Android、HTML5上的遊戲開發的框架!使用它來開發的話,就可以同時在桌機上、Android 和 支持HTML5的brower上執行!是不是很吸引人,但是什麼是game development framework啊?這要從application說起了!
  • Application

     

Application就是應用程式,一個應用程式裏面往往包含了Files, Audio, Input, Graphics等元件,而程式就是從input讀取操作,來反應相對應的行為。也是所有的應用程式都有著相同的構成要素!
  • Game framework

 那什麼又是Game framework呢?遊戲有一個gerneral 的行為模式,也就是




LoadAssets(); 
While(notFinished){
    processUserInput(); 
    updateGameWorld(); 
    renderGameWorld();
}

LoadAssets(); 遊戲為了反應速度可以順暢,所以在開始前會將所需的資源(ex. 圖片、聲音),先load至記憶體中,以省去到時讀取的時間
之後便是一個無窮的迴圈來執行遊戲,裏面主要有三個步驟:
processUserInput(); 處理玩家的輸入(ex. touch, keyboard, sensor等的輸入)
updateGameWorld(); 由輸入或者一些規則來更新遊戲中的世界 (ex. 被打到消失、球掉下來等)
renderGameWorld(); 後一步便是把更新後的世界呈現給玩家 (ex. 畫面更新、音樂的播放等)
這三個步驟重復的執行,便形成了一個遊戲的基本框架。   

  • libgdx function

 說了這麼多,怎麼都沒有看到有什麼和libgdx相關的,這就來了!libgdx有什麼用呢?java本身就是有提供了一些對於file、audio、graphic的操作了!但是對於遊戲來說有些不足,遊戲的畫面處理需要更多function來滿足,libgdx在這方面implement許多加強fuction來滿足。另一個目的就是提供統一的function來使得開發的遊戲可以在不同平台上面執行!
  • libgdx gram framwork

光是提供一些更便利的function還算不上是game framework,所以的game framework必需把之前所提的game framwork implement出來,讓game developer不需再考量framework如何運作,而可以把心力放在遊戲的內容本身!使用libgdx不需要寫一個無窮的while迴圈,因為這部分已經完成了,game developer便可以將心力集中在 game、screen、stage、actor等的安排上!








2012年3月14日 星期三

DDMS with radio logcat

DDMS is a very powerful tool in Android. You can use it to monitor the process and log. But if you try to look the log in DDMS, you find that there is no RIL log. It’s not convenient for developing the RIL related program. As we know the DDMS is open source code in google’s Android project. So we can get the source code from google, modify this function to fit our requirement.

1.      DDMS script
First we have to understand the DDMS. After you finish building the android source code, you will find the ddms command under the out/host/linux-x86/bin directory.
After open this file, you will find it will run the “$jarpath” variable in this script.
   And


So this script will run ddms.jar file. We have to looking for the ddms.jar.

2.      ddms.jar
How to find out the ddms.jar in the huge android source code repository? As we know android make file will use the “Android.mk” file to build the source code.
You can find the Android.mk file of ddms.jar under the sdk/ddms/app directory.

Open it and verify the “LOCAL_MODULE” variable and “include $(BUILD_HOST_JAVA_LIBRARY)”. Then you can make sure there is the ddms.jar source code directory.

3.      logcat
We have already find out the DDMS source code. But before we start to modify it we have to understand the logcat command parameter. You can issue the logcat command to look at that. 

By the document you can use the “logcat –b radio” to log from the radio buffer. But you will miss the main(default) log message when you issue that command. Fortunately you can issue the “logcat –b main –b radio” command get the main and radio log at the same time.

4.      modify the source code
Everything you need has already in your hand. The last thing you need to do is find out where the “logcat” is in ddms source code. In GB version it’s in the “LogPanel.java”. In ICS version it’s in the “LogCatReceiver.java”.
The “LogCatReceiver.java” file under the sdk/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat directory.
Open it. You will find out the LOGCAT_COMMAND variable.


The only thing you need to do is change it to “logcat –b main –b radio –v long”.
Is it easy, right?

5.      Rebuild DDMS and enjoy it. ^__^

2011年7月1日 星期五

Android改變按鈕顏色

    最近在研究Android 的UI想到需要改變按鈕的顏色,讓UI更漂亮 or 讓使用者知道目前所選擇的項目,Google了一下,有幾種方法,整理讓有需要的人,參考參考!


1. setBackgroundColor
原本的按鈕型式改變了,旁邊的圓弧形不見了,變成了直角,看起跟其它按鈕格格不入。
Button1.setBackgroundColor(Color.GREEN)

2. xml來客製button
利用在xml中設定shape的圖形來畫button,彈性大,可做漸層等效果。
必須先製作一個描述 shape xml
 

<?xml version="1.0" encoding="utf-8"?>
<selector
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item>       
        <shape>
            <gradient
                android:id="@+id/shape"
                android:startColor="#ff0000"
                android:endColor="#ffff00"
                android:angle="270" />
            <corners
                android:radius="10dp" />
            <padding
                android:left="10dp"
                android:top="10dp"
                android:right="10dp"
                android:bottom="10dp" />
        </shape>
    </item>
</selector>
 
然後把Background設成該xml即可
 
Button2.setBackgroundResource(R.layout.button);
 

3. 改變 buttonbackground filter
改變backgound filter來改變顏色,簡單!

Button4.getBackground().setColorFilter(
   0xFF00FF00, 
   android.graphics.PorterDuff.Mode.MULTIPLY );


2011年6月23日 星期四

Eclipse輸入自動提示功能

   話說前陣子重新安裝了 Eclipse之後,輸入自動提示功能就消失了!人是很難回頭的,現在沒有自動提示的功能,幾乎沒有辦法寫程式了!上網找了資料先說一下這個功能在Eclipse中叫做 Auto-Activation 有幾個選項


Auto activation delay : 要停留多久才出現提示,如果不想等待的話,就設成 0 吧!當然如果你希望機器給你點回憶的時間,享受打字的快感,就設長一點吧!
Auto activation triggers for Java : 什麼時候會出現提示,預設是 ".",就是在找物件裏面的東西才出現,有人建議把 a~z, A~Z都加入,看個人需求囉!

Auto activation triggers for Javadoc : 用在doc的提示

   OK,故事還沒有說完,檢查了一下,這些設定都沒有錯,怎麼Eclipse還是沒有提示?
再查了一下,原來這個只是提示的功能設定,至於要提示些什麼在Advanced下面,把Java Proposals 打勾即可!應該是我的Eclipse下是載Classic版,所以預設沒有打勾吧!上次就沒有遇到這個問題。