<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title><![CDATA[LOJA Studio - Technique]]></title>
<link>http://loja.cn/blog/</link>
<description><![CDATA[]]></description>
<language>zh-cn</language>
<copyright><![CDATA[Copyright 2005 PBlog3 v2.8]]></copyright>
<webMaster><![CDATA[loja@tom.com(LOJA)]]></webMaster>
<generator>PBlog2 v2.4</generator> 
<image>
	<title>LOJA Studio</title>
	<url>http://loja.cn/blog/images/logos.gif</url>
	<link>http://loja.cn/blog/</link>
	<description>LOJA Studio</description>
</image>

			<item>
			<link>http://loja.cn/blog/article/technique/270.html</link>
			<title><![CDATA[[转载]M8软件开发经验总结：移植黄金岛斗地主的经验分享]]></title>
			<author>loja@tom.com(LOJA)</author>
			<category><![CDATA[Technique]]></category>
			<pubDate>Sun,27 Sep 2009 12:49:26 +0800</pubDate>
			<guid>http://loja.cn/blog/default.asp?id=270</guid>
		<description><![CDATA[<p style="text-align: center"><strong>移植黄金岛斗地主的经验<span class="t_tag" href="tag.php?name=%B7%D6%CF%ED" onclick="tagshow(event)">分享</span></strong></p>
<p style="text-align: center">by houss&nbsp;&nbsp;2009.08.02 (update 2009.09.27)</p>
<p><br />
<br />
&nbsp;&nbsp;移植黄金岛斗地主到m8<span class="t_tag" href="tag.php?name=%CA%D6%BB%FA" onclick="tagshow(event)">手机</span>,是我第一次给wince平台写程序,过程中遇到了各种各样的<span class="t_tag" href="tag.php?name=%CE%CA%CC%E2" onclick="tagshow(event)">问题</span>,也走了很多的弯路;<br />
&nbsp;&nbsp;我想写这篇文章,可以使更多的人更快速的进入m8的开发队伍;<br />
<br />
&nbsp;&nbsp;对于一些基础问题,请遵循这样的步骤去<span class="t_tag" href="tag.php?name=%BD%E2%BE%F6" onclick="tagshow(event)">解决</span>:阅读m8的<span class="t_tag" href="tag.php?name=SDK" onclick="tagshow(event)">SDK</span>头<span class="t_tag" href="tag.php?name=%CE%C4%BC%FE" onclick="tagshow(event)">文件</span>和帮助文档\使用msdn的帮助文档\网上搜索\<span class="t_tag" href="tag.php?name=%C2%DB%CC%B3" onclick="tagshow(event)">论坛</span>问\qq群问;<br />
<br />
一:图像显示接口<br />
&nbsp; &nbsp;给m8写程序,可以使用标准的wince窗口<span class="t_tag" href="tag.php?name=%CF%B5%CD%B3" onclick="tagshow(event)">系统</span>和利用GDI来绘图;所以我用几天时间就让斗地主图形<span class="t_tag" href="tag.php?name=%BD%E7%C3%E6" onclick="tagshow(event)">界面</span>在m8上跑起来了(当然问题还有很多); 这部分代码在WIN32的环境下也可以编译运行，说明兼容性很不错;&nbsp;&nbsp;(当然程序也可以直接继承自CMzApp\CMzWnd，代码可以简单很多); <br />
&nbsp; &nbsp;用GDI遇到了些性能问题;<span class="t_tag" href="tag.php?name=%D3%CE%CF%B7" onclick="tagshow(event)">游戏</span>使用BitBlt全屏最快只能跑到6帧;就开始尝试使用DDraw来解决; 这里我<span class="t_tag" href="tag.php?name=%BD%A8%D2%E9" onclick="tagshow(event)">建议</span>不要使用flip模式,兼容性不好; 也不要lock住主表面直接往里面写,这也会遇到兼容性问题;而是将游戏画面都先绘制到一个后备表面,然后-&gt;Blt到主表面;这样就能兼容所有已经公布的<span class="t_tag" href="tag.php?name=%B9%CC%BC%FE" onclick="tagshow(event)">固件</span>了! (成功绕过所有固件驱动bug)<br />
&nbsp; &nbsp;DDraw表面好像只支持RGB16(r5g6b5)模式,而不能成功启用24位或32位模式(GDI下也只能支持16位色),然而m8的<span class="t_tag" href="tag.php?name=%C6%C1%C4%BB" onclick="tagshow(event)">屏幕</span>是支持24位颜色数的! 如果我们的软件不去支持就有点浪费了; 我们可以使用DDraw的覆盖面(Overlay)技术来启用24位色深显示! m8的SDK为我们包装了一个简单易用的类MzDDrawOverlay,使用它就可以实现了;<br />
&nbsp; &nbsp;在使用DDraw和覆盖图的时候,键盘输入会是个问题:软键盘弹出来了但看不见; 我的解决办法是键盘弹出的时候切换显示到GDI模式;<br />
<br />
二:<span class="t_tag" href="tag.php?name=%C9%F9%D2%F4" onclick="tagshow(event)">声音</span><span class="t_tag" href="tag.php?name=%B2%A5%B7%C5" onclick="tagshow(event)">播放</span>接口<br />
&nbsp;&nbsp;我原来的声音播放有一套基于DirectSound技术的实现;但在m8的wince平台上却没有该组件;在网上<span class="t_tag" href="tag.php?name=%CF%C2%D4%D8" onclick="tagshow(event)">下载</span>了一个开源的DirectSound组件的替代实现,但播放还是有问题(乱响),没有找到原因; 最后干脆重写了声音播放模块,基于wavOut来实现了; 为了支持同时播放多个声音,需要启动不同的线程来打开(waveOutOpen)声音设备;<br />
&nbsp;&nbsp;游戏中m8上的声音控制键能够控制<span class="t_tag" href="tag.php?name=%B6%FA%BB%FA" onclick="tagshow(event)">耳机</span>的音量,但不能控制外放的音量;&nbsp;&nbsp;m8上一直都保持一个全局的最大音量值, IMixer接口控制的是全局音量,调节该值可以控制音量,waveOutSetVolume也可以,在程序退出的时候,记得把它恢复成最大值;&nbsp;&nbsp;其实我不建议这样做;因为万一程序出现崩溃,系统音量就得不到恢复了,影响面太广给用户带来麻烦; 我的方法是自己控制传递给wavOut的pcm数据(乘以一个系数),从而达到控制音量的目的; 用waveOutSetVolume加打开的wavOut句柄做参数应该也可以更简单的做到；<br />
<br />
三:网络<br />
&nbsp;&nbsp;网络我用的TCP\IP协议的socket, <br />
&nbsp;&nbsp;#include &lt;Winsock2.h&gt;<br />
&nbsp;&nbsp;#pragma comment (lib, &quot;ws2.lib&quot;)<br />
&nbsp;&nbsp;然后使用标准的socket那套函数,win平台使用前需要WSAStartup;<br />
&nbsp;&nbsp;m8上,联网前可以用QueryNetWorkStatus来查询网络链接支持情况,如果没有网络链接可以用Dial_StartGprsConnect2来打开<span class="t_tag" href="tag.php?name=GPRS" onclick="tagshow(event)">GPRS</span>(或EDGE)网络;<br />
&nbsp;&nbsp;要支持cmwap联网,需要走有代理的http协议,我就没有那么多资源来支持了;<br />
&nbsp;&nbsp;注意： wince上不支持recv函数的MSG_PEEK方式；<br />
<br />
四:文件系统<br />
&nbsp;&nbsp;我用的c运行库那一套,fopen等等;<br />
<br />
五:时间 <br />
&nbsp;&nbsp;获得当前时间GetLocalTime;&nbsp; &nbsp;启动计时器SetTimer&nbsp;&nbsp;但他们的精度都太低了,只到秒; <br />
获得系统重启动到现在运行了的时间GetTickCount，精度还不错; <br />
&nbsp;&nbsp;我建议使用mmtime那套高精度计时器: timeGetTime timeSetEvent&nbsp; &nbsp;#pragma comment (lib, &quot;mmTimer.lib&quot;)<br />
<br />
六:多线程<br />
&nbsp;&nbsp;用的CreateThread那套函数,临界区用的CriticalSection; 都是win32标准的;<br />
<br />
七:cab包<br />
&nbsp;&nbsp;0.9.0.4及以下固件不支持带压缩<span class="t_tag" href="tag.php?name=%B8%F1%CA%BD" onclick="tagshow(event)">格式</span>的cab安装包; <br />
&nbsp;&nbsp;现在用得最多的0.9.0.5固件不支持包里面含有同名文件(当然是不同文件夹);我试过先改名再利用cab的重命名安装命令也没有绕过这个bug(更高版本的固件试了可以安装);估计系统安装的时候先把所有文件解压到一个文件夹(这时重名的文件就被覆盖了);再移动到目的目录;&nbsp;&nbsp;我的重名文件非常多,没有办法只能自己写了一个简单的文件系统: 将所有文件合并成一个文件,并保存好文件路径和其起始位置; 所有的文件读取请求都先从这个总文件里找;<br />
<br />
<br />
八:获取固件版本号<br />
<br />
&nbsp;&nbsp;程序可能需要针对不同的固件进行不同的处理;<br />
(谢谢[LBE]小饽)<br />
PLATFORMVERSION pv[4];<br />
&nbsp; &nbsp; if(!SystemParametersInfo(SPI_GETPLATFORMVERSION, sizeof(pv), pv, SPIF_UpdateINIFILE))<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;return FALSE;<br />
&nbsp; &nbsp; wsprintf(strVersion, L&quot;%d.%d.%d.%d&quot;, pv[1].dwMajor, pv[1].dwMinor, pv[2].dwMajor, pv[2].dwMinor);<br />
<br />
typedef struct _PLATFORMVERSION <br />
{<br />
&nbsp; &nbsp; DWORD dwMajor;<br />
&nbsp; &nbsp; DWORD dwMinor;<br />
}PLATFORMVERSION;<br />
<br />
&nbsp;&nbsp;注意: 很多不同的固件使用了相同的版本号!&nbsp;&nbsp;这时<span class="t_tag" href="tag.php?name=%CD%C6%BC%F6" onclick="tagshow(event)">推荐</span>判断alarm.dll的md5值来确认固件版本;<br />
<br />
<br />
九:&nbsp;&nbsp;旋转屏幕用ChangeDisplaySettingsEx:&nbsp;&nbsp;<br />
bool rotateScreen(unsigned long dwRotaion,unsigned long&amp; old_dwRotaion){//0 1 2 4<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;DEVMODE settings;<br />
&nbsp; &nbsp; memset(&amp;settings, 0, sizeof(DEVMODE));<br />
&nbsp; &nbsp; settings.dmSize = sizeof(DEVMODE);<br />
<br />
&nbsp; &nbsp; settings.dmFields = DM_DISPLAYORIENTATION;<br />
&nbsp; &nbsp; ChangeDisplaySettingsEx(NULL, &amp;settings, NULL, CDS_TEST, NULL);<br />
&nbsp; &nbsp; old_dwRotaion = settings.dmDisplayOrientation;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;if (dwRotaion&lt;0) return true;<br />
&nbsp; &nbsp; if (dwRotaion == old_dwRotaion)<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;return true;<br />
<br />
&nbsp; &nbsp;settings.dmDisplayOrientation = dwRotaion;<br />
&nbsp; &nbsp;return (DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettingsEx(NULL, &amp;settings, NULL, 0, NULL));<br />
}<br />
&nbsp;&nbsp;m8上横屏代码: rotateScreen(0); <br />
<br />
十: 获取唯一机器码<br />
&nbsp; &nbsp; m8的SDK没有找到这样<span class="t_tag" href="tag.php?name=%B9%A6%C4%DC" onclick="tagshow(event)">功能</span>的API; <br />
&nbsp; &nbsp; 也没有实现DEVICEID标准:<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;#define IOCTL_HAL_GET_DEVICEID CTL_CODE(FILE_DEVICE_HAL, 21, METHOD_BUFFERED, FILE_ANY_ACCESS)<br />
&nbsp; &nbsp;&nbsp; &nbsp;BOOL r= KernelIoControl(IOCTL_HAL_GET_DEVICEID,0, 0,buff,nBuffSize,&amp;dwOutBytes);<br />
&nbsp; &nbsp; 不同机器上返回的设备ID是一串相同的字符串;<br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp;可以用IMEI号来做唯一机器码标识; 下面这个代码可以获得IMEI和IMSI号<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;//Ge DeviceSIMInfo&nbsp; &nbsp; <br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;const int nBuffSize = MAX_PATH*2;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;char buff[nBuffSize+1]={0};<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;DWORD dwOutBytes=0;<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;HLINEAPP hLineApp = 0;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;HLINE hLine = 0;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;DWORD dwNumDevs;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;DWORD dwAPIVersion = TAPI_API_HIGH_VERSION;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;DWORD dwExtVersion = 0;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;DWORD dwMediaMode = LINEMEDIAMODE_DATAMODEM | LINEMEDIAMODE_INTERACTIVEVOICE;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;LINEINITIALIZEEXPARAMS lineInitializeExParams;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;lineInitializeExParams.dwTotalSize = sizeof(lineInitializeExParams);<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;lineInitializeExParams.dwOptions =&nbsp;&nbsp;LINEINITIALIZEEXOPTION_USEEVENT; //The application desires to use the Event Handle event notification mechanism<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;LONG tapiresult = lineInitializeEx(&amp;hLineApp, 0, 0,TEXT(&quot;SimTry&quot;), &amp;dwNumDevs, &amp;dwAPIVersion,&amp;lineInitializeExParams); //returns 0 (SUCCESS)<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;LINEGENERALINFO* lineGeneralInfo = (LINEGENERALINFO*)malloc(sizeof(LINEGENERALINFO));//保存设备序列号的信息的结构体<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;memset(lineGeneralInfo,0,sizeof(LINEGENERALINFO));<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;lineGeneralInfo-&gt;dwTotalSize = sizeof(LINEGENERALINFO);<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;bool bRes=false;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;for (DWORD dwDeviceID = 0; dwDeviceID &lt; dwNumDevs;++dwDeviceID) {<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;tapiresult = lineNegotiateExtVersion(hLineApp, dwDeviceID, dwAPIVersion, EXT_API_LOW_VERSION,EXT_API_HIGH_VERSION, &amp;dwExtVersion); //returns 0 (SUCCESS)<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;tapiresult = lineOpen(hLineApp, dwDeviceID,&amp;hLine, dwAPIVersion, 0, 0,LINECALLPRIVILEGE_OWNER, dwMediaMode, 0);&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;//returns 0 (SUCCESS)<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;tapiresult = lineGetGeneralInfo(hLine,lineGeneralInfo); //returns 0 (SUCCESS)<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;if((tapiresult == 0) &amp;&amp; (lineGeneralInfo-&gt;dwNeededSize &gt; lineGeneralInfo-&gt;dwTotalSize)){<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; //重新获取最新的值<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; DWORD dwNeededSize = lineGeneralInfo-&gt;dwNeededSize;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; free(lineGeneralInfo);<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; lineGeneralInfo = (LINEGENERALINFO*)malloc(dwNeededSize);<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; lineGeneralInfo-&gt;dwTotalSize = dwNeededSize;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; tapiresult = lineGetGeneralInfo(hLine, lineGeneralInfo);<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;}<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;if (tapiresult==0){<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; //成功 保存设备的IMEI&nbsp;&nbsp;unicode字符串<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; lstrcpy((TCHAR*)&amp;buff[0], (TCHAR*)((char*)lineGeneralInfo+ lineGeneralInfo-&gt;dwSerialNumberOffset));<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; dwOutBytes=2*lstrlen((TCHAR*)&amp;buff[0]);<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; //IMSI<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; //if(lineGeneralInfo-&gt;dwSubscriberNumberSize &gt; 2) {<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; //&nbsp; &nbsp; for(int j=0;j&lt;(long)lineGeneralInfo-&gt;dwSubscriberNumberSize/2;j++)<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; //&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;szIMSI[j] = *((unsigned short *)(lineGeneralInfo) + j + lineGeneralInfo-&gt;dwSubscriberNumberOffset/2);<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; //}<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; bRes=true;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; break;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;}<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;}<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;//回收资源<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;free(lineGeneralInfo);<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;if(hLine)<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;lineClose(hLine);<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;if(hLineApp)<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;lineShutdown(hLineApp);<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp;但是,在开飞行模式的时候,调用会失败;&nbsp;&nbsp;(<span class="t_tag" href="tag.php?name=%D7%A2%B2%E1" onclick="tagshow(event)">注册</span>表里也可以读取到IMEI号和设备码,但飞行模式下,好像也取不到,没有测试过)<br />
&nbsp; &nbsp;&nbsp;&nbsp;可以用com9的AT指令来获得IMEI和设备码,飞行模式下也没有问题了:<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;HANDLE hCOM9 = CreateFile( L&quot;COM9:&quot; , GENERIC_READ|GENERIC_WRITE , FILE_SHARE_READ|FILE_SHARE_WRITE , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL );<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;if ( hCOM9 != INVALID_HANDLE_VALUE ){<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; DWORD dwBytes;<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; char p = 13;//cr<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; char q = 10;//lf<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; WriteFile( hCOM9 , &quot;AT+CGSN;+CGMM&quot; , 13 , &amp;dwBytes , NULL );<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; WriteFile( hCOM9 , &amp;p , 1 , &amp;dwBytes , NULL );<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; WriteFile( hCOM9 , &amp;q , 1 , &amp;dwBytes , NULL );<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; Sleep(200);<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; if (ReadFile( hCOM9 , buff , nBuffSize , &amp;dwBytes , NULL )){<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;//buf中报存了4行文本(ansi字符);&nbsp;&nbsp;第二行就是IMEI号,第三行是设备码,第四行是&quot;OK&quot;;&nbsp;&nbsp;(某些情况下,第二行之前可能多出一个空行(多出一个换行符13),从而变成5行!)<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp; CloseHandle( hCOM9 );<br />
&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;&nbsp; &nbsp;}<br />
<br />
<br />
<br />
十一:其他<br />
&nbsp; &nbsp;ansi字符串和unicode字符串的转换可以用这组函数:MultiByteToWideChar\WideCharToMultiByte<br />
<br />
&nbsp; &nbsp;启动执行其他程序可以用ShellExecuteEx;&nbsp;&nbsp;用&quot;open&quot;方式,我用它来调用浏览器打开一个网页<br />
<br />
&nbsp;&nbsp;另外,我不建议程序修改CPU的自动节能;感觉作用不大,还是让它自己管理吧;<br />
<br />
<br />
(如果在我移植斗地主之前有这样的一篇文章,我肯定能节省至少一半的时间)<br />
本文章做了一些修正&nbsp;&nbsp;<strong>请参看DreamMiniOne 的一些纠正和补充<br />
</strong><br />
&nbsp;</p>
<blockquote>
<div class="t_msgfont"><strong>DreamMiniOne:</strong></div>
<div class="t_msgfont">&nbsp;</div>
<div class="t_msgfont" id="postmessage_15245496">大侠的文章对大家帮助很多啊，不过小弟有几点想补充一下：<br />
一:图像显示接口<br />
如果是DIB位图的话，BitBlt确实会比较慢，如果楼主用的是SDK中的ImagingHelper，即使在GDI模式下，速度应该也是不错的。一般的兼容位图480x780，在竖屏下作一次BitBlt大概只需要6ms。<br />
<br />
二:声音播放接口<br />
不需要把音频数据乘以系数来调整音量，waveOutSetVolume可以针对每一个打开的音频handle独立的调节音量的大小，并且不影响系统的总音量。waveOutSetVolume的参数有点讲究，是一个32位的DWORD值，低16位代表左声道的音量，高16位代表右声道的音量，音量取值范围是0 ~ 0xFFFF，但这个数值的单位貌似是db数，所以人耳听起来音量是非线性调节的，我用的简易公式是这样的，输入参数取值范围是0~100<br />
<br />
void SetVolume(DWORD volume)<br />
{<br />
&nbsp; &nbsp; &nbsp; &nbsp; if (hWaveOut != 0)<br />
&nbsp; &nbsp; &nbsp; &nbsp; {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DWORD volumeToSet = (volume &lt;= 0) ? 0 : (0x7FFFU + (volume * (0xFFFFU - 0x7FFFU) / 100));<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MMRESULT ret = waveOutSetVolume(hWaveOut, (volumeToSet &amp; 0xFFFF) | ((volumeToSet &amp; 0xFFFF) &lt;&lt; 16));<br />
&nbsp; &nbsp; &nbsp; &nbsp; }<br />
}<br />
<br />
三:网络<br />
如果要使用CMWAP访问网络<br />
那么socket在connect的时候，连的地址的端口就要是代理的地址和端口<br />
然后在第一次发送请求时，返回的数据要全部照收，然后抛弃掉，再重新发送一次，返回来的数据才是正确的。我是广东的移动卡测试的，发送的是http请求。<br />
<br />
五:时间 <br />
GetTickCount的精度是10ms，其实够用了。</div>
</blockquote>
<p>&nbsp;</p>]]></description>
		</item>
		
			<item>
			<link>http://loja.cn/blog/article/technique/260.htm</link>
			<title><![CDATA[[M8]管它（Schedule Task）多语言添改说明]]></title>
			<author>loja@tom.com(LOJA)</author>
			<category><![CDATA[Technique]]></category>
			<pubDate>Sat,27 Jun 2009 21:37:25 +0800</pubDate>
			<guid>http://loja.cn/blog/default.asp?id=260</guid>
		<description><![CDATA[<p><span style="font-size: 14px">&ldquo;管它&rdquo;的语言保存在和SchduleTask.exe同目录的Language.ini里，用记事本打开就可以编辑。</span></p>
<p><span style="font-size: 14px">打开后出现这样的格式：</span></p>
<blockquote>
<p><span style="font-size: 14px">[Config]<br />
Version=1700</span><br />
LangCount=2<span style="font-size: 14px"><br />
[Language1]<br />
0=English<br />
1=ScheduleTask<br />
2=...<br />
..=...<br />
[Language2]<br />
0=简体中文<br />
1=管它<br />
2=...<br />
..=...</span></p>
</blockquote>
<p>&nbsp;</p>
<p><span style="font-size: 14px">[Config]节中的Version代表的是语言文件的版本，用于程序文件检查对应。此处请不要修改。<font size="2">LangCount表示语言总数，在修改添删语言后注意修改此处（1.7及以后版本需要，之前版本自动判断）。</font></span></p>
<p><span style="font-size: 14px">[Language1]到[LanguageN]是每个语言的节，可以自己添加，数目不限制。<br />
[LanguageN]中0代表语言名称，1代表软件名称（中文叫&ldquo;管它&rdquo;，英文叫&ldquo;ScheduleTask&rdquo;），软件名可以自行根据&ldquo;计划任务&rdquo;的意思翻译。从2开始到最后一个就是程序界面中用到的语言，注意序号所翻译的内容必须和给定的语言对应，字符数尽量简短。</span></p>
<p><span style="font-size: 14px">翻译时注意：</span></p>
<p><span style="font-size: 14px">1.用记事本保存时不要改变编码类型，也就是保持为&ldquo;Unicode&rdquo;编码，这样不会破坏非本地语言的保存。<br />
2.[LanguageN]节中10到16是星期的全称，17到23是星期的简写，简写越短越好，简写不要超过2个字符。<br />
3.如果发现有空的地方请翻译时也留空，这个是为以后新版本新增语言预留的。<br />
4.语言按照规定翻译并保存正确后，启动主程序就会看到以下界面。&nbsp;</span></p>
<p><span style="font-size: 14px"><img alt="" src="http://loja.cn/blog/attachments/month_0906/1200962721330.png" /></span></p>
<p>&nbsp;</p>
<p><span style="font-size: 14px">&ldquo;管它&rdquo;的语言文件下载，其中已经包含English和简体中文：</span></p>
<p><span style="font-size: 14px"><font color="#000000">Version1000</font></span>:<img alt="" border="0" style="margin: 0px 2px -4px 0px" src="http://loja.cn/blog/images/download.gif" /><span style="font-size: 14px"><a href="http://loja.cn/blog/attachments/month_0906/s2009627215010.rar">点击下载此文件</a></span></p>
<p><span style="font-size: 14px"><span style="font-size: 14px"><font color="#000000">Version1700:<a href="http://loja.cn/blog/attachments/month_0908/m20098911191.rar"><img alt="" border="0" style="margin: 0px 2px -4px 0px" src="http://loja.cn/blog/images/download.gif" />点击下载此文件</a></font></span></span></p>]]></description>
		</item>
		
			<item>
			<link>http://loja.cn/blog/article/technique/237.htm</link>
			<title><![CDATA[The SOM(Self-Organizing Map) algorithm]]></title>
			<author>loja@tom.com(LOJA)</author>
			<category><![CDATA[Technique]]></category>
			<pubDate>Sun,01 Jun 2008 00:09:55 +0800</pubDate>
			<guid>http://loja.cn/blog/default.asp?id=237</guid>
		<description><![CDATA[<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 2" class="MsoNormal" align="center"><b><span style="FONT-SIZE: 18pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 18.0pt" lang="EN-US"><font size="3">The SOM algorithm </font></span></b><b><span style="FONT-SIZE: 18pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 18.0pt" lang="EN-US"><font size="3">Some Background</font>&nbsp;&nbsp;</span></b></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 2" class="MsoNormal" align="center"><b><span style="FONT-SIZE: 18pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 18.0pt" lang="EN-US"></span></b>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">Self-adaptive topological maps were initially inspired by modelling perception systems found in mammalian brain. A perception system involves the reception of external signals and their processing inside the nervous system. The complex mammalian skills, such as seeing and hearing seemed to bear similarity to each other in the way they worked. Namely, the primary characteristic of these systems is that neighbouring neurons encode input signals which are similar to each other.</span>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left">&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 3" class="MsoNormal" align="left"><b><i><span style="FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt" lang="EN-US">General idea of the SOM model&nbsp;&nbsp;</span></i></b></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 3" class="MsoNormal" align="left"><b><i><span style="FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt" lang="EN-US"></span></i></b>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">The Self-Organizing Map (SOM) was introduced by Teuvo Kohonen in 1982. The SOM (also known as the Kohonen feature map) algorithm is one of the best known artificial neural network algorithms. In contrast to many other neural networks using supervised learning, the SOM is based on unsupervised learning.&nbsp;&nbsp;</span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">The SOM is quite a unique kind of neural network in the sense that it constructs a topology preserving mapping from the high-dimensional space onto map units in such a way that relative distances between data points are preserved. The map units, or neurons, usually form a two-dimensional regular lattice where the location of a map unit carries semantic information. The SOM can thus serve as a clustering tool of high-dimensional data. Because of its typical two-dimensional shape, it is also easy to visualize.&nbsp;&nbsp;</span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">Another important feature of the SOM is its capability to generalize. In other words, it can interpolate between previously encountered inputs&nbsp;</span><b><span style="FONT-SIZE: 18pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 18.0pt" lang="EN-US">&nbsp;</span></b></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><b><span style="FONT-SIZE: 18pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 18.0pt" lang="EN-US"></span></b><span style="FONT-SIZE: 18pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 18.0pt" lang="EN-US">&nbsp;
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 2" class="MsoNormal" align="left"><span style="FONT-SIZE: 18pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 18.0pt" lang="EN-US"><strong><font size="3">The SOM algorithm</font>&nbsp;</strong></span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 2" class="MsoNormal" align="left"><span style="FONT-SIZE: 18pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 18.0pt" lang="EN-US"><strong></strong></span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 2" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">The basic idea of SOM is simple yet effective. The SOM defines a mapping from high dimensional input data space onto a regular two-dimensional array of neurons. Every neuron i of the map is associated with an n-dimensional reference vector <img alt="" src="http://loja.cn/blog/attachments/month_0805/42008531235744.gif" /> <shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"></shapetype><stroke joinstyle="miter"></stroke>
<formulas>
</formulas>
<f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f>
<path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path>
<lock v:ext="edit" aspectratio="t"></lock><shape style="WIDTH: 75.75pt; HEIGHT: 17.25pt" id="_x0000_i1025" type="#_x0000_t75" alt=""></shape><imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.gif" o:href="http://koti.mbnet.fi/~phodju/nenet/Pics/SOM1.gif"></imagedata>, where n denotes the dimension of the input vectors. The reference vectors together form a codebook. The neurons of the map are connected to adjacent neurons by a neighbourhood relation, which dictates the topology, or the structure, of the map. The most common topologies in use are rectangular and hexagonal.</span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span>&nbsp;</p>
<span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">Adjacent neurons belong to the neighbourhood Ni of the neuron i. In the basic SOM algorithm, the topology and the number of neurons remain fixed from the beginning. The number of neurons determines the granularity of the mapping, which has an effect on the accuracy and generalization of the SOM.&nbsp;&nbsp;</span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">During the training phase, the SOM forms an elastic net that folds onto the &quot;cloud&quot; formed by input data. The algorithm controls the net so that it strives to approximate the density of the data. The reference vectors in the codebook drift to the areas where the density of the input data is high. Eventually, only few codebook vectors lie in areas where the input data is sparse.&nbsp;&nbsp;</span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">The learning process of the SOM goes as follows:&nbsp;&nbsp;</span>&nbsp;</p>
<ol type="1">
    <li style="MARGIN: 0cm 0cm 12pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-pagination: widow-orphan; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">One sample vector x is randomly drawn from the input data set and its similarity (distance) to the codebook vectors is computed by using e.g. the common Euclidean distance measure:<br /><br /><shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"></shapetype><stroke joinstyle="miter"></stroke>
    <formulas>
    </formulas>
    <f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f>
    <path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path>
    <lock v:ext="edit" aspectratio="t"></lock><shape style="WIDTH: 116.25pt; HEIGHT: 23.25pt" id="_x0000_i1025" type="#_x0000_t75" alt=""></shape><imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.gif" o:href="http://koti.mbnet.fi/~phodju/nenet/Pics/SOM2.gif"></imagedata>
    <p><img alt="" src="http://loja.cn/blog/attachments/month_0805/72008531235838.gif" /></p>
    </span></li>
    <li style="MARGIN: 0cm 0cm 12pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-pagination: widow-orphan; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">After the BMU has been found, the codebook vectors are updated. The BMU itself as well as its topological neighbours are moved closer to the input vector in the input space i.e. the input vector attracts them. The magnitude of the attraction is governed by the learning rate. As the learning proceeds and new input vectors are given to the map, the learning rate gradually decreases to zero according to the specified learning rate function type. Along with the learning rate, the neighbourhood radius decreases as well.<br /><br />The update rule for the reference vector of unit i is the following:<br /><br /><shape style="WIDTH: 251.25pt; HEIGHT: 38.25pt" id="_x0000_i1026" type="#_x0000_t75" alt=""></shape><imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image002.gif" o:href="http://koti.mbnet.fi/~phodju/nenet/Pics/SOM3.gif"></imagedata>
    <p><img alt="" src="http://loja.cn/blog/attachments/month_0805/b200853123592.gif" /></p>
    </span></li>
    <li style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">The steps 1 and 2 together consitute a single training step and they are repeated until the training ends. The number of training steps must be fixed prior to training the SOM because the rate of convergence in the neighbourhood function and the learning rate is calculated accordingly.
    <p><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">After the training is over, the map should be topologically ordered. This means that n topologically close (using some distance measure e.g. Euclidean) input data vectors map to n adjacent map neurons or even to the same single neuron.</span></p>
    </span></li>
</ol>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="justify"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">
<p><img alt="" src="http://loja.cn/blog/attachments/month_0805/g2008531235933.gif" /></p>
</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;<b><i><span style="FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt" lang="EN-US">Map quality measures&nbsp;&nbsp;</span></i></b>&nbsp;&nbsp;&nbsp; </p>
</span>&nbsp;&nbsp;
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">After the SOM has been trained, it is important to know whether it has properly adapted itself to the training data. Because it is obvious that one optimal map for the given input data must exist, several map quality measures have been proposed. Usually, the quality of the SOM is evaluated based on the mapping precision and the topology preservation.
<p>&nbsp;<b><i><span style="FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt" lang="EN-US">Mapping precision&nbsp;&nbsp;</span></i></b>&nbsp;</p>
</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">The mapping precision measure describes how accurately the neurons 'respond' to the given data set. For example, if the reference vector of the BMU calculated for a given testing vector xi is exactly the same xi, the error in precision is then 0. Normally, the number of data vectors exceeds the number of neurons and the precision error is thus always different from 0.&nbsp;&nbsp;</span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">A common measure that calculates the precision of the mapping is the average quantization error over the entire data set:&nbsp;</span>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 2" class="MsoNormal" align="left">&nbsp;<img alt="" src="http://loja.cn/blog/attachments/month_0806/4200861010.gif" />&nbsp;</p>
</span></p>
&nbsp;&nbsp;
<p>&nbsp;</p>
&nbsp;&nbsp;
<p>&nbsp;</p>
&nbsp;&nbsp;&nbsp;
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 2" class="MsoNormal" align="left">&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 3" class="MsoNormal" align="left"><b><i><span style="FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt" lang="EN-US">Topology preservation&nbsp;&nbsp;</span></i></b></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 3" class="MsoNormal" align="left"><b><i><span style="FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt" lang="EN-US"></span></i></b>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">The topology preservation measure describes how well the SOM preserves the topology of the studied data set. Unlike the mapping precision measure, it considers the structure of the map. For a strangely twisted map, the topographic error is big even if the mapping precision error is small.&nbsp;&nbsp;</span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">A simple method for calculating the topographic error:&nbsp;&nbsp;</span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 2" class="MsoNormal" align="left"><img alt="" src="http://loja.cn/blog/attachments/month_0806/b2008610138.gif" /></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 2" class="MsoNormal" align="left">&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">where <img alt="" src="http://loja.cn/blog/attachments/month_0806/6200861029.gif" />&nbsp;<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"></shapetype><stroke joinstyle="miter"></stroke>
<formulas>
</formulas>
<f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f>
<path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path>
<lock v:ext="edit" aspectratio="t"></lock><shape style="WIDTH: 30pt; HEIGHT: 18pt" id="_x0000_i1025" type="#_x0000_t75" alt=""></shape><imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.gif" o:href="http://koti.mbnet.fi/~phodju/nenet/Pics/SOM7.gif"></imagedata>is 1 if the first and second BMUs of <shape style="WIDTH: 14.25pt; HEIGHT: 18pt" id="_x0000_i1026" type="#_x0000_t75" alt=""></shape><imagedata src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image002.gif" o:href="http://koti.mbnet.fi/~phodju/nenet/Pics/SOM8.gif"></imagedata>are not next to each other. Otherwise&nbsp;<img alt="" src="http://loja.cn/blog/attachments/month_0806/r2008610249.gif" />&nbsp; is 0.
<p>&nbsp;<b><i><span style="FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt" lang="EN-US">Visualizing the SOM&nbsp;&nbsp;</span></i></b>&nbsp;</p>
</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">The SOM is easy to visualize and over the years, several visualization techniques have been devised. Due to the inherently intricate nature of the SOM, however, not one of the visualization methods discovered so far, has proven to be superior to others. At times, several different visualizations of the same SOM are needed to fully see the state of the map. From this, in can be concluded that every existing visualization method has its merits and demerits. The rest of this section provides an overview to three of them, two of which visualize the reference vectors while the remaining one visualizes the data histograms.&nbsp;&nbsp;</span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 3" class="MsoNormal" align="left"><b><i><span style="FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt" lang="EN-US">Visualizing the reference vectors&nbsp;&nbsp;</span></i></b></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 3" class="MsoNormal" align="left"><b><i><span style="FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt" lang="EN-US"></span></i></b>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">The Sammon mapping represents the SOM in much the same way as </span><i><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt" lang="EN-US">Figure 6</span></i><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"> does. The idea is that the originally high-dimensional reference vector space is compressed into two dimensions, making the visualization of the data possible. The Sammon mapping tries to find an optimum non-linear projection for the high-dimensional data so that the resulting vectors projected onto a two-dimensional surface would still retain the same relative mutual Euclidean distances as they did in the higher dimensionality.&nbsp;&nbsp;</span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">Unified distance matrix, or u-matrix, is perhaps the most popular method of displaying SOMs. It represents the map as a regular grid of neurons as illustrated in </span><i><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt" lang="EN-US">Figure 9</span></i><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">. The size and topology of the map can readily be observed from the picture where each element represents a neuron. First, when generating a u-matrix, a distance matrix between the reference vectors of adjacent neurons of two-dimensional map is formed. Then, some representation for the matrix is selected, e.g. a gray-level image. The colors in the figure have been selected so that the lighter the color between two neurons is, the smaller is the relative distance between them.&nbsp;</span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 2" class="MsoNormal" align="left"><img alt="" src="http://loja.cn/blog/attachments/month_0806/f2008610336.gif" /></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 2" class="MsoNormal" align="left">&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><i><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt" lang="EN-US">Figure 6: The u-matrix visualization of the SOM. The map size is 12 x 8 neurons and the topology is hexagonal. The map has also been labelled</span></i><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">.</span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">
<p>&nbsp;<b><i><span style="FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt" lang="EN-US">Visualizing the data histograms&nbsp;&nbsp;</span></i></b>&nbsp;</p>
</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">The purpose of a data histogram is to show how input data vectors are clustered by the SOM. The data histogram visualization shows how many vectors belong to a cluster defined by each neuron. The histogram can be generated by using a trained SOM and a data set. The BMU is searched for each data vector, after which a hit counter associated with the BMU is increased by one. There are several possible ways of visualizing the resulting histograms, one of which is shown in</span><i><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt" lang="EN-US"> Figure 7</span></i><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">.&nbsp;</span>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 2" class="MsoNormal" align="left"><img alt="" src="http://loja.cn/blog/attachments/month_0806/c200861043.gif" /></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><i><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt; mso-ansi-language: PT-BR" lang="PT-BR">Figure 7: A 3D data histogram visualization. </span></i><i><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt" lang="EN-US">The map size is 12 x 8 neurons and the topology is hexagonal</span></i><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">.</span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">
<p>&nbsp;<b><i><span style="FONT-SIZE: 14pt; FONT-FAMILY: Arial; mso-font-kerning: 0pt" lang="EN-US">Hierarchical SOMs&nbsp;&nbsp;</span></i></b>&nbsp;</p>
</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">The input of one SOM can be taken from the output of another. The input can also be formed of several output vectors from many SOMs. This kind of structure is referred to as a hierarchical SOM. The topmost SOM in the structure (see </span><i><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt" lang="EN-US">Figure 8</span></i><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">) clusters the outputs and provides a means of monitoring the operations of the underlying SOMs. As the SOM hierarchy is traversed upwards, the information becomes more and more abstract.</span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">
<p><img alt="" src="http://loja.cn/blog/attachments/month_0806/c2008610445.gif" /></p>
</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;<i><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt; mso-bidi-font-size: 12.0pt" lang="EN-US">Figure 8: Hierarchical SOM with the BMUs indicated. The topmost SOM takes input from the outputs of the three lower level SOMs</span></i><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">.</span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan" class="MsoNormal" align="left"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">
<p><font size="3">&nbsp;</font><b><span style="FONT-SIZE: 18pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 18.0pt" lang="EN-US"><font size="3">Applications of SOM</font>&nbsp;&nbsp;</span></b>&nbsp;&nbsp;</p>
</span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US">The most important practical applications of SOMs are in exploratory data analysis, pattern recognition, speech analysis, robotics, industrial and medical diagnostics, instrumentation and control. The SOM can also be applied to hundreds of other tasks where large amounts of unclassified data is available. </span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"></span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"><font color="#333399"></font></span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"><font color="#333399"></font></span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"><font color="#333399">Download Word Document(<font face="Arial">Package Uing WinRAR</font>):</font></span></p>
<p style="MARGIN: 0cm 0cm 0pt" class="MsoNormal"><span style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; mso-bidi-font-family: 宋体; mso-font-kerning: 0pt" lang="EN-US"><a href="http://loja.cn/blog/attachments/month_0806/a2008610832.rar"><img style="MARGIN: 0px 2px -4px 0px" border="0" alt="" src="http://loja.cn/blog/images/download.gif" /><font face="Arial">点击下载此文件</font></a></span></p>
<p style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-pagination: widow-orphan; mso-outline-level: 2" class="MsoNormal" align="left">&nbsp;</p>]]></description>
		</item>
		
			<item>
			<link>http://loja.cn/blog/article/technique/235.htm</link>
			<title><![CDATA[全国哀悼日，把网页色调改为灰色]]></title>
			<author>loja@tom.com(LOJA)</author>
			<category><![CDATA[Technique]]></category>
			<pubDate>Mon,19 May 2008 10:48:46 +0800</pubDate>
			<guid>http://loja.cn/blog/default.asp?id=235</guid>
		<description><![CDATA[今天起正式进入全民哀悼日，举国同哀。也许使用IE的朋友已经注意到本站已经变成了灰色。<br/>不是你的浏览器出了问题，而是为了配合全国哀悼日，表达我们的沉痛之情，我们已经将网页变为黑白灰度的。<br/>你可以按照以下方法设置相同效果。<br/>如果你使用了CSS文件，那请在CSS文件前加入这个代码:<br/><div class="UBBPanel codePanel"><div class="UBBTitle"><img src="http://loja.cn/blog/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent">html { filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1); }</div></div><br/>注：使用PJBlog的朋友在当前使用皮肤的layout.css文件最前加入以上代码即可。<br/><br/><br/>如果你没有使用CSS文件，请在页面的&lt;head&gt;&lt;/head&gt;之间加入以下代码：<br/><div class="UBBPanel codePanel"><div class="UBBTitle"><img src="http://loja.cn/blog/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent">&lt;style type=&#34;text/css&#34;&gt;<br/>&lt;!--<br/>html { filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1); }<br/>--&gt;<br/>&lt;/style&gt;</div></div><br/>注：如果页面内已经有&lt;style type=&#34;text/css&#34;&gt;标记，只需在其中加入html{.....}即可。<br/><br/>需要注明的是，以上实现网页灰度的方法只对IE浏览器有效（除IE8）。]]></description>
		</item>
		
			<item>
			<link>http://loja.cn/blog/article/technique/227.htm</link>
			<title><![CDATA[[转载+收藏] A* Pathfinding for Beginners]]></title>
			<author>loja@tom.com(LOJA)</author>
			<category><![CDATA[Technique]]></category>
			<pubDate>Thu,13 Mar 2008 09:39:40 +0800</pubDate>
			<guid>http://loja.cn/blog/default.asp?id=227</guid>
		<description><![CDATA[<p>很早前在Lendy的blog上看到过，防止需要时L的blog爆掉，今天转了过来。</p>
<h1 align="left"><font face="Arial" color="#808080"><hr /><font color="#000000">&nbsp;</font></font><font face="Arial" color="#808080">A* Pathfinding for Beginners</font></h1>
<p align="left"><span style="FONT-WEIGHT: normal; FONT-STYLE: normal"><font face="Arial" size="2">By Patrick Lester (Updated July 18, 2005)</font></span></p>
<hr />
<p><font face="Arial" size="2">The A* (pronounced A-star) algorithm can be complicated for beginners. While there are many articles on the web that explain A*, most are written for people who understand the basics already. This article is for the true beginner.</font><font face="Arial" size="2">&nbsp;</font></p>
<p><font face="Arial" size="2">This article does not try to be the definitive work on the subject. Instead it describes the fundamentals and prepares you to go out and read all of those other materials and understand what they are talking about. Links to some of the best are provided at the end of this article, under Further Reading.</font></p>
<p><font face="Arial" size="2">Finally, this article is not program-specific. You should be able to adapt what's here to any computer language. As you might expect, however, I have included a link to a sample program at the end of this article. The sample package contains two versions: one in C++ and one in Blitz Basic. It also contains executables if you just want to see A* in action.&nbsp;</font></p>
<p><font face="Arial" size="2">But we are getting ahead of ourselves. Let's start at the beginning ...</font></p>
<p><b><font face="Arial" size="2">Introduction: The Search Area </font></b></p>
<p><font face="Arial" size="2">Let&rsquo;s assume that we have someone who wants to get from point A to point B. Let&rsquo;s assume that a wall separates the two points. This is illustrated below, with green being the starting point A, and red being the ending point B, and the blue filled squares being the wall in between. </font></p>
<font face="Arial" size="1"><font face="Arial" size="1">
<p>&nbsp;&nbsp;&nbsp;&nbsp;<img alt="" src="http://loja.cn/blog/attachments/month_0803/k200831393310.jpg" /><br />[Figure 1]</p>
</font></font>
<p><font face="Arial" size="2">The first thing you should notice is that we have divided our search area into a square grid. Simplifying the search area, as we have done here, is the first step in pathfinding. This particular method reduces our search area to a simple two dimensional array. Each item in the array represents one of the squares on the grid, and its status is recorded as walkable or unwalkable. The path is found by figuring out which squares we should take to get from A to B. Once the path is found, our person moves from the center of one square to the center of the next until the target is reached.&nbsp;</font></p>
<p><font face="Arial" size="2">These center points are called &ldquo;nodes&rdquo;. When you read about pathfinding elsewhere, you will often see people discussing nodes. Why not just call them squares? Because it is possible to divide up your pathfinding area into something other than squares. They could be rectangles, hexagons, triangles, or any shape, really. And the nodes could be placed anywhere within the shapes &ndash; in the center or along the edges, or anywhere else. We are using this system, however, because it is the simplest.</font></p>
<p><b><font face="Arial" size="2">Starting the Search </font></b></p>
<p><font face="Arial" size="2">Once we have simplified our search area into a manageable number of nodes, as we have done with the grid layout above, the next step is to conduct a search to find the shortest path. We do this by starting at point A, checking the adjacent squares, and generally searching outward until we find our target.&nbsp; </font></p>
<p><font face="Arial" size="2">We begin the search by doing the following:</font></p>
<ol>
    <li><font face="Arial" size="2">Begin at the starting point A and add it to an &ldquo;open list&rdquo; of squares to be considered. The open list is kind of like a shopping list. Right now there is just one item on the list, but we will have more later. It contains squares that might fall along the path you want to take, but maybe not. Basically, this is a list of squares that need to be checked out. &nbsp; </font></li>
    <li><font face="Arial" size="2">Look at all the reachable or walkable squares adjacent to the starting point, ignoring squares with walls, water, or other illegal terrain. Add them to the open list, too. For each of these squares, save point A as its &ldquo;parent square&rdquo;. This parent square stuff is important when we want to trace our path. It will be explained more later. &nbsp; </font></li>
    <li><font face="Arial" size="2">Drop the starting square A from your open list, and add it to a &ldquo;closed list&rdquo; of squares that you don&rsquo;t need to look at again for now. </font></li>
</ol>
<p><font face="Arial" size="2">At this point, you should have something like the following illustration. In this illustration, the dark green square in the center is your starting square. It is outlined in light blue to indicate that the square has been added to the closed list. All of the adjacent squares are now on the open list of squares to be checked, and they are outlined in light green. Each has a gray pointer that points back to its parent, which is the starting square.&nbsp; </font><font face="Arial" size="1">
<p><shape id="_x0000_i1026" style="WIDTH: 114pt; HEIGHT: 112.5pt" type="#_x0000_t75" o:ole=""></shape><imagedata src="file:///C:/windows/TEMP/msoclip1/01/clip_image003.png" o:title=""></imagedata><img alt="" src="http://loja.cn/blog/attachments/month_0803/n20083139342.jpg" /><br />&nbsp; [Figure 2]</p>
</font></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><font face="Arial" size="2">Next, we choose one of the adjacent squares on the open list and more or less repeat the earlier process, as described below. But which square do we choose? The one with the lowest F cost.</font></p>
<p><b><font face="Arial" size="2">Path Scoring</font></b></p>
<p><font face="Arial" size="2">The key to determining which squares to use when figuring out the path is the following equation:</font></p>
<p><font face="Arial" size="2">F = G + H&nbsp; </font></p>
<p><font face="Arial" size="2">where </font></p>
<ul>
    <li><font face="Arial" size="2">G = the movement cost to move from the starting point A to a given square on the grid, following the path generated to get there.&nbsp;</font> </li>
    <li><font face="Arial" size="2">H = the estimated movement cost to move from that given square on the grid to the final destination, point B. This is often referred to as the heuristic, which can be a bit confusing. The reason why it is called that is because it is a guess. We really don&rsquo;t know the actual distance until we find the path, because all sorts of things can be in the way (walls, water, etc.). You are given one way to calculate H in this tutorial, but there are many others that you can find in other articles on the web.</font> </li>
</ul>
<p><font face="Arial" size="2">Our path is generated by repeatedly going through our open list and choosing the square with the lowest F score. This process will be described in more detail a bit further in the article. First l<font face="Arial">et&rsquo;s look more closely at how we calculate the equation.</font></font></p>
<p><font face="Arial" size="2"><font face="Arial">As described above, G is the movement cost to move from the starting point to the given square using the path generated to get there. In this example, we will assign a cost of 10 to each horizontal or vertical square moved, and a cost of 14 for a diagonal move. We use these numbers because the actual distance to move diagonally is the square root of 2 (don&rsquo;t be scared), or roughly 1.414 times the cost of moving horizontally or vertically. We use 10 and 14 for simplicity&rsquo;s sake. The ratio is about right, and we avoid having to calculate square roots and we avoid decimals. This isn&rsquo;t just because we are dumb and don&rsquo;t like math. Using whole numbers like these is a lot faster for the computer, too. As you will soon find out, pathfinding can be very slow if you don&rsquo;t use short cuts like these.</font>&nbsp;</font></p>
<p><font face="Arial" size="2">Since we are calculating the G cost along a specific path to a given square, the way to figure out the G cost of that square is to take the G cost of its parent, and then add 10 or 14 depending on whether it is diagonal or orthogonal (non-diagonal) from that parent square. The need for this method will become apparent a little further on in this example, as we get more than one square away from the starting square.</font></p>
<p><font face="Arial" size="2">H can be estimated in a variety of ways. The method we use here is called the Manhattan method, where you calculate the total number of squares moved horizontally and vertically to reach the target square from the current square, ignoring diagonal movement, and ignoring any obstacles that may be in the way. We then multiply the total by 10, our cost for moving one square horizontally or vertically. This is (probably) called the Manhattan method because it is like calculating the number of city blocks from one place to another, where you can&rsquo;t cut across the block diagonally. </font></p>
<p><font face="Arial" size="2">Reading this description, you might guess that the heuristic is merely a rough estimate of the remaining distance between the current square and the target &quot;as the crow flies.&quot; This isn't the case. We are actually trying to estimate the remaining distance along the path (which is usually farther). The closer our estimate is to the actual remaining distance, the faster the algorithm will be. If we overestimate this distance, however, it is not guaranteed to give us the shortest path. In such cases, we have what is called an &quot;inadmissible heuristic.&quot;</font></p>
<p><font face="Arial" size="2">Technically, in this example, the Manhattan method is inadmissible because it slightly overestimates the remaining distance. But we will use it anyway because it is&nbsp;</font><font face="Arial" size="2">a lot easier to understand for our purposes</font><font face="Arial" size="2">, and because it is only a slight overestimation. On the rare occasion when the resulting path is not the shortest possible, it will be nearly as short. Want to know more? You can find equations and additional notes on heuristics <a href="http://www.policyalmanac.org/games/heuristics.htm">here</a>.</font></p>
<p><font face="Arial" size="2">F is calculated by adding G and H. The results of the first step in our search can be seen in the illustration below. The F, G, and H scores are written in each square. As is indicated in the square to the immediate right of the starting square, F is printed in the top left, G is printed in the bottom left, and H is printed in the bottom right. </font><font face="Arial" size="1"><shape id="_x0000_i1027" style="WIDTH: 271.5pt; HEIGHT: 192pt" type="#_x0000_t75" o:ole=""></shape><imagedata src="file:///C:/windows/TEMP/msoclip1/01/clip_image005.png" o:title=""></imagedata></font></p>
<p><font face="Arial" size="1">&nbsp;&nbsp;&nbsp;<img alt="" src="http://loja.cn/blog/attachments/month_0803/z200831393413.jpg" /><br />&nbsp; <font face="Arial" size="1">[Figure 3]&nbsp; </font></font></p>
<p><font face="Arial" size="2">So let&rsquo;s look at some of these squares. In the square with the letters in it, G = 10. This is because it is just one square from the starting square in a horizontal direction. The squares immediately above, below, and to the left of the starting square all have the same G score of 10. The diagonal squares have G scores of 14.&nbsp;</font></p>
<p><font face="Arial" size="2">The H scores are calculated by estimating the Manhattan distance to the red target square, moving only horizontally and vertically and ignoring the wall that is in the way. Using this method, the square to the immediate right of the start is 3 squares from the red square, for a H score of 30. The square just above this square is 4 squares away (remember, only move horizontally and vertically) for an H score of 40. You can probably see how the H scores are calculated for the other squares.&nbsp;</font></p>
<p><font face="Arial" size="2">The F score for each square, again, is simply calculated by adding G and H together.</font></p>
<h1><font face="Arial" size="2">Continuing the Search</font></h1>
<p><font face="Arial" size="2">To continue the search, we simply choose the lowest F score square from all those that are on the open list. We then do the following with the selected square: </font></p>
<p class="MsoNormal" style="MARGIN-LEFT: 0.5in; TEXT-INDENT: -0.25in"><font face="Arial" size="2">4)<span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal">&nbsp;Drop it from the open list and add it to the closed list.</span> </font></p>
<span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal">
<p class="MsoNormal" style="MARGIN-LEFT: 0.5in; TEXT-INDENT: -0.25in"><font face="Arial" size="2">5)&nbsp;Check all of the adjacent squares. Ignoring those that are on the closed list or unwalkable (terrain with walls, water, or other illegal terrain), add squares to the open list if they are not on the open list already. Make the selected square the &ldquo;parent&rdquo; of the new squares. </font></p>
<p class="MsoNormal" style="MARGIN-LEFT: 0.5in; TEXT-INDENT: -0.25in"><font face="Arial" size="2">6)&nbsp;If an adjacent square is already on the open list, check to see if this path to that square is a better one. In other words, check to see if the G score for that square is lower if we use the current square to get there.&nbsp;<span>If not, don&rsquo;t do anything.&nbsp;<br />&nbsp;&nbsp;&nbsp; On the other hand, if the G cost of the new path is lower, change the parent of the adjacent square to the selected square (in the diagram above, change the direction of the pointer to point at the selected square). Finally, recalculate both the F and G scores of that square. If this seems confusing, you will see it illustrated below.</span> </font></p>
<p><span><font face="Arial" size="2">Okay, so let&rsquo;s see how this works. Of our initial 9 squares, we have 8 left on the open list after the starting square was switched to the closed list.<span>&nbsp; Of these, the one with the lowest F cost is the one to the immediate right of the starting square, with an F score of 40. So we select this square as our next square. It is highlight in blue in the following </span></font></span><font face="Arial" size="2">illustration</font><span><font face="Arial" size="2"><span>.</span></font> <font face="Arial" size="1"></font>
<p><span><font face="Arial" size="1"><font face="Arial" size="1">&nbsp;&nbsp;&nbsp;&nbsp;<img alt="" src="http://loja.cn/blog/attachments/month_0803/e200831393650.jpg" /><br />[Figure 4]&nbsp; </font></font></span></p>
<font face="Arial" size="1"></font>
<p><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><font face="Arial" size="2">First, we drop it from our open list and add it to our closed list (that&rsquo;s why it&rsquo;s now highlighted in blue).<span>&nbsp; Then we check the adjacent squares. Well, the ones to the immediate right of this square are wall squares, so we ignore those. The one to the immediate left is the starting square. That&rsquo;s on the closed list, so we ignore that, too.&nbsp;</span> </font></span></p>
<p><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><font face="Arial" size="2">The other four squares are already on the open list, so we need to check if the paths to those squares are any better using this square to get there, using G scores as our point of reference. Let&rsquo;s look at the square right above our selected square. Its current G score is 14. If we instead went through the current square to get there, the G score would be equal to 20 (10, which is the G score to get to the current square, plus 10 more to go vertically to the one just above it). A G score of 20 is higher than 14, so this is not a better path. That should make sense if you look at the diagram. It&rsquo;s more direct to get to that square from the starting square by simply moving one square diagonally to get there, rather than moving horizontally one square, and then vertically one square.&nbsp;</font></span></p>
<p><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><font face="Arial" size="2">When we repeat this process for all 4 of the adjacent squares already on the open list, we find that none of the paths are improved by going through the current square, so we don&rsquo;t change anything. So now that we looked at all of the adjacent squares, we are done with this square, and ready to move to the next square.&nbsp;</font></span></p>
<p><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><font face="Arial" size="2">So we go through the list of squares on our open list, which is now down to 7 squares, and we pick the one with the lowest F cost. Interestingly, in this case, there are two squares with a score of 54. So which do we choose? It doesn&rsquo;t really matter. For the purposes of speed, it can be faster to choose the <u>last</u> one you added to the open list. This biases the search in favor of squares that get found later on in the search, when you have gotten closer to the target. But it doesn&rsquo;t really matter.&nbsp;(Differing treatment of ties is why two versions of A* may find different paths of equal length.)</font></span></p>
<p><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><font face="Arial" size="2">So let&rsquo;s choose the one just below, and to the right of the starting square, as is shown in the following </font></span><font face="Arial" size="2">illustration</font><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><font face="Arial" size="2">.</font></span></p>
<font face="Arial" size="1">
<p><span><font face="Arial" size="1">&nbsp;&nbsp;<img alt="" src="http://loja.cn/blog/attachments/month_0803/x200831393750.jpg" /><br /></font><font face="Arial" size="1">[Figure 5]&nbsp; </font></span></p>
</font>
<p><span><font face="Arial" size="2">This time, when we check the adjacent squares we find that the one to the immediate right is a wall square, so we ignore that. The same goes for the one just above that. We also ignore the square just below the wall. Why? Because you can&rsquo;t get to that square directly from the current square without cutting across the corner of the nearby wall. You really need to go down first and then move over to that square, moving around the corner in the process.&nbsp;(Note: This rule on cutting corners is optional. </font></span><font face="Arial" size="2"><span>Its use depends on how your nodes are placed.)</span></font></p>
<p><span><font face="Arial" size="2">That leaves five other squares.&nbsp; The other two squares below the current square aren&rsquo;t already on the open list, so we add them and the current square becomes their parent. Of the other three squares, two are already on the closed list (the starting square, and the one just above the current square, both highlighted in blue in the diagram), so we ignore them. And the last square, to the immediate left of the current square, is checked to see if the G score is any lower if you go through the current square to get there. No dice. So we&rsquo;re done and ready to check the next square on our open list.&nbsp; </font></span></p>
<p><font size="2"><span><font face="Arial">We repeat this process until we add the target square to the closed list, at which point it looks something like the </font></span></font><font face="Arial" size="2">illustration </font><font size="2"><span><font face="Arial">below.</font></span></font></p>
<font face="Arial" size="1">
<p><span><font face="Arial" size="1">&nbsp;&nbsp;</font>&nbsp;&nbsp;<img alt="" src="http://loja.cn/blog/attachments/month_0803/e200831393821.jpg" /><br />[Figure 6]&nbsp;</span></p>
</font>
<p><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><font face="Arial" size="2">Note that the parent square for the square two squares below the starting square has changed from the previous </font></span><font face="Arial" size="2">illustration</font><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><font face="Arial" size="2">. Before it had a G score of 28 and pointed back to the square above it and to the right. Now it has a score of 20 and points to the square just above it. This happened somewhere along the way on our search, where the G score was checked and it turned out to be lower using a new path &ndash; so the parent was switched and the G and F scores were recalculated. While this change doesn&rsquo;t seem too important in this example, there are plenty of possible situations where this constant checking will make all the difference in determining the best path to your target.&nbsp;</font></span></p>
<p><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><font face="Arial" size="2">So how do we determine the path? Simple, just start at the red target square, and work backwards moving from one square to its parent, following the arrows. This will eventually take you back to the starting square, and that&rsquo;s your path. It should look like the following </font></span><font face="Arial" size="2">illustration</font><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><font face="Arial" size="2">. Moving from the starting square A to the destination square B is simply a matter of moving from the center of each square (the node) to the center of the next square on the path, until you reach the target.</font></span></p>
<font face="Arial" size="1">
<p><span>&nbsp;&nbsp;<font face="Arial" size="1">&nbsp;&nbsp;<br /></font>[Figure 7]</span></p>
</font><span>
<h1><font face="Arial" size="2">Summary of the A* Method</font></h1>
<p><font face="Arial" size="2">Okay, now that you have gone through the explanation, let&rsquo;s lay out the step-by-step method all in one place: </font></p>
<p class="MsoNormal" style="MARGIN-LEFT: 0.25in; TEXT-INDENT: -0.25in"><font face="Arial" size="2">1) Add the starting square (or node) to the open list. </font></p>
<p><font face="Arial" size="2">2)&nbsp;Repeat the following:</font></p>
<p class="MsoBodyText" style="MARGIN-LEFT: 0.25in"><font face="Arial" size="2">a) Look for the lowest F cost square on the open list. We refer to this as the current square.</font></p>
<p class="MsoNormal" style="MARGIN-LEFT: 0.25in"><font face="Arial" size="2">b) Switch it to the closed list. </font></p>
<p class="MsoNormal" style="MARGIN-LEFT: 0.25in"><font face="Arial" size="2">c) For each of the 8 squares adjacent to this current square &hellip;</font></p>
<ul>
    <li>
    <p class="MsoNormal" style="MARGIN-LEFT: 0.25in"><font face="Arial" size="2"><font face="Arial">If it is not walkable or if it is on the closed list, ignore it. Otherwise do the following. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></font></p>
    </li>
    <li>
    <p class="MsoNormal" style="MARGIN-LEFT: 0.25in"><font face="Arial" size="2">If it isn&rsquo;t on the open list, add it to the open list. Make the current square the parent of this square. Record the F, G, and H costs of the square.&nbsp;</font> </p>
    </li>
    <li>
    <p class="MsoNormal" style="MARGIN-LEFT: 0.25in"><font face="Arial" size="2">If it is on the open list already, check to see if this path to that square is better, using G cost as the measure. A lower G cost means that this is a better path. If so, change the parent of the square to the current square, and recalculate the G and F scores of the square. If you are keeping your open list sorted by F score, you may need to resort the list to account for the change.</font> </p>
    </li>
</ul>
<p class="MsoBodyText" style="MARGIN-LEFT: 0.25in"><font face="Arial" size="2">d) Stop when you:</font></p>
<ul>
    <li><font face="Arial" size="2">Add the target square to the closed list, in which case the path has been found (see note below), or</font> </li>
    <li><font face="Arial" size="2">Fail to find the target square, and the open list is empty. In this case, there is no path. <font face="Arial">&nbsp;&nbsp; </font></font></li>
</ul>
<p><font face="Arial" size="2">3)&nbsp;Save the path. Working backwards from the target square, go from each square to its parent square until you reach the starting square. That is your path.&nbsp;</font></p>
<p><font face="Arial" size="2"><u>Note</u>: In earlier versions of this article, it was suggested that you can stop when the target square (or node) has been added to the open list, rather than the closed list.&nbsp; Doing this will be faster and it will <u>almost</u> always give you the shortest path, but not always.&nbsp; Situations where doing this could make a difference are when the movement cost to move from the second to the last node to the last (target) node can vary significantly -- as in the case of a river crossing between two nodes, for example.</font></p>
</span></span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><b><span><font face="Arial" size="2">Small Rant&nbsp; </font></span></b></span></p>
<span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal">
<p><font face="Arial" size="2"><font face="Arial">Forgive me for digressing, but it is worth pointing out that when you read various discussions of A* pathfinding on the web and in assorted forums, you will occasionally see someone refer to certain code as A* when it isn&rsquo;t. For the A* method to be used, you need to include the elements just discussed above -- specifically open and closed lists and path scoring using F, G, and H.<span>&nbsp; There are lots of other pathfinding algorithms, but those other methods are not A*, which is generally considered to be the best of the lot. Bryan Stout discusses many of them in the article referenced at the end of this article, including some of their pros and cons. Sometimes alternatives are better under certain circumstances, but you should understand what you are getting into. Okay, enough ranting. Back to the article.</span></font><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"> &nbsp;</span></font></p>
</span>
<p><font face="Arial" size="2"><font face="Arial"><span style="FONT-STYLE: normal; FONT-VARIANT: normal"><b>Notes on Implementation&nbsp;</b></span></font></font></p>
<span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal">
<p><font face="Arial" size="2"><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><font face="Arial">Now that you understand the basic method, here are some additional things to think about when you are writing your own program. Some of the following materials reference the program I wrote in C++ and Blitz Basic, but the points are equally valid in other languages.</font></span></font><br /><span></span></p>
</span></span><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"></span></span>
<p><b><i><font face="Arial" size="2">1.&nbsp; Other Units (collision avoidance):</font></i></b> <font face="Arial" size="2">If you happen to look closely at my example code, you will notice that it completely ignores other units on the screen. The units pass right through each other. Depending on the game, this may be acceptable or it may not.</font><font face="Arial" size="2"> If you want to consider other units in the pathfinding algorithm and have them move around one another, I suggest that you only consider units that are either stopped or adjacent to the pathfinding unit at the time the path is calculated, treating their current locations as unwalkable. </font><font face="Arial" size="2">For adjacent units that are moving, you can discourage collisions by penalizing nodes that lie along their respective paths, thereby encouraging the pathfinding unit to find an alternate route (described more under #2).</font><font face="Arial" size="2"> <br /></font></p>
<p><font face="Arial" size="2">If you choose to consider other units that are moving and not adjacent to the pathfinding unit, you will need to develop a method for predicting where they will be at any given point in time so that they can be dodged properly. Otherwise you will probably end up with strange paths where units zig-zag to avoid other units that aren't there anymore. </font><font face="Arial" size="2"><br /></font></p>
<p><font face="Arial" size="2">You will also, of course, need to develop some collision detection code because no matter how good the path is at the time it is calculated, things can change over time. When a collision occurs a unit must either calculate a new path or, if the other unit is moving and it is not a head-on collision, wait for the other unit to step out of the way before proceeding with the current path.</font><font face="Arial" size="2"><br /></font></p>
<p><font face="Arial" size="2">These tips are probably enough to get you started. If you want to learn more, here are some links that you might find helpful:<br /></font></p>
<ul>
    <li><font face="Arial" size="2"><a href="http://www.red3d.com/cwr/steer/">Steering Behavior for Autonomous Characters</a>: Craig Reynold's work on steering is a bit different from pathfinding, but it can be integrated with pathfinding to make a more complete movement and collision avoidance system.</font> </li>
    <li><font face="Arial" size="2"><a href="http://ducati.doc.ntu.ac.uk/uksim/uksim%2704/Papers/Simon%20Tomlinson-%2004-20/paper04-20%20CR.pdf">The Long and Short of Steering in Computer Games</a>: An interesting survey of the literature on steering and pathfinding. This is a pdf file.</font> </li>
    <li><font face="Arial" size="2"><a href="http://www.gamasutra.com/features/game_design/19990122/movement_01.htm">Coordinated Unit Movement</a>: First in a two-part series of articles on formation and group-based movement </font><font face="Arial" size="2">by Age of Empires designer </font><font face="Arial" size="2">Dave Pottinger.</font><br /></li>
    <li><font face="Arial" size="2"><a href="http://www.gamasutra.com/features/19990129/implementing_01.htm">Implementing Coordinated Movement</a>: Second in Dave Pottinger's two-part series.</font> </li>
</ul>
<p><b><i><font face="Arial" size="2">2. Variable Terrain Cost: </font></i></b><font face="Arial" size="2">In this tutorial and my accompanying program, terrain is just one of two things &ndash; walkable or unwalkable. But what if you have terrain that is walkable, but at a higher movement cost? Swamps, hills, stairs in a dungeon, etc. &ndash; these are all examples of terrain that is walkable, but at a higher cost than flat, open ground. Similarly, a road might have a lower movement cost than the surrounding terrain.</font></p>
<p><font face="Arial" size="2">This problem is easily handled by adding the terrain cost in when you are calculating the G cost of any given node. Simply add a bonus cost to such nodes. The A* pathfinding algorithm is already written to find the lowest cost path and should handle this easily. In the simple example I described, when terrain is only walkable or unwalkable, A* will look for the shortest, most direct path. But in a variable-cost terrain environment, the least cost path might involve traveling a longer distance &ndash; like taking a road around a swamp rather than plowing straight through it.</font></p>
<p><font face="Arial" size="2">An interesting additional consideration is something the professionals call &ldquo;influence mapping.&rdquo; Just as with the variable terrain costs described above, you could create an additional point system and apply it to paths for AI purposes. Imagine that you have a map with a bunch of units defending a pass through a mountain region. Every time the computer sends somebody on a path through that pass, it gets whacked. If you wanted, you could create an influence map that penalized nodes where lots of carnage is taking place. This would teach the computer to favor safer paths, and help it avoid dumb situations where it keeps sending troops through a particular path, just because it is shorter (but also more dangerous).<br /></font></p>
<p><font face="Arial" size="2">Yet another possible use is penalizing nodes that lie along the paths of nearby moving units. One of the downsides of A* is that when a group of units all try to find paths to a similar location, there is usually a significant amount of overlap, as one or more units try to take the same or similar routes to their destinations. Adding a penalty to nodes already 'claimed' by other units will help ensure a degree of separation, and reduce collisions. Don't treat such nodes as unwalkable, however, because you still want multiple units to be able to squeeze through tight passageways in single file, if necessary. Also, you should only penalize the paths of units that are near the pathfinding unit, not all paths, or you will get strange dodging behavior as units avoid paths of units that are nowhere near them at the time. Also, you should only penalize path nodes that lie along the current and future portion of a path, not previous path nodes that have already been visited and left behind.<br /></font></p>
<p><font face="Arial" size="2"><b><i>3. Handling Unexplored Areas: </i></b>Have you ever played a PC game where the computer always knows exactly what path to take, even though the map hasn't been explored yet? Depending upon the game, pathfinding that is too good can be unrealistic. Fortunately, this is a problem that is can be handled fairly easily.</font></p>
<p><font face="Arial" size="2"><font face="Arial" size="2">The answer is to create a separate &quot;knownWalkability&quot; array for each of the various players and computer opponents (each player, not each unit -- that would require a lot more computer memory). Each array would contain information about the areas that the player has explored, with the rest of the map assumed to be walkable until proven otherwise. Using this approach, units will wander down dead ends and make similar wrong choices until they have learned their way around. Once the map is explored, however, pathfinding would work normally.</font></font></p>
<p><font face="Arial" size="2"><b><i>4. Smoother Paths: </i></b>While A* will automatically give you the shortest, lowest cost path, it won't automatically give you the smoothest looking path. Take a look at the final path calculated in our example (in Figure 7). On that path, the very first step is below, and to the right of the starting square. Wouldn't our path be smoother if the first step was instead the square directly below the starting square?</font></p>
<p><font face="Arial" size="2"><font face="Arial" size="2">There are several ways to address this problem. While you are calculating the path you could penalize nodes where there is a change of direction, adding a penalty to their G scores. Alternatively, you could run through your path after it is calculated, looking for places where choosing an adjacent node would give you a path that looks better. For more on the whole issue, check out <a href="http://www.gamasutra.com/features/20010314/pinter_01.htm">Toward More Realistic Pathfinding</a>, a (free, but registration required) article at Gamasutra.com by Marco Pinter.</font></font></p>
<p><font face="Arial" size="2"><b><i>5. Non-square Search Areas: </i></b><font face="Arial" size="2">In our example, we used a simple 2D square layout. You don't need to use this approach. You could use irregularly shaped areas. Think of the board game Risk, and the countries in that game. You could devise a pathfinding scenario for a game like that. To do this, you would need to create a table for storing which countries are adjacent to which, and a G cost associated with moving from one country to the next. You would also need to come up with a method for estimating H. Everything else would be handled the same as in the above example. Instead of using adjacent squares, you would simply look up the adjacent countries in the table when adding new items to your open list.</font></font></p>
<p><font face="Arial" size="2"><font face="Arial" size="2">Similarly, you could create a waypoint system for paths on a fixed terrain map. Waypoints are commonly traversed points on a path, perhaps on a road or key tunnel in a dungeon. As the game designer, you could pre-assign these waypoints. Two waypoints would be considered &quot;adjacent&quot; to one another if there were no obstacles on the direct line path between them. As in the Risk example, you would save this adjacency information in a lookup table of some kind and use it when generating your new open list items. You would then record the associated G costs (perhaps by using the direct line distance between the nodes) and H costs (perhaps using a direct line distance from the node to the goal). Everything else would proceed as usual.</font></font></p>
<p><font face="Arial" size="2">Amit Patel has written a brief <a href="http://theory.stanford.edu/~amitp/GameProgramming/MapRepresentations.html">article</a> delving into some alternatives. For another example of searching on an isometric RPG map using a non-square search area, <span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><font face="Arial" size="2">check out my article <a href="http://www.policyalmanac.org/games/twoTiered.htm">Two-Tiered A* Pathfinding</a>.</font></span></font> </p>
<p><b><i><font face="Arial" size="2"><span>6.</span></font></i></b><span style="FONT-STYLE: normal"><b><i><font face="Arial" size="2"> Some Speed Tips: </font></i></b></span><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><font face="Arial" size="2">As you develop your own A* program, or adapt the one I wrote, you will eventually find that pathfinding is using a hefty chunk of your CPU time, particularly if you have a decent number of pathfinding units on the board and a reasonably large map. If you read the stuff on the net, you will find that this is true even for the professionals who design games like Starcraft or Age of Empires. If you see things start to slow down due to pathfinding, here are some ideas that may speed things up:&nbsp;</font></span></p>
<ul>
    <li><font face="Arial" size="2">Consider a smaller map or fewer units.</font> </li>
    <li><font face="Arial" size="2">Never do path finding for more than a few units at a time. Instead put them in a queue and spread them out over several game cycles. If your game is running at, say, 40 cycles per second, no one will ever notice. But they will notice if the game seems to slow down every once in a while when a bunch of units are all calculating paths at the same time.</font> </li>
    <li><font face="Arial" size="2">Consider using larger squares (or whatever shape you are using) for your map. This reduces the total number of nodes searched to find the path. If you are ambitious, you can devise two or more pathfinding systems that are used in different situations, depending upon the length of the path. This is what the professionals do, using large areas for long paths, and then switching to finer searches using smaller squares/areas when you get close to the target. If you are interested in this concept, check out my article <a href="http://www.policyalmanac.org/games/twoTiered.htm">Two-Tiered A* Pathfinding</a>.</font> </li>
    <li><font face="Arial" size="2">For longer paths, consider devising precalculated paths that are hardwired into the game.</font> </li>
    <li><font face="Arial" size="2">Consider pre-processing your map to figure out what areas are inaccessible from the rest of the map. I call these areas &quot;islands.&quot; In reality, they can be islands or any other area that is otherwise walled off and inaccessible. One of the downsides of A* is that if you tell it to look for paths to such areas, it will search the whole map, stopping only when every accessible square/node has been processed through the open and closed lists. That can waste a lot of CPU time. It can be prevented by predetermining which areas are inaccessible (via a flood-fill or similar routine), recording that information in an array of some kind, and then checking it before beginning a path search.</font> </li>
    <li><font face="Arial" size="2">In a crowded, maze-like environment, consider tagging nodes that don't lead anywhere as dead ends. Such areas can be manually pre-designated in your map editor or, if you are ambitious, you could develop an algorithm to identify such areas automatically. Any collection of nodes in a given dead end area could be given a unique identifying number. Then you could safely ignore all dead ends when pathfinding, pausing only to consider nodes in a dead end area if the starting location or destination happen to be in the particular dead end area in question.</font> </li>
</ul>
<p><span style="FONT-STYLE: normal"><b><i><font face="Arial" size="2">7. Maintaining the Open List:</font></i></b></span> <font face="Arial" size="2"><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><b><span></span></b></span><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal">This is actually one of the most time consuming elements of the A* pathfinding algorithm. Every time you access the open list, you need to find the square that has the lowest F cost. There are several ways you could do this. You could save the path items as needed, and simply go through the whole list each time you need to find the lowest F cost square. This is simple, but really slow for long paths. This can be improved by maintaining a sorted list and simply grabbing the first item off the list every time you need the lowest F-cost square. When I wrote my program, this was the first method I used.</span></font><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"> <font face="Arial" size="2"><br /></font></span></p>
<p><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><font face="Arial" size="2">This will work reasonably well for small maps, but it isn&rsquo;t the fastest solution. Serious A* programmers who want real speed use something called a binary heap, and this is what I use in my code. In my experience, this approach will be at least 2-3 times as fast in most situations, and geometrically faster (10+ times as fast) on longer paths. If you are motivated to find out more about binary heaps, check out my article, <a href="http://www.policyalmanac.org/games/binaryHeaps.htm">Using Binary Heaps in A* Pathfinding</a>.<br /></font></span></p>
<span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"><span style="FONT-WEIGHT: normal; FONT-STYLE: normal; FONT-VARIANT: normal"></span></span>
<p><font face="Arial" size="2">Another possible bottleneck is the way you clear and maintain your data structures between pathfinding calls. I personally prefer to store everything in arrays. While nodes can be generated, recorded and maintained in a dynamic, object-oriented manner, I find that the amount of time needed to create and delete such objects adds an extra, unnecessary level of overhead that slows things down. If you use arrays, however, you will need to clean things up between calls. The last thing you will want to do in such cases is spend time zero-ing everything out after a pathfinding call, especially if you have a large map. <br /></font></p>
<p><font face="Arial" size="2">I avoid this overhead by creating a 2d array called whichList(x,y) that designates each node on my map as either on the open list or closed list. After pathfinding attempts, I do not zero out this array. Instead I reset the values of onClosedList and onOpenList in every pathfinding call, incrementing both by +5 or something similar on each path finding attempt. This way, the algorithm can safely ignore as garbage any data left over from previous pathfinding attempts.</font><font face="Arial" size="2"> I also store values like F, G and H costs in arrays. In this case, I simply write over any pre-existing values and don't bother clearing the arrays when I'm done.</font><font face="Arial" size="2"><br /></font></p>
<p><font face="Arial" size="2">Storing data in multiple arrays consumes more memory, though, so there is a trade off. Ultimately, you should use whatever method you are most comfortable with.<b><i><br /></i></b></font></p>
<p><font face="Arial" size="2"><b><i>8. Dijkstra's Algorithm: </i></b>While A* is generally considered to be the best pathfinding algorithm (see rant above), there is at least one other algorithm that has its uses - Dijkstra's algorithm. Dijkstra's is essentially the same as A*, except there is no heuristic (H is always 0). Because it has no heuristic, it searches by expanding out equally in every direction. As you might imagine, because of this Dijkstra's usually ends up exploring a much larger area before the target is found. This generally makes it slower than A*. <br /></font></p>
<p><font face="Arial" size="2">So why use it? Sometimes we don't know where our target destination is. Say you have a resource-gathering unit that needs to go get some resources of some kind. It may know where several resource areas are, but it wants to go to the closest one. Here, Dijkstra's is better than A* because we don't know which one is closest. Our only alternative is to repeatedly use A* to find the distance to each one, and then choose that path. There are probably countless similar situations where we know the kind of location we might be searching for, want to find the closest one, but not know where it is or which one might be closest.</font></p>
<font face="Arial" size="2"></font>
<p><font face="Arial" size="2"><b><font face="Arial" size="2">Further Reading</font></b></font></p>
<p><font face="Arial" size="2"><a name="code">Okay</a>, now you have the basics and a sense of some of the advanced concepts. At this point, I&rsquo;d suggest wading into my source code. The package contains two versions, one in C++ and one in Blitz Basic. Both versions are heavily commented and should be fairly easy to follow, relatively speaking.&nbsp; Here is the link.</font></p>
<ul><font face="Arial" size="2">
    <li><a href="http://www.policyalmanac.org/games/AStar.zip">Sample Code: A* Pathfinder (2D) Version 1.9</a> </li>
    </font></ul>
    <p><font face="Arial" size="2">If you do not have access to C++ or Blitz Basic, two small exe files can be found in the C++ version. The Blitz Basic version can be run by downloading the free demo version of Blitz Basic 3D (not Blitz Plus) at the <a href="http://www.blitzbasic.com/">Blitz Basic</a> web site.</font></p>
    <p><font face="Arial" size="2"><font face="Arial" size="2">You should also consider reading through the following web pages. They should be much easier to understand now that you have read this tutorial.</font></font></p>
    <ul><font face="Arial" size="2">
        <li><a href="http://www-cs-students.stanford.edu/~amitp/gameprog.html#Paths"><font face="Arial" size="2">Amit&rsquo;s A* Pages</font></a><font face="Arial" size="2">: This is a very widely referenced page by Amit Patel, but it can be a bit confusing if you haven&rsquo;t read this article first. Well worth checking out. See especially Amit's own <a href="http://theory.stanford.edu/~amitp/GameProgramming/">thoughts</a> on the topic.</font> </li>
        <li><a href="http://www.gamasutra.com/features/19970801/pathfinding.htm"><font face="Arial" size="2">Smart Moves: Intelligent Path Finding</font></a><font face="Arial" size="2">: This article by Bryan Stout at Gamasutra.com requires registration to read. The registration is free and well worth it just to reach this article, much less the other resources that are available there. The program written in Delphi by Bryan helped me learn A*, and it is the inspiration behind my A* program. It also describes some alternatives to A*.</font> </li>
        <li><font face="Arial" size="2"><font face="Arial" size="2"><a href="http://www.gamasutra.com/features/gdcarchive/2000/pottinger.doc">Terrain Analysis</a>: This is an advanced, but interesting, article by Dave Pottinger, a professional at Ensemble Studios. This guy coordinated the development of Age of Empires and Age of Kings. Don&rsquo;t expect to understand everything here, but it is an interesting article that might give you some ideas of your own. It includes some discussion of mip-mapping, influence mapping, and some other advanced AI/pathfinding concepts.</font><font face="Arial" size="2"></font> </font><font face="Arial" size="2"></font></li>
        </font></ul>
        <p><font face="Arial" size="2"><font face="Arial" size="2">Some other sites worth checking out:</font></font></p>
        <ul><font face="Arial" size="2">
            <li><font face="Arial" size="2"><a href="http://www.aiguru.com/pathfinding.htm">aiGuru: Pathfinding</a></font> </li>
            <li><font face="Arial" size="2"><a href="http://www.gameai.com/pathfinding.html">Game AI Resource: Pathfinding</a></font> </li>
            <li><font face="Arial" size="2"><a href="http://www.gamedev.net/reference/list.asp?categoryid=18#94">GameDev.net: Pathfinding</a></font> </li>
            </font></ul>
            <p><font face="Arial" size="2">I also <u>highly</u> recommend the following books, which have a bunch of articles on pathfinding and other AI topics. They also have CDs with sample code. I own them both.&nbsp;Plus, if you buy them from Amazon through these links, I'll get a few pennies from Amazon. :)</font></p>
            <p><iframe marginwidth="0" marginheight="0" src="http://rcm.amazon.com/e/cm?t=almanacofpoli-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=1584500778&amp;fc1=000000&amp;lc1=0000ff&amp;bc1=&amp;lt1=_blank&amp;IS2=1&amp;bg1=ffffff&amp;f=ifr" frameborder="0" width="120" scrolling="no" height="240"></iframe><iframe marginwidth="0" marginheight="0" src="http://rcm.amazon.com/e/cm?t=almanacofpoli-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=1584502894&amp;fc1=000000&amp;IS2=1&amp;lc1=0000ff&amp;bg1=ffffff&amp;bc1=&amp;lt1=_blank&amp;f=ifr" frameborder="0" width="120" scrolling="no" height="240"></iframe></p>
            <p><font face="Arial" size="2">Well, that&rsquo;s it. If you happen to write a program that uses any of these concepts, I&rsquo;d love to see it. I can be reached at&nbsp; </font></p>
            <p><font face="Arial" size="2"><img height="26" alt="" src="http://www.policyalmanac.org/graphics/mail2.jpg" width="211" border="0" /> </font></p>
            <p><font face="Arial" size="2">Until then, good luck! </font></p>]]></description>
		</item>
		
			<item>
			<link>http://loja.cn/blog/article/technique/180.htm</link>
			<title><![CDATA[联想F40老用户免费升级VISTA BIOS]]></title>
			<author>loja@tom.com(LOJA)</author>
			<category><![CDATA[Technique]]></category>
			<pubDate>Fri,25 May 2007 20:38:27 +0800</pubDate>
			<guid>http://loja.cn/blog/default.asp?id=180</guid>
		<description><![CDATA[联想F40 VISTA BIOS正式发布，从此大家不要为了激活正版Vista而手足无措了。所有老F40/F40A用户可以进入DOS升级BIOS到2.01版，然后安装Lenovo OEM Windows Vista (X Edition)即可激活，免费使用正版Vista。<br/>我已经安装并成功激活了Lenovo Windows Vista Ultimate Edition！<br/><br/><img src="http://loja.cn/blog/attachments/month_0705/k2007525201045.png" border="0" alt=""/><br/><br/><br/><span style="color:Blue">【升级BIOS详细步骤】</span><br/>1.下载纯dos程序和升级BIOS程序。（如果有DOS操作系统或系统启动盘请直接看第3步）<br/><img src="http://loja.cn/blog/images/download.gif" alt="下载文件" style="margin:0px 2px -4px 0px"/> <a href="http://loja.cn/blog/attachments/month_0705/t200752520362.rar" target="_blank">点击下载纯DOS镜像文件</a><br/><img src="http://loja.cn/blog/images/download.gif" alt="下载文件" style="margin:0px 2px -4px 0px"/> <a href="http://loja.cn/blog/attachments/month_0705/i2007525203716.rar" target="_blank">点击下载F40 BIOS升级文件</a><br/>2.刻录dos镜像光盘。<br/>3.将bios程序和marker程序(这两个文件夹里的程序文件)同放到fat32盘根目录(如果新建文件夹应该也可以,保险起见我放在根目录了)。<br/>4.设置CD－ROM优先启动，放入纯dos光盘，重起电脑，进入dos。<br/>5.找到fat32盘，可以看见刷bios程序。比如文件在c盘，则输入&#34;c:&#34;回车。<br/>6.运行bios的bat文件，等待....ok....运行SETMARKER...(这里在dos下显示不了长名字,可以改名字或运行显示的setm*~1名字)，提示写入spl2成功...ok。<br/>7.重起电脑，用everest看看吧～应该是恭喜你的时候了。<br/>8.如果运行出错，可以重启后重试。<br/><br/><span style="color:Red">●注：<br/>1.联想天逸f40和f40A都通用，不过必须是940以上的芯片组才可以，早期的915不可以,940,943,945都可以。可以将BIOS版本由1.xx升到2.01。<br/>2.必须在纯DOS下运行，并把相关升级文件放到文件系统为FAT32的磁盘中。<br/>3.如果你没有一定的电脑基础，最好不要自己升级。<br/>4.升级中一定要装上电池，并确保途中不要进行电源切换。<br/>5.本站对由于你操作错误，或其他不可抗力的原因导致BIOS损坏或其不良后果不负责任。</span><br/><br/><span style="color:Blue">【安装Windows vista ultimate】</span><br/>●先到这里下载<br/>Lenovo Windows Vista Ultimate Edition Recovery DVD (CHS) <br/><a href="http://tianyi.it168.com/thread-412680-1-1.html" target="_blank" rel="external">http://tianyi.it168.com/thread-412680-1-1.html</a><br/><br/>●下载完之后：<br/>第一，选中所有压缩包，点击右键选择“解压到当前文件夹”。所有的压缩包解压以后是：<br/>LENOVO_VISTA_CHS_RDVD_UM.ISO<br/>MD5:b23a4481075a76dd5632255af1064b4e<br/><br/>第二，刻DVD盘。重启电脑，用光盘启动安装。<br/><span style="color:Red">必须从光盘启动安装，否则没有OEM信息。<br/>特别强调，不要从虚拟光驱加载安装。</span><br/><br/>第三，应该恭喜你也能看到上面的图片！～～]]></description>
		</item>
		
			<item>
			<link>http://loja.cn/blog/article/technique/150.htm</link>
			<title><![CDATA[批处理文件]]></title>
			<author>loja@tom.com(LOJA)</author>
			<category><![CDATA[Technique]]></category>
			<pubDate>Wed,01 Nov 2006 19:22:53 +0800</pubDate>
			<guid>http://loja.cn/blog/default.asp?id=150</guid>
		<description><![CDATA[后缀是bat的文件就是批处理文件，是一种文本文件。简单的说，它的作用就是自动的连续执行多条命令，批处理文件的内容就是一条一条的命令。那它有什么用呢？ <br/><br/>比如，在启动wps软件时，每次都必须执行 <br/><br/>C:\&gt;cd wps <br/>C:\WPS&gt;spdos <br/>C:\WPS&gt;py <br/>C:\WPS&gt;wbx <br/>C:\WPS&gt;wps <br/><br/>如果每次用WPS之前都这样执行一次，您是不是觉得很麻烦呢？ <br/><br/>如果有一个方法，只需编写一个批处理文件，就会自动执行刚才的所有命令，您想不想学呢？ <br/><br/>当您看完此节，自己编写的第一个批处理文件顺利执行时，您一定会大吃一惊的。 <br/><br/>此外电脑每次启动时都会寻找autoexec.bat这条批处理文件，从而可执行一些每次开机都要执行的命令，如设置路径path、加载鼠标驱动mouse、磁盘加速smartdrv等，可以使您的电脑真正自动化。 <br/><br/>echo、@、call、pause、rem 是批处理文件最常用的几个命令，我们就从他们开始学起。 echo 表示显示此命令后的字符 <br/>echo off 表示在此语句后所有运行的命令都不显示命令行本身 <br/>@ 与echo off相象，但它是加在其它命令行的最前面，表示运行时不显示命令行本身。 <br/>call 调用另一条批处理文件（如果直接调用别的批处理文件 ，执行完那条文件后将无法执行当前文件后续命令） <br/>pause 运行此句会暂停，显示Press any key to continue... 等待用户按任意键后继续 <br/>rem 表示此命令后的字符为解释行，不执行，只是给自己今后查找用的 <br/><br/><br/>例：用edit编辑a.bat文件，输入下列内容后存盘为c:\a.bat，执行该批处理文件后可实现：将根目录中所有文件写入 a.txt中，启动UCDOS，进入WPS等功能。 <br/><br/>批处理文件的内容为: 文件表示： <br/><br/>echo off 不显示命令行 <br/><br/>dir c:\*.* &gt;a.txt 将c盘文件列表写入a.txt <br/><br/>call c:\ucdos\ucdos.bat 调用ucdos <br/><br/>echo 你好 显示&#34;你好&#34; <br/><br/>pause 暂停,等待按键继续 <br/><br/>rem 使用wps 注释将使用wps <br/><br/>cd ucdos 进入ucdos目录 <br/><br/>wps 使用wps <br/><br/>批处理文件中还可以像C语言一样使用参数，这只需用到一个参数表示符%。 <br/><br/>%表示参数，参数是指在运行批处理文件时在文件名后加的字符串。变量可以从 %0到%9，%0表示文件名本身，字符串用%1到%9顺序表示。 <br/><br/>例如，C：根目录下一批处理文件名为f.bat，内容为 format %1 <br/><br/>则如果执行C:\&gt;f a: 则实际执行的是format a: <br/><br/>又如C：根目录下一批处理文件的名为t.bat，内容为 type %1 type %2 <br/><br/>那么运行C:\&gt;t a.txt b.txt 将顺序地显示a.txt和b.txt文件的内容 <br/><br/>if goto choice for 是批处理文件中比较高级的命令，如果这几个你用得很熟练，你就是批处理文件的专家啦。 <br/><br/>if 表示将判断是否符合规定的条件，从而决定执行不同的命令。 有三种格式: <br/>1、if &#34;参数&#34; == &#34;字符串&#34; 待执行的命令 <br/>参数如果等于指定的字符串，则条件成立，运行命令，否则运行下一句。(注意是两个等号） <br/>如if &#34;%1&#34;==&#34;a&#34; format a: <br/><br/>2、if exist 文件名 待执行的命令 <br/>如果有指定的文件，则条件成立，运行命令，否则运行下一句。如if exist config.sys edit config.sys <br/><br/>3、if errorlevel 数字 待执行的命令 <br/>如果返回码等于指定的数字，则条件成立，运行命令，否则运行下一句。如if errorlevel 2 goto x2 DOS程序运行时都会返回一个数字给DOS，称为错误码errorlevel或称返回码 <br/><br/>goto 批处理文件运行到这里将跳到goto 所指定的标号处， 一般与if配合使用。 如: <br/><br/>goto end <br/><br/>:end <br/>echo this is the end <br/><br/>标号用 :字符串 表示，标号所在行不被执行 <br/><br/>choice 使用此命令可以让用户输入一个字符，从而运行不同的命令。使用时应该加/c:参数，c:后应写提示可输入的字符，之间无空格。它的返回码为1234…… <br/><br/>如: choice /c:dme defrag,mem,end <br/>将显示 <br/>defrag,mem,end[D,M,E]? <br/><br/>例如，test.bat的内容如下: <br/>@echo off <br/>choice /c:dme defrag,mem,end <br/>if errorlevel 3 goto defrag 应先判断数值最高的错误码 <br/>if errorlevel 2 goto mem <br/>if errotlevel 1 goto end <br/><br/>:defrag <br/>c:\dos\defrag <br/>goto end <br/><br/>:mem <br/>mem <br/>goto end <br/><br/>:end <br/>echo good bye <br/><br/>此文件运行后，将显示 defrag,mem,end[D,M,E]? 用户可选择d m e ，然后if语句将作出判断，d表示执行标号为defrag的程序段，m表示执行标号为mem的程序段，e表示执行标号为end的程序段，每个程序段最后都以goto end将程序跳到end标号处，然后程序将显示good bye，文件结束。 <br/><br/>for 循环命令，只要条件符合，它将多次执行同一命令。 <br/><br/>格式FOR [%%f] in (集合) DO [命令] <br/>只要参数f在指定的集合内，则条件成立，执行命令 <br/><br/>如果一条批处理文件中有一行: <br/>for %%c in (*.bat *.txt) do type %%c <br/>含义是如果是以bat或txt结尾的文件，则显示文件的内容。 <br/><br/>autoexec.bat <br/><br/>DOS在启动会自动运行autoexec.bat这条文件，一般我们在里面装载每次必用的程序，如: path(设置路径)、smartdrv(磁盘加速)、 mouse(鼠标启动)、mscdex(光驱连接)、 doskey(键盘管理)、set(设置环境变量)等。 <br/><br/>如果启动盘根目录中没有这个文件，电脑会让用户输入日期和时间。 <br/><br/>例如，一个典型的autoexec.bat内容如下: <br/><br/>@echo off 不显示命令行 <br/><br/>prompt $p$g 设置提示符前有目录提示 <br/><br/>path c:\dos;c:\;c:\windows;c:\ucdos;c:\tools 设置路径 <br/><br/>lh c:\dos\doskey.com 加载键盘管理 <br/><br/>lh c:\mouse\mouse.com 加载鼠标管理 <br/><br/>lh c:\dos\smartdrv.exe 加载磁盘加速管理 <br/><br/>lh c:\dos\mscdex /S /D:MSCD000 /M:12 /V 加载CD-ROM驱动 <br/><br/>set temp=c:\temp 设置临时目录<br/><br/>－－－－－－－－－－－<br/>下面收录一个用bat文件做的Windows下的垃圾清理文件<br/><div class="UBBPanel codePanel"><div class="UBBTitle"><img src="http://loja.cn/blog/images/code.gif" style="margin:0px 2px -3px 0px" alt="程序代码"/> 程序代码</div><div class="UBBContent"><br/>@echo off<br/>echo 正在清除系统垃圾文件，请稍后......<br/>del /f /s /q %systemdrive%\*.tmp<br/>del /f /s /q %systemdrive%\*._mp<br/>del /f /s /q %systemdrive%\*.log<br/>del /f /s /q %systemdrive%\*.gid<br/>del /f /s /q %systemdrive%\*.chk<br/>del /f /s /q %systemdrive%\*.old<br/>del /f /s /q %systemdrive%\recycled\*.*<br/>del /f /s /q %windir%\*.bak<br/>del /f /s /q %windir%\prefetch\*.*<br/>rd /s /q % windir%\temp &amp; md %windir%\temp<br/>del /f /q %userprofile%\cookies\*.*<br/>del /f /q %userprofile%\recent\*.*<br/>del /f /s /q &#34;%userprofile%\Local Settings\Temporary Internet Files\*.*&#34;<br/>del /f /s /q &#34;%userprofile%\Local Settings\Temp\*.*&#34;<br/>del /f /s /q &#34;%userprofile%\recent\*.*&#34;<br/>echo 清除系统垃圾完成！<a href="http://mail.loja.cn/" target="_blank">LOJA</a> Studio<br/>Echo &amp; pause &lt;--谢谢使用--&gt;<br/></div></div><br/>复制代码到《记事本》，另存为*.bat文件，双击执行即可。]]></description>
		</item>
		
			<item>
			<link>http://loja.cn/blog/article/technique/149.htm</link>
			<title><![CDATA[ASP、JSP与PHP的比较]]></title>
			<author>loja@tom.com(LOJA)</author>
			<category><![CDATA[Technique]]></category>
			<pubDate>Wed,01 Nov 2006 19:18:11 +0800</pubDate>
			<guid>http://loja.cn/blog/default.asp?id=149</guid>
		<description><![CDATA[目前，最常用的三种动态网页语言有ASP(Active Server Pages),JSP(Java Server Pages),<br/>PHP (Hypertext Preprocessor)。 <br/><br/>简 介 <br/><br/>　　ASP全名Active Server Pages，是一个WEB服务器端的开发环境， 利用它可以产生和运<br/>行动态的、交互的、高性能的WEB服务应用程序。ASP采用脚本语言VB Script（Java script<br/>）作为自己的开发语言。 <br/><br/>　　PHP是一种跨平台的服务器端的嵌入式脚本语言. 它大量地借用C,Java和Perl语言的语法<br/>, 并耦合PHP自己的特性,使WEB开发者能够快速地写出动态生成页面.它支持目前绝大多数数<br/>据库。还有一点，PHP是完全免费的，不用花钱，你可以从PHP官方站点(<a href="http://www.php.ne" target="_blank" rel="external">http://www.php.ne</a><br/>t)自由下载。而且你可以不受限制地获得源码，甚至可以从中加进你自己需要的特色。 <br/><br/>　　JSP 是Sun公司推出的新一代站点开发语言，他完全解决了目前ASP,PHP的一个通病－－<br/>脚本级执行（据说PHP4 也已经在Zend 的支持下，实现编译运行）.Sun 公司借助自己在Jav<br/>a 上的不凡造诣，将Java 从Java 应用程序 和 Java Applet 之外，又有新的硕果，就是Js<br/>p－－Java Server Page。Jsp 可以在Serverlet和JavaBean的支持下，完成功能强大的站点<br/>程序。 <br/><br/>　　三者都提供在 HTML 代码中混合某种程序代码、由语言引擎解释执行程序代码的能力。<br/>但JSP代码被编译成 Servlet 并由 Java 虚拟机解释执行，这种编译操作仅在对 JSP 页面的<br/>第一次请求时发生。在 ASP 、PHP、JSP 环境下， HTML 代码主要负责描述信息的显示样式<br/>，而程序代码则用来描述处理逻辑。普通的 HTML 页面只依赖于 Web 服务器，而 ASP 、PH<br/>P、JSP 页面需要附加的语言引擎分析和执行程序代码。程序代码的执行结果被重新嵌入到 <br/>HTML 代码中，然后一起发送给浏览器。 ASP 、PHP、 JSP三者都是面向 Web 服务器的技术<br/>，客户端浏览器不需要任何附加的软件支持。 <br/><br/>技术特点 <br/><br/>ASP: <br/><br/>1. 使用 VBScript 、 JScript 等简单易懂的脚本语言，结合 HTML 代码，即可快速地完成<br/>网站的应用程序。 <br/>2. 无须 compile 编译，容易编写，可在服务器端直接执行。 <br/>3. 使用普通的文本编辑器，如 Windows 的记事本，即可进行编辑设计。 <br/>4. 与浏览器无关 (Browser Independence), 用户端只要使用可执行 HTML 码的浏览器，即<br/>可浏览 Active Server Pages 所设计的网页内容。 Active Server Pages 所使用的脚本语<br/>言 (VBScript 、 Jscript) 均在 WEB 服务器端执行，用户端的浏览器不需要能够执行这些<br/>脚本语言。 <br/>5.Active Server Pages 能与任何 ActiveX scripting 语言相容。除了可使用 VBScript <br/>或 JScript 语言来设计外，还通过 plug－in 的方式，使用由第三方所提供的其他脚本语言<br/>，譬如 REXX 、 Perl 、 Tcl 等。脚本引擎是处理脚本程序的 COM(Component Object Mod<br/>el) 物件。 <br/>6. 可使用服务器端的脚本来产生客户端的脚本。 <br/>　7.ActiveX Server Components(ActiveX 服务器元件 ) 具有无限可扩充性。可以使用 Vi<br/>sual Basic 、 Java 、 Visual C＋＋ 、 COBOL 等编程语言来编写你所需要的ActiveX Se<br/>rver Component 。 <br/><br/>PHP: <br/><br/>1．数据库连接 <br/>　　PHP可以编译成具有与许多数据库相连接的函数。PHP与MySQL是现在绝佳的组合。你还可<br/>以自己编写外围的函数取间接存取数据库。通过这样的途径当你更换使用的数据库时，可以<br/>轻松地更改编码以适应这样的变。PHPLIB就是最常用的可以提供一般事务需要的一系列基库<br/>。但PHP提供的数据库接口支持彼此不统一，比如对Oracle,　 MySQL， Sybase的接口，彼此<br/>都不一样。这也是PHP的一个弱点。 <br/>2．面向对象编程 <br/>　　PHP提供了类和对象。基于web的编程工作非常需要面向对象编程能力。PHP支持构造器、<br/>提取类等。 <br/><br/>JSP: <br/><br/>1．将内容的生成和显示进行分离 <br/>　　使用JSP技术，Web页面开发人员可以使用HTML或者XML标识来设计和格式化最终页面。使<br/>用JSP标识或者小脚本来生成页面上的动态内容。生成内容的逻辑被封装在标识和JavaBeans<br/>组件中，并且捆绑在小脚本中，所有的脚本在服务器端运行。如果核心逻辑被封装在标识和<br/>Beans中，那么其他人，如Web管理人员和页面设计者，能够编辑和使用JSP页面，而不影响内<br/>容的生成。 <br/>　　在服务器端，JSP引擎解释JSP标识和小脚本，生成所请求的内容（例如，通过访问Java<br/>Beans组件，使用JDBCTM技术访问数据库，或者包含文件），并且将结果以HTML（或者XML）<br/>页面的形式发送回浏览器。这有助于作者保护自己的代码，而又保证任何基于HTML的Web浏览<br/>器的完全可用性。 <br/>2．强调可重用的组件 <br/>　　绝大多数JSP页面依赖于可重用的，跨平台的组件（JavaBeans或者Enterprise JavaBea<br/>nsTM组件）来执行应用程序所要求的更为复杂的处理。开发人员能够共享和交换执行普通操<br/>作的组件，或者使得这些组件为更多的使用者或者客户团体所使用。基于组件的方法加速了<br/>总体开发过程，并且使得各种组织在他们现有的技能和优化结果的开发努力中得到平衡。 <br/>3．采用标识简化页面开发 <br/>　　Web页面开发人员不会都是熟悉脚本语言的编程人员。JavaServer Page技术封装了许多<br/>功能，这些功能是在易用的、与JSP相关的XML标识中进行动态内容生成所需要的。标准的JS<br/>P标识能够访问和实例化JavaBeans组件，设置或者检索组件属性，下载Applet，以及执行用<br/>其他方法更难于编码和耗时的功能。 <br/>　　通过开发定制化标识库，JSP技术是可以扩展的。今后，第三方开发人员和其他人员可以<br/>为常用功能创建自己的标识库。这使得Web页面开发人员能够使用熟悉的工具和如同标识一样<br/>的执行特定功能的构件来工作。 <br/>　　JSP技术很容易整合到多种应用体系结构中，以利用现存的工具和技巧，并且扩展到能够<br/>支持企业级的分布式应用。作为采用Java技术家族的一部分，以及Java 2（企业版体系结构<br/>）的一个组成部分，JSP技术能够支持高度复杂的基于Web的应用。 <br/>　　由于JSP页面的内置脚本语言是基于Java编程语言的，而且所有的JSP页面都被编译成为<br/>Java Servlet，JSP页面就具有Java技术的所有好处，包括健壮的存储管理和安全性。 <br/>　　作为Java平台的一部分，JSP拥有Java编程语言“一次编写，各处运行”的特点。随着越<br/>来越多的供应商将JSP支持添加到他们的产品中，您可以使用自己所选择的服务器和工具，更<br/>改工具或服务器并不影响当前的应用。 <br/><br/>应用范围 <br/><br/>&nbsp;&nbsp;ASP是Microsoft开发的动态网页语言，也继承了微软产品的一贯传统——只能运行于微软<br/>的服务器产品,IIS (Internet Information Server) (windows NT)和PWS(Personal Web Se<br/>rver)(windows 98)上。Unix下也有ChiliSoft的插件来支持ASP，但是ASP本身的功能有限，<br/>必须通过ASP＋COM的组合来扩充，Unix下的COM实现起来非常困难。 <br/><br/>&nbsp;&nbsp;PHP3可在Windows,Unix,Linux的Web服务器上正常运行,还支持IIS,Apache等通用Web服务器<br/>,用户更换平台时,无需变换PHP3代码,可即拿即用. <br/><br/>　　JSP同PHP3类似，几乎可以运行于所有平台。如Win NT,Linux,Unix. NT下IIS通过一个插<br/>件，例如JRUN或者ServletExec，就能支持JSP。著名的Web服务器Apache已经能够支持JSP。<br/>由于Apache广泛应用在NT、Unix和Linux上，因此JSP有更广泛的运行平台。虽然现在NT操作<br/>系统占了很大的市场份额，但是在服务器方面Unix的优势仍然很大，而新崛起的Linux更是来<br/>势不小。从一个平台移植到另外一个平台，JSP和JavaBean甚至不用重新编译，因为Java字节<br/>码都是标准的与平台无关的。 <br/><br/>性能比较 <br/><br/>　　有人做过试验，对这三种语言分别做循环性能测试及存取Oracle数据库测试。 <br/><br/>　　在循环性能测试中，JSP只用了令人吃惊的四秒钟就结束了20000＊20000的循环。而ASP<br/>、PHP测试的是2000＊2000循环（少一个数量级），却分别用了63秒和84秒。（参考PHPLIB）<br/>。 <br/><br/>　　数据库测试中，三者分别对 o&#114;acle 8 进行 1000 次 Ins&#101;rt,Up&#100;ate,Sel&#101;ct,和Del&#101;te<br/>： Jsp 需要 13 秒，Php 需要 69 秒，ASP则 需要 73 秒。 <br/><br/>前景分析 <br/><br/>&nbsp;&nbsp;目前在国内PHP与ASP应用最为广泛。而JSP由于是一种较新的技术，国内采用的较少。但在<br/>国外，JSP已经是比较流行的一种技术，尤其是电子商务类的网站，多采用JSP。 <br/>　　采用PHP的网站如新浪网（sina）、中国人（Chinaren）等,但由于PHP本身存在的一些缺<br/>点，使得它不适合应用于大型电子商务站点，而更适合一些小型的商业站点。 <br/>　　首先，PHP缺乏规模支持。其次，缺乏多层结构支持。对于大负荷站点，解决方法只有一<br/>个：分布计算。数据库、应用逻辑层、表示逻辑层彼此分开，而且同层也可以根据流量分开<br/>，组成二维阵列。而PHP则缺乏这种支持。还有上面提到过的一点，PHP提供的数据库接口支<br/>持不统一，这就使得它不适合运用在电子商务中。 <br/>　　ASP和JSP则没有以上缺陷，ASP可以通过Microsoft Windowsd的COM/DCOM获得ActiveX规<br/>模支持，通过DCOM和Transcation Server获得结构支持；JSP可以通过SUN Java的Java Clas<br/>s和EJB获得规模支持，通过EJB/CORBA以及众多厂商的Application Server获得结构支持。 <br/><br/>　　三者中，JSP应该是未来发展的趋势。世界上一些大的电子商务解决方案提供商都采用J<br/>SP/Servlet。比较出名的如IBM的E－business，它的核心是采用JSP/Servlet的WebSphere；<br/>西方另外一个非常著名的电子商务软件提供商，Intershop。它原来的产品Intershop1 2, 3<br/>, 4占据了主要的电子商务软件份额。它们都是通过CGI来提供支持 的。但去年10月后它推出<br/>了Enfinity，一个采用JSP/Servlet的电子商务Application Server，而且声言不再开发传统<br/>软件。 <br/><br/>总之 <br/>　　ASP，PHP,JSP三者都有相当数量的支持者，由此也可以看出三者各有所长。正在学习或<br/>使用动态页面的朋友可根据三者的特点选择一种适合自己的语言。 <br/>]]></description>
		</item>
		
			<item>
			<link>http://loja.cn/blog/article/technique/148.htm</link>
			<title><![CDATA[什么是GNU？]]></title>
			<author>loja@tom.com(LOJA)</author>
			<category><![CDATA[Technique]]></category>
			<pubDate>Wed,01 Nov 2006 18:42:17 +0800</pubDate>
			<guid>http://loja.cn/blog/default.asp?id=148</guid>
		<description><![CDATA[GNU是一个自由软件工程项目。 <br/>GNU工程已经开发了一个被称为“GNU”（GNU是“不是UNIX”的缩写）的、对Unix向上兼容的完整的自由软件系统(free software system)。由Richard Stallman完成的最初的GNU工程的文档被称为‘GNU宣言’，该宣言已经被翻译成多种其它语言。我们还有创作与1983年的GNU工程创始宣言。 <br/>上述单词“free”指的是自由（freedom），而不是价格。你可能需要或者不需要为获取GNU软件而支付费用。不论是否免费，一旦你得到了软件，你在使用中就拥有三种特定的自由。首先是复制程序并且把它送给你的朋友或者同事的自由；而后是通过获取完整的源代码，按照你的意愿修改程序的自由；最后是发布软件的改进版并且有助于创建自由软件社团的自由。（如果你重新发布 GNU软件，你可能对分发拷贝这项体力劳动收费，也可能不收费。） <br/><br/>在1983年构思GNU工程是为了提供一种找回在计算机界早期的盛行的合作精神的方式--为了使合作成为可能而排除有私有软件所有者给合作造成的障碍。 <br/><br/>在1971年，当Richard Stallman开始他在MIT的职业生涯时，他工作于一个专门使用自由软件的工作组。即使计算机公司也经常发布自由软件。程序员可以自由地相互合作，就象他们通常所作的那样。 <br/><br/>到了80年代，几乎所有的软件都是私有的，这意味着它有一个不允许并且预防用户合作的拥有者。这就使得GNU工程成为必要的了。 <br/><br/>每个计算机的使用者都需要一个操作系统；如果没有自由的操作系统，那么如果你不求助于私有软件，你甚至不能开始使用一台计算机。所以自由软件议事日程的第一项就是自由的操作系统。 <br/><br/>一个操作系统不仅仅是一个内核；它还包括编译器、编辑器、文本排版程序，电子邮件软件，和许多其他东西。因此，创作一个完整的操作系统是一乡十分庞大的工作。它将耗费太多的年头。 <br/><br/>由于Unix的全局设计已经得到认证并且广泛流传，我们决定使操作系统与Unix兼容。同时这种兼容性使Unix的使用者可以容易地转移到GNU上来。 <br/><br/>自由的，类似于Unix的内核的初始目标已经达到了。到90年代，我们已经发现或者完成了除了内核之外的所有主要成分。而Linux，一个自由的内核，由Linux Torvalds开发了。把Linux和几乎完成的GNU 系统结合起来，就构成了一个完整的操作系统：一个基于Linux的GNU系统。估计目前大约有十万人在使用基于Linux的GNU系统，包括Slackware、Debian、Red Hat以及其它。 <br/><br/>然而，GNU工程并不限于操作系统。我们的目标是提供所有类型的软件，无论有多少用户需要它。这包括了应用软件。我们已经有了电子表格。我们希望在未来把GNU Emacs扩展为所见即所得的桌面出版系统。 <br/><br/>我们还想为不是计算机专家的用户提供软件。为此我们正在创作‘拖放图标桌面’以帮助初学者使用 GNU系统。 <br/><br/>我们还希望提供游戏和其它娱乐。已经由一些游戏可以使用了。 <br/><br/>自由软件可以走多远？这没有限制，除非诸如版权法之类的法律完全地禁止自由软件。最终的目的是，让自由软件完成计算机用户希望完成的所有工作--从而导致自由软件的过时。]]></description>
		</item>
		
			<item>
			<link>http://loja.cn/blog/article/technique/140.htm</link>
			<title><![CDATA[请各位提点建议评测一下]]></title>
			<author>loja@tom.com(mamg)</author>
			<category><![CDATA[Technique]]></category>
			<pubDate>Wed,20 Sep 2006 21:16:09 +0800</pubDate>
			<guid>http://loja.cn/blog/default.asp?id=140</guid>
		<description><![CDATA[配件&#160;&#160;&#160;&#160;品型&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;报价<br/><br/>主板&#160;&#160;&#160;&#160;映泰 TForce 6100-AM2&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;640<br/>cpu&#160;&#160;&#160;&#160;AMD AM2 Athlon64 3000+ &#160;&#160;&#160;&#160;&nbsp;&nbsp;&nbsp;&nbsp; &#160;&#160;&#160;&#160;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;530<br/>内存&#160;&#160;&#160;&#160;威刚 万紫千红 DDRII667 512*2 &#160;&#160;&#160;&#160;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;320*2<br/>硬盘&#160;&#160;&#160;&#160;希捷 酷鱼7200.7 160G 8M(串口)&#160;&#160;&#160;&#160;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 515<br/>显示器&#160;&#160;&#160;&#160;明基 FP71G+&nbsp;&nbsp; 17&#39;&#160;&#160;&#160;&#160;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1399<br/>显卡&#160;&#160;&#160;&#160;板载&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0<br/>光驱&#160;&#160;&#160;&#160;金将军DVD-ROM黑金版&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#160;&#160;&#160;&#160;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;170<br/>机箱&#160;&#160;&#160;&#160;金河田 炫豪2031B&nbsp;&nbsp;320w&#160;&#160;&#160;&#160;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;325<br/>键鼠&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 50 <br/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4269<br/>]]></description>
		</item>
		
</channel>
</rss>
