2007年5月26日

使用遗传算法进行简单寻路

仿照AI IN GAME里的例子写了一遍
程序下载
(note:编辑config.txt来编写地图,第一二行:长,宽,第三四行:出发点,目的地,其余:地图,1表示障碍物)
简单的寻路问题如下所述:
地图为有限大小的矩形,由小方格组成,其中一些小方格不可以通过,给它命名叫障碍点,给定起点和终点求解一条连接两点的路线

(不 通过障碍点).由于是简单的寻路问题,不要求找到最优解.设想一个实际情况就像一个人在走棋盘迷宫,每次只能走一步,只能往前后左右四个方向走,某些位置 上有障碍.给定一个目的地, 如果可达则给出一条通路.图论中有经典的算法解决这个问题,但是遗传算法为解决这个问题提供了一个新的思路,结合这两种方法可以在令人满意的时间内解决规 模较小的寻路问题。
现在来抽象这个问题。用一个二维数组表示地图
bool map[width][height];
true表示有障碍,false表示没有.
初始点和结束点为地图中的两个坐标.
vector2 src;
vector2 dst;
给定这三个条件的情况下求解此问题。
在这个问题中我们将染色体编码定义为每一步所走的方向,因为只有一个方向log2(4)=2位编码可以确定方向。
按染色体所指示的方向移动,生成一个群体,一代一代的选择。


































(左图为初始地图,红色表示出发点和目的地,黑色表示障碍物,白色表示无障碍地区。)
(右图为结果图,灰色表示寻找到的路径)
实际上遗传算法为这种问题的求解提供了一种完全不同的思路,就是说与图论不同的思路。
而是把线路看作”基因”(Gene),形成一个随机的初始解的群体(种群),然后像生物界里所进行的一样,基因杂交,编译,生物优胜劣汰,一代一代的自然选择,最后得到一个比较优的解。(实际上遗传算法不能保证一定可以找到最优解,甚至不能保证找到解)。

2007年5月10日

川历历汉阳树,芳草萋萋鹦鹉州

五一的最后一天跟lzc去黄鹤楼玩了一下,休息了一天,玩得很开心
中间还发生了一点小小的争论,现在想来论语心得里将人际关系还是很有道理的。不论怎样,友直,友谅,友多闻,益矣。
崔颢《黄鹤楼》
昔人已乘黄鹤去,此地空余黄鹤楼。
黄鹤一去不复返,白云千载空悠悠。
晴川历历汉阳树,芳草萋萋鹦鹉洲。
日暮乡关何处是?烟波江上使人愁。
然后就是贴照片了(lzc照相技术还是不错的,我就en..,呵呵)

(恶搞编钟,因为不喜欢上面的字)

2007年5月6日

Blog上贴代码的心得

Blogsp们都没有为coder们提供特殊服务的意思,往上面贴个代码很是麻烦。因为HTML语言会忽略空格,所以排版是一团糟

以前用csdnblog还不错的,无奈太慢并且界面太死板。现在终于找到一种方法可以把代码像样得贴上去了。

Visual Studio里直接拷贝是不行的,因为会加上很多换行,就是</bp>,而且格式通常会乱

这里使用cpp expertword 2007

Cpp expert下载

Cpp expert是把C++代码转换为htmlpdf等文档(还有图片)的工具,word 2007就更好了,附带了blog写作和管理功能。

  1. 安装cpp expert.设置一下, tools->editor options->editor smart tab use tab character 前面的勾去掉。Auto indent mode前面的勾也可以去掉
  2. 把代码拷贝到cpp expert 左侧的编辑栏中,如果用Visual Studio 的话最好使用空格代替tab(设置方法如下,tools->options->text editor->C/C++->Tabs->Insert Spaces)
  3. 点击右侧的save as html,保存为一份网页文件,这份文件里就已经没有多余的</bp>了。
  4. 打开word 2007,新建博客文档,如果以前没有使用的话会提示输入用户信息和sp信息。用浏览器打开刚才的html文件,吧内容拷贝进来,发布,完成了

以下是样例(我觉得效果还可以)

#include "stdafx.h"

#include "SmpWindow.h"



CAppModule _Module;



int WINAPI _tWinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd )

{

    _Module.Init(NULL, hInstance);



    SmpWindow wndMain;

    if( NULL == wndMain.CreateEx() )

        return 1;        // window creation failed

    wndMain.ShowWindow(nShowCmd);

    wndMain.UpdateWindow();



    MSG msg;

    while( GetMessage(&msg, NULL, 00) )

    {

        TranslateMessage(&msg);

        DispatchMessage(&msg);

    }



    _Module.Term();

    return msg.wParam;

}

2007年4月26日

"null pointer assignment"的由来

很久以前见到过,当时不明白,看了《C专家编程》后明白了
Thanks to sendoh

"无效的指针可能成为程序员的噩梦,人们很容易用一个无效的指针来引用内存。在所有的虚拟内存结构体系里,一旦一个指针进行解引用操作时所引用的内存地址超出了虚拟内存的地址空间,操作系统就会终止这个进程。但MS-DOS并不支持虚拟内存,即使内存访问失败,它也无法立即捕捉到这种情况。
然而,在MS-DOS系统中可以动点小脑筋,在程序结束后检测解除引用空指针的情况,在Microsoft C和Broland C中都采取了这种方法。在进入程序之前,保存内存地址为零的(内存)的值。在程序结束时,系统检查这个地址的值与原来的是否相同。如果不同,基本上可以确定你的程序中使用了空指针来访问内存,运行时系统会打出一条"null pointer assignment"信息"。

更有趣的事情发生在《创世纪 VI》的一个副产品上,Saveage Empire。是《游戏编程全接触》的作者说的。在快要发布的时候屏幕上会打印"Error:(null)pointer assignment",然而空指针很难被找出,于是这样修复了这个问题,用16进制编辑器修改了可执行文件中的这个文本串改为"Thanks for playing Savage Empire."。注意,它们是等长的...

2007年4月19日

Logger中操纵器的实现

代码下载
我突然想起 std::endl 这样一个东西,很想看看究竟它是怎么实现的.就像jjhou先生在<<stl 源码剖析>>中说的"under the hood".
endl的实现(Visual Studio 7.1版本):
代码下载
我突然想起 std::endl 这样一个东西,很想看看究竟它是怎么实现的.就像jjhou先生在<<stl 源码剖析>>中说的"under the hood".
endl的实现(Visual Studio 7.1版本):

_CRTIMP2 inline basic_ostream<char, char_traits<char> >&
__cdecl endl(basic_ostream<char, char_traits<char> >& _Ostr)
{ // insert newline and flush byte stream
_Ostr.put('\n');
_Ostr.flush();
return (_Ostr);
}
流的这一端:
    _Myt& operator<<(ios_base& (__cdecl *_Pfn)(ios_base&amp;))
{ // call ios_base manipulator
(*_Pfn)(*(ios_base *)this);
return (*this);
}
基本原理就是:
1.模板特化了operator<<的一个版本.
2.使用了访问者模式,最终endl调用的还是_Oster的成员函数.
应用到Logger上:
class Logger
{
public:
typedef Logger& (*pfn)(Logger& );

Logger& operator<<(pfn mani)
{
mani(*this);
return *this;
}
......
};

Logger el(Logger& stream)
{
stream << '\n';
return stream;
}
测试一下:
P.S.把模板代码贴成html真是麻烦<要换成&lt;,>要换成&gt;,连&自己也要换成&amp;有没有简单点的办法...
测试一下:
Logger a;
a << 1 << el << std::string("(temp comment)") << el;
a << 1.001 << el << 't' << el;
a.Print();
system("PAUSE");

Release下调试心得

上周末做的这样一次调试,不过最终并没有找到那个诡异的bug
还是明白了一些事情,首先感谢joehust,让我知道,release下调试时IDE给的变量值并不可靠.
最可靠的办法是写一个Logger.
开始看到调试时变量的值跟我预想的完全不一样让我很奇怪.由于代码优化,很多变量的内容观察不到,行的运行顺序也跟想象的不一样,很多行由于被优化掉无法设置断点.
能相信的就只有这么一个Loggor,把变量的内容输到Logger中记录下来.
简单的Logger实现


class Logger
{
public:
template < T value >
Logger& operator <<(T value)
{
std::stringstream ss;
ss << value;
buffer_.append( ss.str() );
buffer_.push_back('\n');
return *this;
}

void Out(const char *file)
{
std::ofstream fileStream;
fileStream.open(file, std::ios::ios_base::app);
fileStream << buffer_;
fileStream.close();
}

void Print()
{
std::cout << buffer_;
}
private:
std::string buffer_;
};

主要是利用stringstream吧一些常用的类型(int,char,float,double等)转换为字符串

Dian团队五周年庆典

Dian Group's Five Year Anniversary
过了两周了才写,最近一直很忙.
但是发现这样也好,很多事情推迟做更有好处.
李培根校长也来了,让团队的人深受感动.李校长让我感觉是很有感情的那样的人.第二天在集贤楼聚餐
(与我素来景仰的aw合影)
aw谈到的产品化让我感触很深,产品化毕竟和简单的与项目结合不同.
尽管团队人员流动比较频繁,尽管不是以公司的形式运作,产品化是我们的远景.
想起以前钟老师做的"Dian团队的产品化之路",真是很有远见

2007年3月29日

简单的计算器

代码和程序下载










用WTL做的一个小东西,其实是数据结构的作业。WTL来开发这种小东西还是很快的
一个简单的计算器,由于作业是C版本,所以改完了仍然不像C++。
但是可以看到代码减少很多,不需要重造stack。
刚在团队培训的时候听说了一个表达式树,应该用表达式树来做的。
现在要多做些练习,想想未来,看看前面

2007年3月26日

Source Insight 的文件标签外挂,终于可以用tab了

点击下载
由于不是内置插件机制实现的所以运行Source Insight前要运行这个插件,有点麻烦。
tab有很多可设置的选项,并且支持源代码管理!但是Tab的配色并不好,自己修改一下就可以了
源下载地址见:
TabSiPlus文件标签外挂 for Source Insight

2007年3月20日

英语课做的一个ppt,宫崎骏

ppt下载
配色和页面布局都花了一些心思,不过内容一般,这个是无音乐版

2007年2月24日

插件系统-选择GetProcAddress还是Interfaces(原文)

CodeProject上的文章,是外网,可能看起来不方便。
本来是要下Visual Leak Detector才到CodeProject上注册的,后来订阅了 RSS,还不错

Introduction

Plugins are the common way for extending applications. They are usually implemented as DLLs. The host application locates the plugins (either by looking in a predefined folder, or by some sort of registry setting or configuration file) then loads them one by one with LoadLibrary. The plugins are then integrated into the host application and extend it with new functionality.

This article will show how to create a host EXE with multiple plugin DLLs. We'll see how to seamlessly expose any of the host's classes, functions and data as an API to the plugins. There will be some technical challenges that we are going to solve along the way.

We'll use a simple example. The host application host.exe is an image viewer. It implements a plugin framework for adding support for different image file formats (24-bit BMP and 24-bit TGA in this example). The plugins will be DLLs and will have extension .IMP (IMage Parser) to separate them from regular DLLs. Note however that this article is about plugins, not about parsing images. The provided parsers are very basic and for demonstration purpose only.

There are many articles describing how to implement a simple plugin framework. See [1], [2] for example. They usually focus on 2 approaches:

1) The plugin implements a standard (and usually small) set of functions. The host knows the names of the functions and can find the address using GetProcAddress. This doesn't scale well. As the number of functions grows the maintenance gets harder and harder. You can only do so much if you have to manually bind every function by name.

2) The function returned by GetProcAddress is used to pass an interface pointer to the plugin or to obtain an interface pointer from the plugin. The rest of the communications between the host and the plugin is done through that interface. Here's how you do it:

The interface way

Interfaces are base classes where all member functions are public and pure virtual, and there are no data members. For example:

// IImageParser is the interface that all image parsers
// must implement
class IImageParser
{
public:
// parses the image file and reads it into a HBITMAP
virtual HBITMAP ParseFile( const char *fname )=0;
// returns true if the file type is supported
virtual bool SupportsType( const char *type ) const=0;
};
The actual image parsers inherit from the interface class and implement the pure virtual functions. The BMP plugin can look like this:
// CBMPParser implements the IImageParser interface
class CBMPParser: public IImageParser
{
public:
virtual HBITMAP ParseFile( const char *fname );
virtual bool SupportsType( const char *type ) const;

private:
HBITMAP CreateBitmap( int width, int height, void **data );
};

static CBMPParser g_BMPParser;

// The host calls this function to get access to the
// image parser
extern "C" __declspec(dllexport) IImageParser *GetParser( void )
{
return &g_BMPParser;
}
The host will use LoadLibrary to load BmpParser.imp, then use GetProcAddress("GetParser") to find the address of the GetParser function, then call it to get the IImageParser pointer.

The host keeps a list of all registered parsers. It adds the pointers returned by GetParser to that list.

When the host needs to parse a BMP file it will call SupportsType(".BMP") for each parser. If SupportsType returns true, the host will call ParseFile with the full file name and will draw the HBITMAP.

For complete sources see the Interface folder in the download file.

The base class doesn't really have to be pure interface. Technically the constraint here is that all members have to be accessible through the object's pointer. So you can have:
- pure virtual member functions (they are accessed indirectly through the virtual table)
- data members (they are accessed through the object's pointer directly)
- inline member functions (they are not technically accessed through the pointer, but their code is instantiated a second time in the plugin)
That leaves non-inline and static member functions. The plugin cannot access such functions from the host and the host cannot access such functions from the plugin. Unfortunately in a large application such functions can be the majority of the code.

For example all image parsers need the CreateBitmap function. It makes sense for it to be declared in the base class and implemented on the host side. Otherwise each parser DLL will have a copy of that function.

Another limitation of this approach is that you cannot expose any global data or global functions from the host to the plugins.

So how can we improve this?

Split the host into DLL and EXE

Take a look at the USER32 module. It has 2 parts – user32.dll and user32.lib. The real code and data is in the DLL, and the LIB just provides placeholder functions that call into the DLL. The best part is that all this happens automatically. You link with user32.lib and automatically gain access to all functionality in user32.dll.

MFC goes a step further – it exposes whole classes that you can use directly or inherit. They do not have the limitations of the pure interface classes we discussed above.

We can do the same thing. Any base functionality you want to provide to the plugins can be put in a single DLL. Use the /IMPLIB linker option to create the corresponding LIB file. The plugins can then link with that library, and all exported functionality will be available to them. You can split the code between the DLL and the EXE any way you wish. In the extreme case shown in the sources the EXE only contains a one line WinMain function whose only job is to start the DLL.

Any global data, functions, classes, or member functions you wish to export must be marked as __declspec(dllexport) when compiling the DLL and as __declspec(dllimport) when compiling the plugins. A common trick is to use a macro:

#ifdef COMPILE_HOST
// when the host is compiling
#define HOSTAPI __declspec(dllexport)
#else
// when the plugins are compiling
#define HOSTAPI __declspec(dllimport)
#endif
Add COMPILE_HOST to the defines of the DLL project, but not to the plugin projects.

On the host DLL side:
// CImageParser is the base class that all image parsers
// must inherit
class CImageParser
{
public:
// adds the parser to the parsers list
HOSTAPI CImageParser( void );
// parses the image file and reads it into a HBITMAP
virtual HBITMAP ParseFile( const char *fname )=0;
// returns true if the file type is supported
virtual bool SupportsType( const char *type ) const=0;

protected:
HOSTAPI HBITMAP CreateBitmap( int width, int height,
void **data );
};
Now the base class is not constrained of being just an interface. We are able to add more of the base functionality there. CreateBitmap will be shared between all parsers.

This time instead of the host calling a function to get the parser and add it to the list, that part is taken over by the constructor of CImageParser. When the parser object is created its constructor will automatically update the list. The host doesn't need to use GetProcAddress to see what parser is in each DLL any more.

On the plugin side:

// CBMPParser inherits from CImageParser
class CBMPParser: public CImageParser
{
public:
virtual HBITMAP ParseFile( const char *fname );
virtual bool SupportsType( const char *type ) const;
};

static CBMPParser g_BMPParser;
When g_BMPParser is created its constructor CBMPParser() will be called. That constructor (implemented on the plugin side) will call the constructor of the base class CImageParser() (implemented on the host side). That's possible because the base constructor is marked as HOSTAPI.

For complete sources see the DLL+EXE folder in the download file.

Wait, it gets even better:

Combine the host DLL and the host EXE

Usually an import library is created only when making DLLs. It is a little known trick that import library can be created even for EXEs. In Visual C++ 6 the /IMPLIB option is not available directly for EXEs as it is for DLLs. You have to add it manually to the edit box at the bottom of the Link properties. In Visual Studio 2003 it is available in the Linker\Advanced section, you just have to set its value to $(IntDir)/Host.lib.

So there you go. You have a host EXE, a number of plugin DLLs, and you can share any function, class or global data in the host with all plugins. There is no need to use GetProcAddress at all, ever, since the plugins can register themselves with the host's data structures.

For complete sources see the EXE folder in the download file.

........ incomplete

插件系统-选择GetProcAddress还是Interfaces(译)

插件系统-选择GetProcAddress还是Interfaces(译)
原文:
Plugin System – an alternative to GetProcAddress and interfaces
代码下载

[介绍]
有很多文章描述如何实现一个简单的插件框架,比如后面的链接[1]和[2]。通常有两种方法
(1)插件实现一组标准的(并且通常是小的)函数(方法)。宿主(host)知道这些函数的名字,并且可以通过使用GetProcAddress函数获得这些函数的地址。这并不合适,随着函数数量的增长,维护变得越来越困难。你必须手动通过函数名绑定函数,这样你就不得不做很多工作。
(2)GetProcAddress所返回的函数被用来传递接口指针(Interface Pointer)给插件或者从插件里获取接口指针。剩下的宿主和插件的通信通过接口完成。下面是一个例子

我们将使用一个简单的例子。宿主程序是一个图片查看器。它实现了一个插件框架来增加对不同图片格式的支持(在这个例子中就是24-bit的BMP图象和24-bit的TGA(Targa)图象)。插件将被实现为DLLs并且将有.imp的扩展名以便和普通dll文件区分开来了.注意,尽管如此,可是这篇文章是关于插件的,而不是关于图象解解析器的。这里所提供的解析器非常基础并且只是用来说明的。


[使用接口的方法]
接口是所有函数都是公共的并且纯虚的基类,并且没有没有数据成员。比如
// IImageParser is the interface that all image parsers
// must implement
class IImageParser
{
public:
// parses the image file and reads it into a HBITMAP
virtual HBITMAP ParseFile( const char *fname )=0;
// returns true if the file type is supported
virtual bool SupportsType( const char *type ) const=0;
};



实际的图象解析器必须继承自接口类并且实现纯虚函数。BMP文件解析器可能是这个样子。
// CBMPParser implements the IImageParser interface
class CBMPParser: public IImageParser
{
public:
virtual HBITMAP ParseFile( const char *fname );
virtual bool SupportsType( const char *type ) const;

private:
HBITMAP CreateBitmap( int width, int height, void **data );
};

static CBMPParser g_BMPParser;

// The host calls this function to get access to the
// image parser
extern "C" __declspec(dllexport) IImageParser *GetParser( void )
{
return &g_BMPParser;
}


宿主将使用LoadLibrary函数来载入BmpParser.imp,然后使用GetProcAddress("GetParser")来得到GetParser函数的地址,然后调用它得到IImageParser类的指针。
宿主将保存了注册了的解析器的邻接表(list),它把GetParser函数返回的指针附加到那个邻接表上去。
当宿主需要解析一个bmp文件的时候,它将调用每个解析器的SupportType(".BMP")。如果返回类型是true,宿主将调用那个解析器并且使用完整文件名调用待解析文件,并将绘制HBITMAP句柄指向的位图。

基类并不真的必须是纯接口。在技术上这里的限制是所有的成员必须可以通过对象指针访问。所以你可以有:
- 纯虚成员函数(它们能通过虚表被间接访问)
- 数据成员(它们可以通过对象的指针直接访问)
- 内联成员函数(技术上它们不能通过指针访问,但是它们的代码又一次在插件里实例化。
这样就剩下了非内联和静态成员函数。插件无法从宿主访问这样的函数,宿主也不能对插件进行这样的操作。不幸的是在一个大型系统之中,这样的函数要占据代码的大部分。

例如所有的图象解析器需要CreateFunction函数。有必要在基类里声明它并且在宿主端实现。否则每个插件都将有一份这个函数的拷贝。
这个方法的另一个限制是你不能由宿主端暴露任何全局成员或者全局函数给插件端。
我们怎么改进呢?

[把宿主分成Dll和Exe]
让我们看一下USER32模块,它有两个部分 - user32.dll 和 user32.lib。真正的代码和数据在dll中,lib仅仅提供调用dll函数的占位函数。最好的事情在于它是自动发生的。当你链接到user32.lib你就自动地获得访问user32.dll函数的权利。(这里翻译的不好)
MFC 实现得更进一步 - 它暴露你能直接使用和继承的整个类。它们没有我们在上面讨论的纯虚接口类的限制。
我们也能做同样的事情。任何你想提供给插件的函数(我私下觉得原文functionality这个词用得不好)都能放在一个单独的Dll里。使用/IMPLIB 链接器选项来创建相应的 LIB 文件。插件能与那个静态库链接,并且所有导出函数都能提供给它们。你能按你喜欢的方式把代码分成Dll 和 Exe。极限情况下,像在代码里演示的那样,Exe 工程里仅仅含有一行WinMain函数,它仅仅用来启动Dll。
任何你想要导出的全局数据,函数,类,或者成员函数必须被标记为 __declspec(dllexport) 在编译插件时。一个常用的技巧是使用宏

#ifdef COMPILE_HOST
// when the host is compiling
#define HOSTAPI __declspec(dllexport)
#else
// when the plugins are compiling
#define HOSTAPI __declspec(dllimport)
#endif

添加宏COMPILE_HOST的定义到Dll工程里,但是不加到插件工程里。

在宿主Dll端:
// CImageParser is the base class that all image parsers
// must inherit
class CImageParser
{
public:
// adds the parser to the parsers list
HOSTAPI CImageParser( void );
// parses the image file and reads it into a HBITMAP
virtual HBITMAP ParseFile( const char *fname )=0;
// returns true if the file type is supported
virtual bool SupportsType( const char *type ) const=0;

protected:
HOSTAPI HBITMAP CreateBitmap( int width, int height,
void **data );
};



现在基类并不仅仅限于一个接口。我们能增加更多基本功能。CreateBitmap函数将被所有解析器共享。
这次不再是宿主调用一个函数来获取解析器并且将它添加到邻接表中,这个功能被CImageParser的构造函数取代。当解析器对象被创建,它的构造函数将自动更新邻接表。宿主不必再使用GetProcAddress函数来看看什么解析器在Dll里。

在插件端:
// CBMPParser inherits from CImageParser
class CBMPParser: public CImageParser
{
public:
virtual HBITMAP ParseFile( const char *fname );
virtual bool SupportsType( const char *type ) const;
};

static CBMPParser g_BMPParser;


当g_BMPParser被创建是它的构造函数 CBMPParser() 将被调用。那个构造函数(在插件端实现)将调用基类的构造函数CImageParser() (在宿主端实现)。那是可能的因为构造函数被标记为HOSTAPI。
等等,还可以变得更好

[把宿主Dll和Exe连接起来]
(这一部分暂时没翻译)

[链接]
[1] Plug-In framework using DLLs by Mohit Khanna
[2] ATL COM Based Addin / Plugin Framework With Dynamic Toolbars and Menus by thomas_tom99

PS.我想,Interface方法,是在第一种方法之上加入了一个间接层。
我现在到没有太强的感觉非内联函数和静态函数会成为这样一个大型系统的主要部分,Interface的派生类中的非内联函数应该只被纯虚接口函数调用,不然就是接口设计有问题了。

<<Programming Windows>>随书光盘下载

<<Programming Windows>>随书光盘下载
最近发现自己Win32方面实在很弱,补了一下。<<Programming Windows>>是"经典的Windows编程导引"了。
书中对Windows API的讲解非常详细。未来的趋势已经确定是.NET了,该学一下了。像Joel所说,Mircosoft那只下金蛋的鸡(Windows API)已经要寿终正寝了。Microsoft下一代的操作系统发布后,.NET将会广泛使用。
这里的下载是原书附带的源代码,实际上中文版电子书也在里面。
以前的代码缺少第四章的,我补上了。电子书第一部分第四章有点小错误,iIndex应为Index,或者在结构的的定义里把 Index该为iIndex,我用的前一种改法,按照匈牙利命名法应该用后一种的。不过考虑到面向对象语言里应该减少对匈牙利命名法的使用,不应该依靠变量名来确定变量类型。

2007年2月17日

过年了Google怎么不换logo啊

难道不为民族节日庆祝一下,sigh
P.S.原来大年初一才换,sigh

2007年2月15日

针对switch/case的小重构

这是放假前的任务了,总觉得代码里有种怪气味,回家的路上看了《设计模式解析》。

需求是这样的:要模仿昆虫的飞行
把昆虫看作一个状态机的话,它的状态包括:位置(pos),俯仰角(pitchAngle),偏航角(yawAngle),翅膀角度(wingAngle)。
位置是昆虫在世界坐标系(三维空间)里的坐标,有x,y,z三个分量。俯仰角表示昆虫身体与水平面的夹角。偏航角表示与竖直平面的夹角。这样的抽象可能有点过于简单,不过现在假定可以满足需求。
最初的想法是采集蝴蝶的飞行过程中的数据,然后用这些数据设置昆虫的状态来模拟昆虫的飞行,这样的话变成难度比较小并且效果应该很好。这样就有两个模块RouteBuilder负责载入数据,MoveInsect负责设置数据改变状态。


void MoveInsect::Move()
{
GetData();
SetInsectState();
}

因为采集数据太困难我们使用了自己生成的数据,这样的生成数据以节点(Node)的形式给出来。Node里包含的并不是要设置的量,而是改变量。比如现在的速度是1,节点里的改变量是2,应用这个节点后速度的值就是3。生成数据的时候发现要寻找昆虫的飞行规律,比如有攀升,俯冲等姿势。这样麻烦就产生了,比如攀升这个动作是需要知道当前状态的,因为攀升时振翅的速度会加快,但是可能上一个状态也是攀升,振翅的速度就已经加快了。这样就必须让MoveInsect知道Node所处的状态。现在的代码

struct Node
{
......
NodeType type_;
}

void MoveInsect::Move()
{
GetData();
SetInsectState();
OtherNodeOp(curNode_);
}
void MoveInsect::OtherNodeOp(Node& node)
{
switch(node.type_)
{
case SWOOP:
break;
......
}
}
设计模式解析里说,switch通常意味着重构的必要
我对模式了解并不多,但是我有一个办法。做一个类的继承体系,基类是NodeMove,派生类包括Swoop等,为MoveInsect增加一个NodeMove& nodeMove_;成员。
但是这样做的作用是什么呢,有多少好处呢,貌似并不多。首先当然是没有了switch,然后呢对象的职责更加明确,并且修改被限制在一个更小的范围内(一个类中)。还有额外的成本,为了修改昆虫的状态我必须声明友元。我得想点别的办法了,借助设计模式的力量,待续

2007年1月25日

从Google Reader上看到了Rss的必然趋势

因为对网络了解不多,其实rss是什么这个问题我到现在还是没搞清楚 ,但是我知道它很方便
像团队的blog聚合,非常方便
现在用google-reader了,把感兴趣的网站(有rss的)都放进来,隔一段时间reader会帮你去查看是否有更新,更新的站点会标记出来,再也不需要逐个网站去翻了。
更好的user experience,更快捷,方便。

2007年1月20日

The past exam

I didn't do very well in the exam.I didn't finish both Physics and discrete mathematics exam.
I should pay more attention to my course next year. In short, i overestimated myself, i have thought that i could do very well even if i just spend little time on it.In fact, i didn't spend a lot of time when i am in grade one,but i still get a satisfactory score,after all a high score is not my ideal.The key is that i didn't take the course seriously.
But i don't feel very bad, on the contrary , i could see a passionate yaker, who will struggle for his future and ideal. Now i have a friend, this is the most exciting thing for me.I have a insight to myself now.During the exam, i read milan kundera's book <<The Unbearable lightness of Being>> , a external book.It tell me a lot about the meaning of the life.
I should make plan for the next year now.
Firstly, take my course seriously.
Secondly, commit to enhance my English ability(especially spoken english )and my programming ability.Seeking the meaning of my life.
Finally,spend more time on basketball, less time on WarCraft.
Do it.