2010-08-23

對戰吧~GWT 踩地雷! [上]

上一次教完如何寫一個生命遊戲(好久以前啊 [遠目])
這次的題目同樣是陣列系的踩地雷
不過,如果單機自己玩也太無聊了點
所以呢... 這次的目標是「對抗電腦版的踩地雷」!
這個題目有點大,讓我們一步一步慢慢來......

首先是先弄出一個 MineGM 的物件
來負責創造地雷世界、運作規則邏輯
所以 MineGM 必須要有這些 field
public static final int UNKNOW = -1;

private int x;
private int y;
private int total;  //總共幾個地雷
private int remainder;  //剩下幾個地雷
private boolean[][] answer; //地雷分佈圖
private int[][] map;  //玩家看到的地圖
private int[] playerHit = new int[2]; //分別踩了幾個

一開始就用亂數把 answer 準備好
至於 map 的內容一開始都是 UNKNOWN,表示還不知道是啥狀況
map 當中還可能出現:
  • 0~8:九宮格內出現的地雷數
  • 9:玩家踩到的地雷
  • -9:電腦踩到的地雷
而 MineGM 還需要有一個 public 的 method「shoot()」
負責接受玩家的輸入、然後回報是否命中
public boolean shoot(int hitX, int hitY, boolean who){
  map[hitX][hitY] = count(hitX, hitY);

  //踩到空地的連鎖反應
  if(map[hitX][hitY]==0){
    for(int i=-1; i<2; i++){
      if(hitX+i==x || hitX+i<0){continue;}
      for(int j=-1; j<2; j++){
        if(hitY+j==y || hitY+j<0){continue;}
        if(map[hitX+i][hitY+j] != -1){
          continue;
        }else{
          shoot(hitX+i, hitY+j, who);
        }
      }
    }
  }

  //不同人踩到地雷要給不同值
  if(map[hitX][hitY]==9){
    remainder--;
    if(who){
      playerHit[0]++;
    }else{
      map[hitX][hitY]=-9;
      playerHit[1]++;
    }
  }
  
  return Math.abs(map[hitX][hitY])==9;      
}

count() 會計算周圍九宮格有幾個地雷
把回傳質設定到對應的 map 上
另外,因為我採取「answer 的周圍多一格空地」的作法
所以「踩到空地的連鎖反應」那段的迴圈可以比較好看一點

雖然已經有 MineGM 建立、維護地雷世界了
但是,我們還是需要另外一個 GameInfo 來包裝給玩家的資訊
不然如果玩家 or 電腦直接拿 MineGM 的 answer 來作弊怎麼辦? Orz
所以在 MineGM 當中弄了一個 static method 來轉換成 GameInfo
public static GameInfo toGameInfo(MineGM server) {
  GameInfo result = new GameInfo();
  result.setMap(server.getMap());
  result.setRemainder(server.remainder);
  result.setTotal(server.total);
  result.setPlayerHit(server.playerHit);
  return result;
}

至於其他的細節就留給大家慢慢寫了......

接下來處理 UI 的部份
這次使用 GWT 2.0 的 UiBinder 來處理排版
使用方法可以看官方文件痞子版的中文翻譯

預計的遊戲畫面長這樣:

上方是數據區
左右兩側是雙方的名字與分數,包了一個 PlayerInfo 來處理
其實很簡單,剛好適合拿來了解 UiBinder

PlayerInfo.ui.xml:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
  xmlns:g="urn:import:com.google.gwt.user.client.ui">
  <ui:style>
  .title{
    padding-left: 5px;  
  }
  </ui:style>
  <g:FlowPanel>
    <g:InlineLabel ui:field="title" styleName="{style.title}"></g:InlineLabel>
    <g:InlineLabel ui:field="hitCount"></g:InlineLabel>
  </g:FlowPanel>
</ui:UiBinder> 

PlayerInfo.java
public class PlayerInfo extends Composite {

  private static PlayerInfoUiBinder uiBinder = GWT.create(PlayerInfoUiBinder.class);

  interface PlayerInfoUiBinder extends UiBinder<Widget, PlayerInfo> {
  }

  @UiField Label title;
  @UiField Label hitCount;
  
  public PlayerInfo() {
    initWidget(uiBinder.createAndBindUi(this));
    setHitCount(0);
  }

  public void setHitCount(int i) {
    hitCount.setText(""+i);
  }

  public void setName(String name){
    title.setText(name+":");
  }
}

中間是還剩下多少地雷,用一個 Label 解決
下方的地雷區則是用 FlexTable 處理
這些東西都放在 MineMain 這個 class 當中
所以 MineMain.ui.xml 會長成這樣:
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
  xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:m="urn:import:org.psmonkey.product.client.mine">
  <ui:style>
  .playerInfo{
    width: 480px;
  }
  .cpu{
    width: 220px;
    background-color: red;
  }
  .player{
    width: 220px;
    background-color: #64A0C8;
  }
  .remainder{
    width: 40px;
    color: white;
    background-color: gray;
    text-align: center;
  }
  </ui:style>
  <g:VerticalPanel>
    <g:HorizontalPanel styleName="{style.playerInfo}">
      <m:PlayerInfo ui:field="cpu" styleName="{style.cpu}"></m:PlayerInfo>
      <g:Label ui:field="remainder" styleName="{style.remainder}"></g:Label>
      <m:PlayerInfo ui:field="player" styleName="{style.player}"></m:PlayerInfo>
    </g:HorizontalPanel>
    <g:FlexTable ui:field="map"></g:FlexTable>
  </g:VerticalPanel>
</ui:UiBinder> 

很懶惰地用 VerticalPanel 跟 HorizontalPanel 解決 XD

接下來,就要處理跟 web server 之間的溝通了! [待續]

2010-08-12

碎唸 ptt 上的管理

好了,文章開頭就直接自爆來意
以通俗的說法,就是:我是以小組長的身份來官官相護的

後頭的廢話懶得看的人,我可以把結論寫在前面:
除了執法尺度不一致、違反上層法規的申訴外
遇到版務爭議的預設值是支持版主

只要版主有確實執行,版規要定的多奇怪
我會支持,不會干涉

※   ※   ※

我相信這篇大多數人而言,沒啥建設性(破壞性倒是有?)
因為絕大多數是我管 CompScience 這幾年來的 murmur

※   ※   ※

在這個 thread,cleanwind 說了一個很妙的比喻
「CodeJob 像是接案方的家,卻像發案方的動物園。」

如果以 design pattern 的角度 [誤]
管理者跟看板使用者(以下簡稱鄉民)也還蠻適用這個譬喻
管理者像是動物園裡頭的動物
鄉民像是遊客,而且還不用買票進場

管理者的一言一行都要被檢視、要被批評
慘一點的會被批鬥、甚至要被思想改造
當然,這或許是管理者必須要付出的代價 or 義務 or whatever
畢竟權利跟義務通常是對等的
只是,如果以此標準把版主的權利跟義務放到天平上衡量
嗯... 大概版主幹個一年可以增加 2% 上天堂的機率這樣?

但是鄉民呢?

我不是說鄉民不能發表意見
而是,以經驗法則來說,有太高的比率
鄉民因為短暫的不爽,黑特、亂版、申訴、罷免
有付出什麼代價嗎?

保險一點的作法就是負責擾亂一池春水,誰也拿你沒轍
就像 F23ko 的推文,堪稱典範:

吃雞排,看熱鬧,等罷免。
我對這個版的好壞根本沒興趣,也沒心力去付出。
只是看這版主的個性,出狀況、起衝突是遲早的事。

激進一點的,養個帳號出來搞
反正另一個帳號 or 重新註冊又是一條好漢

但是管理者得付出多少代價來處理?
(答:經歷一次事件可以增加 0.5% 上天堂的機率)
版主搞掉幾個?
看板的品質被拖累了多少?

我們真的要理會這種人嗎?

※   ※   ※

回頭看一下版主上任的相關時間表

→2010.07.27 下午,我張貼徵版主的公告
→2010.08.03 凌晨,WolfLord 在 Sub_CS 張貼申請書
    當天,這裡的版標就已經改成
    「新版主政見已貼在 Sub_CS 版」(到現在還沒改是怎樣? [指])
→2010.08.09 半夜,WolfLord 正式就任

徵版主至今,將近兩個禮拜的時間
除了 NotOnSale 那篇不會被受理的文章跟推文
有任何人提出「我要當版主」的申請跟詢問嗎?

從 WolfLord 申請至今,將近一個禮拜的時間
有任何人提出質疑、提出管版理念不妥的地方嗎?

是因為資訊被隱藏起來嗎?
是因為不開放討論嗎?
是因為給的時間不夠多嗎?
是因為 WolfLord 申請書跟實際版規有出入嗎?

我想,這些答案都是「不是」,那麼
為甚麼在正式上任之前都沒有任何(反對)意見
而等到木已成舟之後,才抱怨這個、詰譙那個
還可以批評版主「自我感覺良好」?

有機會發言不發言、有機會掌權不掌權
然後結論確立之後才吵吵嚷嚷要翻案
別人執掌方法不合己意就指責人專制獨裁
這真的是為這個「組織」好而產生的努力嗎?
還是根本就是自我中心、自我感覺良好的作為?

我們真的要理會這種人嗎?

※   ※   ※

我超討厭推文一次超過三行的人
我超討厭連狀聲詞都不能用注音符號的規定
我超討厭案主發案不用寫基本預算

然後咧? 那又怎樣?

你超討厭噓文會被水桶
你超討厭發案之後要回來 update/delete 不然會被劣文
你超討厭水桶解除要寫悔過書

然後咧? 那又怎樣?

版規要怎麼定,那是版主的自由
精準地說,站規賦予版主的權利
從免費入園的遊客變成被觀賞的動物,換來的權利

從另一個角度來說,因為遊客(可能)來來去去
而必須始終都在的,是被觀賞的動物
而必須「面對音樂」,是被觀賞的動物
所以版規要怎麼定,是由版主作決定

需不需要聆聽採納鄉民的意見? 不需要

這就像 Java 跟 .net 哪個好,可以沒完沒了的爭論
你還是得決定這個案子要用哪一個
又或著說,今天說 Java 好的鄉民比較多,所以用 Java
明天說 .net 好的鄉民比較多,所以改寫成 .net
案子這樣搞能不出事嗎?
那為甚麼「管理」這檔事就可以這樣搞?

更進一步講,一個決策必須正反論點都考慮清楚
或是簡稱「要有配套措施」
壓根不是光看哪邊人比較多就能解決的事情

獨裁? 獨裁又怎樣?
這世界上不採取民主制度的組織團體多的是
如果一群腦袋不清楚、說話不用負責的人搞民主
能得到好的結果,只能解釋為神蹟

在 ptt 改站規 or 鄉民講話得付出代價之前
我會贊成、甚至鼓勵版主獨裁

※   ※   ※

日劇《奇蹟餐廳》
來用餐的客人都是國王
但是,不要忘了
國王,也是有被砍頭的
※   ※   ※

原文寫於 2010.08.12 ptt.cc 的 CodeJob 版。由於新版主 WolfLord 的治版理念十分特別,才剛上任就引發不少議論,因此碎念出這篇......

2010-05-20

GWT 2.1 M1 登場!

原文網址:http://googlewebtoolkit.blogspot.com/2010/05/gwt-21-milestone-1-is-now-available.html

GWT 2.1 M1 版當中,你可以更進一步地以雲端方式建立 business application 但卻如以往一樣容易。使用 GWT 新的 data presentation widget 以及 MVP framework,你可以弄出很好看的 web application、可是執行起來卻很快——無論你是要操作 25 筆資料還是 2500 萬筆資料。我們將這個 widget 設計的非常 lightweight 來達到這個目標,不用 compostie 跟 widget 改使用 DIV 跟 HTML;而 framework 讓你可以很容易地僅在需要的時候只抓取你所要的資料。

為了讓你建立 web application 更快一點,現在你可以使用 VMware 的 Spring Roo ,僅僅使用幾個指令就可以建造一個功能性十足的 application。這些 tools 都已經在  SpringSource Tool Suite (STS) 上可以取得了,包括 Google Plugin for Eclipse、App Engine SDK——提供你一個整合性的開發環境。

最後,當你使用 GWT 開發時,做出來的 application 就是一個 HTML5 的 application 了。這表示已經準備好可以開始進入雲端計算的領域了。

想開始行動了嗎? 看一下我們的商業版 GWT,以及 2.1 版將會有哪些東西?兩個 GWT codesite 上的章節吧!

2010-05-04

徵短期 Java Programmer

工作內容
在我的虐待下跟我一起用 Java 寫 web

無須承擔 project 成敗、需求分析等雜事
也無須作任何 layout 以外美術方面的工作

我盡可能做到標準上班時程
但是遇到 trouble 的話就還請共體時艱
(我一定不會比你早下班就是了,這可以保證 XD)

工作地點不確定,有可能在某間公司、我家
或是長期進駐某間咖啡館...... XD

工作時間可能可以不固定,但是 co-work 是一定的
(要不要 pair programming 就再看看)

理論上下禮拜一(05.10)開始
預計執行兩個月、可能會延長不會縮短

工作地點
台北縣市

聯絡方法
pt2club (gmail)

來信只要留下聯絡方式、這幾天方便面談的時間即可
請不要附學歷、證照清單
想要推薦自己的話
請以 project 經驗、blog 網址、ptt 文章代碼... 等方式
實際丟 code 更歡迎(雖然最近沒太多時間看 Orz)


必備能力
  • basic J2SE、OOP skill
    • 至少迴圈要會寫、物件要會包
    • 知道 interface 跟 abstract class 差別
  • Eclipse 操作
  • 中英文盲打
  • 使用 gmail

進階能力(不會也沒關係,但是會用到這些)
  • GWT
  • basic sql
    • 目前不考慮用 or-mapping,所以還是要下 sql
  • Servlet、Filter
加分條件(依重要順序)
  • 社團經驗(登山社尤佳)
  • 龜毛 programmer
  • 文字紀錄控
  • SD 經驗
  • 熟悉 google 相關服務(sites、docs)
待遇
30K/month 以上,無勞健保、不用扣稅
如果Programming 能力很好、能幫我少掉很多煩惱
薪水我是不會吝嗇的

另外,補一下嘴砲層的待遇
因為要作的是一個 prototype
如果反應好會有後續發展......

附註
真正的案主不是我,所以薪水不是我發的
(如果薪水有差額,會用我的薪水補)
需求訪談、需求分析也有人處理
而跟 coding 有關的事情由我負責

我個性不太好,所以
如果連 Java 版的風格都不能接受的話
那請千萬不要浪費時間來應徵
因為實際 work 起來絕對會更龜毛個幾倍

除了 GWT,這個 project 也不會用到什麼高深技術
一來是 prototype 不必要徒增風險
二來是我也不會啥高深技術... [無誤]
不過對程式碼品質、文件的要求卻非常重視
如果只習慣寫出能 run/compile 就好的人,也請不要來應徵

2010-04-02

GwtQuake:將 Web 提昇到下一個境界

原文:http://timepedia.blogspot.com/2010/04/gwtquake-taking-web-to-next-level.html

技術校正、審閱:tkcn

早在 2009 年 11 月的 GWT 高層腦會議上,我和 Joel Webber 就專注於改善 Web 和 UI latency 議題。有人在介紹 WebGL 時,我發現坐在後頭 Joel 看起來完全沒在聽。當我走近他時,他說:「看過這玩意了嗎?」他晃了晃 notebook 展示 Jake2——將 Quake2 用 Java 移植成 Java Web Start application。幾年前我就看過這個 project 了,只是不知道已經進展到這種地步。

就在那時,我不用問也知道他想幹麼——他提議我們用 GWT 改寫 Jake2!


Web 化的方式
「將 Jake2 這類的東西,用 GWT 來 compile 成 JavaScript」的想法,看起來好像很簡單。因為 GWT 本來就是把 Java compile 成 JavaScript。不過要能 compile 仍需要對程式碼作一堆調整、以及將 I/O 對應到合適的 Web API。

你可能已經知道,GWT 其實只有實做 JRE 的一部份,而 Jake2 使用了很多 GWT 當中沒有的 Java class:

  • 3D 的 LWJGL library
  • java.nio.Buffer
  • 網路對戰需要用的 java.net.*
  • AWT 中關於鍵盤的內容
  • 載入資料要用到的檔案系統 API
  • 影音要用的 OpenAL

更重要的是,它是用 synchronous API 作 I/O,但是 JavaScript 是使用 event driven 的 I/O 方式。

I/O 對應
Joel 將 Jake2 的 I/O 系統重新改寫成用 event driven pump 來載入檔案。我們做的第一件事就是處理關卡與 model 的檔案載入,使用 2D <canvas> wireframe renderer 來處理 rendering(沒有用 WebGL)。接著 Stefan Haustein 貢獻了使用 WebGL 的 javascript array 來實做 Java NIO Buffer 的 JRE class,以及用 WebGL 為基礎的 GL renderer。

Joel 很神奇的用 WebSocket 加上了多人對戰的功能,即使測試的人分散在 Atlanta、Mountain View、甚至是 Sydney(雪梨),我們還是廝殺的很爽。

我繼續轉換所有的聲音成 MP3 格式,並且實做了只用 DOM Audio element 的初步 sound renderer。後來,我把 OpenAL 程式碼重構成一個(譯註:GWT 的)base class,並且提供了 OpenAL Inverse Distance Clamped 聲音 model 的實做,用來調整 3D 位置中的音量變化。除了 audio.volumn 之外,沒有用其他東西。

Stefan 使用 LocalStorage 來實做 RandomAccessFile 供遊戲存檔用,以及用 <video> tag 來實做 video 播放。

大部分的工作在今年一月用 part time 的方式完成,但在那之後進度就卡住了。例如 Stefan 就專注在移植整個單人遊戲(無須 server)成靜態的內容。

我會在 Google I/O 上頭作更詳細的解剖報告,請務必參加!

執行速度呢?
我覺得執行速度可能不快,不過說實話,我從來沒想過我們會做到這種程度;但事實證明,正常播放的 framerate 是有達成的。在 MacBook 上的 WebKit/Chrome 有 20~25fps、在 Mac Pro 桌機則有 45fps。Joel 則說在 Linux(notebook)可以到 60fps。

這對 web 的意義是什麼?
多年來,人們總覺得 browser 對這類事情而言,是一個貧乏的平台,所以需要 Flash、Silverlight、JavaFX 或 native 程式碼。儘管你不應該期望在瀏覽器上頭看到像《Far Cry》或《Call of Duty》這種頂級的作品,但這不能解釋為甚麼一堆 casual game 是用 Flash、或是用 Objective-C(在 iPhone/iPad 上)寫的,而我們使用的類似技術卻作不到。

此外,因為是網頁,你要邀請某人進入你的遊戲或分享遊戲,只要傳一個網址就可以了。你可以只接 tweet 你的遊戲網址、點下去就可以加入遊戲當中。而不需要安裝。雖然 Flash 也可以做到,但直接在 browser 當中會覺得比較「自然」。

我希望這個移植可以鼓勵某些人變得更大膽、更瘋狂地嘗試建立各種 Web App,因為如果 Quake2 用 JavaScript 跟 browser API 都辦得到,更令人驚艷的 application 正等你開發出來。所以,開始動手吧!

移植版的 source code 在:http://code.google.com/p/quake2-gwt-port

----
譯註:關於 quake2 的 GWT 移植版,在 GWT 官方 Blog 也有提到,不過該篇文章沒有這篇仔細,所以選擇翻譯這篇。雖然這個時間點實在令人遐想,不過在 Google Code 上頭的確有「非常真實」的程式碼可以觀看,有興趣者不妨試試看。