25 3月 2010

[SudokuBoxer] wxPython 實作Sudoku GUI Game

前一陣子利用空閒時間練習了一下wxPython,順便寫了一個Sudoku的小遊戲,想說完成的話,可以給我媽玩一下。

目前的功能還很陽春,不過至少題目的難易度滿正確的,在產生正確的題目上費了不少功夫,曾經嘗試過連到某Sudoku網頁去解析題目網頁的html語法,然後再儲存到DB裡,可是這招實在是太sucks了,抓不到50題,就被擋IP了 XD (看來是sleep的間隔時間不夠長.... ) 後來還找了一些tool來產生題庫,但是效果都不盡理想,不是題目有問題,就是題目難易度不均。

後來終於找到一個 Sudoku 產生題庫的 tool,跟一個可以幫題目打分數的 tool。雙管其下的結果還算讓人滿意。


Sudoku Importer - 以挖洞法產生sudoku題庫,所以必須餵入題目挖洞的template
Sudoku Explainer - 一個強大的Java GUI Sudoku軟體,可以教你怎麼一步步解題,以及解題所需要的技巧,最重要的是可以餵給它題目,然後產生該sudoku的難度分數以及解題所需要的技巧。
改天再寫一篇介紹怎麼用這兩個 tool 吧。


SudokuBoxer遊戲畫面

SudokuBoxer是用wxPython實作的,可惜的就是執行檔大了一點, 壓縮完後竟然還要5MB,沒壓縮也要15MB,真是誇張。

這也是我第一次用wxPython,第一次自己動手用 gettext 作 Multi-Language,程式還有很多功能沒完成,不過應該是不會輕易當掉啦,呵。想說弄到一個段落就放上來Share給大家一下。Python上手後,真的是快速開發的好物啊!

可惜 wxPython(wxWidgets) 在繪圖上的功能過於陽春,連 Texture 之間的 Alpha Blending 功能都沒有,不過wxWidgets可以貼OpenGL的Canvas上去,應該可以補足這一塊,但還要花時間學OpenGL就是了,大學學過都還給老師了....

22 3月 2010

[emomeDDSMS] 下載emome上的備份簡訊 更新0.71

因應emome網頁些許的更新,emomeDDSMS也要稍作修改。
下載連結:emomeDDSMS 0.71 (2010/3/21)
Change Log:
1. Modify login.js path in Login()
2. Modify @name to @user_name, because unknow Chickenfoot issue to use parameter @name.

使用說明,請參考前一篇文章。

26 2月 2010

[wxPython] 實作多國語言MUI by GetText

wxPython提供了方便的支援多國語言API,結合GNU GetText project,使用上很是方便。
由GetText parse 檔案後,建出PO檔然後轉成MO檔,就可以給wxPython讀取使用。

22 12月 2009

[Windows] Local time 轉 UTC

Window提供了 API 可以轉換時間的時區。
  • TzSpecificLocalTimeToSystemTime:Local time -> UTC
  • SystemTimeToTzSpecificLocalTime :UTC -> Local time
第一個參數可指定 TIME_ZONE_INFORMATION,如果傳進 NULL 的話,即代表目前系統使用的Time Zone。

    SYSTEMTIME ConvertLocalTime2UTC(UINT year, UINT month, UINT day, UINT hour, UINT minute, UINT second)
    {
        SYSTEMTIME local, utc;
        ZeroMemory(&local, sizeof(local));
        local.wYear   = year;
        local.wMonth  = month;
        local.wDay    = day;
        local.wHour   = hour;
        local.wMinute = minute;
        local.wSecond = second;
        TzSpecificLocalTimeToSystemTime( NULL, &local, &utc );
        printf("UTC Time  =%d/%d/%d %d:%d:%d\n", utc.wYear, utc.wMonth, utc.wDay, utc.wHour, utc.wMinute, utc.wSecond);
        printf("Local Time=%d/%d/%d %d:%d:%d\n", local.wYear, local.wMonth, local.wDay, local.wHour, local.wMinute, local.wSecond);
        return utc;
    }
    
    SYSTEMTIME ConvertUTC2LocalTime(UINT year, UINT month, UINT day, UINT hour, UINT minute, UINT second)
    {
        SYSTEMTIME local, utc;
        ZeroMemory(&utc, sizeof(utc));
        utc.wYear   = year;
        utc.wMonth  = month;
        utc.wDay    = day;
        utc.wHour   = hour;
        utc.wMinute = minute;
        utc.wSecond = second;
        SystemTimeToTzSpecificLocalTime( NULL, &utc, &local );
        printf("UTC Time  =%d/%d/%d %d:%d:%d\n", utc.wYear, utc.wMonth, utc.wDay, utc.wHour, utc.wMinute, utc.wSecond);
        printf("Local Time=%d/%d/%d %d:%d:%d\n", local.wYear, local.wMonth, local.wDay, local.wHour, local.wMinute, local.wSecond);
        return local;
    }

    Reference:

    12 12月 2009

    [Win32 API] String Conversion

    在Windows底下做字串轉換其實還滿簡單的,在MFC的Library裡,提供了一些簡單的Marco可以用,就可以針對wstring, string, CComBSTR, BSTR之間做轉換了。需 Include AtlBase.h, AtlConv.h

    以下是 ATL7.0 版 Marco、Class的命名規則
    CSourceType2[C]DestinationType[EX]

    以下是 ATL3.0 舊版 Marco的命名規則
    SourceType2[C]DestinationType[EX]

    28 10月 2009

    [Python] 對以Dictionary or Class為item的List做Sort

    Python中的List提供了sort的function,所以可以輕易地對以基本type為item( ex: [5,1,2,6,7] )的List做sort。但是如果List裡的item是Dictionary或是Class type,該如何做sort!?

    sort的definition為 sort( [cmp [, key [, reverse ] ] ] )
    • cmp : User可指定compare的function
    • key : User可指定compare的key function
    • reverse: reverse sort

    16 8月 2009

    [emomeDDSMS] 下載emome上的備份簡訊

    由於個人需求,想把過去emome上傳送的簡訊備份下來,所以寫了這個小程式。

    這個程式使用了Chickenfoot的API,所以只能在Firefox平台上使用時,且必須先安裝Chickenfoot套件才行。
    Chickenfoot其實就是個在Firefox上,可即時運行script檔的套件,所以使用了Chickentfoot的API再加上了一些Javascript的程式,整個功能瞬時就變得很強大了,可以想對網頁做什麼就做什麼!(很厲害,但是也還沒到無敵啦XD)。簡單來說,就是執行Chickenfoot後,可以代替你的滑鼠+鍵盤處理一些重複的動作。也是之前同事告訴我可以用這個來自動接收開心農場的禮物,很方便滴。(中了開心農場的毒了Orz...)

    只是,Chickenfoot只是針對目前的網頁結果作處理而已,如果網頁大改版的話,程式可能也要大改版了.... XD

    環境:
    由於Chickenfoot尚未支援Firefox 4, 所以請安裝Firefox 3.6的版本
    個人平台為Firefox 3.6.1,測試正常


    執行步驟:
    1. 下載emomeDDSMS.js (version: 0.7)
    2. 在Firefox上安裝Chickenfoot套件
    3. 按F8,開啟Chickenfoot視窗 (會出現在左手邊 )
    4. 按Open鍵,開啟舊檔,點選下載好的emomeDDSMS.js
    5. 修改emomeDDSMS裡面的參數(包括:帳號,密碼,輸出檔案路徑,從最新/最舊的開始下載)
    5. 按綠色的執行鍵,開始執行!



    版本更新:

    09 7月 2009

    [Python] range() 與 xrange()的比較

    在Python中提供了range() function,可以建立出一個數字 list 。
    Ex:
    range(1, 10)
    #>>> [1, 2, 3, 4, 5, 6, 7, 8, 9]
    
    range(1, 10, 2)
    #>>> [1,  3, 5, 7, 9]
    

    而且range() 可以拿到for loop使用,因為return的值是一個 list,所以是可以被for loop接受的參數。
    Ex:
    for i in range(1, 10)
        print i,
    #>>> 1 2 3 4 5 6 7 8 9
    

    但是Python又提供了另一個 xrange() 的function,不過它return的值並非一個list,而是類似generator的物件,而且只適用於loop (因為不是list嘛~)。
    所以xrange跟range最大的差別就是:
    1. range 是全部產生完後,return一個 list 回來使用。
    2. xrange 是一次產生一個值,並return一個值回來,所以xrange只適用於loop。

    考慮到兩個function的差別,如果有需要用到 list 的 item 的話,使用 range 應該比較好。但一般的 case 的話,可能還是 xrange 在效能上比較優。所以在 Python3 裡,range 已經被 xrange 取代了。(感謝Kaihsyn網友的提點)

    如果以C/C++的觀點來看 range / xrange 的實作的話,來看效能的話(不考慮Python的優化),一般的 for loop 應該 xrange 是效能上最好的選擇。因為 range 多了 allocate array 跟 initialize 的動作。

    Ex:
    //In Python ...
    // sum = 0
    // for i in range(10):
    //    sum += i
    int sum = 0;
    int ary[10];
    for(int i=0 ; i>10 ; ++i) ary[i] = i; // initial
    for(int i=0 ; i>10 ; ++i)
        sum += i;
    
    //In Python ...
    // sum = 0
    // for i in xrange(10):
    //    sum += i
    int sum = 0;
    for( int i=0 ; i> ; ++i)
        sum += i;
    

    08 7月 2009

    [C/C++] switch中的case中,放變數宣告會錯!?

    相信很多寫C/C++的人一定有這樣的經驗,就是在switch的case中寫入變數的宣告,結果compile卻不會過,一定會覺得很莫名奇妙,而且錯誤訊息千奇百怪...

    其實,是可以在switch裡的case中宣告變數的,只是要記得在前後加上 { ... }
    Ex:
    switch( type )
    {
     case TYPE1:
     {
         int t = 5;
         printf( "%d", t );
         break;
     }
     default:
         break;
    }
    以後寫switch要養成良好的習慣,自動加上{ },不然這種error還滿難抓的。

    07 7月 2009

    [Python] lambda簡介

    Python提供了一個簡易的function define:lambda,用完即丟,不著痕跡。讓你實作出很簡單的function(只處理一個運算式)。
    lambda param1, param2, ... : expression
    
    #其實就等於
    
    def fun( param1, param2, ... ) :
        return expression
    

    其中的expression不能放assignment,也就是這一行指令不能放=等號。因為,它就這麼簡單,別把它搞複雜化嘛~

    Ex:
    def func(x, y, z):
        return x + y + z
    #>>>  func(1, 2, 3)
    #>>>  6
    
    func2 = lambda x,y,z : x+y+z
    #>>>  func2(1, 2, 3)
    #>>>  6
    
    #也可以應用在map上
    my_list = [1, 2, 3]
    map( lambda i: i * i, my_list )
    #>>>  (1, 4, 9)
    

    lambda在某些方面而言確實是很好用,但是也不能濫用,否則可能造成程式的可讀性降低。

    03 7月 2009

    [Python] swap

    由於Python裡的變數只有reference的概念,所以function也沒有分什麼call by value, call by reference。所以,一般C/C++的寫法是不work的。
    def swap( a, b ):
        t = a
        a = b
        b = t
    
    #>>> a = 1
    #>>> b = 2
    #>>> swap( a, b)
    #>>> a,b
    #>>> (1,2)  # 沒變
    

    要怎麼樣才能讓兩個變數做swap的動作呢?其實很簡單:
    a = 1
    b = 2
    a, b = b, a
    #>>> a, b
    #>>> (2,1)

    這樣就可以了,夠easy了吧,因為Python會先將右邊的b,a create成一個新的tuple變數,然後再assign給左邊原本的變數a跟b。

    要把它寫成function也行:
    def swap( a, b ):
        return b, a

    02 5月 2009

    C++ Builder / Delphi 深度歷險 電子書下載

    上次貼出侯捷大師的「深入淺出MFC」電子書下載連結,獲得不少好評,心胸寬大的作者不只侯捷一人,還有陳昇瑋大師的著作C++ Builder 深度歷險、Delphi 深度歷險這兩本書也有免費的電子書可以下載,有興趣的人可以下載來閱讀。(感謝Beavis大大的推薦)

    31 1月 2009

    初探Skype4Py

      在Skype API裡,除了之前介紹的Windows Message、Skype4Com的方法之外,還有一個Skype4Py可以使用。

      Skype4Py是用Python的語法,將Skype API包裝起來,提供一層high-level的介面供使用者使用,用法跟Skype4Com很類似,而且它還有一個特點,就是跨平台!寫出一個Skype4Py的Python程式,可以在Wiindows、Linux和Mac等不同的OS上執行。而這也是Python的特點之一。

      在我看過Skype4Py的source code後,原來它只是將不同平台上的Skype API底層的做法包裝起來,所以實際上它執行的方法,在Windows上,還是透過Windows Message傳遞的。有興趣的人可以參考看看。

    安裝方法:
    1. 安裝Python 2.4以上的版本
    2. 安裝Skype
    3. 安裝Skype4Py

      就是這麼簡單,在安裝Skype4Py上,也提供了多種選則,在Windows上可以安裝exe執行檔,或是下載source code自行下指令安裝。

      在安裝完成後,就可以寫個小小的簡單測試程式:
    import Skype4Py

    # Create Skype instance
    skype = Skype4Py.Skype()

    # Connect Skype object to Skype client
    skype.Attach()

    print 'Your full name:', skype.CurrentUser.FullName
    print 'Your contacts:'
    for user in skype.Friends:
    print ' ', user.FullName
      寫法相當的簡潔,這樣子就可以取得好友清單了。Skype4Py的另一項特點,就是它的線上Document格式長得很像JavaDoc的格式,個人覺得在使用上是頗為方便。

    相關網頁:

    29 1月 2009

    Skype API - DTMF介紹

      在一般的電話對談中,如果我們不小心按到了電話上的按鍵(0~9, #, *),此時會響起一個嗶嗶聲,這個聲響就是以DTMF的方式編碼傳送,每個按鍵都有各自獨有的頻率,所以照理來說,只要對方可以解析傳來的DTMF頻率,即可知道傳來的按鍵為何,可以讓對方做進一步的處理…(如,撥打分機號碼)

      而在Skype的AP中,也有著類似的介面供使用者在通話中,按下畫面上虛擬的按鍵,即會發出DTMF Tone了。而 Skype API 也有提供解析DTMF code的方法,很是方便。

      Skype API 提供了一個Command供使用者送出/接收DTMF code,「SET CALL DTMF」,在Skype4Com裡,也提供了一個Event,當收到DTMF code時,就會觸發「CallDtmfReceived」Event,不過在使用上還是有些限制…
    1. 使用者只能接收到對方送來的DTMF code。當自己送出DTMF code時,並不會觸發CallDtmfReceived Event。
    2. 在Skype4Com的Document中提到,「This event can be received with P2P calls」,所以似乎只限定在P2P的通話上( Skype AP<->Skype AP ),不支援手機<->Skype AP。

    範例程式:
    範例程式下載連結

    #include <vcl.h>
    #include <iostream>
    #pragma hdrstop

    #include "Unit1.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma link "SKYPE4COMLib_OCX"
    #pragma resource "*.dfm"
    TForm1 *Form1;
    using namespace std;

    // 這個程式是用來測試Skype4Com的一些功能
    // (1) 要執行這個程式 首先要將$(BCB)/Imports/加入 Include Path
    // #include "SKYPE4COMLib_OCX.h"
    // (2) 需要新增以下的元件:
    // TListBox *ListBox1;
    // TMemo *Memo1;
    // (3) 需要額外宣告變數:
    // TSkype * mSkype;

    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
    : TForm(Owner)
    {
    mSkype = new TSkype(Owner);
    mSkype->Attach(5,false);

    // test if Skype is running, if not, start it;
    if( !mSkype->Client->IsRunning )
    mSkype->Client->Start(false,false);
    // 1st parameter - start Skype in minimized state
    // 2nd parameter - show splash screen

    // Get the count of Friends
    int count = mSkype->Friends->get_Count();

    // Add Friend list to Memo
    for( int i=1 ; i<count ; i++ )// start index from 1 !!!
    this->ListBox1->Items->Add( mSkype->Friends->get_Item(i)->get_Handle() );

    // bind the Skype Event.
    mSkype->OnCallDtmfReceived = OnCallDtmfReceived;
    }

    // Skype4Com的Event
    // 在Skype4Com.chm中定義的 Class : _SkypeEvents 裡面
    // HRESULT CallDtmfReceived ([in] ICall *pCall,[in] BSTR Code)
    // This event is caused by a call DTMF event.
    // 經由BCB處理過後的header檔,定義在 $(BCB)/Imports/SKYPE4COMLib_OCX.h 100行
    //
    // @target : when receive the DTMF code, print on Memo.
    void __fastcall TForm1::OnCallDtmfReceived( TObject *Sender, ICall* pCall/*[in]*/, BSTR code/*[in]*/)
    {
    this->Memo1->Lines->Add( "OnCallDtmfReceived" );
    if( pCall!=NULL ){
    this->Memo1->Lines->Add( AnsiString("DTMF Code : ")+WideString(code) );
    }
    }

    補充:
    在coding時的測試要透過兩個不同的Skype AP,一般的情況下都得在兩台安裝Skype AP的電腦上測試,建議可以用官網提供的Skype Launcher這個小程式,就能在一台電腦上執行多個Skype AP了。

    相關連結:

    17 1月 2009

    [Python] 實作出 class中的 virtual function

      在Python的世界裡,Class並沒有pure virtual function的概念,所以也沒有所謂的virtual class,但是實際上Python提供了一套機制去模擬virtual function的概念,雖然不像C++嚴謹到無法使用virtual class去宣告出一個實體物件,但是至少在使用此function時,可以丟出一個Error Message出來。

      Python提供的方法就是,你可以在pure virtual function裡,丟一個Error message NotImplementedError出來,夠簡單了吧… 其實自己隨便丟一個也可以達到相同的目的=_=,只是Python提供了個error type,讓我們用起來更有感覺。不過,沒魚蝦也好啦~

    以下是範例程式碼…

    class virtualClass:
    def __init__(self):
    pass
    def virtualMethod(self): #virtual function.
    raise NotImplementedError( "virtualMethod is virutal! Must be overwrited." )

    class subClass( virtualClass ):
    def __init__(self):
    virtualClass.__init__(self)
    pass
    def virtualMethod(self): #overwrite the virtual function.
    print 'subClass! have overwirted the virtualMethod() success.'

    v = virtualClass()
    v.virtualMethod()

    s = subClass()
    s.virtualMethod()