還好,第一版的程式沒有難產。這版的目的很簡單,就是把題目實作出來,同時我會盡量套用物件導向的理念去設計程式的結構,而不是只把結果算出來而已。其實我一直覺的,這類生命模擬的程式,是非常適合用OOPL來實作的範例,大概OOPL所有強調的特性 (封裝、繼承、多型、動態聯結... 等等) 都用的到,算是完美的應用範例題吧!
不過很奇怪的,我特地 GOOGLE 了一下,不知 OOPL 高手都不屑寫這種範例還是怎樣,找到的範例程式,不管用什麼語言 (C/C++/Java/C#都有) 寫的,清一色都很沒有物件導向的 fu ... 好吧,只好自己來寫一個。
第一步,一定是先看看你的程式,分析出需要那些類別/物件,及它們之間的關係。比較正規的作法就是 UML 的 UseCase 了。不過這範例其實不大,我就直接跳到 Class Diagram 了 (因為VS2008剛好有現成的...)... 主要的類別有兩個: World (世界) 及 Cell (細胞)。
World 就是給 Cell 生活的空間,我們只訂義一個有限大小的二維空間,就一個 M x N 的棋盤這樣。而 Cell 則是一個細胞,描述單一一個細胞本身,在各種不同的條件下會有什麼反應。先貼一下 class diagram:
圖1. class diagram (World & Cell)
老實說,這張圖還蠻乏善可陳的,World對外公開的介面,大概包含了幾個主要功能,就是取得指定座標的 Cell (GetCell), 及把目前的整個 World 狀態印出來 (ShowMaps) 的 method 而已。而 Cell 的公開介面,不外乎是它目前是活著還是死的,還有它的建構式,及呼叫後會把狀態轉移到下一次狀態的 method。
其它都是 World / Cell 互相溝通用,或是 Init 用的 Method / Prop, 就不多作介紹。先來看看主程式,扮演上帝的你,如何讓這堆單細胞生物,在你的世界裡活起來:
static void Main(string[] args) { int worldSizeX = 30; int worldSizeY = 30; int maxGenerationCount = 100; World realworld = new World(worldSizeX, worldSizeY); for (int generation = 1; generation <= maxGenerationCount; generation++) { realworld.ShowMaps(string.Format("Generation: {0}", generation)); Thread.Sleep(1000); for (int positionX = 0; positionX < worldSizeX; positionX++) { for (int positionY = 0; positionY < worldSizeY; positionY++) { // do day pass Cell cell = realworld.GetCell(positionX, positionY) as Cell; cell.OnNextStateChange(); } } } }
主程式我還沒把不相干的動作刪掉,也才廿一行... line 1 ~ 5 只是初始值,line 6 建立整個世界,之後就每跑完一個世代 (generation) 就休息一秒鍾,繼續下一次進化。這樣隨著時間的過去,畫面上會一直更新整個世界的狀態... 直到只定的次數到了為止。
class World 的部份就沒什麼特別的,就只是把一個二維陣列包裝一下而已。直接貼 Code 就混過去吧 XD,一樣沒有刪掉程式碼,原 CODE 照貼:
public class World { private int SizeX = 0; private int SizeY = 0; private Cell[,] _map; public World(int maxPosX, int maxPosY) { this._map = new Cell[maxPosX, maxPosY]; this.SizeX = maxPosX; this.SizeY = maxPosY; for (int posX = 0; posX < maxPosX; posX++) { for (int posY = 0; posY < maxPosY; posY++) { this._map[posX, posY] = new Cell(this, posX, posY); } } } internal void PutOn(Cell item, int posX, int posY) { if (this._map[posX, posY] == null) { this._map[posX, posY] = item; item.PosX = posX; item.PosY = posY; } else { throw new ArgumentException(); } } public Cell GetCell(int posX, int posY) { if (posX >= this.SizeX) return null; if (posY >= this.SizeY) return null; if (posX < 0) return null; if (posY < 0) return null; return this._map[posX, posY]; } public void ShowMaps(string title) { Console.Title = title; Console.SetWindowSize(this.SizeX * 2, this.SizeY); Console.SetCursorPosition(0, 0); Console.Clear(); for (int y = 0; y < this.SizeY; y++) { for (int x = 0; x < this.SizeX; x++) { Cell item = this.GetCell(x, y); Console.SetCursorPosition(x * 2, y); Console.Write(item.IsAlive? "●":"○"); } } } }
接下來是封裝每個細胞本身跟環境互動的影響,把上一篇講的規則對應成程式碼的樣子。先來看看 CODE:
public class Cell //: Life { protected World CurrentWorld { get; private set; } internal int PosX = 0; internal int PosY = 0; private const double InitAliveProbability = 0.2D; private static Random _rnd = new Random(); public Cell(World world, int posX, int posY) //: base(world, posX, posY) { this.CurrentWorld = world; // setup world this.PosX = posY; this.PosY = posY; this.CurrentWorld.PutOn(this, posX, posY); this.IsAlive = (_rnd.NextDouble() < InitAliveProbability); } public bool IsAlive { get; private set; } protected IEnumerable<Cell> FindNeighbors() { foreach (Cell item in new Cell[] { this.CurrentWorld.GetCell(this.PosX -1, this.PosY-1), this.CurrentWorld.GetCell(this.PosX, this.PosY-1), this.CurrentWorld.GetCell(this.PosX+1, this.PosY-1), this.CurrentWorld.GetCell(this.PosX-1, this.PosY), this.CurrentWorld.GetCell(this.PosX+1, this.PosY), this.CurrentWorld.GetCell(this.PosX-1, this.PosY+1), this.CurrentWorld.GetCell(this.PosX, this.PosY+1), this.CurrentWorld.GetCell(this.PosX+1, this.PosY+1)}) { if (item != null) yield return item; } yield break; } public void OnNextStateChange() { int livesCount = 0; foreach (Cell item in this.FindNeighbors()) { if (item.IsAlive == true) livesCount++; } if (this.IsAlive == true && livesCount <1) { //孤單死亡:如果細胞的鄰居小於一個,則該細胞在下一次狀態將死亡。 this.IsAlive = false; } else if (this.IsAlive == true && livesCount >= 4) { //擁擠死亡:如果細胞的鄰居在四個以上,則該細胞在下一次狀態將死亡。 this.IsAlive = false; } else if (this.IsAlive == true && (livesCount == 2 || livesCount == 3)) { //穩定:如果細胞的鄰居為二個或三個,則下一次狀態為穩定存活。 //this.IsAlive = true; } else if (this.IsAlive == false && livesCount == 3) { //復活:如果某位置原無細胞存活,而該位置的鄰居為三個,則該位置將復活一細胞。 this.IsAlive = true; } else { // ToDo: 未定義的狀態? assert } } }
這裡開始應用到 OOPL 第一個特性: 封裝。從程式碼可以看到,主要的邏輯都被包在裡面了,就 Game Of Life 裡提到的四條規則。
程式這樣寫起來,比那些作業的標準答案看起來舒服多了吧? 雖然行數多了一些,不過看起來比較有 OO 的樣子了。當然只是看起來爽是沒用的,這樣的架構,到目前為只除了邏輯清楚一點之外,還看不到其它很明顯的好處。不過當這個規責稍微複雜一點,OOPL的優點就會被突顯出來了。
下回,把題目做點變化,再來看看程式該如何調整… ((待續))
--
附件: 範例程式碼
[前言]
好久沒寫點自己覺的有內容的東西了... 最近 code 寫的少,實在沒有什麼了不起的新技術可以分享,而 thread 那種 "古典" 計算機科學的東西也寫的差不多了.. 就懶了起來。
雖然沒新技術好寫,不過老狗玩的把戲還是能榨出點渣的... 很多人都熟新技術,可以寫出很炫的程式,不過也常看到程式的結構真的是亂搞一通的... 所以我打算寫些 [設計案例] 的文章,舉一些我實作過的案例,說明什麼樣的問題可以用什麼方式或技術來解決。其實我想寫的就是像 design patterns 那類的東西,只不過我程度還差的遠,只能稱作 "案例" ... Orz
----------------------------------------------------------------------------------
最近 facebook 上有一些小遊戲,不知道在紅什麼... 突然間大家都在玩,就都是些模擬遊戲,像是開心農場、My FishBowl … 之類的,你要在裡面種東西或養魚,條件充足就會長大,收成等等... 然後透過 Facebook API 可以跟別人互動的遊戲。看到這類的 GAME,不禁想起過去在唸書時,幾個經典的作業題目,其中一個 [生命遊戲] (Game of Life) 就是這種 GAME 的始祖...
在 Wiki 找的到這段介紹:
http://zh.wikipedia.org/zh-hk/%E7%94%9F%E5%91%BD%E6%B8%B8%E6%88%8F
生命遊戲(Game of Life),又稱生命棋,是英國數學家約翰·何頓·康威(John Horton Conway)在1970年發明的細胞自動機(cellular automaton,也翻譯成「格狀自動機」)。
它最初於1970年10月在《科學美國人》(Scientific American)雜誌中馬丁·葛登能(Martin Gardner)的「數學遊戲」專欄出現。
1970… 我還沒出生... Orz, 不過, 這麼一個古老經典的問題,找的到一大堆範例程式,或是作業解答。清一色是用 C 這類配的上它的年紀的程式語言寫的,就算有 JAVA 版,大概也是換湯不換藥... 這四十年程式語言及軟體技術的進步,寫這種程式總該有點改變吧?
這篇我想寫的,就是這樣的問題,配合現在的 .NET / C#,能怎麼寫它? 這年代的軟體開發技術,對這種古典的程式能發揮什麼效益?
(警告: 剛好要交作業的人,可千萬別用我的方法交出去啊... 你的助教看不懂可能會給你零分...)
先找個範例來看看... 為了不讓過多的畫面處理程式碼,干擾到主程式的架構,我特地找了兩個 console based 的範例:
Java 版:
http://tw.myblog.yahoo.com/dust512/article?mid=25&prev=28&next=-1
多語言版 (C, Java, Python, Scala):
http://caterpillar.onlyfun.net/Gossip/AlgorithmGossip/LifeGame.htm
這... 這就是典型的 "Java 版 C 程式碼" 的範例... 用 Java 來寫只寫這樣,有點用牛刀的感覺... 新的開發環境強調這幾項:
這些技術怎麼套進這程式? 先來看看這遊戲有幾個障礙要克服吧。遊戲的規則簡單明瞭,借轉貼上面第二個範例的說明:
生命遊戲(game of life)為1970年由英國數學家J. H. Conway所提出,某一細胞的鄰居包括上、下、左、右、左上、左下、右上與右下相鄰之細胞,遊戲規則如下:
- 孤單死亡:如果細胞的鄰居小於一個,則該細胞在下一次狀態將死亡。
- 擁擠死亡:如果細胞的鄰居在四個以上,則該細胞在下一次狀態將死亡。
- 穩定:如果細胞的鄰居為二個或三個,則下一次狀態為穩定存活。
- 復活:如果某位置原無細胞存活,而該位置的鄰居為三個,則該位置將復活一細胞。
以前我最討厭寫這種程式了,這種程式寫起來就跟 Regexp 一樣,是 "write only” 的 code… 怎麼說? 程式寫好後,可能自己都看不懂了,因為邏輯被切的亂七八糟... GAME 裡可能同時有好幾個細胞,每個都有獨立的規則,不過程式卻是一個主迴圈,每次執行每個細胞的一小段邏輯... 程式的流程就這樣被切碎了... 我打算用C#的 yield return, 解決這邏輯破碎的問題。
第二個障礙,就是這類程式,某種程度都是隨著時間的進行而跑的,比如上面的條件都是 "下一次狀態" … 把每次狀態改變定義一個時間 (比如一秒),這就是個 realtime 的模擬程式了。如果有的細胞是一秒改變一次狀態,有的是兩秒,有的是五秒... 那就傷腦筋了... 你的程式會被切的更破碎... 這些每種細胞特殊的部份,我打算用 OOP 的多型來解決。
最後,這種很明顯是 "並行" 的問題,照道理來說,用多執行緒是最適合的了。不過隨便也有成千上萬個 "細胞" 在成長,每個都來一個 thread 養它,再高級的 server 都撐不住吧? 這邊會來探討一下,怎麼用執行緒相關的技巧,來解決這問題。
--------------------------------------------------------------------------------------
寫到這裡,突然覺的這題目好大... Orz, 搞不好這幾篇要撐幾個月才寫的完... 至少有個題材好寫,等到我生出第一個 sample code, 就會有下一篇了... 如果有同好也想試試看的,也歡迎分享看看你的 code… 只不過我沒像 darkthread 有本錢提供獎品... 哈哈 :D
被這東西搞了半天,過了幾個月後發現有善心人事寫了個工具,今天看到了特地來記一篇... 免的以後又忘了 @@
話說 Microsoft 從幾年前開始被一堆 security 的問題苦惱後,決定所有產品都把安全視為第一優先... 這是件好事啦,不過為了 security 問題,真的會把 MIS 及 DEV 的相關工作難度加上好幾倍... 今天這個就是一例: 在沒有 AD 環境下,如何遠端的管理 Hyper-V server ?
之前把家裡的 SERVER 升級到 Windows Server 2008 + Hyper-V, PC 升級為 Vista 後,當然很高興的抓了 Hyper-V 的遠端管理工具回來裝。想說大概跟以往的 MMC 一樣,輸入 SERVER 的資訊,帳號密碼打一打,就可以用了...
事情當然沒這麼簡單,不然就沒這篇了... 直接使用的結果當然只是丟個沒權限之類的訊息。GOOGLE 找了一下解決方式... 找到這文章 (有五篇,別以為很辛苦的把它照作就結束了,還有 part 2 ~ part 5 @@):
細節就不講了,要調整的步驟還真它X的多... 先在 CLIENT / SERVER 都建好帳號,防火牆要允許 WMI,DCOM... 再設定 WMI 相關的權限給指定的帳號,還有後續一堆安全相關的設定要開... 最後搞了半天,真的成功了,不過... 最近趕流行,把 Vista 換成 Windows 7... 真糟糕,這堆步驟又要來一次 @@
這次又找了一下解決方式,還是一樣有這堆設定要改,不過跟幾個月前找到的同一個 BLOG,版主真是個好人,他把他整理出來的步驟寫成了個工具: HVRemote.wsf … 沒錯,就只是個 script 而已,不過它可不簡單。先看一下它的網站:
http://code.msdn.microsoft.com/HVRemote
http://technet.microsoft.com/en-us/library/ee256062(WS.10).aspx
作者把上面那一大串的步驟都寫成 script 了,你只要把這 script 抓下來,放到 client / server 都執行一次,就搞定了 :D 真專業,還有一份很完整的操作說明 PDF 檔... 一定要推一下這個工具 (Y)
附帶提一下,Hyper-V 遠端管理工具是透過 MMC 來執行的,但是我喜歡像 Remote Desktop 那種簡單的作法,只要開個連線工具,驗證過之後就可以遠端桌面這樣... Hyper-V 也有提供這樣的工具。只要裝好管理工具,你的電腦就會有這檔案:
C:\Program Files\Hyper-V\vmconnect.exe
搞什麼,連登入視窗都弄的跟 Remote Desktop Client 一模一樣,有時不小心還真會弄錯 =_=
開起來後就是大家熟悉的 Hyper-V 遠端管理的畫面了。這工具只是讓你省掉從 MMC 去 connect VM 這些步驟而以,像 RDP 一樣開了就能用:
當然透過這工具,上面那堆設定步驟也要照做才會通啦,只是順帶提一下這個 tips 而已。有了 HVRemote 這工具,要設定遠端管理 Hyper-V VM 就更輕鬆了,有需要的人就參考看看吧!
先寫在前面,這篇不是什麼技術的探討或是評論,純脆是我個人看到這消息的想法而已。很久沒貼些軟體相關的文章了,最近比較少在動手寫 Code, 自然就沒什麼新題材好寫 @@,不過這兩天倒是看到一個蠻令人興奮的新聞,就是:
JPEG XR 已經正式通過 ISO 標準了!!
http://jpeg.org/newsrel26.html
http://blogs.msdn.com/billcrow/archive/2009/07/29/jpeg-xr-is-now-an-international-standard.aspx
JPEG 應該已經無人不知,無人不曉了吧? 不過當年還是有朋友鬧過笑話... 曾有人正經八百的來問我
"什麼是 [結合照片專業群組] 啊???" 就是 JPEG 啦 (無聊的話看一下底下的題外話)
我還丈二金剛摸不著頭腦,把他在看的整篇文章拿過來看,才晃然大悟他到底在問啥 =_= ... 原來是 "JPEG: Joint Photographic Experts Group”的縮寫... 當然類似的 MPEG (Moving Picture Experts Group) 也碰過類似的笑話... 無聊 GOOGLE 一下,竟然還查的到一篇範例...
http://support.microsoft.com/default.aspx/kb/235928/zh-tw
My God… 這翻譯真是比之前碰到了 "註冊傑克" 還絕 XD...
之前其實沒特別注意這些標準,曾經有印像的就是用 wavelet 壓縮方式的 JPEG2000... 嘗試取代 JPEG,也取得 ISO 的標準化,不過一直沒達成它的目的,只在特定領域還有應用空間。兩年前 Microsoft 隨著 Vista / WPF 推出 Windows Media Photo 的格式,後來為了讓它成為標準,換了個叫沒有 MS 色彩的名字: HD Photo, 最後變成現在的 JPEG XR ..
我是在兩年前,隨著 .NET 3.0 推出 WPF,剛好自己用的 CANON 相機的 RAW FILE 又被 WPF 支援,所以開始研究相關的 API 及 support .. 在關於 HD Photo 眾多報導中,有個觀點是我相當認同的。找不到較具代表性的消息來源,我就憑記憶寫一下,大意是:
隨著技術進步,未來影像設備 (如印表機,掃描器,顯示器等等) 的色彩表現能力及色域會遠超過 JPEG 格式的範圍 (現在就是了),因此儲存格式支援的動態範圍 (dynamic range) 越高,對於影像的長期保存越重要。
這就是處女座的龜毛個性啊... 衝著這個看法,我從 Canon PowerShot G2 時代開始,我就試著盡量用 .CRW 格式 (CANON RAW) 來保存相片,而不是用 JPEG。後來換了 Canon PowerShot G9,正好 WPF 出來,我就開始改用保存 .CR2 檔,而另外轉一份 JPEG 檔來作一般用途 (畢竟 JPEG 還是方便的多)。不過一張照片花掉 15 ~ 20mb, 保存起來壓力還真不小 =_=
現在看到 JPEG XR 的標準化,正好是我要的東西啊 :D 我需要的正是個能妥善保存這些影像資料細節的方式,同時能讓我輕鬆愉快的使用,不用耽心工具支不支援,或是其它五四三等問題困擾...。這些問題對阿宅來說,一點都不困難,有一缸子的工具辦的到,不過... 如果隨變看個照片,或是要 COPY 給家人朋友看,還要動用一堆雞絲,那也太辛苦了一點... 能有個通用的標準格式及大廠背書,那是再好也不過了 :D
所以,接下來要做什麼? 我突然慶興我一直都有留著這幾年拍下來的 RAW file (.CRW / .CR2) 檔案... 該是替我的歸檔程式翻新的時後了,下一步是開始嘗試用 .WDP 來取代現在放兩份 RAW + JPEG 的方式...
自從上次騎了一次關渡到八里之後,其實後來又去騎了幾次,發現也沒想像中的困難嘛,於是這次就計劃來拼長一點的路線... 關渡到鶯歌。會挑這路線,主要是上次騎到二重疏洪道時,有個路人問我:
"請問往鶯歌要怎麼騎?”
我才發現,原來可以騎到鶯歌啊... 不過當下的反應是騎到那邊腿會斷掉吧? 不過用 google maps 看了一下,單程 35 公里 (加上迷路的一段路,來回應該有 80 了)... 之前近 30 公里都拼完了,騎到鶯歌好好休息,再騎回來應該沒什麼了不起吧? 加上上次那篇有人留話嗆了一句
"是男人就要挑戰百里長征啦"
.... 愛面子的男人於是就很天真的出發了... =_=
很多人問我,為什麼每次都從關渡出發? 哈哈... 原因只有一個: 我很懶 :D,因為那邊捷運出站就有租車店,一輛還可以的變速登山車,當天租一次一台只要一百塊... 想想我一個月頂多騎一次,帶車子搭捷運票價也不止這個錢... 用租的比較方便,所以每次騎的路線就都挑從關渡為起點..
不過這次騎完,開始改變想法了... 哈哈,最後面再講。先來看看這次計劃的路線:
有 GOOGLE Maps 真是方便... 這次路線很簡單,前 1/3 是之前騎過的,之前是繞蘆洲三重一圈就回關渡了,這次會過重新橋,就改沿著大漢溪左岸,一路騎到鶯歌鎮...
出發前上網查了查,發現很多人騎過這段,最後是參考這個人的行程,看了才知道原來鶯歌有個 [阿婆壽司] ... 特色是便宜又不錯吃。雖然我沒有特別愛吃壽司,不過就把它當個目標吧,不然拼到鶯歌我也不知道要幹嘛 XD
算了算時間,一趟算 2.5 hr, 來回 5 hr, 加上一個小時休息吃東西,嗯,不用太早出門...
(啊,大家不要學... 你會後悔的 =_=)
2009/07/19 12:25
過程就不多說了 :P,到了關渡捷運站後,東摸西摸,騎上車開始動身後,過了大度路就先拍一張。我懶的拿紙筆出來計了,就拿起相機拍一拍了事 (時間可以從 EXIF 查,正好省掉記錄的動作),只可惜我的 G9 不支援 GPS ... 不然連地圖都不用標了 :D Canon 你什麼時後要出內建 GPS 的相機...
路上的便利商店,買了兩罐冰釀綠茶,加上租車店老闆送的一罐水... 就上路了...
2009/07/19 13:37
悠哉的騎了一個小時,到了重新橋... 橋下有跳蚤市場,真熱鬧... 好多人 :D,不過騎著車不好人擠人,就沒進去逛了..
2009/07/19 13:43
雖然沒進去逛,不過也是要拍張照紀念。這邊的路標示實在不怎麼清楚,到了橋下就迷路了 :D 哈哈.. 在那邊摸了十幾分鐘,地圖拿出來,還看太陽在那邊認一認方向,硬著頭皮找了對的方向就騎下去... 沒有自行車道,只好走省道,自己識相一點靠邊邊騎...
好在沒騎多遠,就找到自行車道 =_=,就一路沿著大漢溪左岸的自行車道一路往西南騎...
雖然是 "自行車道",不過實際上也只是快速道路隔一條出來給自行車專用... 經費的關係吧 @@,沒關係,有就好,標示清楚一點就好。至少這邊不會騎一段就找不到路... 這是好處 :P
2009/07/19 14:02
騎到一半,才發現,原來新莊的 IKEA 就在路邊耶 :D
沒想到第一次來新莊的 IKEA 是騎著自行車來... 今天沒機會進去逛逛,只好拍張照紀念一下。
2009/07/19 14:15
騎到一半,看到一座天橋,上去後就可以在河提上面繼續騎,或是跨過河提到另一面的巷道裡。我也忘了看誰的文章介紹,他特別介紹了天橋兩側的鐵管... 我就糊理糊塗的跟著牽上去...
(大家不要學啊,這條路是錯的 XD 請不要上橋,繼續沿著自行車道騎就好 …)
都走錯了,不過走過總要留個記錄,還是貼一下好了,不要小看那兩根鐵管併起來的軌道,這樣子牽單車上橋還真的很輕鬆耶 (Y)(Y)(Y),不但很輕鬆就推上去了,鐵管中間還能卡著腳踏車的輪胎,不會亂跑,連車子都不用特別去控制它的方向,只要花點力氣把車往前推就好,真是聰明的設計 (Y)
2009/07/19 14:32
沿著河岸騎了一段之後,自行車道到這邊就結束了... 這邊下來把車扛上河提之後,就進入最後一段 [淡水-鶯歌] 10KM 的車道...
我是不知道為什麼這段叫 [淡水-鶯歌] 啦 @@,不曉得的人還以為真的 10 KM 就到了... 總之,這 10 KM 騎完就到鶯歌了,快到了快到了...
2009/07/19 14:49
遠遠看到這棟建築,還以為是什麼紀念館還是啥的... 原來是個抽水站...
2009/07/19 15:05
路過看到的,覺的很有意思就拍一下 :D
河邊放了一堆消波塊,竟然有人把它漆成這個樣子... 哈哈,真有創意,看起來就像一堆躲在草叢裡探出頭找獵物的迅猛龍...
2009/07/19 15:37
一路都沒看到路標,也不知道到底還多久 @@,最後怎麼覺的那一公里好遠... 騎到這邊早就沒力氣了,都慢慢騎... 總算撐到了鶯歌。看看地圖,其實離火車站沒多遠,不過懶的過去照相了 @@,動身去找阿婆壽司..
2009/07/19 16:12
一開始問了一個媽媽,說往前騎,看到中正三路左轉就到了 (最後找到的地點是中正一路右轉)...
騎錯之後又問一個廿歲左右的小妹妹... 前面路口右轉就到了 (最後是左轉才對 =_=)
路人都報錯,我怎麼還找的到? @@,一切都要感謝全家便利商店外面整面牆上畫的地圖... 哈哈,最後是靠那張地圖找到的...
停下來吃了盒壽司 + 茶碗蒸,肚子餓了什麼都好吃... 50塊就吃飽了... 順手多帶了一盒回去... 水到這邊也都喝光光,去便利商店再補兩罐...
2009/07/19 19:00
回程的路線都一樣,就不再多介紹了,當然迷路過的地方就不會再走錯了 :P
路上河邊有好多人在玩搖控飛機,看了好想也去買來玩... :D 有個傢伙好強,控制的好靈活,其它的只是在亂飛而已。看他表演了好幾招,最後還表演了高級空戰技巧 - 英麥曼迴轉 (Immelman turn) ... 可惜他秀完這招就降落了 (降落的動作也很乾淨利絡... 其它的看起來都像要墜機的樣子 XD),不然我大概會在旁邊一直看吧...
其實從鶯歌要回程起,早就沒啥力氣了 :D,回來的速度就慢多了,騎回二重已經七點了... 當天天空雲還蠻厚的,不過我鐵齒沒搽防曬油,兩隻手被曬的好痛 Q_Q ...
不過也多虧這樣的天氣,當天有晚霞耶... 趕路歸趕路,有大景還是要停下來照一下 :D
不過沒背腳架,騎的很累手也拿不穩相機 @@,只好亂拍一通... 貼幾張還可以看的相片....
2009/07/19 19:27
騎到關渡大橋,那段上坡早就沒力了,連試著騎上來的念頭都沒有.. 當大家都往前衝時我就很沒面子的下來用牽的... 哈哈。一路上一直很納悶,怎麼那些身材嬌小的長腿正妹,每個體力都這麼好 =_= 騎在前面跟都跟不上.... 車子比較好的關係嘛 @@
牽上橋後,休息一下,相機靠著欄干拍了幾張夜景,拍完就繼續往捷運站趕路了...
2009/07/19 19:50
總算... 我頭一次這麼期待進到捷運站... 哈哈,總算可以坐下來了... 不然騎一天下來,屁股還真的會痛 @@
趕在 20:00 之前,總算拼完今天的行程了 :D 哈哈... 今天這樣騎下來,才發現裝備是很重要的... 平時騎兩三個小時那種就沒差了,要騎長程一點的真的要準備一下... 喝的一次就喝掉五罐小保特瓶... 延路都沒便利商店好補貨... 手套要戴 (不然手會握的很痛),排汗衣褲 (不然流一堆汗很難過),適合的背包 (一樣... 不然背很難過),還有電池夠力的 MP3 (我買了台 iPico, 還不錯 (Y),連續聽了七個小時... 只有最後一小段路沒得聽)...
最後,挑台自己的車好像也很重要... 哈哈... 這天我動過不只一次的念頭,很想到鶯歌就扛著腳踏車,搭火車回台北... 不過想到還要回到關渡去還車,就很懶... 還是騎回去好了。看看地圖,如果有自己的車的話,搭捷運到永寧,出來就樹林那一帶了,騎一個小時左右就可以到鶯歌了吧,省了不少路 :D 不過等到有買車再試吧...
這次相片放在 facebook 上,有興趣的人過去看看吧 :D
這次在鶯歌,又有路人在鶯歌問我 "請問大溪要怎麼去" @@
嗯,再說... 這一定是巧合... 這一定是巧合...