对“富饶之城”的改进

本来我不喜欢打桌游的,尤其是“三国杀”,第一次跟别人玩时觉得规则太复杂,可能是我们人太多的原因,记得当时有十个人,一圈打了近一个小时。

后来过年回家时和一个哥们坐硬座,为了打发时间就一起打起了桌游。他当时带了两种牌,一个是“三国杀”,一个是“富饶之城”。我刚学会打“富饶之城”便喜欢上它了,感觉它规则比较简单,可玩起来很复杂,讲究策略和心理战术。“三国杀”也跟着他仔细学了学,虽然会打了但是还是感觉规则太繁琐,而且运气成份太大,有时候大半天都摸不到好牌,只能郁闷地一过再过……所以我还是喜欢“富饶之城”。

买“富饶之城”的牌会送一本规则说明,我们一开始打时没仔细读,导致在一些细节打法不对,后来看着说明更正了。但是直到昨天才发现我们还有两个地方打的不对,我认为这两个地方值得商讨:

1) 若一个玩家建成8个建筑,游戏便在该回合结束时结束。而且,最后一个出场的“军阀”(假设你没有加扩展牌)不允许拆拥有8个建筑的玩家的城市!我们之前打的都是允许。我觉得允许才更有意思,因为当某个玩家建了8个建筑时游戏不会立即结束而是等到这个回合转完才结束,这么做无非就是允许后面的玩家继续建建筑,因为第2个建够8个的玩家会加2分。既然允许后面的继续建,那就也应该允许后面的“军阀”去拆,这样才会使最后的胜利不至于很容易倒向第一个建够8个的那个玩家。

2) 第一个建够8个建筑的玩家可能获得的加分太多,比如我如果建了5种颜色的建筑,那么我第一个建够8个时可以加7分!7分是个什么概念?如果你打过你就知道,建一个7分的建筑有多么不容易!最后加分太多就会导致前期更注重建筑数量而不是质量,反正后面有4~7分可以加嘛!我只要保证我不落后别人那么多分即可。而且,如此一来,“建筑师”角色到后期会成为重点防范的对象,只要谁建够5个了,那么那个人就得开始被全场人提防了!

以上两点都是在照顾第一个建够8个建筑的玩家,过分地鼓励了注重建筑数量而非质量,这让该游戏失去了更多的精彩。

我觉得可以这么改进:

1) 允许“军阀”拆建够8个建筑的玩家的城市;

2) 减少最后的加分,比如:建够5种颜色的建筑加2分,第一个建完8个加3分,第二个加2分。

如果你觉得这两条太激进,你可以考虑只选择其中一个。

其实,桌游打多了你就会发现,设计桌游最重要的是什么?平衡!一定要做到游戏玩起来时各个玩家之间的平衡,平衡只要稍微被打破,出现一边倒的局面,这游戏就不好玩了。至于里面有多少运气成份,那要看你个人喜好了,我不喜欢运气成份太大的桌游,因为思考在某种程度上被弱化了。

另外,打桌游没必要太遵守“规则说明”,自己觉得怎么打更合理就可以怎么打。

以上是个人意见,仅供参考。

仿韩峰体日记一篇

3月12日星期五-2――8℃晴

上午到了公司,继续检查昨天发现的 bug。中午和其它几个部门搞了个Lunch&Learn,讲了很长时间,我吃了两盒饭。下午提前下班去踢球,晚上凌晨要开会。吃完饭和同学在家打了桌游《富饶之城》,输了。

神啊,赐个妞儿吧!

唉,你不知道,我的苦说三天三夜都说不完!

你说,人生咋就这么坎坷捏?时运咋就这么不济捏?命途咋就这么多舛捏?

你说,找姑娘这么种事儿,说简单吧也简单,没准三言两语就勾搭上一个;说难吧也难,没准相亲相了四五十个也碰不上一个对眼儿的。可为虾米这种事儿到我这咋就如此难于上青天捏?

说来话长……

很久很久以前……

我上高中那会儿,喜欢一个文科的姑娘,正儿八经的美女。那时多傻多天真啊,连搭个讪都不好意思!况且高三文理分明,隔行如隔山啊。最后千辛万苦啊,跋山涉水啊,好不容易才认识了人家姑娘吧,上大学去了,当然不是在同一个地方,然后没多久散了……

然后上了大学。事实证明人的进化是和环境密不可分的。以前上高中时下课还可以遥望一下文科班美眉,身在理科心在文嘛!上了大学就不行了,整个新校区基本上全是理科恐龙,要望只能去隔壁的师大或者“可望不可及”的外院。而且,你想想,万一哪天校园里蹦出个美女来也是狼多肉少啊,僧多粥少啊!你还没闻到姑娘的味儿姑娘就被抢走了!久而久之,对女生也就没多大兴趣了,终于进化成奥特曼了!

忙忙碌碌过了四年,毕业了,上班了。我一直以为我的大学够杯具了,上班后我发现我错了!作为一个搞挨踢的男青年,公司里的女的(注意,是“女的”,不是“女生”)竟然还不如以前上课教室里的女生多,而且结婚的结婚,生娃的生娃,有些简直都可以叫大妈了。这叫我们情何以堪?所以每天只能仰面四十五度,对着黑黑的电脑屏幕(对不起,不是哥装13,哥用的是 console 界面,而且屏幕有些高),内牛满面……

其实那段时间也不是没啥发展,我又不是太宅太腼腆太害羞的那种,偶尔碰到看得上的美女也搭讪。看看人家别人怎么搭讪:“哎,姑娘,这块砖头是你丢的嘛?” 再看看咱,挨踢青年怎么搭讪:“喂,这位女程序员同志,请问这XXX源代码中YYY文件第Z行是你写的吗?问题其实是这样的……” 结果可想而知嘛!姑娘也许会说:“你才是程序员呢,你们全家都是程序员!哥无恩!”

于是我没事还出去旅旅游,旅途上可以顺便看看有各地特色的姑娘,也确实遇到几个不错的姑娘,说中文的有,说洋文的也有,可问题是人家姑娘才认识你多久啊,总不至于跟你回西朝鲜的首都这种破地方吧?再说了我又不是犀利哥,哪有本事去勾引姑娘们来?还不如好见好散咯。所以不要动不动就喜欢姑娘!博爱可以,但要爱对地方!

转眼间时间到了去年,认识了那么一个姑娘,正儿八经的文艺女青年,学文学的,腼腆内向,有时还会害羞,聊也聊得来,说也说得开,也有很多共同喜好,总之呢,挺合适的,也挺喜欢的。可姑娘偏偏要回家考研,她又是个好学的姑娘,所以很长时间基本上见不到人。等呗,等考上再说呗,可成绩一出来偏偏又没考上,得了,北京人家不来了!散吧。

你说说,这到底是怎么回事儿捏?说我长得丑吧?不至于,咱也有好几个姑娘追过啊,虽然追我的姑娘长得确实不咋的……说我性格不好吧?也不是啊,咱虽然不算是阳光灿烂型的,可至少也是开朗型的。只要不是某些极品人士,都可以谈得来。是猿粪问题吧?对不起,我都这把年纪了,这玩意儿我早就戒了!是我要求高吧?也不高啊,只要是长得说得来的,说话谈得来的就成,这怎么说也不算挑剔吧?

唉,你说我还能怎样!神啊,赐个妞儿吧!

网络端口预留

最近这些天我在做内核的一个新功能:/proc/sys/net/ipv4/ip_local_reserved_ports,这个文件的作用是告诉内核保留一些指定的端口,这样以来对于那些使用固定端口号的第三方应用程序来说就能保证它们总是能成功使用这些端口,而不是被内核自动分配端口时抢占。

我们知道在调用比如 bind(2) 时指定端口0其实是告诉内核自动去分配一个可用的端口,这个端口是随机的,而且范围是在 /proc/sys/net/ipv4/ip_local_port_range 指定的之内。不光 bind(2),你调用 connect(2) 时也会自动获得一个端口,它也是这样得到的。所以,如果我们都使用端口0去让内核分配端口世界会很和谐,各个程序相安无事,但是很多服务器程序需要有个固定的端口的,随机分配的端口是不能接受的,于是就有了那些已知的固定端口号。问题还没解决,如果我们的服务器程序的端口号不在里面怎么办?去 IANA 申请吧,不至于,可能你的程序不够知名,或者 IANA 没有批准等等申请不上,怎么办?

一个方法是使用那个 ip_local_port_range ,把范围调整到不包含你的端口的范围。这样做有个明显的缺点,如果你的端口号正好在当前 ip_local_port_range 的正中间,那样会有一半的端口都要被排除掉了,而且很明显 ip_local_port_range 的本意也不让你做这种事的。于是就有了 ip_local_reserved_ports,引入它的目的就是为了让你在这种情况下预留端口。

我写的最初的补丁只支持像 ip_local_port_range 那样的输入格式,比如:”50000 50100”,但是 Octavian 觉得这种格式灵活性不高,如果能支持指定多个任意范围的端口号那就更好了。于是他接过我的补丁继续做,从我的 v2 一直到现在的 v6,期间经过了多次讨论和测试,现在基本上已经成熟了。如果不出意外,应该可以汇入到主线内核中。新的 ip_local_reserved_ports 可以支持“50000,50100-50200” 这种格式,可以非常方便地指定要预留的单个端口或者端口范围。

注意,ip_local_reserved_ports 和 ip_local_port_range 关系不大,前者里的端口完全可以在后者的范围之外,这么设计一是为了简单,二是为了防止竞争,你可以先把 ip_local_port_range 调整到你预留的端口范围之外,然后等写好预留端口的列表之后再把前面的范围调回去。比如我们可以这么写代码:
[bash]
from=cut -f1 /proc/sys/net/ipv4/ip_local_port_range
to=cut -f2 /proc/sys/net/ipv4/ip_local_port_range
if [ “$1” -lt $to ] && [ “$1” -gt $from ]; then
echo “$from $[$1-1]” > /proc/sys/net/ipv4/ip_local_port_range
fi
original=cat /proc/sys/net/ipv4/ip_local_reserved_ports
original=”$original, $1”
echo “$original” > /proc/sys/net/ipv4/ip_local_reserved_ports
echo “$from $to” > /proc/sys/net/ipv4/ip_local_port_range
[/bash]

archlinux 编译安装内核

一离开 Red Hat 的开发环境很多东西都不顺手,编译安装内核就是一个例子。在 Fedora/RHEL 上,直接 make install 就什么都装好了,到了 archlinux 下可就不行了,它上面没有 /sbin/installkernel 不说,制作 initrd 工具也不一样,内核 config 放置不一样,就连内核版本号命名方式也不一样。所以就得自己写脚本来搞定了。

首先,你要把 CONFIG_LOCALVERSION 和 CONFIG_LOCALVERSION_AUTO 关了,前者是加自己的版本标识,后者是使用 git 来决定当前编译内核的版本号,所以说你会得到类似 2.6.33-rc7-ARCH-00010-g6339204-dirty 的东东,很烦人,直接关掉。

然后就是内核 config 文件的放置,Fedora 上都是单独放到 /boot 下,而 archlinux 是编译进内核的,也就是说在 /proc/config.gz 里,是通过 CONFIG_IKCONFIG_PROC 来控制的。我觉得放置在哪没多大关系,咱又不差内存。;)

好了,下面就是脚本了,它可以帮你完成安装内核这个最后的步骤,有点像 installkernel。但你必须在内核源代码根目录下运行,而且假设你执行完了 make modules_install 这一步,当然了,假设你使用的是 grub。

有兴趣的同学可以把它改成 installkernel 一样的接口,这样就可以直接 make install 了。

[bash]

!/bin/bash

#

1. This must be run in the top kernel source directory.

2. Assume you already install the modules.

version=make kernelversion
cp System.map /boot/System.map.${version}

Maybe only works on x86

cp arch/uname -m/boot/bzImage /boot/vmlinuz-${version}
mkinitcpio -k “${version}” -c /etc/mkinitcpio.conf -g /boot/kernel.${version}.img

kernel_args=cat /proc/cmdline
root_device=awk '/^root/ { print $2; exit; }' /boot/grub/menu.lst
if ! grep -q “Test Kernel ${version}” /boot/grub/menu.lst
then
cat >> /boot/grub/menu.lst <<eof

title Test Kernel ${version}
root ${root_device}
kernel /boot/vmlinuz-${version} ${kernel_args}
initrd /boot/kernel.${version}.img
EOF
fi
[/bash]

Integer format conversion

我们知道 C99 中引入了uint32_t,uintmax_t 这样的标准整数类型,可有一个随之而来的问题,那就是它们在 printf()/scanf() 中对应的是 format conversion 该用什么呢?

其实这个问题由来已久,比如之前就有的标准类型:ptrdiff_t,printf()有专门的一个 “t” length modifier 来对应它。再比如非标准的 pid_t,我们是没有对应的 length modifier 可用的,这时该怎么办?其实这种问题的一般处理原则是,先把它们转化成可能的最大整数类型,比如这个 pid_t,POSIX 只要求它是一个 signed integer type,所以至少转化成 long 才比较安全,所以我们可以:

printf(“%ldn”, (long)pid);

所以我们最开始的那个问题也可以这么处理,但是很明显这种处理方式并不优雅,尤其是对于标准整数类型来说。一种解决方案是像 ptrdiff_t 那样引入新的 length modifier,但这恐怕需要增加不少,所以C99采取了另一种方式——添加标准的宏来代替直接使用字符串,比如针对 uint32_t,uintmax_t 我们可以使用 PRIu32 和 PRIuMAX,像这样:

printf(“%” PRIu32 “%” PRIuMAX “n”, uint32, uintmax);

这些宏可以在 C99 标准附录 B.7 找到,可以在 <inttypes.h> 中看到其定义(在 glibc 源代码中对应 sysdeps/generic/inttypes.h)。有兴趣的可以直接去看一下源代码,其实就是对已有的 format conversion 进行的宏封装。

那些宏也挺好记的:PRI 代表 printf,SCN 代表 scanf,PRI/SCN后面的第一个字母其实就是对应的常见的 conversion specifier,比如 uint32_t 肯定对应一个u。再后面要么对应长度比如uint32_t中的32,要么对应max什么的。

最后,对于 intmax_t 和 uintmax_t 这两个类型,printf()有对对应的 “j” length modifier 可以直接用,对于 size_t 和 ssize_t ,有对应的 “z”。

dogtail

fedora 那边一哥们在搞自动化测试的东西,今天过去看了看,发现这哥们在用一个叫 dogtail 的东西,一个 Python 模块,很酷的一个东东。看来我再一次 out 了,头一次听说这玩意儿。

这玩意儿说白了其实就是图形界面程序的自动化测试工具。我们知道图形化的程序很难自动化的,它不像命令行的程序,写个脚本就搞定了。根本原因在于,点击鼠标和敲击键盘得由人来完成。这玩意儿的目的就是代替人来完成这些功能,比如点击鼠标按某个按钮。我在前一个公司时见过一个同事搞这种测试,不过他是在 M$ 平台上测的,我一直以为 Linux 上面没这个替代品。今天看来我错了,Linux 不光有,而且还有 Python 模块。

它不光可以代替人输入,也可以输出,比如说你想读某个应用程序比如 firefox 文本框里面的文字,你也可以用它。如此一来,图形界面在很大程度上就和命令行界面变得一样“程序员友好”(相对于“用户友好”一词)了,你可以 grep 它的输出,你可以用脚本来对它进行输入。

如果你看一下它的用法,你会发现如果单单是只有接口,它也是很难用的,因为我感觉它其实是对图形程序的“元数据”(其实是叫AT-SPI objects)进行读取,在图形接口层上,所以接口很面向图形界面,除非是天天搞图形界面的开发者,其他开发者很难一下子搞清楚这些东西。但是它还提供了一个很牛的 sniff 工具,通过它你可以对已有的图形程序的“元数据”有一个很直观的浏览,你想读哪一个程序的哪一部分数据很容易找到。所以配合着 sniff,这个东西就相当好用了。

这个项目也是red hat的,其主页在 fedorahosted.org 上,也有文档示例。Red Hat Magazine 上也有一个系列来介绍它:

Automated GUI testing with Dogtail
Dogtail’s Python Modules (and how to use them)
Dogtail’s object oriented tree API (and how to use it)

贵国互联网亚克西(参赛作品)

为参加韩寒的亚克西填词大赛,小生特作词一首。本词乃原创,如有巧合,纯属雷同!

哥玩的不是词,是押韵。。。

—————————-亚克西的分割线—————————-

小屁民我今天心欢喜
高高兴兴把网上
谁知道那网站
有一半都已被屏蔽

什么亚克西
什么亚克西呀
派对的政策亚克西

连接被重置了
服务器找不到
youtube来,facebook哟
究竟是什么惹了你

什么亚克西
什么亚克西呀
派对的政策亚克西

这边有绿坝娘
那边有防火墙
动不动你们还封机房
到底是什么让你这么急

什么亚克西
什么亚克西呀
派对的政策亚克西

京字备来国字号
什么网站也逃不掉
预祝贵国大局域网
早日落成创奇迹

什么亚克西
什么亚克西呀
派对的政策亚克西

贵国互联网真开放
网上都是五毛党
就你们国情最特殊
天天强烈愤慨真生气

什么亚克西
什么亚克西呀
派对的政策亚克西

09年总结,10年计划

去年的总结还记忆犹新,今天又要写年终总结了,唉,一年又这么过去了……

首先,对照去年的计划看看哪些实现了,哪些还没有完成,如下:

>1. 找到一份新工作;

完成。在 Red Hat 做内核开发工作,对我来说这是在世界上所有开源软件公司能找到的最好的工作之一。入职近10个月以来学到了很多东西,而且工作轻松,从来不加班。(“从来不加班”居然都可以作为广告似得来炫耀,国内挨踢公司的杯具!)

>2. 找一个女朋友;

果然如当初预计,没完成。。。来年继续努力吧。谁让咱做挨踢呢,这种事对挨踢宅男来说就是整个一杯具!!内牛满面……

>3. 如果2太难实现,可考虑:认识更多的新朋友;

这个还是比较容易实现的。北京人多,所以出去参加活动什么的认识的人自然也多。非常喜欢北京那些搞户外的组织,活动氛围非常好,来年继续活动!

>4. 到更多的地方去旅游;

出色完成!:-) 今年去了美丽的云南,四川,还去了东三省,体会到了真正的寒冷。北京周边就更不用说了,逛过的地方很多了。其实按理来说来年应该计划去西藏,但是考虑到计划去葡萄牙了已经,所以去西藏的计划只好搁置到后年。

>5. 如果因为种种原因4没完成,那么一定要完成这个:学到更多的知识(不可仅限计算机);

完成一半。计算机专业知识确实学到很多,但其它的就太少了,关键是没时间看那些业余书籍,感觉学的知识越来越窄了……

>6. 如果上述目标都tmd完不成,至少至少,一定要完成这个:高高兴兴地生活。

这个完成得也可以。生活越来越简单了,不想追求太多虚荣的东西,没用!有时候能和朋友们一起吃个饭,喝喝酒,这就已经很高兴了。做好本职工作,做自己喜欢的事情,该吃就吃,该睡就睡!

综上,除了有一个半没有完成外,其余目标均实现,75分。这一年过得还算不错。所以10年的目标就已经很清楚了:

1. 找到一个女朋友,感叹号!愿春哥保佑啊!

2. 做好自己现在的工作,学到更多的东西。

3. 写的书希望可以圆满完成并出版。

4. 认识更多的人,结识更多的朋友。

5. 希望7月份可以回葡萄牙一趟;如果条件允许,还准备去山西,河南,甘肃,内蒙古等地旅旅游。

6. 学到更多的非专业知识;了解更多的“好想法”。

7. 想买一个单反,学学摄影知识;想买把吉他,重新学一下弹吉他(此条非必须)。哼,等咱吉他学好了,咱也去天桥上摆个摊儿弹……挨踢男青年中的文艺青年——男青年中的好青年!!

好了,就这些吧。最后祝各位虎年快乐,愿来年不再是茶几(摆满了杯具),不再是牙缸(本身是杯具却装满了洗具),而是浴缸(大洗具)!