Home

Previous 20

Feb. 5th, 2007

买电脑

庆祝一下,昨天买了平生第一个笔记本电脑。买的时候因为经济拮据,千挑万挑最终买了一个4000整的,呵呵。也是本人第一次用VIA的CPU。。。感觉不错,价格实惠量又足 ^_^
不知道这台笔记本电脑将会陪伴我度过多少个不眠的夜晚,经历多少个城市呢?

Jan. 15th, 2007

红色的溪水

红色的溪水像扩张的血脉。黑色的树木像飘飞的长发。一个精灵带着我环游整个梦境。我看见了死后的自己。我的左手腕刺着一把尖刀。我的心脏还在活跃的跳。我的眼睛黯然无色。我的嘴角留着纯净的微笑。
天冷了。花落了。精灵变成凶狠的恶鬼。咆哮的向我逼近。他有锋利的牙齿似乎要将我吞噬。他用一把尖刀刺向我左腕。
血干了。我死了。心脏仍然在跳。但是不属于我。我死在我垂死的梦里。我的眼睛黯然无色。我的嘴角留着纯净的微笑

另一则:
我穿上最华丽的衣服在夜里翩然起舞。飘扬的舞裙里面是我苍白的骨骼。不要恐惧。这是我的乐园。你来这里。用你的血液为我浇灌一朵花。那血红色的。我最爱的。你可以安然睡去。不用担心被可恶的阳光刺醒。 感受宁静。漆黑的夜。在我美丽而死寂的花园。

转自DyingBride at xiasl.net

Nov. 8th, 2006

C语言中的指针和内存泄露

* Always use memset along with malloc, or always use calloc.
1.永远把memset和malloc一起使用,或者永远用calloc
* Whenever writing values to pointers, make sure you cross check the number of bytes available and number of bytes being written.
2.但写数据到指针所指的内存时,一定要检查可用空间的大小,和写入的字节数。
* Before assigning the pointers, make sure no memory locations will become orphaned.
3.在给一个指针赋值的时候,确定没有内存区域丢失。
* Whenever freeing the structured element (which in turn contains the pointer to dynamically allocated memory location), first traverse to the child memory location and start freeing from there, traversing back to the parent node.
4.当释放结构体成员的内存时(这个结构体有成员指针指向动态分配的内存),要先把子内存区域释放掉,再释放父内存区域。
* Always properly handle return values of functions returning references of dynamically allocated memory.
5.适当的处理返回指向动态分配的内存的指针的函数。(好绕嘴+_+)
* Have a corresponding free to every malloc.
6.对于每一个malloc都有一个对应的free
* Make sure you are not accessing null pointer.
7.确保你不会访问null指针。

Aug. 18th, 2006

介绍两个辅助开发工具

在c++开发中使用vim和ctags
译自: http://cantor.ee.ucla.edu/~jsab/vim_ctags_cpp.html

如果你所有的源代码都在一个文件夹树内,那么可以简单的运行这个命令:
ctags --recurse --language-force=c++ --extra=+q --fields=+i *.cpp *.h
然后你就可以用多种方式穿梭于源代码中。在下面THE_TAG用于代表你要跳转的东西。
1.当光标在THE_TAG上的时候按 "g ctrl+]"
2.":ts THE_TAG" 或 ":tselect THE_TAG"
3.":sts THE_TAG"
4.当光标在THE_TAG上的时候按 "ctrl+]"
5.":ta THE_TAG" 或 ":tag THE_TAG"
6.":sta THE_TAG"
7."ctrl+t" 将让你回到跳转前的地方。

第1,2,3条会让你在一些tags里选择.
第4,5,6条会直接把你代到第一个可能的tag,
第1,4条在vim普通模式下使用.
第2,5条是在命令模式下使用.
第3,6条跟第2,5条一样,只是会打开一个新窗口显示跳转的内容.

这个命令可以解决找不到tag文件的问题:
set tags=/path/tags



global的使用方法

global与ctags一样,也是一个通过分析源代码来方便开发的工具.但是相比ctags,global功能更强,更适合大型项目(只是c?).
global的常用功能有:
  1. 找到一个函数的定义,这个和ctags一样.
  2. 找到一个函数被使用的地方.(reference)
  3. 找到每个符号(除了函数名以外的标识符)出现的地方.
  4. 列出一个文件中的所有标签.
global可以单独作为一个命令使用,也可以和vim,emacs整合,由于我使用vim,就介绍一下vim里使用global的方法吧:
先安装global插件,在vim.org上搜索gtags脚本.下载后放到 ~/.vim/plugin/ 里.
然后cd到项目的根目录,运行:gtags,生成包含源代码信息的数据库.
用vim打开一个文件,光标移动到要查找的标识符.
:Gtags 查找函数的定义
:Gtags -r 查找函数被使用的地方
:Gtags -s 查找标识符被引用的地方
:Gtags -f 列出当前文件里的所有标签
这样global会在vim里打开一个叫quickfix的窗口,每一行列出查找到的条目.可以使用下列命令进行跳转:
:cn 下一个条目
:cp 上一个条目
:ccN 跳到第N个条目.
:cl 列出所有条目
也可以用鼠标双击,更方便!
基本功能就这么多,也基本上够用了.顺便再推荐一个vim的老牌插件:TagList 呵呵
btw:好像global对c++支持不够好,虽然它的主页上说支持c++.比如:不能区别成员函数所属的类,等等.

Jun. 17th, 2006

在linux下玩游戏

linux平台的游戏是比较少的(和windows相比)
这些游戏主要是模拟器一类的:
街机模拟: xmame
PS模拟: epsxe
GBA: visual boy advance,gnome file上有一个python写的前端,很好用。
snes(超级任天堂): zsnes
还有还有红白机...偶没有考古的热情,就不介绍了吧...
如果你是用debian的话,这些模拟器软件在apt里都有(除了那个vba前端)
rom方面google一下就能找到很多.还有,这个网站上提供汉化的rom:http://www.emu618.com/

网络游戏方面嘛,首要推荐的就是"蓝迪游戏".国内唯一一个提供mac和linux平台在线游戏的公司.http://www.bluedj.com/ 以前还玩过一个java的网游.. 在 miniclip.com,名字叫runescape.上它的主页就看到了.如果你喜欢MUD 倒有不少.. 中文的也有:谁与争锋

剩下的还有id的产品:quake 3 4 doom 3...等等.但是偶不大喜欢
无聊的时候常到这里转转吧:http://www.happypenguin.org/ linux下的游戏,不管开源不开源,都会在这里发布.

Jun. 15th, 2006

灵活的Fontconfig

Fontconfig是一个字体自定义和配置库。

今天终于把文档看完了,自己配置了一下,非常方便。因为我有正版的windows所以就用了SimSun字体,呵呵.不要指责我哈
实现了下面几个功能:
1.SimSun在小字体的时候使用内嵌的点阵.
2.在字体pixel size大于18的时候换成楷体
3.使用斜体的时候关闭抗锯齿

May. 31st, 2006

[转]Linux和windows在启动方面的比较

Linux和windows在启动方面的比较

linux:第一步:硬件读取引导扇区;
windows:第一步:硬件读取引导扇区;

linux:第二步:加载LILO或者grub
windows:第二步:加载NTLDR并读取BOOT.ini文件(类似与lilo.conf或者grub.conf)

linux:第三步:加载内核;
windows:第三步:NTDETECT运行并决策硬件设备;

linux:第四步:挂装根文件系统;
windows:第四步:NTLDR加载NTOSKRNL.EXE,NT内核和HAL.DLL,硬件基本驱动层。

linux:第五步:启动init,一切进程的“祖父”;
windows:第五步:NT准备好C:盘;

linux:第六步:读取/etc/inittab文件;
windows:第六步:服务器管理器SMSS.EXE加载,它读入注册表registry并决定需要加载哪些服务;

linux:第七步:允许所有运行级别1指定的脚本程序;
windows:第七步:加载WIN32系统;

linux:第八步:在运行级别1的结尾处告诉系统前进到运行级别3;
windows:第八步:启动提供登录服务的winlogon;

linux:第九步:允许所有运行级别3指定的脚本程序;系统就绪;
windows:第九步:SCREG,注册表扫描工具和LSASS,本地安全授权工具随winlogon一起启动,开始加载驱动程序,系统就绪;

Mar. 21st, 2006

语言的进化

语言的进化

作者: Paul Graham

Kevin Kelleher提出, 可以用一个语言对过去语言的改进, 来表达这个语言的特点。这种描述方式很有意思。令人惊奇的是: 居然有这么多语言都可以这样来描述。

Algol: 汇编语言太低级。

Pascal: Algol数据类型太少。

Modula: Pascal搞系统级编程不行。

Simula: Algol搞模拟不行。

Smalltalk: Simula的对象化程度太次。

Fortran: 汇编太低级。

Cobol: Fortran语法太吓人。

PL/1: Fortran数据类型不够用。

Ada: 所有现成的语言好象都缺点啥。

Basic: Fortran太吓人。

APL: Fortran处理数组不行。

J: APL居然没有自己的字符集。

C: 汇编太低级。

C++: C太低级。

Java: C++是杂牌货, 我们快被微软Microsoft搞垮了。

C#: Java是Sun控制的。

Lisp: 图灵机的计算模式糟得很。

Scheme: MacLisp是杂牌。

T: Scheme没有库。

Common Lisp: Lisp变种太多了。

Dylan: Scheme没有库, Lisp语法太吓人。

Perl: Shell脚本/awk/sed不太象编程语言。

Python: Perl是杂牌。

Ruby: Perl是杂牌, Lisp语法太吓人。

Prolog: 编程没有逻辑是不行的。

Jan. 2nd, 2006

debian中输入法启动配置文件的位置

一般在xinit 中设置的启动输入法都没有效果。
事实上真正有效果的是这个文件:
/etc/X11/Xsession.d/25xchinput-start
例如:
export XMODIFIERS=@im=fcitx ; fcitx

如果是scim就是这样写:
export XMODIFIERS=@im=SCIM #case matters for this variable!
export GTK_IM_MODULE=scim
export QT_IM_MODULE=xim
scim -d #scim need start as deamon,or will cause problem!

http://www.scim-im.org/wiki/documentation/installation_and_configuration/all/system_configuration
不知道有没有人翻译,很有用,有时间偶就翻译了。

(no subject)

游戏一: 
   
  据说这个游戏比碟仙还要恐怖。 
   
  游戏是这样玩的,选4个人。在夜半时分,在一个长方形的空白房间内,将所有灯光灭掉,然后在房间的4个角,每个角站一个人,然后面朝墙角,最好不要向后看。游戏开始时,其中一个角的人就向另外一个角走去,轻轻拍一下前面那个人的肩膀。接着,被拍的人就按照同样的方法向另外一个角走去(大家走的方向是一致的,都顺时针或都逆时针),然后拍第3个人的肩膀。以此类推,但是,如果当你走到一个没有人的角落,就要先咳嗽一声,然后越过这个墙角继续向前走,直到见到下一个人。 
   
  过了一段时间,你就会发现,会出现没有人咳嗽的时候,就说明每一个角都有人,但是却有一个人始终在走。那么多出来的那个人是谁呢?
   
  听说有一个学校里的男生寝室的人一起玩这个游戏,第二天全部提出转学。
   
  还有一个外国的登山队,晚上因为太冷不能睡,怕一睡就起不来了,就玩这个游戏,到第二天早上发现有一个队员死了,而且是在玩游戏之前就死了。 
   

Dec. 27th, 2005

fcitx跟随,和x ~

有个想法:能不能更多的用openGL来进行x的渲染.
google了一下 x render extension 没有找到我想要的.
我在一个视频里看到,一个hacker写的程序,在x里使用opengl渲染,可以做出很多特效.像拖动窗口时的水波效果.很酷~~!但是我忘了程序的名字,以至于一直都没有再google到.-_-!

关于fcitx的屏幕跟随.

听说fcitx在kde里是可以跟随的,但是在gtk/gnome的环境里就不行了.scim却可以.scim用了一个叫gtk_immodule的东西,在gtk2的程序里就使用这个来跟随,因为gtk2好像和xim的东西冲突.发现拼音输入很适合我.如果fictx可以自动跟随的话,那就太爽了.拼音打字不用动脑子,只是动的手多了一点.

Dec. 25th, 2005

哇哈哈 会考语文得优..

偶在语文的作文里胡扯,没一句切题的(整篇在阐述老师改卷不看作文的好处..-_#)这样也能得优..我无言了 看来老师确实没看作文.XD

怎样合理安排学习?

1.现在学习的课程:
c++
操作系统
debian手册

c++语法部分快结束了,自认为学的还很扎实.以前我是学过一遍的,只是不认真罢了.书里的编程练习只做了一半,不过觉得也够了.很快就可以进入数据结构部分了.不过这本书还是只是一本入门的书,看了这本还不能说,我会c++了..
操作系统刚刚开始.还不知道该给自己定一个什么目标...
debian手册很有意思哈.看完这个应该算是对debian熟悉了.
lfs我也想做一次,毕竟是一种"了解linux的标志"

认识了zxw,我觉得可能向软件工程这方面研究比较有钱途吧.嗯,就这样吧..

Dec. 20th, 2005

睡觉之前的废话

最近用拼音很爽啊.以后汉语变成拼音语言算了.没必要用象形.其实一点也不象形,被简化的.. 很惨.文字应该读音一样嘛.古代的文言文,可能就是因为使用象形文字,而象形文字的信息量比较大,导致文字书写和讲话不一样.XD 以上属臆想.咳..
发现vim很强,在vim.org上找了很多利害的插件.时间紧张我就试了一个.SuperTab.功能比cppcomplete弱了一点.但快捷键是比cppcomplete好.速度更快了.我很有可能把cppcomplete给换掉.还有就是我苦苦寻找的像vc,anjuta那样在一个窗口列出工程里的类,成员变量等的工具,被发现了.也是vim插件.名字还未知,我是从一个video里看到的.(SuperTab在~/software/下,还没写入vimrc). 我一直没有找到vim的plugin目录应该放在哪..我把~/.vimrc给放到~/.vim/.vimrc下,vim的插件就不能加载了.plugin更没地方放,我现在只有把plugin写到配置文件了.:(
今天在家呆一天,所以明天还是要多出去转转了.
ok,go bed now..seeyou

Dec. 18th, 2005

会考

对于一个二中的学生,会考是一件很容易的事情.而对于已经两个月没进教室的我来说,却不是那么简单.政治还可以随便瞎扯,语文作文,就不行了.实际上这句话已经被我推翻.今天,是本人头一次,也许也是最后一次,在语文作文中瞎扯.在我的作文中,仔细的分析了作为一个人民教师,不看作文内容就改分的重要性.而且在信息学的角度做了一定的阐述.-_-3
高中毕业就去工作的人生会是怎样的呢?
我已无法挽回.
今天花了20块钱,买了一本操作系统.偶要系统的学习一下.哇哈哈..

Dec. 14th, 2005

安装以源代码发布的软件

安装以源代码发布的软件
 
1.解压缩
对于*.tar.bz2的文件用
tar jxvf 文件名
对于*.tar.gz的文件用
tar zxvf 文件名
2.cd到被解压的源代码目录
3.输入命令./configure
如果提示缺少某些开发包,则要另外安装.通过rpm包等方式.
4.make
5.su输入密码变成超级用户
6.make install
卸载:
在源代码目录里:
make uninstall

安装一个软件之前最好先看看源代码目录下的:
README 和 INSTALL文件.

Dec. 10th, 2005

一个程序员对自己的未来很迷茫

一个程序员对自己的未来很迷茫,于是去问上帝。
“万能的上帝呀,请你告诉我,我的未来会怎样?”
上帝说“我的孩子,你去问Lippman,他现在领导的程序员的队伍可能是地球上最大的”
于是他去问Lippman。
Lippman说“程序员的未来就是驾驭程序员”
这个程序员对这个未来不满意,于是他又去问上帝。
“万能的上帝呀,请你告诉我,我的未来会怎样?”
上帝说“我的孩子,你去问Gates,他现在所拥有的财产可能是地球上最多的”
于是他去问Gates。
Gates说“程序员的未来就是榨取程序员”
这个程序员对这个未来不满意,于是他又去问上帝。
“万能的上帝呀,请你告诉我,我的未来会怎样?”
上帝说“我的孩子,你去问侯捷,他写的计算机书的读者可能是地球上最多的”
于是他去问侯捷。
侯捷说“程序员的未来就是诱惑程序员”
这个程序员对这个未来不满意,于是他又去问上帝。
“万能的上帝呀,请你告诉我,我的未来会怎样?”
上帝摇摇头“唉,我的孩子,你还是别当程序员了”)
(_呵呵)

Nov. 28th, 2005

c++ scope

C++ names can be used only in certain regions of a program. This area is called the “scope” of the name. Scope determines the “lifetime” of a name that does not denote an object of static extent. Scope also determines the visibility of a name, when class constructors and destructors are called, and when variables local to the scope are initialized. There are five kinds of scope:

* Local scope. A name declared within a block is accessible only within that block and blocks enclosed by it, and only after the point of declaration. The names of formal arguments to a function in the scope of the outermost block of the function have local scope, as if they had been declared inside the block enclosing the function body. Consider the following code fragment:

{ int i;}

Because the declaration of i is in a block enclosed by curly braces, i has local scope and is never accessible because no code accesses it before the closing curly brace.
* Function scope. Labels are the only names that have function scope. They can be used anywhere within a function but are not accessible outside that function.

* File scope. Any name declared outside all blocks or classes has file scope. It is accessible anywhere in the translation unit after its declaration. Names with file scope that do not declare static objects are often called “global” names.

* Class scope. Names of class members have class scope. Class member functions can be accessed only by using the member-selection operators (. or –>) or pointer-to-member operators (.* or –>*) on an object or pointer to an object of that class; nonstatic class member data is considered local to the object of that class. Consider the following class declaration:

class Point{ int x; int y;};

The class members x and y are considered to be in the scope of class Point.
* Prototype scope. Names declared in a function prototype are visible only until the end of the prototype. The following prototype declares two names (szDest, szSource); these names go out of scope at the end of the prototype:

char *strcpy( char *szDest, const char *szSource );

Nov. 2nd, 2005

Makefile的使用方法

<<跟我一起写 Makefile>>

Makefile基本格式:
target : prerequisites
command
target : prerequisites
command
...
...
如果prerequisites中的文件有一个比target新的话,就执行command.一个规则一个规则的递归. 注意command前要有一个tab.

label :
command
当使用make label 命令时,执行command.如:
clean:
rm exec a.o b.o c.o d.o
make clean 就会删除 exec a.o b.o c.o d.o

Makefile中还可以定义变量
object = a.o b.o c.o d.o

exec : $(object)
gcc -o exec $(object)

原文写的时间应该是比较早了,里面还用cc. 不过原理倒是让我搞清楚了. 呵呵
(未完成)

Nov. 1st, 2005

又暂时放弃了c++ 学习c 去了

迷茫,那本厚书被我看了一半的时候,放弃了. 主要原因是:国人参与的很多开源项目都是用c写的,有我喜爱的很多软件.像fcitx,openq都是用c写的.我在source forge上看了一下.总的来说c++的项目是比c多的.c++的有16000,c的有15000.势均力敌啊. 但是现在怎么又冒出来一个用gtkmm的qq项目. 我就迷茫了.. c和c++ 都要学吗? 总要有个先学吧.. 两个都学了,不会乱吧.(汗) c学好了可以去做嵌入式,c++学好了能做什么呢? 真晕了,又想去学c++.
我的生活我的学习都没着落呢,我去得了湛江吗? 我能见到宝宝吗? 即使去了,能上的了学吗?

shell版俄罗斯方块(一位高手所写)- -

shell版俄罗斯方块(一位高手所写)- -
Tag: shell版俄罗斯方块

#!/bin/bash
# Tetris Game
# 10.21.2003 xhchen

#颜色定义
cRed=1
cGreen=2
cYellow=3
cBlue=4
cFuchsia=5
cCyan=6
cWhite=7
colorTable=($cRed $cGreen $cYellow $cBlue $cFuchsia $cCyan $cWhite)

#位置和大小
iLeft=3
iTop=2
((iTrayLeft = iLeft + 2))
((iTrayTop = iTop + 1))
((iTrayWidth = 10))
((iTrayHeight = 15))

#颜色设置
cBorder=$cGreen
cScore=$cFuchsia
cScoreValue=$cCyan

#控制信号
#改游戏使用两个进程,一个用于接收输入,一个用于游戏流程和显示界面;
#当前者接收到上下左右等按键时,通过向后者发送signal的方式通知后者。
sigRotate=25
sigLeft=26
sigRight=27
sigDown=28
sigAllDown=29
sigExit=30

#七中不同的方块的定义
#通过旋转,每种方块的显示的样式可能有几种
box0=(0 0 0 1 1 0 1 1)
box1=(0 2 1 2 2 2 3 2 1 0 1 1 1 2 1 3)
box2=(0 0 0 1 1 1 1 2 0 1 1 0 1 1 2 0)
box3=(0 1 0 2 1 0 1 1 0 0 1 0 1 1 2 1)
box4=(0 1 0 2 1 1 2 1 1 0 1 1 1 2 2 2 0 1 1 1 2 0 2 1 0 0 1 0 1 1 1 2)
box5=(0 1 1 1 2 1 2 2 1 0 1 1 1 2 2 0 0 0 0 1 1 1 2 1 0 2 1 0 1 1 1 2)
box6=(0 1 1 1 1 2 2 1 1 0 1 1 1 2 2 1 0 1 1 0 1 1 2 1 0 1 1 0 1 1 1 2)
#所有其中方块的定义都放到box变量中
box=(${box0[@]} ${box1[@]} ${box2[@]} ${box3[@]} ${box4[@]} ${box5[@]} ${box6[@]})
#各种方块旋转后可能的样式数目
countBox=(1 2 2 2 4 4 4)
#各种方块再box数组中的偏移
offsetBox=(0 1 3 5 7 11 15)

#每提高一个速度级需要积累的分数
iScoreEachLevel=50 #be greater than 7

#运行时数据
sig=0 #接收到的signal
iScore=0 #总分
iLevel=0 #速度级
boxNew=() #新下落的方块的位置定义
cBoxNew=0 #新下落的方块的颜色
iBoxNewType=0 #新下落的方块的种类
iBoxNewRotate=0 #新下落的方块的旋转角度
boxCur=() #当前方块的位置定义
cBoxCur=0 #当前方块的颜色
iBoxCurType=0 #当前方块的种类
iBoxCurRotate=0 #当前方块的旋转角度
boxCurX=-1 #当前方块的x坐标位置
boxCurY=-1 #当前方块的y坐标位置
iMap=() #背景方块图表

#初始化所有背景方块为-1, 表示没有方块
for ((i = 0; i < iTrayHeight * iTrayWidth; i++)); do iMap[$i]=-1; done


#接收输入的进程的主函数
function RunAsKeyReceiver()
{
local pidDisplayer key aKey sig cESC sTTY

pidDisplayer=$1
aKey=(0 0 0)

cESC=`echo -ne "\33"`
cSpace=`echo -ne "\40"`

#保存终端属性。在read -s读取终端键时,终端的属性会被暂时改变。
#如果在read -s时程序被不幸杀掉,可能会导致终端混乱,
#需要在程序退出时恢复终端属性。
sTTY=`stty -g`

#捕捉退出信号
trap "MyExit;" INT TERM
trap "MyExitNoSub;" $sigExit

#隐藏光标
echo -ne "\33[?25l"


while (( 1 ))
do
#读取输入。注-s不回显,-n读到一个字符立即返回
read -s -n 1 key

aKey[0]=${aKey[1]}
aKey[1]=${aKey[2]}
aKey[2]=$key
sig=0

#判断输入了何种键
if [[ $key == $cESC && ${aKey[1]} == $cESC ]]
then
#ESC键
MyExit
elif [[ ${aKey[0]} == $cESC && ${aKey[1]} == "[" ]]
then
if [[ $key == "A" ]]; then sig=$sigRotate #<向上键>
elif [[ $key == "B" ]]; then sig=$sigDown #<向下键>
elif [[ $key == "D" ]]; then sig=$sigLeft #<向左键>
elif [[ $key == "C" ]]; then sig=$sigRight #<向右键>
fi
elif [[ $key == "W" || $key == "w" ]]; then sig=$sigRotate #W, w
elif [[ $key == "S" || $key == "s" ]]; then sig=$sigDown #S, s
elif [[ $key == "A" || $key == "a" ]]; then sig=$sigLeft #A, a
elif [[ $key == "D" || $key == "d" ]]; then sig=$sigRight #D, d
elif [[ "[$key]" == "[]" ]]; then sig=$sigAllDown #空格键
elif [[ $key == "Q" || $key == "q" ]] #Q, q
then
MyExit
fi

if [[ $sig != 0 ]]
then
#向另一进程发送消息
kill -$sig $pidDisplayer
fi
done
}

#退出前的恢复
function MyExitNoSub()
{
local y

#恢复终端属性
stty $sTTY
((y = iTop + iTrayHeight + 4))

#显示光标
echo -e "\33[?25h\33[${y};0H"
exit
}


function MyExit()
{
#通知显示进程需要退出
kill -$sigExit $pidDisplayer

MyExitNoSub
}


#处理显示和游戏流程的主函数
function RunAsDisplayer()
{
local sigThis
InitDraw

#挂载各种信号的处理函数
trap "sig=$sigRotate;" $sigRotate
trap "sig=$sigLeft;" $sigLeft
trap "sig=$sigRight;" $sigRight
trap "sig=$sigDown;" $sigDown
trap "sig=$sigAllDown;" $sigAllDown
trap "ShowExit;" $sigExit

while (( 1 ))
do
#根据当前的速度级iLevel不同,设定相应的循环的次数
for ((i = 0; i < 21 - iLevel; i++))
do
sleep 0.02
sigThis=$sig
sig=0

#根据sig变量判断是否接受到相应的信号
if ((sigThis == sigRotate)); then BoxRotate; #旋转
elif ((sigThis == sigLeft)); then BoxLeft; #左移一列
elif ((sigThis == sigRight)); then BoxRight; #右移一列
elif ((sigThis == sigDown)); then BoxDown; #下落一行
elif ((sigThis == sigAllDown)); then BoxAllDown; #下落到底
fi
done
#kill -$sigDown $$
BoxDown #下落一行
done
}


#BoxMove(y, x), 测试是否可以把移动中的方块移到(x, y)的位置, 返回0则可以, 1不可以
function BoxMove()
{
local j i x y xTest yTest
yTest=$1
xTest=$2
for ((j = 0; j < 8; j += 2))
do
((i = j + 1))
((y = ${boxCur[$j]} + yTest))
((x = ${boxCur[$i]} + xTest))
if (( y < 0 || y >= iTrayHeight || x < 0 || x >= iTrayWidth))
then
#撞到墙壁了
return 1
fi
if ((${iMap[y * iTrayWidth + x]} != -1 ))
then
#撞到其他已经存在的方块了
return 1
fi
done
return 0;
}


#将当前移动中的方块放到背景方块中去,
#并计算新的分数和速度级。(即一次方块落到底部)
function Box2Map()
{
local j i x y xp yp line

#将当前移动中的方块放到背景方块中去
for ((j = 0; j < 8; j += 2))
do
((i = j + 1))
((y = ${boxCur[$j]} + boxCurY))
((x = ${boxCur[$i]} + boxCurX))
((i = y * iTrayWidth + x))
iMap[$i]=$cBoxCur
done

#消去可被消去的行
line=0
for ((j = 0; j < iTrayWidth * iTrayHeight; j += iTrayWidth))
do
for ((i = j + iTrayWidth - 1; i >= j; i--))
do
if ((${iMap[$i]} == -1)); then break; fi
done
if ((i >= j)); then continue; fi

((line++))
for ((i = j - 1; i >= 0; i--))
do
((x = i + iTrayWidth))
iMap[$x]=${iMap[$i]}
done
for ((i = 0; i < iTrayWidth; i++))
do
iMap[$i]=-1
done
done

if ((line == 0)); then return; fi

#根据消去的行数line计算分数和速度级
((x = iLeft + iTrayWidth * 2 + 7))
((y = iTop + 11))
((iScore += line * 2 - 1))
#显示新的分数
echo -ne "\33[1m\33[3${cScoreValue}m\33[${y};${x}H${iScore} "
if ((iScore % iScoreEachLevel < line * 2 - 1))
then
if ((iLevel < 20))
then
((iLevel++))
((y = iTop + 14))
#显示新的速度级
echo -ne "\33[3${cScoreValue}m\33[${y};${x}H${iLevel} "
fi
fi
echo -ne "\33[0m"


#重新显示背景方块
for ((y = 0; y < iTrayHeight; y++))
do
((yp = y + iTrayTop + 1))
((xp = iTrayLeft + 1))
((i = y * iTrayWidth))
echo -ne "\33[${yp};${xp}H"
for ((x = 0; x < iTrayWidth; x++))
do
((j = i + x))
if ((${iMap[$j]} == -1))
then
echo -ne " "
else
echo -ne "\33[1m\33[7m\33[3${iMap[$j]}m\33[4${iMap[$j]}m[]\33[0m"
fi
done
done
}


#下落一行
function BoxDown()
{
local y s
((y = boxCurY + 1)) #新的y坐标
if BoxMove $y $boxCurX #测试是否可以下落一行
then
s="`DrawCurBox 0`" #将旧的方块抹去
((boxCurY = y))
s="$s`DrawCurBox 1`" #显示新的下落后方块
echo -ne $s
else
#走到这儿, 如果不能下落了
Box2Map #将当前移动中的方块贴到背景方块中
RandomBox #产生新的方块
fi
}

#左移一列
function BoxLeft()
{
local x s
((x = boxCurX - 1))
if BoxMove $boxCurY $x
then
s=`DrawCurBox 0`
((boxCurX = x))
s=$s`DrawCurBox 1`
echo -ne $s
fi
}

#右移一列
function BoxRight()
{
local x s
((x = boxCurX + 1))
if BoxMove $boxCurY $x
then
s=`DrawCurBox 0`
((boxCurX = x))
s=$s`DrawCurBox 1`
echo -ne $s
fi
}


#下落到底
function BoxAllDown()
{
local k j i x y iDown s
iDown=$iTrayHeight

#计算一共需要下落多少行
for ((j = 0; j < 8; j += 2))
do
((i = j + 1))
((y = ${boxCur[$j]} + boxCurY))
((x = ${boxCur[$i]} + boxCurX))
for ((k = y + 1; k < iTrayHeight; k++))
do
((i = k * iTrayWidth + x))
if (( ${iMap[$i]} != -1)); then break; fi
done
((k -= y + 1))
if (( $iDown > $k )); then iDown=$k; fi
done

s=`DrawCurBox 0` #将旧的方块抹去
((boxCurY += iDown))
s=$s`DrawCurBox 1` #显示新的下落后的方块
echo -ne $s
Box2Map #将当前移动中的方块贴到背景方块中
RandomBox #产生新的方块
}


#旋转方块
function BoxRotate()
{
local iCount iTestRotate boxTest j i s
iCount=${countBox[$iBoxCurType]} #当前的方块经旋转可以产生的样式的数目

#计算旋转后的新的样式
((iTestRotate = iBoxCurRotate + 1))
if ((iTestRotate >= iCount))
then
((iTestRotate = 0))
fi

#更新到新的样式, 保存老的样式(但不显示)
for ((j = 0, i = (${offsetBox[$iBoxCurType]} + $iTestRotate) * 8; j < 8; j++, i++))
do
boxTest[$j]=${boxCur[$j]}
boxCur[$j]=${box[$i]}
done

if BoxMove $boxCurY $boxCurX #测试旋转后是否有空间放的下
then
#抹去旧的方块
for ((j = 0; j < 8; j++))
do
boxCur[$j]=${boxTest[$j]}
done
s=`DrawCurBox 0`

#画上新的方块
for ((j = 0, i = (${offsetBox[$iBoxCurType]} + $iTestRotate) * 8; j < 8; j++, i++))
do
boxCur[$j]=${box[$i]}
done
s=$s`DrawCurBox 1`
echo -ne $s
iBoxCurRotate=$iTestRotate
else
#不能旋转,还是继续使用老的样式
for ((j = 0; j < 8; j++))
do
boxCur[$j]=${boxTest[$j]}
done
fi
}


#DrawCurBox(bDraw), 绘制当前移动中的方块, bDraw为1, 画上, bDraw为0, 抹去方块。
function DrawCurBox()
{
local i j t bDraw sBox s
bDraw=$1

s=""
if (( bDraw == 0 ))
then
sBox="\40\40"
else
sBox="[]"
s=$s"\33[1m\33[7m\33[3${cBoxCur}m\33[4${cBoxCur}m"
fi

for ((j = 0; j < 8; j += 2))
do
((i = iTrayTop + 1 + ${boxCur[$j]} + boxCurY))
((t = iTrayLeft + 1 + 2 * (boxCurX + ${boxCur[$j + 1]})))
#\33[y;xH, 光标到(x, y)处
s=$s"\33[${i};${t}H${sBox}"
done
s=$s"\33[0m"
echo -n $s
}


#更新新的方块
function RandomBox()
{
local i j t

#更新当前移动的方块
iBoxCurType=${iBoxNewType}
iBoxCurRotate=${iBoxNewRotate}
cBoxCur=${cBoxNew}
for ((j = 0; j < ${#boxNew[@]}; j++))
do
boxCur[$j]=${boxNew[$j]}
done


#显示当前移动的方块
if (( ${#boxCur[@]} == 8 ))
then
#计算当前方块该从顶端哪一行"冒"出来
for ((j = 0, t = 4; j < 8; j += 2))
do
if ((${boxCur[$j]} < t)); then t=${boxCur[$j]}; fi
done
((boxCurY = -t))
for ((j = 1, i = -4, t = 20; j < 8; j += 2))
do
if ((${boxCur[$j]} > i)); then i=${boxCur[$j]}; fi
if ((${boxCur[$j]} < t)); then t=${boxCur[$j]}; fi
done
((boxCurX = (iTrayWidth - 1 - i - t) / 2))

#显示当前移动的方块
echo -ne `DrawCurBox 1`

#如果方块一出来就没处放,Game over!
if ! BoxMove $boxCurY $boxCurX
then
kill -$sigExit ${PPID}
ShowExit
fi
fi



#清除右边预显示的方块
for ((j = 0; j < 4; j++))
do
((i = iTop + 1 + j))
((t = iLeft + 2 * iTrayWidth + 7))
echo -ne "\33[${i};${t}H "
done

#随机产生新的方块
((iBoxNewType = RANDOM % ${#offsetBox[@]}))
((iBoxNewRotate = RANDOM % ${countBox[$iBoxNewType]}))
for ((j = 0, i = (${offsetBox[$iBoxNewType]} + $iBoxNewRotate) * 8; j < 8; j++, i++))
do
boxNew[$j]=${box[$i]};
done

((cBoxNew = ${colorTable[RANDOM % ${#colorTable[@]}]}))

#显示右边预显示的方块
echo -ne "\33[1m\33[7m\33[3${cBoxNew}m\33[4${cBoxNew}m"
for ((j = 0; j < 8; j += 2))
do
((i = iTop + 1 + ${boxNew[$j]}))
((t = iLeft + 2 * iTrayWidth + 7 + 2 * ${boxNew[$j + 1]}))
echo -ne "\33[${i};${t}H[]"
done
echo -ne "\33[0m"
}


#初始绘制
function InitDraw()
{
clear
RandomBox #随机产生方块,这时右边预显示窗口中有方快了
RandomBox #再随机产生方块,右边预显示窗口中的方块被更新,原先的方块将开始下落
local i t1 t2 t3

#显示边框
echo -ne "\33[1m"
echo -ne "\33[3${cBorder}m\33[4${cBorder}m"

((t2 = iLeft + 1))
((t3 = iLeft + iTrayWidth * 2 + 3))
for ((i = 0; i < iTrayHeight; i++))
do
((t1 = i + iTop + 2))
echo -ne "\33[${t1};${t2}H||"
echo -ne "\33[${t1};${t3}H||"
done

((t2 = iTop + iTrayHeight + 2))
for ((i = 0; i < iTrayWidth + 2; i++))
do
((t1 = i * 2 + iLeft + 1))
echo -ne "\33[${iTrayTop};${t1}H=="
echo -ne "\33[${t2};${t1}H=="
done
echo -ne "\33[0m"


#显示"Score"和"Level"字样
echo -ne "\33[1m"
((t1 = iLeft + iTrayWidth * 2 + 7))
((t2 = iTop + 10))
echo -ne "\33[3${cScore}m\33[${t2};${t1}HScore"
((t2 = iTop + 11))
echo -ne "\33[3${cScoreValue}m\33[${t2};${t1}H${iScore}"
((t2 = iTop + 13))
echo -ne "\33[3${cScore}m\33[${t2};${t1}HLevel"
((t2 = iTop + 14))
echo -ne "\33[3${cScoreValue}m\33[${t2};${t1}H${iLevel}"
echo -ne "\33[0m"
}


#退出时显示GameOVer!
function ShowExit()
{
local y
((y = iTrayHeight + iTrayTop + 3))
echo -e "\33[${y};0HGameOver!\33[0m"
exit
}



#游戏主程序在这儿开始.
if [[ $1 != "--show" ]]
then
bash $0 --show& #以参数--show将本程序再运行一遍
RunAsKeyReceiver $! #以上一行产生的进程的进程号作为参数
exit
else
#当发现具有参数--show时,运行显示函数
RunAsDisplayer
exit
fi

Previous 20

February 2007

S M T W T F S
    123
45678910
11121314151617
18192021222324
25262728   

Advertisement

Syndicate

RSS Atom
Powered by LiveJournal.com