Archive

Archive for October, 2007

真正的“AI”,是不是可以这样?

October 30th, 2007 Fwolf 3 comments

看到Cat ChenS.T.A.L.K.E.R中胡侃这个游戏的AI如何优秀,不禁产生了一种念头,一种新的AI实现思路。

AI就是人工智能,通俗一点说就是控制游戏中NPC如何行动的指令,简单的AI很容易公式化,比如反恐精英cs中的bot,基本上都是按照脚本的规定来行动,更复杂和高级的AI会加入思考、互动的因素,也就更“聪明”一些。

AI往高了说,属于计算机科学的尖端领域,但往简单了说,只不过是科学家设计好公式,利用计算机运算速度快的优势来模拟的思考过程罢了,高深也就高深在了公式/算法和了,计算机只是一个跑得比较快,会先飞的笨鸟罢了。但在很多时候,AI还无法达到普通人的程度,这也就是我的念头了,能否在游戏中,用玩家行为来作为AI,或者为AI提供数据呢?

假想一个游戏,分为两个阵营,拉据战的格局,苏、德双方展开坦克大战,攻夺据点。把游戏分为两个服务器,苏服和德服,苏服上的玩家都是苏军,敌人是AI,不过这个AI就是德服上扮演德军的玩家。这样,以往的NPC就不会再笨呼呼的了,而是“像”真实的玩家一样战斗,甚至血少的时候也会偷懒等等。

最关键的,就是要体现不同于单机游戏的,真实的模拟另一个服务器上玩家的行为模式,同时还要和玩家之间对战区分开来。比如坦克的配置是copy玩家数据,而作为AI的坦克被打爆了玩家可不会掉经验等等。能够把这两点都体现出来,现在的游戏好像还没有。

还想到一个更远一点的例子,在mmorpg中打怪的时候,怪物一般都形成规律了,在什么地方、有什么招数,怎么配置队伍就能打倒它,甚至捡到相同的宝贝。。。这样不腻么?为高级玩家开通变身为怪的功能吧。呼呼,别人组队再来打toj的时候,怎么怪物变了?以前都呆着不动的,今天满大街溜达,也不发招。。。如此这般,也等于是在这段时期内用人的智慧让npc更加完善了,如果聪明的玩家还会在变身为怪物的时候,模拟真实怪物的以为,诱骗其它玩家上钩的话就更加有趣了。

想法扯完了,写完再想实现起来还是有些难度的,不过算是一个思路吧,不要一味钻进如何完善npc自身“功能”的死胡同,引入玩家的隐式互动。关于那个苏德坦克大战的游戏,以前倒还真是玩过(直接玩家对抗的),不过好像网站上不去了,http://www.blitz1941.com/,我这里也仅存三张截图,还算有一定代表性,一起怀念一下吧:


Go to ImageShack® to Create your own Slideshow

Related posts

Categories: Game, Thinks Tags: , ,

将情感进销存的编码从gb2312改变为utf8

October 30th, 2007 Fwolf 2 comments

应一个朋友的需要,用免费开源的情感进销存给他开小店用,刚开始嘛,先试试看好用不。好像情感是国内仅存的免费、开源,又能用,还有人继续维护的进销存软件了,挺难得的。

情感进销存默认的编码全部都是gb2312的,从数据库到html,而我的环境自然是全utf8编码的ubuntu,如果是一次性转换的话,手工也是可以作的,但情感进销存如果出新版,还得从头改过,所以搞了个小脚本来自动转换:

#!/bin/bash

find . -name "*.txt" |xargs -I '{}' iconv_gb2u '{}'
find . -name "*.htm" |xargs -I '{}' iconv_gb2u '{}'
find . -name "*.php" |xargs -I '{}' iconv_gb2u '{}'
find . -name "*.sql" |xargs -I '{}' iconv_gb2u '{}'

#echo "Modify libs/mysql.class.php, change set names gbk to utf8."
# echo "Modify tpls/head.htm, head.emp.html, change http-equiv gbk to utf9"
replace "charset=gbk" "charset=utf8" -- install/*.php
replace "CHARSET=gbk" "charset=utf8" -- install/*.php
replace "SET NAMES 'gbk'" "SET NAMES 'utf8'" -- libs/mysql.class.php
replace "charset=gbk" "charset=utf8" -- tpls/*.htm

# For safe
chmod -x `basename $0`

其中用到的iconv_gb2u也是一个小脚本,作用是使用iconv命令把gb2312编码的文件转换为utf8,原生的iconv只能转换,不能回写同名文件,用这个脚本写到临时文件再拷回来覆盖。

再转回来说咱们的php程序的编码转换,首先要把所有的文件编码都转换了,包括txt类型的readme说明文件,htm类型的模板,php类型的程序,主要是为了看里面的注释,以及sql类型的数据库定义,里面还有初始化的数据,所以必须进行编码转换。这些转换用iconv就可以了,用find配合xargs一次性全部转换完毕。

接下来install/*.php中替换的是html页面的编码,以及执行安装sql创建数据表时指定表的默认编码;libs/mysql.class.php是连接数据库后指定客户端连接的字符集;tpls/*.htm则是替换html页面中的编码定义。这些用到了replace命令,replace可以把文件中的一个字符串替换为另外一个字符串,好像是mysql附带的实用小程序,在本例中够用了,再复杂一点的情况可以考虑使用sed,多行、正则替换都能够完成。

最后一句就简单了,如果对一个文件执行两次iconv,第一次把gb2312转成了utf8,可第二次就不知道转换成哪国编码了,所以为了避免程序被误运行两次,去掉可执行属性。

以后用起来就简单了,如果情感进销存再发布新版,先解压到一个临时文件夹,用这个脚本进行转换之后,再覆盖拷贝过来就可以了。

Related posts

Categories: Linux Tags:

磁带机的简单使用

October 24th, 2007 Fwolf No comments

环境:Ubuntu 7.04 feisty, HP DAT-72 usb外置磁带机。

基本概念

  • 磁带是线性存储设备,没有什么分区表的概念,磁头在哪里,就从哪里开始读。
  • 磁带机好像只能用root用户操作。
  • 磁带上可以划分存储空间,每个存储空间有一个file number,从0开始顺序排列。
  • 磁头在存储空间中的位置用block number来表示,0代表开始,大于0的整数代表块,比如39代表磁头在本file number的第39块的位置,而-1则代表磁头位于本file number的结尾。
  • 同样一部磁带机,用/dev/st0时是当自动回卷设备使用,每次操作完成之后,磁头都返回file number=0, block number=0, BOT的位置;而用/dev/nst0调用时,操作完成时磁头就停在那个位置,不会回到开头。
  • 使用nst非回卷方式,用tar tvf列文件,只有当block number=0时才能出内容,并且列完之后block number为大于0的整数,注意这并不代表本段存储空间的结尾(-1)。

由于磁带机本身具有压缩功能,所以添加文件的时候不建议指定zip或者bz2压缩,因为如果一点点压缩后的数据损坏,会导致全部内容不可识别;如果的确需要压缩的话,可以压缩成本地文件再存储到磁带上,减少对其他文件的影响。

自动回卷的使用方式

这种方式比较简单,用tar直接操作即可,基本上和tar操作本地文件相同。

往新磁带上存储文件,注意如果磁带上已有文件,会被覆盖掉:

tar cvf /dev/st0 file_to_store

向磁带上添加文件:

tar rvf /dev/st0 file_to_store

更新磁带上的同名文件:

tar uvf /dev/st0 file_to_store

列出磁带上的现有文件:

tar tvf /dev/st0

删除磁带上的文件:

tar vf /dev/st0 --delete file_to_delete

但我使用这个命令的时候总是提示错误,文件倒是删掉了,可查看的时候也总有错误信息,难道是无法删除,或者只能全部xvf出来再存到磁带上?不过我们也应当养成一个好的习惯,每次向磁带机存储文件的时候一定要在文件名中带上日期标记。

非自动回卷的使用方式

一般这样使用,都是用到多个存储空间file number的时候;如果还是一个存储段,只是手工移动文件指针就没有什么意义了。

在操作上,文件的存储方式和自动回卷是基本相同的,不同之处在于要注意磁头的位置,并且手工进行必要的位移,以一个新磁带的操作为例来说明(status我只截取有用的部分显示):

# mt -f /dev/nst0 status
file number = 0
block number = 0
General status bits on (41010000):
 BOT ONLINE IM_REP_EN

存入一个新的文件A:

# tar cvf /dev/nst0 A
A
# mt -f /dev/nst0 status
file number = 1
block number = 0
General status bits on (81010000):
 EOF ONLINE IM_REP_EN

注意这时磁头已经移动到了第二段存储空间了,现在再存入一个新的文件B,当然B和A是不在一个存储空间中的:

# tar cvf /dev/nst0 B
B
# mt -f /dev/nst0 status
file number = 2
block number = 0
General status bits on (81010000):
 EOF ONLINE IM_REP_EN

磁头又移动到第三段存储空间了,如果要查看刚才存的第二段存储空间中的内容,需要先移动磁头:

# mt -f /dev/nst0 bsf 2
# mt -f /dev/nst0 status
file number = 0
block number = -1
General status bits on (1010000):
 ONLINE IM_REP_EN

# mt -f /dev/nst0 fsf 1
# mt -f /dev/nst0 status
file number = 1
block number = 0
General status bits on (81010000):
 EOF ONLINE IM_REP_EN

由于有存储空间结束标记,所以这里采用退2进1的方式,详细的磁头移动方式可以看man mt。然后查看文件列表:

# tar tvf /dev/nst0
-rw-r--r-- root/root  21194792 2007-10-24 11:37 B
# mt -f /dev/nst0 status
file number = 1
block number = 2070
General status bits on (1010000):
 ONLINE IM_REP_EN

列出文件列表之后,磁头停在了文件结束的位置,但不是存储空间的结尾。现在移动磁头到本段存储空间的开始,并且添加文件C:

# mt -f /dev/nst0 bsf 1
# mt -f /dev/nst0 status
file number = 0
block number = -1
General status bits on (1010000):
 ONLINE IM_REP_EN

# mt -f /dev/nst0 fsf 1
# mt -f /dev/nst0 status
file number = 1
block number = 0
General status bits on (81010000):
 EOF ONLINE IM_REP_EN

# tar rvf /dev/nst0 C
C
# mt -f /dev/nst0 status
file number = 2
block number = 0
General status bits on (81010000):
 EOF ONLINE IM_REP_EN

首先还是要移动磁头,到这里基本上可以发现mt的fsf和bsf的规律了,fsf是磁头向前移动,并且总是停留在block number = 0的位置,而bsf是磁头向后移动,总是停留在 block number = -1的位置。添加完成文件之后,磁头又定位到了第三个存储空间(下一个)的开始。现在我们依然是移动磁头到第二段存储空间开始,并且用覆盖方式添加文件D:

# mt -f /dev/nst0 bsf 2
# mt -f /dev/nst0 fsf 1
# mt -f /dev/nst0 status
file number = 1
block number = 0
General status bits on (81010000):
 EOF ONLINE IM_REP_EN

# tar cvf /dev/nst0 D
D
# mt -f /dev/nst0 status
file number = 2
block number = 0
General status bits on (81010000):
 EOF ONLINE IM_REP_EN

文件D是用覆盖方式添加的,所以刚才添加的文件B和C现在应该都消失了:

# mt -f /dev/nst0 bsf 2
# mt -f /dev/nst0 fsf 1
# mt -f /dev/nst0 status
file number = 1
block number = 0
General status bits on (81010000):
 EOF ONLINE IM_REP_EN

# tar tvf /dev/nst0
-rw-r--r-- root/root  34201298 2007-10-24 11:57 D
# mt -f /dev/nst0 status
file number = 1
block number = 3341
General status bits on (1010000):
 ONLINE IM_REP_EN

完成,回卷磁带,从开始一直tvf:

# mt -f /dev/nst0 rewind
# tar tvf /dev/nst0
-rw-r--r-- root/root    341054 2007-10-24 11:37 A

# tar tvf /dev/nst0
# tar tvf /dev/nst0
-rw-r--r-- root/root  34201298 2007-10-24 11:57 D

# tar tvf /dev/nst0
# tar tvf /dev/nst0

# tar tvf /dev/nst0
tar: /dev/nst0: Cannot read: Input/output error
tar: At beginning of tape, quitting now
tar: Error is not recoverable: exiting now

# mt -f /dev/nst0 status
file number = 2
block number = -1
General status bits on (9010000):
 EOD ONLINE IM_REP_EN

现在,能看懂这个了么?我用空行隔开的位置正好是block number为0的位置。还有一些其他的操作就比较简单了:

出带,将磁带卷至初始位置然后从磁带机内弹出
# mt –f /dev/nst0 offline

清除磁带中的所有内容,特慢,还伤带,轻易不要用
# mt –f /dev/nst0 erase

我的几个疑问

  • 如何删除file number?
  • 既然磁带是线性存储,如果向前面一个file number中添加文件,存储空间不够怎么办?

小结

搞明白磁带机的存储方式和基本操作,用起来就简单了。个人感觉如果要存的文件数量不多,尤其是只需要存几个大文件的情况,直接用自动回卷方式,只使用一个存储空间就可以了,这样操作比较简单。如果一定要用磁带存储复杂结构的数据,可以考虑手工在各个存储空间之间来回切换的方式,原理都是一样,只是更高一点点的技巧和小心。

同时,保存一份磁带上现有文件的索引也是非常有必要的(tvf的结果),既方便文件的查找,也可以由此推算出磁带上的剩余空间大小。

参考

Related posts

Categories: Linux Tags:

转换AVCHD的m2ts文件到avi

October 23rd, 2007 Fwolf 9 comments

Sony的硬盘录像机是好东西,高清晰、宽屏幕录像,大容量存储,可录的时候爽了,后期浏览和加工转换实在是不方便(这位仁兄也有同样感受: Jeff Cai的流水账 – Play with AVCHD,机型都是Sony HDR-SR1),无论想在哪台电脑上浏览录像,都要装一个Sony Handycam Application Software软件(安装盘仅400M),这个软件也相当霸道,不让选择安装位置、安装哪些组件,甚至不允许单独安装其中的某一个程序,安装完成后居然还提示要重启xp,当然不重启我试了也能使用。注册媒体库位置的时候不让选择网上邻居资源或者映射的网络驱动器。

如果这些都不是问题的话,录像文件拷出来能用其他工具浏览或加工也行啊,可偏偏他的录像格式m2ts(扩展名MTS)目前支持的工具还相当少,不过还是在网上找到了一些文章,能够用开源工具进行转换。Sony自带软件也能转换成通用格式,不过我的印象是会损失一些清晰度,用肉眼就能轻易的分辨出来的差异。参考文章:

基本思路都是这样的:

  • 用xporthdmv把m2ts转换为mpv和mpa格式
  • 用ldecod把mpv转换为yuv格式
  • 用yuv4mpeg把yuv转换为y4m格式
  • mpa直接当ac3格式的音频使用
  • 用ffmpeg合成视频和音频部分为avi格式(avi就是一个容器)

讨论中还有一些其他的提示:

  • ffmpeg可以用mencoder替代
  • ldecod生成的yuv文件大小可以达到4G/分钟,不过可以用命名管道(named pipe)来省去使用中间文件
  • 视频和音频的同步,pal格式录像可以设定fps为25,ntsc格式录像可以使用参数-r 29.97。

参考文章中的第一篇给了一个附件(我还在这里存了一份解压、编译好的版本),这个很好用,下载下来解包,里面的readme.txt和Makefile解释了使用方法,不过在ubuntu下使用的话,建议先作以下几步准备工作:

  • 安装svn客户端
  • 用apt安装x264-bin和ffmpeg以及mplayer
  • 在’src/JM/ldecod’目录下创建一个空的子目录’obj’
  • 脚本运行之后会自动转换samplevideo.avi,会用去一些时间,想省略的话把这个文件删除或改名即可
  • download文件中有一句set version=12.2,现在的jm版本已经是12.4了,更新之,不然下载不到(404错误)

然后就简单了:

  • ./download
  • ./compile
  • ./install

或者再用installasroot安装,你就可以使用m2tstoavi了:

$ m2tstoavi 
usage: /usr/local/bin/m2tstoavi filename.m2ts ...

我也转了一个自己录的文件,完成后发现视频、音频不同步,并且播放速度很慢,可能是一些设置参数的问题,转换方式肯定是没有问题的,并且好像是目前最好的方式了。(修改/usr/local/bin/m2tstoavi,注意上面说的pal和ntsc制式的区别)mplayer播放最终生成的avi文件,信息如下:

Playing samplevideo.avi.
AVI file format detected.
VIDEO:  [h264]  1440x1080  24bpp  29.970 fps  13323.1 kbps (1626.4 kbyte/s)
Clip info:
 Software: MEncoder 2:1.0~rc1-0ubuntu9.1
open: No such file or directory
[MGA] Couldn't open: /dev/mga_vid
open: No such file or directory
[MGA] Couldn't open: /dev/mga_vid
[VO_TDFXFB] Can't open /dev/fb0: No such file or directory.
[VO_3DFX] Unable to open /dev/3dfx.
It seems there is no Xvideo support for your video card available.
Run 'xvinfo' to verify its Xv support and read DOCS/HTML/en/video.html#xv!
See 'mplayer -vo help' for other (non-xv) video out drivers. Try -vo x11
Opening video filter: [screenshot]
==========================================================================
Opening video decoder: [ffmpeg] FFmpeg's libavcodec codec family
Selected video codec: [ffh264] vfm: ffmpeg (FFmpeg H.264)
==========================================================================
==========================================================================
Forced audio codec: mad
Opening audio decoder: [liba52] AC3 decoding with liba52
Using SSE optimized IMDCT transform
Using MMX optimized resampler
AUDIO: 48000 Hz, 2 ch, s16le, 448.0 kbit/29.17% (ratio: 56000->192000)
Selected audio codec: [a52] afm: liba52 (AC3-liba52)
==========================================================================
AO: [alsa] 48000Hz 2ch s16le (2 bytes per sample)
Starting playback...
VDec: vo config request - 1440 x 1080 (preferred colorspace: Planar YV12)
VDec: using Planar YV12 as output csp (no 0)
Movie-Aspect is 1.78:1 - prescaling to correct movie aspect.
SwScaler: reducing / aligning filtersize 5 -> 4
SwScaler: reducing / aligning filtersize 5 -> 4
SwScaler: reducing / aligning filtersize 1 -> 1
SwScaler: reducing / aligning filtersize 5 -> 4

SwScaler: BICUBIC scaler, from yuv420p to bgr24 using MMX2
SwScaler: using 4-tap MMX scaler for horizontal luminance scaling
SwScaler: using 4-tap MMX scaler for horizontal chrominance scaling
SwScaler: using n-tap MMX scaler for vertical scaling (BGR)
SwScaler: using MMX2 YV12->BGR24 Converter
SwScaler: 1440x1080 -> 1920x1080
VO: [x11] 1440x1080 => 1920x1080 Planar YV12 
A:4358.2 V:   2.9 A-V:4355.240 ct:  0.297  89/ 89 148%  0%  1.1% 37 0 

有时间了再仔细研究视频、音频不同步和播放速度很慢的问题。不过还是那句话,技术都是好东西,可对商业利益的无止境追求使他们变成了恶魔。

软件环境:Ubuntu 7.04 Feisty

Update @ 2008-02-14

发现视频、音频不同步的原因了,我的机器太慢!精度太高了,3.2双核都跑不动!对结果再此进行降频转换之后,播放还是很流畅的,但感觉人物动作略微有一点点快呢?帧率不对?

mencoder -oac copy -ovc xvid -xvidencopts bitrate=5000 $file.avi -o $output.avi

Related posts

Categories: Linux Tags: , , ,

通过代理更新Gregarius

October 14th, 2007 Fwolf 3 comments

Gregarius是我现在使用的rss阅读器,其它在线的比如google reader、zhuaxia我网速太慢,使用不顺畅,纯离线方式的吧,比如liferea,在浏览的时候依然要解析html和联网(feed内容中有图像),还是在本机架一个Gregarius,cron定时更新,然后用firefox看方便,保存有价值的文章也更方便。

原先更新都是用wget:

wget --no-check-certificate -O /tmp/gregarius.update https://my_local_machine_name/gregarius/update.php

wget的输出会已本地用户邮件形式被mutt收下来,设定好之后,有一段没时间看rss也没在意,这天忽然发现原来wget只要retry 3、4次就能更新完全部feed,现在需要十几次,而我的feed增长显然没达到这种程度;并且有些网站在Gregarius中看到已经很久没有更新了(-t 1可以指定只retry一次,默认是20次,-t 0为无限制retry下去)。同时在feed管理中看到,很多网站的名字都加上了删除线,比如“月光博客”,最后终于发现,这些名字打上了删除线的blog的feed全部托管在feedburner,并且内容全部没有更新,原因,自然是开始于前段时间的feedburner无法访问。

feedburner无法访问我倒不怕,我一直都在本机用squid、privoxy、tor智能中转web访问请求,现在只要让gregarius更新feed时用上我这个本地的代理服务器squid就可以了,看了一下gregarius的代码,远程读取rss使用的是Snoopy类,本地文件为extlib/Snoopy.class.inc,调用是在extlib/rss_fetch.inc文件中,大概第317行,function _fetch_remote_file部分,在这里添加如下内容即可:

$client->read_timeout = MAGPIE_FETCH_TIME_OUT;
$client->use_gzip = MAGPIE_USE_GZIP;

// 这几行是添加的内容,其它是原文件中的 Modify by Fwolf @ 2007-10-14
// Use proxy localhost:3128 when fetch feed
$client->proxy_host = "localhost";
$client->proxy_port = "3128";
$client->_isproxy = true;
$client->read_timeout = 0;  // tor via squid is slow
//

if (is_array($headers) ) {
    $client->rawheaders = $headers;
}

就这么简单,$client的设置参照Snoopy类的定义即可,然后调用不再使用wget,而是直接运行update.php:

cd /local/path/to/gregarius; php -f update.php

这样更新的结果会清晰的输出:

Engadget Simplified Chinese ...
OK (HTTP 200), 3 New Items

玩意儿 ...
OK (304 Not modified), 0 New Items

津津乐道 ...
HTTP Timeout (Local cache), 0 New Items

小众软件 ...
OK (HTTP 200), 0 New Items

如果加上-- --silent就没有输出了,第一个--是给截止php接收参数的参数,--silent才是给update.php用的。

本文针对Gregarius 0.5.5 revision1761。

Related posts

Categories: Internet, Tools Tags: