Archive for the ‘C/C++’ category

Python使用HGE引擎

八月 25th, 2009

大家肯定都知道在Python下面寫2D遊戲有個眾所階知的選擇就是pygame,雖然它簡單好寫,對於簡單的遊戲來說已經足夠,但是他有一個致命的缺點,就是速度太慢了,在pygame的背後是SDL,用純軟體畫圖的函式庫,既然為純軟體繪圖,遇上旋轉、半透明等等需求,更顯得吃力和不切實際,所以該怎麼辦才好呢?

答案是用Haaf’s Game Engine,它是一款用DirectX做為backend的Open source遊戲函式庫,我在先前的文章裡已經有做簡單的介紹,就不再重覆,那這函式庫和Python又有什麼關聯呢? 他是用C++寫的,Python沒辦法用,正因為這樣,我一直一來想幫他寫一個python的binding,我一直想如果Python也能用HGE寫起來一定很開心,我試著找了一下有沒有已經存在這樣的專案,有找到一個,但是居然是在萬惡的GNU授權下的,讓我百思不得其解,那專案的作者到底在想什麼? 想讓大家寫Open source的Game嗎? 我們都知道GNU是大名頂頂的病毒授權,任何程式使用了用GNU的函式庫都會被感染,代表你的主程式一樣得變成GNU的開源授權,我個人非常討厭打著自由名義但是卻有強烈的強迫性質的GNU授權,況且HGE的授權是非常寬鬆的 zlib/libpng License,實在想不透為什麼一個binding可以用超嚴格的GNU,不過那是那作者的自由,我也管不著,在不能接受那惡心的授權,加上我看了一下他的專案似乎好像也沒有很完整的進度,於是我還是決定自己開了一個新的專案

Python HGE

在這樣的情況下,我前些天抽空開了一個新的Open source專案: Python-HGE,把一些最核心的程式碼都用boost.python包裝給Python使用,最核心的部份完成度很高,剩下的需要我在未來有空慢慢補上,License是MIT,如果你問我為什麼選MIT,我想答案應該是商業用途一樣也可以,不像GNU那種假腥腥的自由,還有一個重點就是,我覺得麻省理工這名字聽起來很酷,讓我想起每次在Discovery看到的東西

效能問題

我照著原本HGE的Tutorial7的程式寫了一個Python的版本,這個範例的目的就是在展示HGE的效能,純C++的版本速度當然是很快,而Python的版本FPS掉了不少,一開始讓我覺得有點失望,讓我開始懷疑如果效能掉很多的話,那用Python寫HGE還有價值嗎? 後來仔細思考了一下,對於一般的2D遊戲來說,要像這demo整畫面跑來跑去的圖片加透明效果的情況實在不多,就算有也很難到這樣上千張的圖片,再者我都還沒進行最佳化、跑profile等等,而且雖說FPS掉不少,但是那是和C++數百的FPS比起來,在60以上其實都是可以接受的,加上我測試的這台電腦已經有點年代,對現代的電腦和GUP來說情況只會更好,在如此的考量之下,Python HGE還是有搞頭的

python版的tutorial 7截圖

t7

這個demo可以在這裡下載

目前狀況

目前雖然核心部份已經高度完成,不過我還沒有把編出來的pyd釋放的打算,如果想嘗鮮的話可以直接從那個demo裡面找pyd出來用,又或著自己check out原始碼進行編譯

參與開發

如果有興趣的話,歡迎參與專案的開發,如同我上面所提到的,我用的是boost.python,一款基於C++的python binding函式庫,如果你熟悉boost.python的話當然是最好,就算沒有也沒關系,因為其實大部份工作都是剪下貼上之類的,可以參考我已經寫好的部份,有些函數回傳例如指標之類的東西需要特別處理,除此之外都只是很簡單無腦工作

VC++ 9.0的編譯器鬼打牆錯誤

一月 30th, 2009

今天要將一些C++程式弄成Python模組,使用Boost.Python,以bjam編譯時一直跑出一堆鬼打牆的錯誤訊息

這個時候不應有 \Utilities\Bin\x86″;F:\Inprise\vbroker\bin;F:\Borland\CBUILD~1\Bi
n;F:\Borland\CBUILD~1\Projects\Bpl;』F:\Microsoft。

這個時候不應有,到底是什麼鬼東西是這裡不應該有的,我仔細觀察了一下,把bjam呼叫的內容全印出來,可是都找不到有參數是那段一堆路徑,再仔細看看那堆路徑看起來像是Path裡的東西,想一想bjam應該丟參數給compiler而已,於是就懷疑是VC++ 9.0 Express的問題,花了好大的力氣,讓我找到了

這篇文章 :

Serious Visual Studio 2008 install bug that can break your builds

才解決這個問題,原來是安裝的SDK像』C:\Program Files\Microsoft DirectX SDK (June 2006)\Utilities\Bin\x86″有括號,在bat檔裡被錯誤解析的樣子

很多時候其實都希望程式設計相關的錯誤訊息不要中文化,像是這個,』這時候不應該有』,放到Google搜尋只會出現一堆不相關的東西,但是原文』was unexpected at this time.』 下去找很快就能找到相關的資料,我記得之前在Ubuntu下編譯程式,就有遇到編譯器錯誤訊息輸出被中文化的情況…,真的是鬼打牆,沒翻還好,一翻根本不知道它在說什麼鬼,也沒辦法貼到Google找資料

Google Unit Test Framework試玩

一月 21st, 2009

一直一來我都知道Unit Test對於程式的開發是蠻重要的一個環節,在以往我們常常不停地改寫程式,在這個過程中,有意無意地常常會有東西被改壞掉還不知道,而我們檢查的方式可能很常是透過一直修改程式碼或輸入的資料來測試,但是當程式越來越大,我們測試時只專注在一個地方,此時所要測試的程式越來越多,不小心出錯的可能也越來越多,每改寫一次就是一次昂貴的人力檢查,最後程式就像一艘漏水的船,補了這裡,那裡卻又多了一個洞,船員像無頭蒼蠅一樣四處補洞,這樣的情況就是Unit Test能解決的問題,透過Unit Test,每次寫的程式碼都交給程式自動測試,一來測試的速度很快,不管是一百次還是一千次,總比人工測試來得快速、正確、廣範,但這不是免費的,代價就是程式設計師要寫很多Unit Test的程式碼,還要想要如何寫Unit Test的程式,進一步的還有測試導向的開發模式(Test-driven development),程式是在Unit Test寫完之後才開始寫,這樣一來迫使程式設計師在一開始就得把設計想好,邊寫邊想的做法不再可行,這或許算缺點也算優點

這些我都知道,但都沒有很確實去做,之前有用Python寫過Unit Test,他那種寫法我很喜歡,但C++卻沒有,直到這次想開發某些東西,我決定要試著落實TDD,但在開始以前,要有合適的工具,也就是自動測試的框架,起初我使用Boost.Test,雖然說可以使用,但是我不得不抱怨,他的文件是寫給鬼看的,好幾十頁的文件裡面廢話連篇,分類也很不明確,難以找到重點,或許是我英文程度太差,我真的讀不太懂Boost.Test到底怎麼用,靠著東拼西湊勉強終於還算可以使用,但是或許是我搞不太清楚它一堆Compile時用的Macro定義的Flag如何使用,編譯起來不知為何非常地慢

不合胃口(有些反胃的感覺)的文件,讓我覺得該是時候和Boost.Test說再見,尋找新歡的時候到了,無意間發現,在不知道什麼時候突然冒出來的Google Unit Test Framework,似乎才剛釋放出來沒多久,是Google內部C++寫Unit Test的框架,開放成Open source的專案,看起來很不錯,文件簡單明瞭,不像Boost.Test幾十頁連篇翻半天還不知道Unit Test到底要怎樣執行,他們主張為什麼要使用Google Unit Test Framework的理由:

  1. Tests should be independent and repeatable. It’s a pain to debug a test that succeeds or fails as a result of other tests. Google C++ Testing Framework isolates the tests by running each of them on a different object. When a test fails, Google C++ Testing Framework allows you to run it in isolation for quick debugging.
  2. Tests should be well organized and reflect the structure of the tested code. Google C++ Testing Framework groups related tests into test cases that can share data and subroutines. This common pattern is easy to recognize and makes tests easy to maintain. Such consistency is especially helpful when people switch projects and start to work on a new code base.
  3. Tests should be portable and reusable. The open-source community has a lot of code that is platform-neutral, its tests should also be platform-neutral. Google C++ Testing Framework works on different OSes, with different compilers (gcc, MSVC, and others), with or without exceptions, so Google C++ Testing Framework tests can easily work with a variety of configurations. (Note that the current release only contains build scripts for Linux – we are actively working on scripts for other platforms.)
  4. When tests fail, they should provide as much information about the problem as possible. Google C++ Testing Framework doesn’t stop at the first test failure. Instead, it only stops the current test and continues with the next. You can also set up tests that report non-fatal failures after which the current test continues. Thus, you can detect and fix multiple bugs in a single run-edit-compile cycle.
  5. The testing framework should liberate test writers from housekeeping chores and let them focus on the test content. Google C++ Testing Framework automatically keeps track of all tests defined, and doesn’t require the user to enumerate them in order to run them.
  6. Tests should be fast. With Google C++ Testing Framework, you can reuse shared resources across tests and pay for the set-up/tear-down only once, without making tests depend on each other.

聽起來很合我胃口,於是就下載來試試,首先,要得編譯Google Test的library,以Visual Studio來說,開啟它的.sln檔,然後編譯就可以了

接著是如何使用Google Test? 雖然有點小麻煩,但其實也還好,首先include 『gtest/gtest.h』,接著是lib的設定,因為Google Test的lib是使用/MT參數進行編譯,所以你的專案也一樣要設為/MT或/MTd(Debug 模式下使用),然後link gtest.lib就可以了,如果不這樣做,你會看見一大堆xxx aleardy defined in xxx的link錯誤

而我用Code Blocks似乎因為編譯參數不太一樣又遇到一堆link錯誤,後來發現好像是Code Blocks的Console Application專案一開始就link的msvcrtd.lib一系列.lib所造成的,將那些移除只剩gtest.lib或gtestd.lib就可以正確執行,我隨手從它的範例裡組合出一個測試的執行檔

#include

#include 

using namespace std;

// Returns n! (the factorial of n).  For negative n, n! is defined to be 1.
int Factorial(int n) {
  int result = 1;
  for (int i = 1; i <= n; i++) {
    result *= i;
  }

  return result;
}

// Returns true iff n is a prime number.
bool IsPrime(int n) {
  // Trivial case 1: small numbers
  if (n <= 1) return false;

  // Trivial case 2: even numbers
  if (n % 2 == 0) return n == 2;

  // Now, we have that n is odd and n >= 3.

  // Try to divide n by every odd number i, starting from 3
  for (int i = 3; ; i += 2) {
    // We only have to try i up to the squre root of n
    if (i > n/i) break;

    // Now, we have i <= n/i < n.
    // If n is divisible by i, n is not prime.
    if (n % i == 0) return false;
  }

  // n has no integer factor in the range (1, n), and thus is prime.
  return true;
}

// Step 2. Use the TEST macro to define your tests.
//
// TEST has two parameters: the test case name and the test name.
// After using the macro, you should define your test logic between a
// pair of braces.  You can use a bunch of macros to indicate the
// success or failure of a test.  EXPECT_TRUE and EXPECT_EQ are
// examples of such macros.  For a complete list, see gtest.h.
//
//
//
// In Google Test, tests are grouped into test cases.  This is how we
// keep test code organized.  You should put logically related tests
// into the same test case.
//
// The test case name and the test name should both be valid C++
// identifiers.  And you should not use underscore (_) in the names.
//
// Google Test guarantees that each test you define is run exactly
// once, but it makes no guarantee on the order the tests are
// executed.  Therefore, you should write your tests in such a way
// that their results don't depend on their order.
//
// 

// Tests Factorial().

// Tests factorial of negative numbers.
TEST(FactorialTest, Negative) {
  // This test is named "Negative", and belongs to the "FactorialTest"
  // test case.
  EXPECT_EQ(1, Factorial(-5));
  EXPECT_EQ(1, Factorial(-1));
  EXPECT_TRUE(Factorial(-10) > 0);

  //
  //
  // EXPECT_EQ(expected, actual) is the same as
  //
  //   EXPECT_TRUE((expected) == (actual))
  //
  // except that it will print both the expected value and the actual
  // value when the assertion fails.  This is very helpful for
  // debugging.  Therefore in this case EXPECT_EQ is preferred.
  //
  // On the other hand, EXPECT_TRUE accepts any Boolean expression,
  // and is thus more general.
  //
  //
}

// Tests factorial of 0.
TEST(FactorialTest, Zero) {
  EXPECT_EQ(1, Factorial(0));
}

// Tests factorial of positive numbers.
TEST(FactorialTest, Positive) {
  EXPECT_EQ(1, Factorial(1));
  EXPECT_EQ(2, Factorial(2));
  EXPECT_EQ(6, Factorial(3));
  EXPECT_EQ(40320, Factorial(8));
}

// Tests IsPrime()

// Tests negative input.
TEST(IsPrimeTest, Negative) {
  // This test belongs to the IsPrimeTest test case.

  EXPECT_FALSE(IsPrime(-1));
  EXPECT_FALSE(IsPrime(-2));
  EXPECT_FALSE(IsPrime(INT_MIN));
}

// Tests some trivial cases.
TEST(IsPrimeTest, Trivial) {
  EXPECT_FALSE(IsPrime(0));
  EXPECT_FALSE(IsPrime(1));
  EXPECT_TRUE(IsPrime(2));
  EXPECT_TRUE(IsPrime(3));
}

// Tests positive input.
TEST(IsPrimeTest, Positive) {
  EXPECT_FALSE(IsPrime(4));
  EXPECT_TRUE(IsPrime(5));
  EXPECT_FALSE(IsPrime(6));
  EXPECT_TRUE(IsPrime(23));
}

int main(int argc, char** argv) {
  // Prints elapsed time by default.
  //testing::GTEST_FLAG(print_time) = true;

  // This allows the user to override the flag on the command line.
  testing::InitGoogleTest(&argc, argv);

  return RUN_ALL_TESTS();
}

很簡單明瞭吧? 然後它執行的結果畫面如下

Google test 執行結果

Google test 執行結果

沒想到還有顏色,看起來蠻酷的對吧,很酷有時候也是選擇專案的理由之一,在這樣試玩下來,雖然還沒深入研究,還有實際寫Unit Test,但是感覺起來真的很不錯,有興趣的人可以試一試

Google C++ 程式風格指南

一月 21st, 2009

今天在找比Boost.Test更好用的Unit Ttest Framework時,在看Google Unit Test Framework時,無意間發現了Google的程式風格指南,裡面有C++的程式風格指南,我看了一下覺得還蠻有參考價值的,他們不是沒有理由的規定編程的風格,每條理由都有清楚寫出優點、缺點、甚至討論等等,做為決定團隊程式語言風格的指南決定,或是看他們決定的理由,都很有幫助

學寫C++的人可以參考看看

註 : 每個條目要按一個向下的三角形會展開細節,優缺點和討論等等

HGE project wizard template for Code::Blocks

一月 10th, 2009

I am learning HGE (Haaf’s Game Engine) these days. It is troublesome to set up all include and library directory stuff every time you want to write an application based on HGE. For this reason I spent some time to learn how to create a Code::Blocks project wizard template, and finally finish it. It is quite simple to install the HGE project wizard template into Code::Blocks. The only step you have to do is unzip the zip file to the location you install Code::Blocks and restart Code::Blocks. If you have installed other nonstandard templates, those templates might disappear from the project list, because Code::Blocks use 『share\CodeBlocks\templates\wizard\config.script』 to list all templates, and you overwrite it. To solve that problem, you can merge config.script manually. It is not too difficult to understand that file if you are going to learn how to write a game with C or C++ :D

Download : HGE project wizard template for codeblocks

Code::Blocks的HGE專案樣版

一月 10th, 2009

最近開始研就HGE (Haaf’s Game Engine),為了能方便開新專案寫HGE的程式,我特地研究了一下如何製作Code::Blocks的Wizard template,有個樣版每次開新專案就很方便,不用每次都要設定link之類的麻煩事情,我將它上傳,有興趣的就抓回去使用吧,安裝方法很簡單,只要解壓縮到Code::Blocks安裝的目錄下即可,如果你有安裝其它Project Wizard template的話,有可能會抓不到,或讓其它安裝的template被蓋掉,因為Code::Blocks是依照share\CodeBlocks\templates\wizard\config.script這個script檔來決定有哪些template,遇到這個問題的話,就請手動合併config.script檔案,內容很簡單,應該看了大概就明白在做什麼的

HGE project wizard template for codeblocks

簡易Compiler(其實是Interpreter) : Micro 實作

十月 13th, 2008

昨天

花了一個晚上的時間把Compiler作業Micro直譯器寫出來了,為啥說它是直譯器,因為光寫文法解析實在很無聊,它的語法又太簡單,反正讓它能執行也多沒幾行程式,就順手讓它可以直接執行,還蠻有趣的,第一次寫比較正規的語法解析器,我想起很久很久以前我寫過一個滑鼠鍵盤的巨集程式

滑鼠鍵盤巨集程式

滑鼠鍵盤巨集程式

就有解析自創的簡單語法,可是方法實在很暴力很蠢 XD,用了一些五四三的方法硬湊出來,現在我寫完這個作業覺得scanner和parser這樣才是比較正規的做法,我還用了Interpreter Pattern來實作

Micro

課本上的Micro語言實在有點簡單過頭了,只有輸入、輸出、運算而已,運算也只有加和減,本來想修改的,可是又要設計BNF和考慮運算優先順序等等麻煩的問題就打消念頭,只寫了兩個簡單的程式

begin
    read (a, b, c);
    sum := a + b + c;
    write (sum);
end
begin
    read (f1, f2);
    f3 := f1 + f2;
    f4 := f2 + f3;
    f5 := f3 + f4;
    f6 := f4 + f5;
    f7 := f5 + f6;
    write (f1, f2, f3, f4, f5, f6, f7);
end

下載

micro直譯器

有興趣可以載回去玩玩看,不過同學請注意,參考看看就好,要拿來當作業交被逮到可不關我的事= =

不守標準出了名的M$

九月 29th, 2008

問題

今天有人問了這樣一個問題,如何不讓scanf取得指定長度後剩下的字元,被下一個scanf取得

解法

首先我想到的是scanf一個字串,可是如果字串長度剛好,就會造成要再輸入一次,於是我又想到了fflush來清空stdin的緩衝區,查了MSDN,也寫了一個小程式來測試,果然可行,但是…

» Read more: 不守標準出了名的M$

萬惡的未定義行為

九月 27th, 2008

一切罪惡的開始

i = 10;
i = i++ + ++i;

請問 i 的值在上面C語言程式執行完後答案為多少?

» Read more: 萬惡的未定義行為