过年回来没干劲了

博客也荒废了

不想干事情的状态再持续下去的话,整个人就会完全废掉了。

其实需要干的事情很多很多啊。结果都扔在那里。然后自己一个人呆在一边发呆。

需要动力啊。

最近在做图形库的接口抽象。之前做的widget引擎和图形库的耦合过于紧密了,现在想要加上DX的支持的话就相当于整个项目重写一遍。没有办法,只好想办法把图形库的通用接口抽离出来。之后用DX实现一下那套接口。说起来貌似挺容易。但是从哪个层次抽离接口呢。由于我们原来使用的是Cairo图形库,最初的想法是把Cairo的每一个API都当作是接口的一个函数。这样做改动不大,原来的代码可能几乎不怎么动就能把接口抽离。问题在于抽离了接口之后,怎么去实现…Cairo是一套平面矢量库,DX的API跟它差的十万八千里。要用非常别扭的方法才能实现那些接口。那样做的结果只有性能下降。本来用DX是要提高性能的,这样做实在得不偿失。

于是只好在较高的层面来做抽象。分析widget里面每个DOMObject衍生类使用到Cairo的函数,发现主要使用到的其实只有render和translate两个函数(其实translate本来也是属于render的一部分,后来因为通用性强才抽出来做独立的函数的),除此之外还有一些使用到的,比如getCurentRect,或者img::setSRC,这些函数其实本可以不使用Cairo,比如setSRC完全可以只是设置一个字符串路径。 到render的时候才去读取文件。这样一方面能提高些许效率(假如有人反复setSRC却不显示那个图片,其实本不需要读取那个文件),另一方面也能减少DOMObject和图形库的耦合。至于getCurrentRect之类,应该在每次render的时候将位置,大小还有mask(用于hittest)的信息存储在某处,想要获取的时候直接去用就好了。这样做就几乎把所有跟图形库的耦合全都缩小到render函数里面了。之后只需写一个公共接口,然后用工厂方法对不同的DOMObject子类生成不同的render实现传指针进去就好了。这样在有DX支持的系统上,可以使用DX,而在没有DX支持的板子上,程序可以动态适应,换用Cairo版的render实现。比较灵活。

这两天总算拖着拖着做了这么一点,接口基本上抽离出来了,但是抽出来之后发生了一些bug, 主要是TextArea和Colorize部分出了问题。争取尽快把bug解决掉好提交代码吧。。还有太多太多事情等着我做呢!!

SC AI – 微操

这个命题想了好久。实在不容易定义一个准确清晰的模型来描述这个问题。

从简单的开始吧。

首先SC地图是米字格拼成的,从每个位置向外都有八个方向。当然很传统的,每个位置都可以视为可通过或不可通过。除此之外,在可通过的位置上还有一些比如高度,是否掩护之类的一些属性需要考虑。暂时先讨论开阔地吧。

从最简单的情况开始考虑。比如红蓝两方各有2个狂徒,如何微操可以尽快消灭敌人呢?进一步简化问题,令红方谋求进攻,而蓝方决定防守。当然是将两个狂徒同时攻击对手的同一个狂徒。同时尽可能防止对手的两个狂徒攻击自己的同一个。如何做到这一点呢。假如红方在不断移动,而蓝方仅仅是站着,直到红方攻击蓝方才给予反击,那么,红方应该移动到怎样的位置时就可以决定攻击了呢?应该是红方的两个狂徒都能移动并攻击蓝方的1号狂徒,而蓝方的2号狂徒移动并加入战斗所需时间至少比1号开始同时遭受红方两个狂徒攻击晚一轮攻击所需时间。这样红方就能在攻击中占得至少一次攻击的便宜。由此看来,蓝方必须保证自己的两个狂徒之间的距离不超过红方任何狂徒到己方两个狂徒的最大值的最小值(好吧我语无伦次了)。解释一下就是红方两个狂徒到蓝方一个确定的狂徒之间的距离取最大值,而在以两个蓝方狂徒为目的地的距离之间取最小值。

橙色线表示的就是红方两个狂徒到蓝方狂徒距离的较大值。要在这个较大值中再取较小值。

显然为了做到这一点,蓝方必须移动。蓝方必须移动而保证两个狂徒间的距离没有对手到自己的距离远。这很容易做到。只需两个狂徒尽可能贴近就好了。此外当红方试图接近其中一个蓝方狂徒的时候,蓝方受到威胁的狂徒(被取了最小值的那个)向后移动绕到另一个狂徒侧面,从而使得两个距离变得尽可能相等。

假如蓝方使用这种防御方式,则红方将很难找到理想的攻击位置。但是由于蓝方为了保证距离相等必须不断移动。在移动过程中总会出现与红方距离不和谐的状态。红方只需抓住机会尽快冲上去就好了。当然蓝方鉴于此,一定不会简单的同红方对拼。而会不断后退避免冲突。无论怎样。这个最大值的最小值可以作为一个合理的AI指导原则。至于进一步的讨论要等实际测试之后再做分析了。

接下来讨论一下更多的狂徒群P的情况。想要找出一个完美的模型非常不易。可以用一条边将处于视野范围内的狂徒跟自己连起来。这样所有距离较近的狂徒就能连成一个无向图。边长表示狂徒的距离。前面说到的最大值的最小值可以用一些图论算法找出来。可是现在的问题变得非常复杂。因为之前仅考虑两个狂徒同时攻击某个单独的狂徒。而现在却需要考虑令1~n个狂徒同时攻击一个狂徒。这有n的组合种方式,还要乘以敌对狂徒的数量。这过于复杂,不可能实时计算。

采取机器学习很可能是必要的。可是如何构造决策树和估值函数却非常困扰。

现在能想到的一种简单的策略是将手下的狂徒两两结对。之后每两个一组去捕猎对手的某一个狂徒。当然过程中可以决定切换目标或者撤退。但是这种策略很可能无法发挥狂徒数量多的优势。或许可以进一步将每两组狂徒编为一个小队,每个小队去尝试捕猎对手的某2个狂徒,然后再把这两个目标分配到小组。这就形成了树状结构,像军队那样层层管理。或许这样的主意会不错。至于如何编制,以及各个级别的AI如何实现,还是等测试一段时间再总结讨论吧。

chrome无敌插件-Nothing

Nothing

有史以来最完美的插件诞生了!

他完完全全符合他的说明,他完完全全遵照需求。他不占用任何内存和CPU。他无时无刻不在尽心尽责地运行着,并且将任务完成到100%的完美,不含任何bug。没有任何程序可以超越他。

荣登Chrome Extensions排行榜前十。

评论说到:

(anonymous)
This app was amazing, probably the best extension for google chrome, recommended for all google chrome users

Voluntas
finally . . . a reason to leave firefox

而对这个神件的最佳评论应该是:

我和我的编译器

“要不然…要不然…今晚再编译一次?明早我过来看结果,好不好?”

“想编就编呗”,她漫不经心的说。

5个小时的等待…在得到确定答复之前,你永远都不会知道结果。“她编译通过了吗?”,你嚼着米饭在想。“她编译通过了吗?”,你一边走路一边想。“通过啦!通过啦!”,你从梦中发出会心的微笑。然而第二天去那滴滴答答闪着光标的屏幕前,你一定能发现一行行刺眼的红字。

我发现我的编译器是个女孩子,无论我怎么追求她,她总是拒绝我。

Don’t know how to build #^$&@.lib

光标假装认真的一下一下的闪着。“我跟你说过多少次了!”,这次我真的有点发火,“按照makefile执行!”她一定知道怎么编译的。她只是想试试我。我这样暗自想着,并且忍住偷笑。可是抬头看着那闪烁的光标,这次看起来她是认真的。她真的不知道怎么编译了。为什么在服务器上她每次都能顺利编译通过。在我这里就不行。或许她只是想要一个更刚猛的CPU,更宽敞的内存和更顺畅的网络。这是我所没有的。

重新检查,makefile, sources还有dirs,我完全没有碰过,原原本本的从服务器上拷贝下来。可是根据编译脚本本该编译出来的lib就这样神奇般的在编译进几十个exe之后,从硬盘上消失了,连一比特的碎片都没有留下。这不可能。这没有道理。要不我去单独编译一下lib?那不行,那需要太多依赖了。他们都在之前的编译环节中被删除了。我也许可以跟别人借一个lib过来。不过编译环境选的不一样,这样编出来的东西很可能不能跑。

“要不然…要不然…今晚再编译一次?”故事就这样进行着。

“现在我正编一个debug版,但是retail版也需要编译一下。一起编译可以吗?”

“没问题”,她望着窗外。

我没有自信。不过她看起来没什么不愉快。“那劳驾你了。”

第二天,不仅retail没编出来,连新来的debug也fail掉了。

Can’t open file ^*%%&*, check if other progress have opened it.

她不能容忍在我的机器上同时运行其他编译进程。

近来我发现,原来奇迹般的清除编译好的lib文件的,都是该死的杀毒软件!我错了。我不该让她跟杀毒软件呆在一起的。我把杀毒软件彻彻底底的从硬盘清除掉。就如同他删除那些lib文件一样,不留一比特碎片。还好她不会不依不饶,事情过了也就原谅了我。

我最喜欢卡夫卡的树,在雪地上横躺着一棵树。他看起来漂浮在雪面,似乎轻轻一推就会滑落山崖。不对。他已经深扎大地,深埋雪底。不过,那也仅仅是看起来如此而已。

你永远不知道下一次能否顺利编译成功。

不过,经历这些事情,我更加牢记了程序员的三大定律:

1. 她永远不会犯错

2. 如果犯错都是我的错

3. 我一定会犯错

以上

SC经济学

今天考虑了一下最基本的SC经济学。

我把这个问题设定为:在给定的时间Te之内,怎样做才能得到最大化的采矿量。

首先不考虑卡人口卡矿的问题,就是说一直不停的造农民,不造水晶,造农民的时候钱也总是够用。那么需要知道的几个时间是造农民的时间Tscv,农民采到以块矿的时间Tg,他还细分成移动时间Tgm和采集时间Tgg。于是矿从和基地的距离Lm和农民的移动速度Vscv成为需要知道的参数。Tgm = Lm/Vscv。Tgg和Tscv可以在游戏中实测得到。那么我们的第一个问题就是一个矿从需要多少农民。根据经验的话,当基地和矿从的距离最近的时候,一个矿从3个农民比较合适。如果用计算的话,就需要知道,采矿时同一个矿从的几个农民之间的距离是多少。想象两个农民都挤在一个矿从前面,一个开始采集,一个等待。当采集的那个农民离开的时候,等待的开始采集。经过了Tgg时间,离开的农民移动了Tgg Vscv距离,而等待的农民恰好开始移动。所以一个矿从所能容纳的农民数量是2Lm/(Tgg Vscv)。向下取整是经济值(没有农民等待),向上取整是最大值(每个矿从最多有一个农民等待)。更多就是浪费了。

那么在这个理想模型下,到达时间Te能采多少矿呢?到矿从饱和之前,假设训练了n个农民。这一共花了n Tscv时间。在这段时间内的采矿量是个等差数列求和,因为从第5个农民开始,每个农民的采矿量都比前面一个少Tscv时间所能采的矿量。总共少了(n-4)(n-5)/2这么多。所以总的采矿时间就是T’ = Tscv(n·n – (n-4)(n-5)/2)。在加上矿从饱和之后的采矿时间n(Te-T’), 可求出总采矿时间Ttotal。再用采矿量M=Mg Ttotal/Tg可求出总的采矿量(Mg=8,每个农民一次的采矿量)。

现在我们来考虑到Te时矿从没有达到饱和的情况。这个样的话应该什么时候停止造农民呢?因为一个造一个农民的消耗是Mscv=50。而一个农民一次采Mg=8的矿。因此要让这个农民“盈利”,需要他采Tg(Mscv/Mg)的时间,向上取整是7Tg。也就是说,假如准备造第n个农民的时候,所剩的时间小于7Tg,则应该停止造农民开始憋矿。这样的话就应该造(Te-7Tg)/Tscv个农民,向下取整。仍然可以用前面的采矿时间-采矿量方式计算总量。

我们继续考虑卡人口卡钱问题。。啊我前面农民都用scv表示了,就这么将就吧。接下来以神族为主,因为神族的建筑方式比较简单,并且我们参赛也将以神族为主。其实经验告诉我们,当Te比较大时(也就是说不快攻时),8BP是最好选择。这是因为8BP卡钱不多,并且Tscv的时间加上因为卡钱等第9个农民的时间跟一个Tpylon的时间差不多,因此卡到第10个农民的时间也不多。不过这里面的计算确实开始复杂起来。要仔细分析的话,首先需要知道任意时间Tr的时候手上的现钱有多少。根据前面的分析,这个时候的总采矿量已经知道,再减去造农民和水晶花掉的钱,就是手上的现钱Mtr。用Tpylon/Tscv得到造一个水晶的时间相当于造多少个农民。这里向下取整后,把余下的时间也记录下来。因为考虑到卡钱的问题,时间很可能刚好凑够。用Mtr-Mpylon 得到从这个时间开始造pylon剩下的钱,并计算Mtr-Mpylon-Mscv得到卡钱的量,并以当前拥有的农民数量估算卡钱时间(理论上讲,根据农民的出生时间和选择采矿的矿从可以计算出来他的位置和状态,并且精确的计算每个卡钱的时间。不过这些计算实在复杂,并且我们有API嘛,这些数据可以游戏时实时得到,就无需我在这里静态的去计算了……不过以后可能还是会把这里的一些公式补上,因为我们还是需要估计对手的矿量吧)。最后总的采矿量就是前面理想模型的总矿量减去这里卡钱卡人口时间里一个农民的采矿量(被卡的那个农民)。当Te较大的时候,采取这个策略总是最经济的,可以称之为经济策略。因为假如矿不够硬憋钱憋到Mpylon然后造水晶,之后又需要憋钱等农民,卡农民时间必然更长。并且经验告诉我们等到Mtr够Mpylon的时候,一般来说不会出现卡人口的情况(比如8BP,神族基地提供9人口)。但是当Te较小的时候(快攻),很有可能为了快出狂徒而停农民憋钱(比如经典的6BP)。因为这里我没有考虑这个问题,所以暂时不推了。

呜写到这里也累了,下次再来考虑血量伤害等的计算公式吧。

谷歌撤离中国及其他

最近网上闹得沸沸扬扬的就是谷歌撤离中国这件事情。这件事情的起因和经过过于扑朔迷离,各种分析和“解密”满天飞,但是由于到处充斥着美分和五毛,所能相信的实在不多。仅有这篇New Approach to China是Google的官方blog, 可以参考。

文中最使我关注的就是,为什么Google要强调是“人权活动家”的邮箱受到了攻击,还有他们为什么认定攻击来自中国政府。至少,他们确定了受攻击的邮箱是“人权活动家”们的,至少说明他们看了绝不止一封受害人的邮件,而是几乎全部。前阵子大家都说聊天信息或者邮件会遭受政府审查太可怕了,要加密怎样怎样,想想看Google的那些员工随时都在“审查”你的邮件,你到不担心了,岂不可笑。也许你说,Google员工没有政治目的,可是假如你知道你的邮件都是赤身裸体躺在Google的服务器里面,你还敢写私人信件吗?你还能相信任何一个邮件服务商吗。最后,大家不要忘记了,美国是有“爱国者法案”的,凡是Google能够看到的东西,一切都在美国的眼皮底下。然而,假设Google的blog说的是事实,中国政府试图侵入Google邮箱失败。就是说美国时时刻刻都盯着的大笔邮件,对中国是完全屏蔽的,这样一来在中美两国的国家政治较量中,中国就处于严重劣势。难道你一方面激烈反对中国的邮件审查另一方面却容忍美国看你的隐私吗?这简直连美分党都不如。况且很早就听说美国禁止商业加密算法超过128位(可能后来又更新了),就是因为美国的情报机构无法在有效时间内破解比那更大的加密信息。其实全球的通信都在美国掌握之中。还有就是英国的情报机构,这个闻名遐迩了吧,当年图灵呆的地方,二战曾破解德国的恩格码。这是监听全球通讯的另一个岗哨。我也反对政府监听平民的通讯,但是假如美国和英国都在监听,而中国监听不到,这就使中国的国际形势处于劣势。

有人说,Google撤离中国会打破中国与西方近30年来的“和谐”,太愚蠢了。中国和西方,什么时候和谐过。想想某某功,想想西藏新疆台湾,哪一件事不是西方在捣乱。李大师不是逃到美国去了吗?烧死中国几万无知百姓,难道看不出这是谁在捣乱中国政治?某喇嘛,是谁动不动要接见他,动不动要给他和平奖?新疆,我的线索不多,不过跟西方肯定也有关联。毕竟东突已经到了中东地带了。而中东正是西方热切盯着的一块肥油。至于台湾,就不用说了吧,前几天还有人想卖给他废旧武器。。

自由,人权,固然是我们所向往的东西。监督权,言论自由的权利,固然是我们应该行使的权利。但是西方自由世界,为什么想把这个意识形态强加到我们头上,难道是为了纯善?想象力丰富的中国人民能在阿凡达中看到拆迁,就看不到西方自由世界用暴力毁灭另一种意识形态的野心和原罪?

用民主和自由的假大空的口号动摇中国政治,用房地产、石油和证券要挟中国经济,用假意的伪善和美分党博得中国舆论和民意。接下来美国要干什么呢?假如中国政府失去对市场的“社会主义”控制,让他完全资本化自由化,中国就完全失去对资本的控制了。因为资本市场是遵循达尔文主义的,拥有更大资本的人必胜。或者说,美国和他操纵着的无数金融大鳄必胜。中国经济崩盘(尤其是房市崩盘),企业倒闭,群众失业,加上之前政府已经不稳定,必然导致政治的瓦解和混乱。美国或许就能趁机扶持傀儡政府,永远的把中国变成他的廉价劳动力市场,生产车间和垃圾处理厂。有人以为房市崩盘了就能买到房子了,这是在做梦。房市崩盘的时候你就失业了。并且那时候你手里的钱都贬的连柴米油盐都买不起,还想买房子。。。

或许有人说,中国政府太腐败了,还不如让美国来治理我们。你们太天真了。美国才不会把他们国家的福利搬到中国来。假如中国政治混乱,经济崩溃,美国从中坐收渔利,只不过是把中国的利润带回美国而已。顶多在中国扶持一个傀儡政府,还不是一样的贪污腐败。民主是要的,监督也是要的,但是这些权利应该是我们自己来争取,而绝不是依靠美国来“解放”。

好吧,说到这里大家都觉得我是五毛党了。我是反美分党,但我也不相信五毛。看看现在网上的论战,简直是傻的一塌糊涂。我绝不希望美国毁灭中国的稳定,但我同样痛恨建立在这个“稳定”之上的贪污、官僚和愚蠢。有人嘲笑中国法律,难道是中国人不懂法吗?不是,而是中国没有法律。因为立法人、执法人和监督人,也就是人代会、国务院和检察院,都接受党的领导。大家都是一家人。自己定规矩,自己执行,然后自己监督自己。这样的政治体系下面根本不可能有法制。有人说重庆打黑是”回归人制“,其实去掉回归二字就可以了。中国从来就没有法制过。比如我们最痛恨的GFW,这个东西合法吗?没有人可以去质问这个问题。因为假如他不符合以前的法,只要下次把法律修订一下,重新出台一个啥补充说明,他就又变得合法了。不过话又说回来了,监督人也不回去质问,谁会自己质问自己呢。

我只是说,现在管理我们的政府和假如他崩溃了,美国搞个傀儡,其实没什么差别,就是一个地狱和另一个地狱的差别而已。然而大家应该都明白的,治世绝对胜于乱世(比如国民党治国能力或许不比共产党差,但是国民党在乱世,周围都是不可抗力,所以二战时期搞得乌烟瘴气不得人心)。绝对不要被谣言和美分五毛迷惑,被“少数”人煽动,把稳定扔掉了。连秩序都不存在的空洞的自由和民主,只会是个比现在更差的地狱。要争取自由民主,要学习甘地、曼德拉,用正义唤起民知,和平和稳定的迎接黎明。

否则无论你的口号是什么,最终得到的都仅仅是暴政。

好吧其实我也不过是个无知屁民,我所知道的信息也是非常有限的,仅有CCTV也好NY也好华尔街也好得来的一点点消息。不管哪一方面的消息都是加工过的,都是不可信的。但是把前前后后的事情放到一起总结,就能看出问题的轮廓。我只是看到网上太多喷子都在胡说八道,肯定是接受了美分五毛在“引导”(误导)舆论视听。尤其这次Google退出中国,明显是利用中国的大批狗粉对中国进行舆论施压。真不想看到更多的群众被煽动被利用。(有人说群众眼睛特别雪亮不容易被煽动,这纯属胡说。否则网上哪来那么多跟风帮顶哪来那么多SB呢。。绝大多数的人只是图一时口舌之快,打倒日本帝国主义连带砸了日本店抢了SONY WALKMAN,谁会细想这背后的动机和结果呢。。现在网上冷静的声音太少,这才最可怕。我也仅是自言自语,我不期望说服别人。我只期望更多的人能自己冷静分析,得出自己的结论。不要跟风,被煽动。)

以上

中伊网战和DNS

今天见识到了国家级的网战较量。结果也不过于DNS攻击和DDOS。

硬件的问题是没办法说了,那个相当于军备竞赛,蛮无聊的说。DNS劫持就比较有趣。毕竟DNS只不过是一个电话簿。攻击了电话簿既没影响网站也没影响用户和中间的信道质量,其实影响力本不会这么大的。要说直接攻击一个网站,要破解服务器密码,或者通过系统漏洞拿到系统操作权限,对于成规模的企业级应用已经相当不易,更不要说国家级网站。不能钓鱼成功或者通过所谓“社会工程学”得到一些情报的话,直接攻破异常困难。像今天这样几个小时搞定一个网站估计是不太现实了。由于DNS服务器不断监听网络DNS报并且不断更新自己数据的这个“易变”的特点,才使得DNS攻击变得异常容易。

其实之前GFW不也是大量采用DNS劫持的手段嘛。那时候我就想过,如果DNS服务器能够分成动态和静态两套互补的体系,则安全性更强不易遭受攻击。(当然政府直接施压你就没辙了。。这个属于“社会工程学”范畴。。)静态DNS是记录长期稳定的DNS路由,不能轻易更新,也不会遭受突如其来的DNS污染。因为新来的DNS不会被他识别为“稳定”的,因此他会拒绝更新。而动态DNS部分则如传统DNS般不断更新。这样一旦出现DNS不稳定的情况,可以通过人工介入的方法(除了可以让管理员手动开启外,也可以考虑让访问用户举报这种方式。但是举报者又可使用DDOS来进行攻击,但攻击结果也不过是转成静态路由而已,对他们的好处不大),强制使用静态路由。当然使用了较为稳定的静态路由的缺点就是速度可能会严重下降。但这也是为了安全性而做的一点牺牲嘛。DNS机制没有仔细研究过,没办法直接在这里提出相应算法和解决方案。不过相信这个思路肯定是可行的。如果研究生期间还没出现类似产品或论文的话,我可以考虑做这方面的研究哈哈。。

另外,除了公共DNS服务可以静态化之外,个人host也可以静态化。这个我也很早就在想了,可惜一直没实际做出来。就是不断读取浏览器访问的域名和IP,然后全都记录下来。一旦发现域名劫持,可以把过去记录下来的域名/IP对导入host中去做一些尝试。一般来讲,封锁IP的速度会慢于域名劫持。所以在域名劫持之后原来的这些IP或许还有可以访问到的。当然啦,如果政府真的下力打击的话,这些IP早晚也还是会封光。。不过,至少。。还有喘息的机会嘛留一丝丝。。

对了对了,补充一点,本地记录IP,对一些公共DNS崩溃造成网络拥堵的情况也能缓解不少问题。甚至每个PC都可以成为一台小型DNS服务器。这样就像p2p的思路一样,大家互帮互助来进行DNS解析。当然大型公共DNS服务还是主力啦。

好吧今天看到DNS争夺战这么激烈,忽然想到以前想过的一些idea,算是做个记录吧。

消息派发转为对象方法-用对象处理窗口消息

前两天听了组里的TechTalk,正好讲到ATL里面怎样做窗口消息的派发的很有意思。
一般来讲,用对象来窗口消息有个通病,就是很难解决HWND和对象指针之间的mapping问题。通常的做法可能是使用一个全局的哈希或其它数据结构来存储所有HWND和对象指针之间的一一对应关系。与其凡是要做窗口的对象封装的时候都去重新发明轮子,不如直接使用ATL。

ATL的做法比较有趣,他没有维护这样一个数据结构来存储HWND和对象指针之间的一一对应关系,而是使用了一些trick,把一小段代码使用setwindowlong设置成那个窗口的winproc。在这一小段代码里面,他会把这个winproc的参数栈做一个修改,用两句汇编指令,把第一个参数HWND hWnd替换成this指针并跳转到相应的winproc中去。而那个winproc会首先将第一个参数static_cast成自己窗口类型的指针,并根据需要调用相应的消息处理函数。

至于实现这些的具体细节,我记忆力不好没有完全记住,不过网上有很多相关文章也无需我多述。大体上说他在createwindow的时候将该窗口对象的指针和创建它的线程编号放入一个全局数组(以此来防止不同的线程同时创建窗口而可能造成的冲突),并把一个叫做StartWindowProc的初始化函数用SetWindowLong设置成该窗口的消息处理函数(这个函数其实只会进入一次)。这个初始化函数在第一个窗口消息发生的时候(即该函数首次进入),会去计算窗口指针和他的成员消息处理函数的位移,并生成那一段汇编代码的thunk,并将他的地址插入到消息处理函数处。此后再进入消息处理函数就会经过这段thunk从而使第一个参数变成了相应对象的this指针并跳转到相应的真正的消息处理函数。

不过这个方案也有一些问题。比如,那段thunk是当作窗口对象的成员存储在数据段的。有些系统会禁止在数据段运行code。在这类系统上需要另外开一片有执行权限的内存,然后把这段thunk放到那段内存中去。还有就是不同的CPU指令是不同的,必须为每一个目标系统写对应的thunk指令段。有比如他在createwindow的时候把窗口指针放在全局链表的头部,之后再首次得到消息的时候从头部开始找属于该线程的第一个指针进行配对。虽然加上了线程id来保证不会有同时创建两个窗口造成冲突误判的问题,但这里面仍然有安全性的concern。(线程ID和窗口句柄的长度都是4字节,为何存储的是线程指针而不是窗口句柄呢?我在talk中没有想到要问这个,这个也许有其他方面的concern吧。。)

另外就是talk中提到一个细节比较有趣,就是如果使用模板的话,多态可以不使用虚函数实现,而使用模板。


template <class T>
class base
{
public:
void print()
{
static_cast<T*>(this)->print();
}
};

class derived:public base<derived>
{
public:
void print()
{
print("hello\n");
}
};

这样做因为转型都是编译期完成的,可以减少继承带来的运行时负担。

ID秀

reddit上有一个组织大家说出自己ID含义的帖子,蛮有劲的

mandolinhero
|-----------------|-----------------|-----------------|-----------------|
|-----------------|-----------------|-------------0---|-----------------|
|-------0-2---2-3-|-2-0---2-0---2---|-------0-2-5---5-|-2-0---2-0-------|
|-2-4-5-----------|-----5-----5---5-|-2-4-5-----------|-----5-----5-4-5-|

曼陀林英雄回了一首歌

comment-repeater
|-----------------|-----------------|-----------------|-----------------|
|-----------------|-----------------|-------------0---|-----------------|
|-------0-2---2-3-|-2-0---2-0---2---|-------0-2-5---5-|-2-0---2-0-------|
|-2-4-5-----------|-----5-----5---5-|-2-4-5-----------|-----5-----5-4-5-|

于是评论复读机就把他复读了一下

Hibernator
Pretty music makes me sooo … sleeeepy …. zzzzzzzz
冬眠家说:优美的音乐搞得我好困啊zzzz

hush_hush
Shhhhhh
嘘~说:嘘~ ~

IAmARealDoctor
You have cancer.
我是个纯医生说:你得了绝症

rocketsurgery
You have moon cancer.
火箭医疗师说:你得的是月亮癌

TheG00GLE
Did you mean: You have a new form of cancer
google说:您是不是要找:你得了一种新类型的癌症

i_just_lost_the
game
我刚刚输掉了说:比赛

winrar
And I won!
winrar说:是我赢了!

deltageek
Are you sure it’s not lupus? I think it’s lupus.
delta奇客说:你确定这不是狼疮吗?我觉得这是狼疮。(不是啥月亮癌)

contrarian
It’s never lupus.
反对主义者说:这从来就不是狼疮。

beta_pup
I’ll never be the alpha dog.
beta狗说:我从来就不是alpha犬

RandomNoises
woof woof
随机噪声说:呜呜

ButteredPotato
steams
黄油土豆说:蒸了

Veggie
You’d go good with some carrots or broccoli.
蔬菜说:你跟胡萝卜或西兰花一起吃,味道肯定棒!

来源:http://www.reddit.com/r/reddit.com/comments/aly4i/say_something_in_character/

数格子

我发现程序员最经常干又不太容易弄对的一件事情就是数格子。所以得好好整理一下。。
好吧,也说不上不容易弄对了。。是我智商太低总也弄不对。。。不能因此就认为别人也弄不对。。

举个最简单的例子。你有a个格子,要从第b个开始(包含)连续搬c个,怎么搬。
简单嘛,从b开始,到b+c和a中的较小值(不含)(注意b是从0开始计算的序号,并且0<=b<a ,a和c都是正整数)
搬动的区间是[b,min{b+c,a})

其实a,b,c都是我命名很完好的变量名:allitemNum, begin, count.恰好abc了。不知为何这么巧。

然后遇到一个反过来的例子,就把我搞晕掉了。还是这a个格子,但是这回要从后往前数第b个,连续向前搬c个。
我承认。。这个问题我反复搞错,整整弄了一天时间。。确实是智商有问题吧。。
先找出来这个反过来数到b,他的序号是多少呢?
数到b,所以是b+1个格子。于是前面差了a-(b+1)个格子。这么多格子里面并没有包含反过来数到b的那一个。如果要包含他,还得加一。于是包含反过来数到b的那个格子,从第0个到他,一共是a-(b-1)+1个格子。序号就应该是a-(b-1)+1-1,简单来说就是a-b-1。
(再次承认我肯定是想麻烦了。。不过就是想不明白。。画了好多图了。。哪位智商高的给我指条明路。。)
然后还需找出在向前数c个,那个格子在哪里。
这回好办了,到第b个总共b+1个格子,在向前数c个就是b+c+1个。他的序号是b+c。把这个序号替换掉上面的b就得到a-b-c-1。
要注意上面那个a-b-1这个格子还是要包含的(要搬走的),所以再向后续一个格子。而前面这个起始点,必须比0小。
于是得到搬动的区间是[max{a-b-c-1,0},a-b)

呼,就这么简单的几句话,想了我一整天。。真是糊涂啊糊涂。。而且到现在都想不出合适的理解这些代数的方法。。只能硬推。。肯定是小脑发育不全。。

能记录下来的还有一些可以算是定理的东西吧。就称之为数格子定理好了。

用两个序号相减,得到的是两个序号之间的格子数量,包含前端不含后端。
比如。。8-3=5
0,1,2,[3,4,5,6,7),8,9

因此同理,从某个序号加上一个数量,得到新的序号是包含他自己向后数那么多个的序号,含前端不含后端。

3+5=8
0,1,2,[3,4,5,6,7),8,9
8+(-5)=3
0,1,2,3,(4,5,6,7,8],9

总数量为a的格子里面,b与a-b-1轴对称
10-2-1 = 7
0,1,[2],3,4,5,6,[7],8,9

最后就是编程技巧,要搬格子的话,先算好区间[b,e),之后好办

for(int i = 0; i+b < e; i++){
dest[i] = source[b+i];
}

好吧再次承认这么脑残的东西我也搞不明白实在太傻逼了。。不过咱就是傻逼怎么着了!!
上次还遇到更傻逼的事情

UINT a = 2,b = 3;
if(0<a-b){...}

结果居然这个判断就掉进去了。我百思不得其解。为什么0<-1居然能是true呢,为什么为什么呢。。
终于悟了unsigned int 没有-1, -1是最大值。。。哭死。。果然还是上课没认真听讲下课没好好完成作业啊。。
这也是一个问题,就是格子的序号一般怕太多格子数不完了都用unsigned int的。但是一般也可能会需要用序号相减来计算之间的格子数量的情况。结果这里面就产生了矛盾。当然经常记着去比较一下大小先还是对的。但是那样也还是很麻烦哪。。。