2011年2月26日 星期六

中央銀行新聞稿唬爛解讀

這次要唬的是中央銀行新聞稿,請大家不要太早跳出本文。

新聞參考資料(100年1月消費者貸款及建築貸款餘額統計表):兩個數據:購置住宅貸款及建築貸款。房地產循環目前在A3的位置,成交量異常活躍,房地產持有人數量大。目前還不是最高點。至於「課奢侈稅打到房市投資客要害」之類的新聞,完全不用鳥他,也不要高興太早,仔細聽市場聲音就對了。房地產循環不會跳過B1、B2,更不可能直接進入B3,有耐心的人才能等到B3,凡是買在A3、B1、B2的人都要倒大楣。

新聞發布第040號(民國100年1月份五大銀行新承做放款平均利率):利率上升0.030個百分點,原因可能是購屋、週轉金及消費性貸款利率上升所致。為了追求真理,我們必須在一生中,儘可能把所有事物都懷疑一遍。央行也不例外。我的看法很簡單:供需。

新聞發布第039號(中央銀行受財政部委託,於 100 年 2 月 24 日標售 財 100 - 2 期 182 天期國庫券,開標結果如次):天天都便宜。

新聞參考資料(100年1月民間借貸利率):上升一點點。看法不變:供需。

新聞發布第036號(關於本(17)日有媒體報導「央行打炒房 鎖定竹中高」、「新竹台中高雄 打房觀察名單」、「央行再砍炒房 向竹、中、高揮刀」等則,查與事實未符,為免誤導讀者,特此澄清):央行有央行的職責,央行不見得有好的工具,央行再怎麼出招,效果應該比不上一張開徵奢侈稅的芭樂票,如果真的如此,那太可悲了。

以上,謝謝大家。

2011年2月25日 星期五

解讀中國升息密碼

以下內容純為唬爛,千萬不要當真。

事情可以從富十康跳樓事件談起。其實說來說去,都是「錢」的問題,中國工人薪資低,任勞任怨好壓榨,商人看準這點,不斷鼓勵工人賣肝加班趕出貨,薪水能少就少,盡量壓低人事成本。商人無祖國,這邊不便評論是非。

然而,有點腦的工人都知道,自己靈魂已經賣給血汗工廠,頭上彷彿有透明的玻璃,整天被狗幹還是無法獲得認同,也無法再往上爬升。只要是人,都想過好日子,既然活的痛苦,不如歸去算了。或許是跳多了,產生龐大輿論壓力,不得不逼大老闆調薪。錢多自然好辦事,不過錢買不回靈魂。

扯遠了,總之,中國需求變大,開銷增加,購買力降低。於是工人要求老闆加薪,政府也暗中幫工人發聲,錢變多了,成本墊高,物價也跟著上漲,於是工人再要求老闆加薪。於是形成工資和價格互相拉高的現象,這會引起急遽性的通膨。

民眾害怕通膨,怕氧氣越來越不值錢,於是將氧氣投入房地產市場,加上中國人對房子的特殊情感,使得中國房地產快速飆高。房地產終究有其循環,不可能無限制漲上天。

中國政府當然不是白癡,不可能任由氧氣亂竄,可以預見升息發生,而且會不斷發生。金融海潚證明,不受控制的金融市場,最終會引起大災難。中國政府曾走過金融海潚,自然知道這個道理。

中國政府除了「升息、打房」外,還要做到兩件事:增加建設擴張貨幣。建設正在做(十二五),貨幣還在奮鬥中,人民幣能夠撼動美元計價的世界嗎?值得觀察。

總之,升息只是一種結果,原因才是最重要的。中國房地產崩崩吧!但不是現在。以上內容純為唬爛,千萬不要當真,專心聽市場聲音才是正道

PS. 為什麼台灣沒有急遽性通膨?原因很簡單,薪水凍漲。去年受僱員工平均薪資為44430元,雖恢復到金融海嘯前水準,卻只比當時多6元。謝主隆恩,感謝老闆凍漲!

2011年2月24日 星期四

和平就是大調

天下大勢合久必分,分久必合。個人相信 Qaddafi 會垮台,40幾年的高壓統治快要崩潰了。歷史就是那麼有趣,歷史會不斷的重演。

和平就是大調,人民有權力追求財富及自由。

面對 Libya 動盪,我們該做怎麼樣的調整呢?仔細聽市場聲音就夠了。以下是個人唬爛想法:
  1. 短期內,氧氣會跑到原物料上。

  2. 短期內,台灣氧氣貶值,彭神知道台灣氧氣趨勢,以中庸之道跟著趨勢走,不會放任台灣氧氣重貶。

  3. 房地產的氧氣還是十分充足,奢侈稅打房新聞不可能瞬間改變房地產趨勢,持續注意大家心理怎麼想,新聞本身不重要,重要的是民眾對新聞的反應。
祝福 Libya 人民得到自由與財富。謝謝大家。

Clean Code - Meaningful Names

最重要的一點就是 Use intention-revealing names,其他都是本規則的延伸。

之前設計 Physics class,裡面最主要的功能就是 simulate,既然如此,就用 intention-revealing name: Simulator 取代意圖不明的 Physics name。取好名字十分重要,平均來說,寫一行新程式,就要看四行舊程式,有時還得修舊程式。既然常常往前看,何不把舊程式弄好看一點,好看的舊程式,可以幫程式設計師省下不少時間。

為了達到這種境界,我又改了一些 codes,這次還是以 BubbleBall Level One 當例子:
class LevelOneTest {
public:
LevelOneTest() {
simulator_ = new Box2dSimulator();
simulator_->setEdge(...);
simulator_->setPlayer(...);
simulator_->setGoal(...);
}

~LevelOneTest() {
delete simulator_;
}

void setPiece(const Vector2& position, float angle) {
simulator_->setTriangle(...);
}

Simulator* simulator_;
};

struct TestItem { ... };

TEST(LevelOneTest, StressTest) {
TestItem item[] = { ... };

for (int i = 0; i != arraysize(item); ++i) {
LevelOneTest test;
test.setPiece(...);
EXPECT_EQ(..., IsGoaledAfter(...));
}
}

Simulator 的界面:
struct Body {
Vector2 position;
float angle;
BodyType type;
};

class Simulator {
public:
virtual ~Simulator() {}

virtual void setPlayer(...) = 0;
virtual void setGoal(...) = 0;
virtual bool isGoaled() const = 0;

virtual void setEdge(...) = 0;
virtual void setRect(...) = 0;
virtual void setTriangle(...) = 0;
virtual void setCircle(...) = 0;

virtual void simulate(float time_step) const = 0;

virtual std::vector<Body> body(...) const = 0;
virtual Body player() const = 0;
};

為了好名字,改再多次都值得。

2011年2月23日 星期三

高現金殖利率的股票

萬變不離其宗,進股市就是要賺錢。高現金殖利率只是某一種選股方式,至於賺不賺錢,帳戶會告訴你答案。

此外,穩定發放股利的公司,不太可能是爛貨,填息權是遲早的事,2+2=5-1,如果等不到減一,賠錢也是剛剛好而已。當然,凡事都有例外,車諾比核能電廠爆炸之前,美國電廠股利也發的不錯,系統性風險不是開玩笑的。

總之,不管黑貓白貓,能捉老鼠的就是好貓;持進理由上百種,能幫你賺錢的就是好公司。

貨幣之於證券市場,就像氧氣之於呼吸,汽油之於引擎

貨幣是證券市場的氧氣,也是房地產的氧氣。房地產市場吸走不少氧氣,最近原物料也吸走不少氧氣。貨幣+心理=趨勢,證券市場大家心理仍舊看多,導致目前趨勢不明。這是我的想法。至於個股的話,有一些特別的想法,明天來說好了。

關於房地產的聲音:
戴德梁行總經理顏炳立指出,市場上目前不少B級產品卻賣A級價格、新北市動輒賣6、70萬元,這些價格與品質脫鉤的物件,未來恐將會有泡沫的隱憂,房價恐怕會被打回原形。
我原先的想法:合理房價約等於200-250個月租金,只要相信,合理價格就會出現,有耐心就會等到。

以上是我的想法,謝謝大家。

PS. 股市大膽猜測:B1。對於未來只能用猜的,準不準帳戶會說話。

2011年2月22日 星期二

楊進添「被捅一刀」

標題出自:軟硬兼施!深夜才叫牛丼給菲特使

楊進添說的很好:「這就有如一個好朋友,忽然之間,被另外個好朋友,無預警在後面捅了一刀。」人無信不立,沒有信用,什麼都不用談。

人要守信用,公司也要守信用,國家更要守信用。

一個國家興衰的關鍵在於信用。一個公司興衰的關鍵也在於信用。人也不例外。德國有信用,汽車/工業產品深獲世人肯定。股市裡有一些不守信用的公司,什麼時候捅你一刀你都不曉得,這種公司要特別小心。至於人,除了自我要求外,請大家睜大眼睛謹慎交友嘍。

多交好人,多幫助好人,讓好人幫助你,整個世界就會越來越好。舉例來說,我長的很醜,但心地很善良,要交朋友就要找這種好咖。謝謝大家。

2011年2月21日 星期一

熱錢敢炒匯就試看看

2月10日央行副總裁周阿定宣示熱錢敢炒匯就試看看,這不代表台幣將會貶值,也不代表將會升值,就跟柳樹一樣,風吹自然隨風起,趨勢是央行最好的朋友,美國如果持續量化寬鬆,台幣自然會反應。

中央銀行3月底將召開首季理監事會,可以觀察後續變化,市場已經有不少風聲。個人猜測央行真的很關心通膨,但談不上全面抵抗,適度通膨是好的。當然有些專家不以為然,個人不評論未來,我只關心世界各國怎麼做。

Andre Kostolany:寧願要5%的通貨膨脹率,也不要5%的失業率,輕度通貨膨脹根本不會危害經濟。只要薪水跟著漲,還怕啥通膨?謝謝大家收看。

C++ Coding Standards - Prefer composition to inheritance.

Herb Sutter and Andrei Alexandrescu 的理由是:Avoid inheritance taxes: Inheritance is the second-tightest coupling relationship in C++, second only to friendship. 除了 tight-coupling 外,一個重要的原因是 OO-modeling 哲學:兒子不能超過爸爸。兒子指的是 derived class,爸爸當然是 base class.

之前寫的 BubbleBall Level One 是錯誤示範,兒子超過爸爸了。改寫後如下:
class Box2dLevelOne {
public:
Box2dLevelOne() {
physics_.initWorld();
physics_.setEdgeBackground(...);
physics_.setPlayer(...);
physics_.setGoal(...);
}
~Box2dLevelOne() {
physics_.deinitWorld();
}

void setTriangle(...) {
physics_.setTriangle(...);
}

bool isGoaledAfter(int seconds) {
float time_step = 1.0f/60.0f;
for (int i = 0; i < seconds; ++i) {
physics_.simulate(time_step);
if (physics_.isGoaled()) {
return true;
}
}
return false;
}

private:
Box2dPhysics physics_;
};

TEST(Box2dLevelOne, StressTest) {
const TestItem item[] = { ... };

const int size = arraysize(item);
for (int i = 0; i != size; ++i) {
Box2dLevelOne level;
level.setTriangle(...);
EXPECT_EQ(item[i].is_goaled, level.isGoaledAfter(60 * 10));
}
}

以上。當然我還犯其他錯誤 (過早最佳化,沒有利用 assert 來說明內部假設與不變性),接下來會修掉這些錯誤。繼續加油吧!

2011年2月19日 星期六

土地資產概念股

可以從幾個角度來看:

清算價值 - 固定資產的實現價值大約只足夠彌補流動資產價值減損的部分,所以,一個工業公司證券的「淨流動資產價值」可能約略等於其清算價值。如果證券價格遠低於他的淨流動資產價值,請用力思考背後所隱藏的事實 [Graham, The Interpretation of Financial Statements]

概念股 - 對於投機人士來說,媒體評論完全多餘,而且毫無用處。專家引用報章評論,尋找合乎邏輯的因素,但證券市場有自己的邏輯,和普通消費者的邏輯沒什麼關係。不論在世界上的那一個股票市場中,最不好的股票就是所謂的「概念股」,因為概念股的股價完全不隨趨勢走動,全球各地股市皆然。這種股票高低震盪,表現的只不過是十萬名歇斯底里的股票專家或所謂半調子行家的反應罷了,而這些人的想法往往說變就變。[Andre Kostolany]

我的想法很簡單:房地產火熱,土地資產價值增加,但買賣土地不是工業公司的本業,企業就該專心本業才對。處份閒置土地雖然增加不少獲利,但換個方面想,有可能之前產能過剩,導致閒置廠房過多(不利),或者經營團隊太過保守,沒有新的投資活動(不利),這都要仔細思考。(PS. 補一槍。爛公司特徵之一:股本佔股東權益比超過 5成,最近很夯的這家公司,股本/股東權益 = 17成,真是有夠誇張的)

別人不敢登的屍體,我們一定要登頭版。別人拍不到的內褲,我們一定要拍的到。台灣媒體這麼多,怎麼報?亂報咩,亂報不就得了。

2011年2月18日 星期五

唬爛不用錢!筆記型電腦產業研究

低毛利時代 - 營收不斷往上,利潤沒有等比例的提升,呈現很明顯的肥尾:肥尾吃不到,只能吃菜尾。如果肥尾吃的到,我就不會宅在這邊貼文章了。

市場 - NB 以外銷為主,美國、歐洲佔極大的比例,歐美不好,台灣 NB 產業也會不好。當然,新興市場也逐漸在抬頭,不可輕忽。

換機潮 - 不可否認 Microsoft 新一代的作業系統 Windows 7 很炫很好用,但品質不等於賺錢,以前 Windows 95 熱賣,還不是當的亂七八糟。市場有很多聲音,除了仔細聆聽外,更要用大腦去思考,獨立下決定,才不會人云亦云,做出很瞎的判斷。

消費性NB vs 商用 NB - 消費性NB 成長率遠高於商用 NB,現在消費性NB 非常便宜 (低毛利的好處),大家也樂於接受 NB,自然 NB 產業營收就會往上,但還是要留意:利潤沒有等比例提升。買房子剛好相反,大家越買房子,房子越貴,原因很簡單:限量是殘酷的。

人才 - 低毛利壓縮人事成本,鳥薪水請鳥人,請不起人才,不能怪供給出問題。這會造成惡性循環,壓低成本請鳥人,鳥人沒有競爭力,公司賺不了錢,毛利率更低,只好再壓低成本請鳥人…台灣這種產業很多,令人十分擔心。

匯率風險 - 產品以歐美為主要市場,更要考慮美元、歐元匯率風險。此外,關鍵零組件 (LCD、CPU、HDD 等等) 仍靠美、日、韓、台廠商供應,材料成本難以掌握,跨國做生意真的要思考許多層面。

如果有更好的機會,個人不會壓 NB產業,上一個工作就壓錯寶,不投資品牌,台灣永遠是血汗工廠。以上為唬爛研究,僅供參考。

Test on BubbleBall Level One

不囉嗦直接看 test:
#include <gtest/gtest.h>
#include "base_level.h"
#include "base_level_helper.h"

class LevelOne : public BaseLevel {
public:
LevelOne() {
InitWorld();
SetEdgeBackground(math::Vector2(-50.0f, 0.0f), math::Vector2(50.0f, 0.0f));
SetPlayer(math::Vector2(-10.0f, 3.0f));
SetGoal(math::Vector2(10.0f, 0.3f));
}
~LevelOne() {
DeinitWorld();
}

bool IsGoaledAfter(int seconds) {
float time_step = 1.0f/60.0f;
for (int i = 0; i < seconds; ++i) {
Simulate(time_step);
if (IsGoaled()) {
return true;
}
}
return false;
}
};

TEST(LevelOneTest, ReachGoal) {
LevelOne level;
level.SetTriangle(math::Vector2(-10.0f, 0.0f), 0.0f);

EXPECT_TRUE(level.IsGoaledAfter(60 * 10));
}

TEST(LevelOneTest, AnotherWayToReachGoal) {
LevelOne level;
level.SetTriangle(math::Vector2(-10.0f, 0.1f), 0.0f);

EXPECT_TRUE(level.IsGoaledAfter(60 * 10));
}

TEST(LevelOneTest, WrongPosition) {
LevelOne level;
level.SetTriangle(math::Vector2(-2.0f, 0.0f), 0.0f);

EXPECT_FALSE(level.IsGoaledAfter(60 * 5));
}


從測試可以看到 BaseLevel class 非常好用:生世界,接著設定背景、玩家、目標、三角形,接著模擬,詢問物體方位,判斷有沒有達陣,最後滅世界,就那麼簡單。這就是典型 Template method patterns 加 builder patterns 的應用。至於 BaseLevel 細節,我就不多說了,人有秘密才有神秘感,哈哈。

謝謝大家收看,接下來要拼 Level Two 了。(附註:當初以為已經過測試了,其實沒有。當我再寫其他類似測試後,發覺失敗,於是再把缺的東西補起來,修掉一些 bugs,弄到剛剛終於過了。@台灣時間 2011年2月20日 AM1:23,太苦了,要來睡覺了,晚安。)

「豪宅對墓地 賭場大亨搶著要」新聞筆記

1. 嫌惡設施這裡有介紹,思考一下有沒有道理,還有其他嫌惡設施嗎?至少我就想醫院。雖然走幾步路就可看病,但要留意太平間與急診室的位置。

2. 房子不可能完美無缺,可以被買家挑毛病的點,專業上叫抗性,例如:鄰棟距離太近、旁邊有嫌惡設施、格局差,都是所謂的抗性。房子有抗性,價格自然不漂亮,千萬不要覺得便宜就買,你喜歡的別人不一定喜歡,價格是最真實的,到時候買家把你砍到流血,千萬不要喊痛。

3. 房仲偶爾會唬爛高壓電塔會拆,福地會遷走,請仔細查證。個人對嫌惡設施沒有意見,不過房價會說話,身體會說話,心理也會說話,不好脫手的產品不要買,如果不幸碰到系統性風險,很有可能賣也賣不掉。

以上,謝謝大家。

2011年2月17日 星期四

市場的聲音

不管是看財報,還是看論文,最重要的內容在哪裡?在小字註解,惡魔總是躲在細節裡。

公開資訊觀測站即時重大訊息最下面有一行小字,大家看仔細了:
以上資料均由各公司輸入後由本系統對外公佈,資料如有虛偽不實,均由該公司負責.
呵呵,René Descartes說:為了追求真理,我們必須在一生中,儘可能把所有事物都懷疑一遍。

今天這件事讓我想到一篇好文,討論暴力傾向的好文:
首先,沒有「正常人」這回事,一旦進入吵雜的境界(非常生氣),稍微失常的人,可能不知不覺中,自然就會產生某些後果(摔東西、暴力),讓人退化成小學生,反應切換成全自動,無法冷靜思考,推理能力大減。

很遺憾,這些後果沒有一個好的!!!

對女人摔東西沒什麼,但他媽的實在很容易跟家暴混淆。
剛好想到這篇文章,很有意思。至於是非對錯,就留給市場評斷吧,咱們聽聲音就好了。謝謝大家。

2011年2月16日 星期三

Exploring Information Leakage in Third-Party Compute Clouds 筆記

Here is a link.

Risks:
1. Customers must trust their cloud providers to respect the privacy of their data and the integrity of their computations.
2. Cloud infrastructures can also introduce non-obvious threats from other customers due to the subtleties of how physical resources can be transparently shared between virtual machines.

For 1, 無解。這是信用問題。信用問題不解決,什麼都不用談了。
For 2, require two main steps: placement and extraction.
Placement refers to the adversary arranging to place their malicious VM on the same physical machine as that of a target customer.

Extraction refers to extract confidential information via a cross-VM attack.

問題思考:
1. Can one determine where in the cloud infrastructure an instance is located?
2. Can one easily determine if two instances are co-resident on the same physical machine?
3. Can an adversary launch instances that will be co-resident with other user’s instances?
4. Can an adversary exploit cross-VM information leakage once co-resident?
結論:
1. Cloud providers may obfuscate both the internal structure of their services and the placement policy to complicate an adversary’s attempts to place a VM on the same physical machine as its target.
2. One may focus on the side-channel vulnerabilities themselves and employ
blinding techniques to minimize the information that can be leaked.

3. RightGrid architecture: RightGrid.

2011年2月15日 星期二

Test/Code Cycle in XP

1. Write one test
2. Compile the test. It should fail to compile, as you haven't yet implemented the code that the test calls.
3. Implement just enough to compile.
4. Run the test and see it fail.
5. Implement just enough to make the test pass.
6. Run the test and see it pass.
7. Refactor for clarity and to remove duplication.
8. Repeat from the top.

多做幾次就熟悉了。看文章可以吸收一成知識,聽演講吸收三成,照著做可以吸收七成,舉一反三可以達到九成。舉個例來說,世界上好書那麼多,如果每個人認真閱讀,並且化為實際行動,對全世界才有實際貢獻,世界上嘴砲的人太多了,尤其是台灣。前天曾雅妮登上球后寶座,這就是很好的榜樣,台灣要走出去,光在那邊唬爛,一點用也沒有。

回歸正題,今天再寫個測試,包含物體旋轉測試、組合物體測試等等 (目前還缺反轉重力測試,剛剛偷加果然失敗)。把一些細節補上,測試過了,但 duplicated code 太多,這時候就要 refactor。

例如 copy/paste CreateFixture() 兩次,那我就把這個 method 抓到共用的 header file,給一份實做就好了,將來 CreateFixture() 要改動,就不用改兩份一模一樣的 code,或是漏改其他份 code。以上是簡單的例子,更多例子可以參考 Refactoring: Improving the Design of Existing Code,謝謝大家收看。

2011年2月14日 星期一

交易員的靈魂貳之一

爛公司具有以下特點:

1. CEO陶醉於極致的成就
2. 股本佔股東權益比超過 5成
3. 股本形成中來自現金增資的比率越多越好
4. 一家公司上市上櫃滿兩年以後,盡量發生大幅度現金增資的行為
5. 「有創意」令人存疑的盈餘

以上僅供參考,請小心服用,謝謝大家。

2011年2月13日 星期日

Do The Simplest Thing That Could Possibly Work

今天加 SphereStack test,果然爛掉。為什麼?這是因為個人奉行:
Do the simplest thing that could possibly work.

這就是 test-driven 的精神,除非測試失敗,否則不要寫多餘的程式碼,即使下個測試會用到。因此原先系統不支援圓形物體,這就是為什麼會爛掉的原因。

在這當下,才是真正寫程式碼的時機。
  if (config.shape_config->type == ShapeConfig::Polygon) {
...
b2PolygonShape shape_impl;
...

b2FixtureDef config_impl;
config_impl.shape = &shape_impl;
config_impl.friction = config.friction;
config_impl.restitution = config.restitution;
config_impl.density = config.density;

itself_->CreateFixture(&config_impl);
}
else if (config.shape_config->type == ShapeConfig::Circle) {
...
b2CircleShape shape_impl;
...

b2FixtureDef config_impl;
config_impl.shape = &shape_impl;
config_impl.friction = config.friction;
config_impl.restitution = config.restitution;
config_impl.density = config.density;

itself_->CreateFixture(&config_impl);
}
好多重複的程式碼,雖然可以立即 refactor,改善既有的程式碼,但目前測試都沒過,千萬別急著動,這也是 test-driven 的精神。測試過了再來 refactor,順便確保 refactored code 是對的。

跑測試,沒過。見鬼了!不是的,因為我又少支援線段物體,只好再加上去讓他過。
  if (config.shape_config->type == ShapeConfig::Polygon) { 
...
}
else if (config.shape_config->type == ShapeConfig::Circle) {
...
}
else if (config.shape_config->type == ShapeConfig::Edge) {
...
b2EdgeShape shape_impl;
...

b2FixtureDef config_impl;
config_impl.shape = &shape_impl;
config_impl.friction = config.friction;
config_impl.restitution = config.restitution;
config_impl.density = config.density;

itself_->CreateFixture(&config_impl);
}
更多重複的程式碼。這不重要,重要的是先跑測試。啊!過了。接著再來 refactor 吧!
  b2Shape* shape_wrapper;

if (config.shape_config->type == ShapeConfig::Polygon) {
...
b2PolygonShape* shape_impl = new b2PolygonShape();
shape_wrapper = shape_impl;
...
}
else if (config.shape_config->type == ShapeConfig::Circle) {
...
b2CircleShape* shape_impl = new b2CircleShape();
shape_wrapper = shape_impl;
...
}
else if (config.shape_config->type == ShapeConfig::Edge) {
...
b2EdgeShape* shape_impl = new b2EdgeShape();
shape_wrapper = shape_impl;
...
}
else {
return;
}

b2FixtureDef config_impl;
config_impl.shape = shape_wrapper;
config_impl.friction = config.friction;
config_impl.restitution = config.restitution;
config_impl.density = config.density;

itself_->CreateFixture(&config_impl);

delete shape_wrapper;
再跑測試,還是過,refactor 品質沒有問題 (可能 code 還很髒,可能還有 bug,不過至少可以過 SphereStack)。Do the simplest thing that could possibly work.

More Acceptance Tests

Box2d Testbed project 藏有許多漂亮的 demos,之前已經完成最簡單的 freefall 測試,這次玩複雜一點的 VaryingFriction 測試:準備五個箱子,摩擦係數皆不同。摩擦係數高 > 0,走的距離短,最後會卡在滑坡上;摩擦係數零的箱子會一直滑下去 (牛頓第一運動定律:動者恆動靜者恆靜)。

這次 test 採用 gtest 的 Test Fixtures,這樣就可以寫各式各樣類似的測試 (僅僅 time_step 會變)。

整個 code 很簡單:
#include <gtest/gtest.h>
#include "physics_simulation/box2d/box2d_service.h"
#include "physics_simulation/box2d/box2d_world.h"
#include "physics_simulation/box2d/box2d_body.h"

#include "physics_simulation/world_config.h"
#include "physics_simulation/body_config.h"
#include "physics_simulation/fixture_config.h"
#include "physics_simulation/polygon_shape_config.h"
#include <math.h>

namespace physics_simulation {
namespace box2d {

class VaryingFrictionTest : public testing::Test {
protected:
virtual void SetUp();
virtual void TearDown();

World* world_;
Body* box_[5];
Body* track_[3];
Body* ground_;

private:
void SetUpWorld();
void SetUpGround();
void SetUpTopTrack();
void SetUpMiddleTrack();
void SetUpBottomTrack();
void SetUpRightStopper();
void SetUpLeftStopper();
void SetUpFiveBoxes();

Body* stopper_[2];
};

void VaryingFrictionTest::SetUp() {
SetUpWorld();
SetUpGround();
SetUpTopTrack();
SetUpMiddleTrack();
SetUpBottomTrack();
SetUpRightStopper();
SetUpLeftStopper();
SetUpFiveBoxes();
}

void VaryingFrictionTest::TearDown() {
delete world_;
}

void VaryingFrictionTest::SetUpWorld() {
Service* service = new Box2dService();

WorldConfig config;
config.gravity.set(0.0f, -10.0f);
this->world_ = service->createWorld(config);

delete service;
}

void VaryingFrictionTest::SetUpGround() {
BodyConfig config;
this->ground_ = world_->createBody(config);

PolygonShapeConfig shape;
shape.setAsEdge(math::Vector2(-40.0f, 0.0f),
math::Vector2( 40.0f, 0.0f));
FixtureConfig fixture;
fixture.shape_config = &shape;
fixture.density = 0.0f;
this->ground_->createFixture(fixture);
}

void VaryingFrictionTest::SetUpTopTrack() {
BodyConfig config;
config.position.set(-4.0f, 22.0f);
config.angle = -0.25f;
this->track_[0] = world_->createBody(config);

PolygonShapeConfig shape;
shape.setAsBox(13.0f, 0.25f);
FixtureConfig fixture;
fixture.shape_config = &shape;
fixture.density = 0.0f;
this->track_[0]->createFixture(fixture);
}

void VaryingFrictionTest::SetUpMiddleTrack() {
BodyConfig config;
config.position.set(4.0f, 14.0f);
config.angle = 0.25f;
this->track_[1] = world_->createBody(config);

PolygonShapeConfig shape;
shape.setAsBox(13.0f, 0.25f);
FixtureConfig fixture;
fixture.shape_config = &shape;
fixture.density = 0.0f;
this->track_[1]->createFixture(fixture);
}

void VaryingFrictionTest::SetUpBottomTrack() {
BodyConfig config;
config.position.set(-4.0f, 6.0f);
config.angle = -0.25f;
this->track_[2] = world_->createBody(config);

PolygonShapeConfig shape;
shape.setAsBox(13.0f, 0.25f);
FixtureConfig fixture;
fixture.shape_config = &shape;
fixture.density = 0.0f;
this->track_[2]->createFixture(fixture);
}

void VaryingFrictionTest::SetUpRightStopper() {
BodyConfig config;
config.position.set(10.5f, 19.0f);
this->stopper_[0] = world_->createBody(config);

PolygonShapeConfig shape;
shape.setAsBox(0.25f, 1.0f);
FixtureConfig fixture;
fixture.shape_config = &shape;
fixture.density = 0.0f;
this->stopper_[0]->createFixture(fixture);
}

void VaryingFrictionTest::SetUpLeftStopper() {
BodyConfig config;
config.position.set(-10.5f, 11.0f);
this->stopper_[1] = world_->createBody(config);

PolygonShapeConfig shape;
shape.setAsBox(0.25f, 1.0f);
FixtureConfig fixture;
fixture.shape_config = &shape;
fixture.density = 0.0f;
this->stopper_[1]->createFixture(fixture);
}

void VaryingFrictionTest::SetUpFiveBoxes() {
PolygonShapeConfig shape;
shape.setAsBox(0.5f, 0.5f);

FixtureConfig fixture;
fixture.shape_config = &shape;
fixture.density = 25.0f;

const float friction[5] = { 0.75f, 0.5f, 0.35f, 0.1f, 0.0f };
for (int i = 0; i < 5; ++i) {
BodyConfig config;
config.type = BodyConfig::Dynamic;
config.position.set(-15.0f + 4.0f * i, 28.0f);
box_[i] = world_->createBody(config);

fixture.friction = friction[i];
box_[i]->createFixture(fixture);
}
}

namespace {

float dist(const Vector2& u, const Vector2& v) {
return Vector2(u.x - v.x, u.y - v.y).length();
}

} // namespace

TEST_F(VaryingFrictionTest, AfterOneMinute) {
const int steps = 60 * 60; // One minute
const float time_step = 1.0f/60.0f;
for (int i = 0; i < steps; ++i) {
world_->simulate(time_step);
}

// Box #0 and #1 are on the top track.
for (int i = 0; i < 2; ++i) {
EXPECT_LT(dist(box_[i]->position(), track_[0]->position()),
dist(box_[i]->position(), track_[1]->position()));
EXPECT_LT(dist(box_[i]->position(), track_[0]->position()),
dist(box_[i]->position(), track_[2]->position()));
}

// Box #2 is on the bottom track
EXPECT_LT(dist(box_[2]->position(), track_[2]->position()),
dist(box_[2]->position(), track_[1]->position()));
EXPECT_LT(dist(box_[2]->position(), track_[2]->position()),
dist(box_[2]->position(), track_[0]->position()));

// Box #3 is on the ground
EXPECT_FLOAT_EQ(0.51503909f, box_[3]->position().y);

// Box #4 is out of the screen
EXPECT_TRUE(box_[4]->position().length() > 2000.0f);
}

} // namespace box2d
} // namespace physics_simulation
強力推薦大家使用 Google C++ Testing Framework. 接下來再寫幾個 acceptance tests,然後開始偷竊游戲物理設定。

2011年2月12日 星期六

Tendenz = Geld + Psychologie

趨勢等於資金加心理。現在來分析心理。先看幾個消息:

摩根富林明調查:台灣投資人信心指數大躍進 (2011.02.09),就業市場,進入求才年 (2011.02.09),消費者信心指數新高 景氣復甦有感覺了 (2011.1.26)。

群眾心理不言可喻。

不過事情總是有變化,群眾心理有點鬆動,繼續聽市場的聲音吧。

交易員的靈魂壹之一


Q: 2006 年 12 月 12 日出現一根跌幅超過 2%以上的長黑日K線,不妨就從這個提示開始思索:過去幾次遇到上述情況後的大盤表現,以往回檔過程中總共出現幾次跌幅超過 2%的長黑日K線?

A: 不知道。

Q': 某月出現一根超長的黑月K線,過去幾次遇到上述情況後的大盤表現,以往回檔過程中總共出現幾次超長的黑K月線?

A': 送分題自己查。這次呢?先等二月份過完吧。

另外,自己也清楚 Zurich axiom 所說的:On Patterns - Chaos is not dangerous until it starts to look orderly. Beware the chartist’s illusion - it is characteristic of human minds to perceive links of cause and effect where none exist. 就算是送分題,也要特別小心,免錢的最貴,只有思考才是王道。未來會怎樣?老話一句:「不知道」

2011年2月11日 星期五

RE: 美元匯率趨勢

彭神指出,新台幣在是今年全球升值幅度最大的貨幣,但新台幣大幅升值,會讓企業出現匯損。彭淮南說,最近還收到做雨刷企業主電子郵件抱怨,說新台幣升值,但國外買主不同意調價,已一、二個月拿不到訂單了。

彭神表示,新台幣兌美元匯率升值可使新台幣計價的進口物價升幅,低於以美元表示的物價升值幅度,舒緩進口物價上漲壓力,不過台幣也不能一直升,因為從總體來看,出口降低,人均所得也會降低。

彭神指出,很多人誤以為新台幣升值會讓購買力增加,但事實上從國民總所得來看,如果台幣升過頭,造成出口減少、貿易出超下降,以新台幣表示的國內生產毛額(GDP)會下降,民眾所得反而減少,根本沒錢去買東西。

彭神說,央行會持續監督外資動向,要求資金匯入後最多只能留下3%當周轉金,其餘要在一周內投入股市;未來外資每匯入10元,最多只能拿3元去買公債等固定收益商品,剩下7元都必須投入股市,否則就得立即撤出。

彭神表示,據央行掌握資訊,先前沒有投入股市的疑似熱錢兵分三路,分別停泊在借券保證金、公債和新台幣存款。



外資還會炒匯嗎?這是買點還是埋點?結論跟上篇類似:「未來向上還是向下?我不知道,真的不知道,但彭神的確很關心台幣。」

這次不一樣

Tendenz = Geld + Psychologie,趨勢等於資金加心理。

資金方面,昨天彭淮南指出,外資慣用的操作手法就是,波段買進、波段賣出,之前已經累計匯入三千多億,也在期貨大量放空,對外亂喊新台幣會升到多少多少元,卻適時賣出、獲利了結「大賺兩方面」,但「股市的部分我不評論」。彭淮南僅表示,外資持有台股市值約三成,一旦資金撤出,有相當大的影響力。至於目前是否為外資由買轉賣的波段起始點,彭淮南仍保持一貫神祕地表示,「匯價由市場決定,央行只是維持動態穩定」。

(註:大資金「波段買進、波段賣出」十分合理。至於「對外亂喊新台幣會升到多少多少元」,怎麼看都不像「亂喊」,這僅僅是完美投機計畫步驟之一,被騙只是剛剛好。)



當然,上面消息只代表「三成」股市的聲音,其他七成怎麼說,我不知道。至於心理方面,不予評論。

這次不一樣?真的嗎?其實我很害怕,金融海嘯前,各類基金炒翻天,投資型保單狂賣。現在房地產也夯到不行,最近也有三個單位向我推銷儲蓄型保單,更別說有人拉我直銷。

(某層面被說服了,個人需要「教育訓練」素材。至於拉下線賺獎金,這我不幹。錢不是臭的,但拉下線的錢是臭的。)

(我朋友認為:「先有很多錢,才創業」,這觀念不對,應該是「先創業,錢會自己過來」。至於「複製」,除非有改變,每個人都在複製舊有的習慣,要改變才會有機會。至於拉下線就不用說了,你還是為某人工作,拿微乎其微的獎金。月入百萬?哪個行業最頂尖的人月入不到百萬?就算是最噱的黑道,下面小弟有月入百萬嗎?公司規模 892m usd,敢唬爛我 400b usd,這也差太多了吧。)



個人相信:這次還是一樣。歷史就是不斷的重演。

2011年2月10日 星期四

美元匯率趨勢


Link: ForecastChart.com

點選 20 Year Graph - Taiwan Dollar (TWD) 可看到 20年長期趨勢,截圖在旁邊。未來向上還是向下?我不知道,真的不知道,但台幣的確在升值。

ForecastChart.com 網頁旁邊有 Currency Exchange Rate Forecasts,可以觀察幾個重要的通貨,研究一下趨勢,有感覺了嗎?

這就是趨勢。

註:最近美金儲蓄險很夯,友人一直向我推薦。個人認為,凡事都要「簡單化」,如果看準美元已經升不上去,準備要狂貶了,直接買美元才是最簡單,也是最好的投機方式。美金儲蓄險「不是」簡單的投機方式。

此外,Max Gunther 說:Long-range plans engender the dangerous belief that the future is under control. It is important never to take your own long-range plans, or other people’s, too seriously. 說的太好了,六年之後的事,不是我們能操縱的,把「美金儲蓄險」當做「美金儲蓄險」,問題會簡單的多。

Acceptance Tests

Extreme programming uses testing two ways: Customers develop acceptance tests that determine the overall behavior of the system, and Programmers create unit tests while programming.

As a Customer, you'll create tests for each story you request. You'll measure the progress in developing the system by running these tests.

目標: 偷竊物理模擬小遊戲.

物理模擬部分,已經抽出「合適」的 interfaces,implementor 採用 Box2D,為了「證明」Box2D 滿足遊戲 (customer) 需求,自然要有幾個簡單的小測試。這種測試就稱為 acceptance tests。

第一個測試就是自由落體 (freefall):
TEST(Box2d, Freefall) {
Service* service = new Box2dService();

// Construct a world, which will hold and simulate the rigid bodies.
WorldConfig world_config;
world_config.gravity.set(0.0f, -10.0f);
World* world = service->createWorld(world_config);

// Config ground body.
BodyConfig ground_config;
ground_config.position.set(0.0f, -10.0f);
Body* ground = world->createBody(ground_config);

// Config ground body fixture.
PolygonShapeConfig ground_shape_config;
ground_shape_config.setAsBox(50.0f, 10.0f);

FixtureConfig ground_fixture_config;
ground_fixture_config.shape_config = &ground_shape_config;
ground_fixture_config.density = 0.0f;
ground->createFixture(ground_fixture_config);

// Config dynamic body.
BodyConfig dynamic_config;
dynamic_config.type = BodyConfig::Dynamic;
dynamic_config.position.set(0.0f, 4.0f);
Body* dynamic = world->createBody(dynamic_config);

// Config dynamic body fixture.
PolygonShapeConfig dynamic_shape_config;
dynamic_shape_config.setAsBox(1.0f, 1.0f);

FixtureConfig dynamic_fixture_config;
dynamic_fixture_config.shape_config = &dynamic_shape_config;
dynamic_fixture_config.density = 1.0f;
dynamic_fixture_config.friction = 0.3f;
dynamic->createFixture(dynamic_fixture_config);

// Simulate.
const float time_step = 1.0f/60.0f;
const int steps = 60;
const float expected[] = {
3.997222f, 3.991667f, 3.983333f, 3.972222f, 3.958333f, 3.941667f,
3.922222f, 3.900000f, 3.875000f, 3.847222f, 3.816667f, 3.783333f,
3.747222f, 3.708333f, 3.666667f, 3.622222f, 3.575000f, 3.525000f,
3.472222f, 3.416667f, 3.358333f, 3.297222f, 3.233333f, 3.166667f,
3.097222f, 3.025000f, 2.950000f, 2.872222f, 2.791667f, 2.708333f,
2.622222f, 2.533333f, 2.441667f, 2.347222f, 2.250000f, 2.150000f,
2.047222f, 1.941667f, 1.833333f, 1.722222f, 1.608334f, 1.491667f,
1.372223f, 1.250000f, 1.125000f, 1.014582f, 1.014651f, 1.014708f,
1.014756f, 1.014796f, 1.014830f, 1.014858f, 1.014881f, 1.014900f,
1.014917f, 1.014930f, 1.014942f, 1.014951f, 1.014959f, 1.014966f
};
EXPECT_EQ(steps, arraysize(expected));

for (int i = 0; i < steps; ++i) {
world->simulate(time_step);
EXPECT_TRUE(fabs(dynamic->position().x()) < 0.001f);
EXPECT_FLOAT_EQ(expected[i], dynamic->position().y());
EXPECT_TRUE(fabs(dynamic->angle()) < 0.001f);
}

// Clean up.
delete world;
delete service;
}
程式碼有點長,偷自 Box2d's HelloWorld,哈哈,天下文章一般抄。若要比較 float/double 大小,EXPECT_FLOAT_EQ() macro 是一個很好的選擇。總之,此 acceptance test 沒過,我們必須讓他過。(只貼有意思的部分)
// box2d_world.cc
Body* Box2dWorld::createBody(const BodyConfig& config) {
b2BodyDef config_impl;

config_impl.position.Set(config.position.x(), config.position.y());
config_impl.angle = config.angle;
config_impl.linearVelocity.Set(config.linear_velocity.x(),
config.linear_velocity.y());
config_impl.angularVelocity = config.angular_velocity;
config_impl.linearDamping = config.linear_damping;
config_impl.angularDamping = config.angular_damping;
if (config.type == BodyConfig::Static) {
config_impl.type = b2_staticBody;
} else if (config.type == BodyConfig::Dynamic) {
config_impl.type = b2_dynamicBody;
} else if (config.type == BodyConfig::Kinematic) {
config_impl.type = b2_kinematicBody;
}
config_impl.active = config.is_active;

return new Box2dBody(itself_->CreateBody(&config_impl));
}

// box2d_body.cc
void Box2dBody::createFixture(const FixtureConfig& config) {
if (config.shape_config->type == ShapeConfig::Polygon) {
PolygonShapeConfig* shape
= dynamic_cast< PolygonShapeConfig* >(config.shape_config);

b2PolygonShape shape_impl;
shape_impl.m_vertexCount = static_cast(shape->vertices.size());
for (int i = 0; i != shape_impl.m_vertexCount; ++i) {
shape_impl.m_vertices[i].Set(shape->vertices[i].x(),
shape->vertices[i].y());
shape_impl.m_normals[i].Set(shape->normals[i].x(),
shape->normals[i].y());
}
shape_impl.m_centroid.Set(shape->centroid.x(), shape->centroid.y());

b2FixtureDef config_impl;
config_impl.shape = &shape_impl;
config_impl.friction = config.friction;
config_impl.restitution = config.restitution;
config_impl.density = config.density;

itself_->CreateFixture(&config_impl);
}
}

偷加一個 method 給 PolygonShapeConfig:
void PolygonShapeConfig::setAsBox(float half_x, float half_y) {
vertices.push_back(math::Vector2(-half_x, -half_y));
vertices.push_back(math::Vector2( half_x, -half_y));
vertices.push_back(math::Vector2( half_x, half_y));
vertices.push_back(math::Vector2(-half_x, half_y));

normals.push_back(math::Vector2( 0.0f, -1.0f));
normals.push_back(math::Vector2( 1.0f, 0.0f));
normals.push_back(math::Vector2( 0.0f, 1.0f));
normals.push_back(math::Vector2(-1.0f, 0.0f));

centroid.setZero();
}
跑一跑居然過了,太神奇了傑克。這就是一個簡單的 acceptance test,謝謝大家收看。

2011年2月9日 星期三

Bernanke Says Unemployment Will ‘Remain Elevated’

Link: Bloomberg

記住,這只是 Bernanke 的意見,市場「某個」聲音,失業率將來怎麼走,只有上帝知道。「失業率」不重要,重要的是「大眾對失業率的反應」,心理學造就百分之九十的行情。

失業率是什麼?很簡單,失業率是「失業人口佔勞動力的比率」,大眾怎麼反應,只有市場會告訴你答案,政治裡也有答案,不要談政治,不要談市場,上帝造人,為什麼造兩個耳朵、兩隻眼睛,卻只造一個嘴巴?Remain Elevated?

最後祝大家兔年躺著爽爽賺,謝謝大家。

Development Driven by Tests

哲學: Development is driven by tests. You test first, then code. Until all the tests run, you aren't done. When all the tests run, and you can't think of any more tests that would break, you are done adding functionality.

例子: (Use case) 儲存/讀取遊戲設定。

先寫 test: (使用 Google C++ Testing Framework)
TEST(WinFileRepository, SetValue) {
const std::string name("options");
// Set
{
Repository* repository = new WinFileRepository(name);
repository->setValue("reset_level_button", "single_tap");
repository->setValue("offset", "off");
delete repository;
}

// Get
{
Repository* repository = new WinFileRepository(name);
EXPECT_TRUE(repository->value("reset_level_button") == "single_tap");
EXPECT_TRUE(repository->value("offset") == "off");
delete repository;
}
}

Compile failed. 用最簡單的方式實作,目的只是為了 pass compiling:
void WinFileRepository::setValue(...) {
}

std::string WinFileRepository::value(...) const {
return default_value;
}

Compile 過了,但是 test 不過。那就實作正確的程式碼吧:(略過細節)
// win_file_repository.h
class WinFileRepository : public Repository {
public:
WinFileRepository(...);
~WinFileRepository();

void setValue(...);
std::string value(...) const;

private:
void read();
void write();

std::string file_name_;
std::map map_;
std::string separator_;
std::string delimiter_;
};

// win_file_repository.cc
namespace {

bool ReadFileToString(...) { ... }
int WriteFile(...) { ... }

} // namespace

WinFileRepository::WinFileRepository(...)
: file_name_(name),
separator_(separator),
delimiter_(delimiter) {
read();
}

WinFileRepository::~WinFileRepository() {
write();
}

void WinFileRepository::setValue(...) {
map_[key] = value;
}

std::string WinFileRepository::value(...) const {
std::map::const_iterator it = map_.find(key);
if (it != map_.end()) {
return it->second;
} else {
return default_value;
}
}

void WinFileRepository::sync() {
write();
}

void WinFileRepository::read() {
std::string contents;
ReadFileToString(file_name_, &contents);

size_t prev_pos = 0;
for (size_t pos = contents.find(delimiter_, prev_pos);
pos != std::string::npos;
pos = contents.find(delimiter_, prev_pos)) {
const size_t sep_pos = contents.find(separator_, prev_pos);

map_[contents.substr(prev_pos, sep_pos - prev_pos)]
= contents.substr(sep_pos + 1, pos - sep_pos - 1);

pos++;
prev_pos = pos;
}
}

void WinFileRepository::write() {
std::string contents;
std::map::iterator it;
for (it = map_.begin(); it != map_.end(); it++) {
contents.append(it->first);
contents.append(separator_);
contents.append(it->second);
contents.append(delimiter_);
}

WriteFile(file_name_, contents.c_str(), static_cast(contents.size()));
}
最後真的 pass test 了,感動。以上大量參考 Chromium projects, Qt4...抄才是王道呀!當然實作很醜,要漂亮就得用 protocol buffer 或是 boost::serialization,但個人真的太懶了,能夠 pass tests 就夠了。

2011年2月8日 星期二

On Forecasts

Zurich axiom: Human behavior cannot be predicted. Distrust anyone who claims to know the future, however dimly.

Nobody has the foggiest notion of what will happen in the future. Nobody. Never lose sight of the possibility you have made a bad bet.

個人解讀:只有帳戶裡的錢是真的,沒有對帳單,一切都是假的。預測正確不等於操作正確,更不等於賺錢。做對的事,做錯也沒關係,承認錯誤停損就好啦。預測是上帝的事,千萬不要妄想當上帝。

2011年2月5日 星期六

State Patterns in Practice (C++)

Recently I posted a workflow here. I want to express the workflow in terms of state patterns. There are only two steps. Step 1: Prepare the framework.

// state/state.h
#ifndef STATE_STATE_H_
#define STATE_STATE_H_
#pragma once

namespace state {

class State {
public:
virtual ~State() {}

virtual void update() = 0;
virtual void draw() const = 0;
virtual void onEnter() {}
virtual void onLeave() {}
};

} // namespace state

#endif // STATE_STATE_H_

// state/state_factory.h
#ifndef STATE_STATE_FACTORY_H_
#define STATE_STATE_FACTORY_H_
#pragma once

#include <string>

namespace state {

class State;

class StateFactory {
public:
virtual ~StateFactory() {}
virtual State* createState(const std::string& name) = 0;
};

} // namespace state

#endif // STATE_STATE_FACTORY_H_

// state/state_manager.h
#ifndef STATE_STATE_MANAGER_H_
#define STATE_STATE_MANAGER_H_
#pragma once

namespace state {

class State;

class StateManager {
public:
StateManager();
virtual ~StateManager() {}

inline State* current_state() { return current_state_; }
virtual void switchToState(State* state);

private:
State* current_state_;
};

} // namespace state

#endif // STATE_STATE_MANAGER_H_

// state/state_manager.cc
#include "state_manager.h"
#include "state.h"
#include "base/basictypes.h"

namespace state {

StateManager::StateManager()
: current_state_(NULL) {
}

void StateManager::switchToState(State* state) {
if (!!current_state_) {
current_state_->onLeave();
}

if (!!state) {
current_state_ = state;
current_state_->onEnter();
}
}

} // namespace state


Step 2: Combine them. I will not post all details but post important files instead.
// app_state_factory.h (not completed)
#include "state/state_factory.h"

class AppController;

class AppStateFactory : public state::StateFactory {
public:
explicit AppStateFactory(AppController* controller);
virtual state::State* createState(const std::string& name);

private:
AppController* controller_;
};

// app_controller.h
namespace state {
class State;
}

class AppStateManager;
class AppStateFactory;

class AppController {
public:
AppController();
~AppController();

void init();
void deinit();

void update();
void draw() const;

void switchToState(const std::string& name);

private:
void initAllStates();

private:
AppStateManager* state_manager_;
AppStateFactory* state_factory_;
std::map<std::string, state::State*> states_;
};

// app_state_manager.h
#include "state/state_manager.h"

class AppStateManager : public state::StateManager {
public:
AppStateManager();
virtual ~AppStateManager();
};

// state/initial_state.h
#include "state/state.h"

class AppController;

class InitialState : public state::State {
public:
explicit InitialState(AppController* controller);
virtual ~InitialState();

virtual void update();
virtual void draw() const;
virtual void onEnter();
virtual void onLeave();

private:
AppController* controller_;
};

// state/initial_state.cc
#include "initial_state.h"
#include "../app_controller.h"

InitialState::InitialState(AppController* controller)
: controller_(controller) {
}

InitialState::~InitialState() {
}

void InitialState::update() {
}

void InitialState::draw() const {
}

void InitialState::onEnter() {
// TODO: Load necessary resources.
if (!!controller_) {
controller_->switchToState("idle");
}
}

void InitialState::onLeave() {
}

Keep working!

2011年2月4日 星期五

過年加班的彭淮南

Source: 彭淮南 過年要加班

加班名單等於彭淮南信任名單。

此外,在 2011.01.31,彭淮南表示:「會密切注意物價問題,並透露央行對今年核心消費者物價指數(CPI)的估計約在1%左右。」央行估計今年CPI最高應該接近2%。彭淮南表示:「央行更在意的是不含蔬果和油價的核心CPI,今年核心CPI的估計約落在1%附近,相較去年的0.44%高出不少。」

繼續聽央行聲音,留意後續利率變化。

Time in C++ class

Source: [chrome] / trunk / src / base / time.h.

Requirement: get the current time, perform simple arithmetic.

To achieve this goal, we do the following steps:

1. In TimeDelta class, keep the following important methods: converts units of time to TimeDeltas, ToInternalValue(), returns the time delta in some unit, computations with other deltas, comparison operators.

2. In Time class, keep the following important methods: Now(), compute the difference between two times, return a new time modified by some delta, comparison operators.

3. In TimeTicks class, keep the following important methods: Now(), compute the difference between two times, modify by some time delta, return a new TimeTicks modified by some delta, comparison operators.

4. Add base/basictypes.h, base/port.h, and build/build_config.h first.

5. Add base/time.cc and platform-specified implementation (For example, we need base/time_win.cc under the Windows platform). Remove unnecessary included header files and implementations. Remove all debugging and logging codes.

Done! Time class is very important because many games need the concept of time. Keep stealing!