mac下利用国外的vps建立代理翻墙

现在很多人都有国外的VPS了,那么我们可以利用它建立SSH隧道代理来实现翻墙,解决很多国外网站上不了或间歇性不能访问的问题。

1、首先到http://nihilex.com/secret-socks去下载SecretSocks并安装。

2、运行之后,在SSH hostname中输入自己vps的ip,在Port number中输入ssh的端口(如果你没有改过的话是22),然后在Username中输入可用ssh登录的用户,在Password中输入密码,然后点击Connect按钮。如果看到绿色的对号,说明连接成功了。

3、配置浏览器中的代理,不过我的chrome和safari都自动发现了代理,不需要特别配置就可以使用了。如果你使用的浏览器没有,那么就手动设置一下代理服务器为127.0.0.1:9999。

需要注意的事项:只在需要翻墙的时候Connect,不需要翻墙时记得Disconnect,否则访问国内的网站会很慢或打不开,而且VPS的流量一般是有限的,需要节约使用。

人生如游戏,请随时存盘

我为什么要写文章?

不知从何时起,我开始记录自己在各个游戏上的经验心得,写了一篇又一篇的教程。将自己脑中思索已久的想法、探索的经历、实践过的经验写出来,实在是一件很快乐的事情。为了这种快乐,我宁愿花无数个小时去码字,排版,配图……

我不禁要问自己,这种快乐的来源是什么?

人的本性是自私的,我也不会例外。为什么把自己辛苦得来的经验分享出来,会让自己得到快乐呢?是为了获取别人敬仰的目光,满足自己的虚荣心吗?还是好为人师,想体验那种优越感呢?

我找到了另一个答案:为了证明自己的存在

那些分享经验心得的文章,证明我曾在这些领域努力过,证明我在那段时间里存在过。这些文章可能会帮助到一些人,也可能会误导一些人,但我的思考和实践会对他们有一定的参考价值,可能会帮助他们解决问题,减少他们犯同样错误的可能性,或者给他们不同思路的启迪。

在一个人的生命中留下你的足迹,使他的生活变得更美好(节省时间、减少痛苦、欣赏美丽……),哪怕施加的影响是极其微小的,这就是你存在的价值。如果你能持续这种影响力,那么你的生命就是不朽的,你就在世间永存。

准备随时死去

人类之所以有别于动物,就是可以通过语言和文字将自己的经验和思想传承下来,而子孙后代通过学习可以快速掌握几代人穷尽一生才探索到的知识。一个人的生命是有限的,而其人生的价值就在于留给后人的东西。

相信玩游戏的朋友们都知道Save / Load大法,其实人生也是一样。

我永远无法知道明天会发生什么事情,自己的生命可能在任何一秒钟终结。而当我死去的时候,我的肉体,拥有的能力,掌握的知识,以及脑中的各种思想都将不复存在。这个世界上我所存在的证据,就是我创造过的一切。我写的文章,我画的画,我写过的程序……

我不希望在死去前那一刻,想到自己还有很多想法没有说出来,还有很多事情没来得及告诉别人……那是多么绝望和痛苦的感觉?那种感觉就像写文章写了几千字,突然停电了才想起没存盘一样。

所以我工作时会建立文档,记下只有自己掌握的知识和工作流程,在必要时可以随时交接。写代码时要经常重构,保证可读性并把自己的思路注释清楚,保证自己可以随时离开。

当我把自己知道和想到的东西都写下来时,我心中感到无比地踏实和满足。就像刚刚离开一个存盘点,在未知的领域迈出新的一步一样,我不惧怕包括死亡在内的任何危险,因为我的经历和成就已经保存下来了。

“随时存盘”是一个好的习惯,游戏一样,工作一样,人生也一样

论六色底及其对比赛公平性的影响

更新:根据在微博上的讨论,我收回关于六色底影响比赛公平性的观点。感谢@铯版 @樊轶群 @冰菓不是水果 @Lazy_锋 @反叛的撸撸咻专四跑题给跪 @陳丹陽_占星 @阳光丶灿烂了 等朋友参与讨论。

所谓六色底,是指由双色底(又称对色底)发展而来,并由现三阶速拧世界纪录保持者Feliks Zemdegs发扬光大的一种技术。具体来说就是在开始还原魔方前,从六种颜色中选择一个作为底色进行还原

目前六色底正在全世界范围流行,我个人也曾练习过一段时间,并尝试在几次比赛中使用六色底。接下来我想谈谈六色底的本质,对比赛公平性的影响,以及自己对这种技术的一些看法。

十字的重要性

就目前最流行的CFOP还原法来说,整个还原过程中最重要,也是最不稳定的部分就是十字(Cross)以及和第一组F2L的衔接。其余的三组F2L,以及接下来的OLL、PLL对一个公式量丰富的玩家来说,是相对稳定的部分。

十字的难易程度取决于打乱case,是完全随机的。如果十字步数少,手法顺,对case的扰动少,第一组F2L就容易计算和观察,也容易直接和做十字的流程连贯起来。反之如果十字步数多,对case的扰动多,第一组F2L的计算观察难度就会大大提高。

因此十字的难度会直接影响到第一组F2L的衔接,进而影响本次还原的成绩。

多色底的本质:换打乱

在多色底技术普及之前,魔方玩家一般都只使用一种固定的颜色作为底色(比如我使用蓝色)。同一个打乱case对使用不同底色的玩家来说其实是完全不同的两个case。

对同样的一个case,白底的十字好做,出好成绩的几率就高,蓝底的十字难做,出成绩的几率就低。这也往往表现在比赛中,采用某种底色的选手们在某个case上的成绩普遍提升,而采用其他底色的玩家则发挥平平。

不知是哪位玩家灵机一动,想出了双色底这种技术。比如使用白色底的玩家,通过练习可以很容易掌握黄色底。这样在打乱case对白色底十字不理想时,可以换用黄色底还原,因为黄色底的十字会完全不一样。

这其实在无形中满足了很多玩家的梦想“这个打乱不好,要是能换一个就好了”。虽然WCA比赛规则是不允许选手提出无故换打乱这种要求的,因为这样会对其他选手不公平。

然而,如果你使用多色底技术,在15秒的观察时间里,你可以自己换打乱!

WCA需要修改比赛规则,以维护比赛的公平性

从公平意义上来说,所有选手在同一轮比赛中应该面对同一个打乱case,这样选手的成绩才可以进行比较

按照目前的WCA比赛规则,打乱公式随机生成,并以“白上绿前”的初始状态进行打乱。表面来说每个选手拿到的是同一个case,但是对使用不同底色的选手来说,其实面对的是不同的打乱,比赛的公平性值得商榷。而允许多色底技术在比赛中使用,会进一步影响比赛的公平性。

在此我建议WCA对比赛规则做出以下改进:

1、选手在比赛前需要申报自己使用的底色。

2、打乱员根据选手申报的底色进行打乱,保证每位选手最终面对的是同一个打乱。

3、裁判则需要监督选手是否按照申报的底色进行还原,否则成绩作废。

我对多色底技术的看法

我相信WCA在最初制订比赛规则时,没有想到会有人使用不同的底色,更没有想到会有人能同时使用多种底色,所以比赛规则出现了一些漏洞。

所谓的多色底技术,其实是利用比赛规则漏洞进行的一种投机行为。而在有选手开始使用双色底后,WCA对这种现象没有任何警惕,以至于愈演愈烈,直至发展到现在的六色底。

诚然多色底是一种很有趣的玩法,自己平时练习娱乐都没有问题。但是在比赛中不应该允许使用多色底,因为它对使用单一底色的玩家不公平

不引入依赖库,细粒度管理js代码

在一个项目刚起步时,往往除了jquery之类的库外,只有一个js文件。

然而随着功能的不断增加,js代码也会不断膨胀,当多到一定程度后(500行以上),维护难度就会大大增加。组织逻辑混乱,debug时很难迅速定位到想修改的地方,写新function时也很难抉择插入的位置。整天在一个长长的js文件里滚来滚去,想想都让人头疼。

一个可选的方案是使用依赖库,诸如requireJS、SeaJS、In.js等等。但需要引入更多的代码,要抽出精力来维护依赖关系,还会增加额外的http请求。

在大多数情况下,js代码不会膨胀到必需引入依赖库的地步。有没有办法可以在不增加新代码和http请求的前提下,对js代码进行细粒度的维护呢?

在目前的项目中,除去jquery等类库后的js代码约有120kb(压缩后58kb),我们使用这样的方案:

1、按模块或者按性质将js拆分成多个文件,比如将和用户相关的部分抽取出来成为user.js、共用的方法抽取出来成为helpers.js等。

2、编写sh脚本(linux)或bat脚本(windows)合并所有js为all.js,并调用yuicompressor进行压缩生成all-min.js。

//windows下的bat脚本
del all.js all-min.js
type source\*.js > all.js
java -jar yc.jar --preserve-semi -o all-min.js all.js

3、在开发环境使用all.js(方便deug),生产环境使用all-min.js。

 

用Win+R启动常用软件及文档,提升工作效率

我们都试过用开始菜单、桌面图标、快速工具栏、辅助桌面管理软件等来管理常用软件,在Win7下还可以直接固定到任务栏,然而这些方法都有或多或少的瑕疵:

开始菜单:第一级可用位置太少,多级的话查找太慢
桌面图标:软件多了之后太乱,难以整理
快速启动栏 / 固定到任务栏(Win7):挤压占用任务栏空间
辅助桌面管理软件:需要安装多余的软件,可定制性差

试验过以上所有方法后,我选择了使用StokeIt以及Win+R法来管理和启动常用软件。这篇文章就来简单介绍一下我使用Win+R法的一些经验。

Win+R法简介

通过在环境变量PATH中添加一个目录,然后将常用软件及文档的快捷方式(.lnk文件)重命名为1~2个字母缩写放入该目录,要启动软件时按Win+R启动“运行”对话框,然后键入自定义的缩写再按回车即可。

详细的入门教程请看善用佳软的文章,本文只总结自己的一些经验。我的习惯是在D盘下建立一个Command目录,然后将所有快捷方式都放在此目录下。

创建对自身的引用

这个目录要经常维护,所以先要为自己建立一个快捷方式,我将其命名为go,并放到Command目录下。之后要维护快捷方式直接Win+R go回车即可。

分组管理快捷方式

在“运行”对话框里是可以直接打开环境变量PATH中定义过的目录下的子目录的,所以在Command目录下可以建立目录对常用软件进行分组。比如我因为工作需要安装了大量的浏览器,而这些浏览器只有在测试的时候才用到,所以我不想给每个浏览器都建立一个缩写,而是建立一个br(browser的缩写)目录,并将所有浏览器的快捷方式都放在br目录下。在需要测试的时候Win+R br,然后选择启动需要的浏览器。

使用批处理

在Command目录下编辑BAT批处理(类似Unix下的shell脚本),可以实现更强大的组合功能,比如创建一个这样的test.bat,使用start命令来一次运行多个软件:

start cr.lnk
start ie.lnk
start ff.lnk

这样通过Win+R test可以同时打开chrome、ie和ff三个浏览器(当然前提是要在Command目录下建立好cr、ie、ff这三个快捷方式)。注意在命令行模式下是不能省略.lnk后缀的。

快速连接远程桌面

第一步:在“运行”中启动mstsc,点击“选项”,输入ip地址,取消勾选“始终要求凭据”。连接并登录一次。

第二步:在C:\Windows\System32目录下找到mstsc.exe,创建一个快捷方式到Command目录,改一个合适的名字(建议以ip最后一节命名,比如ip为10.0.0.88,则命名为88)。右键编辑其属性,在“目标”中的System32\mstsc.exe后加上格式为“/v:IP地址:端口号”的参数,比如“System32\mstsc.exe /v:10.0.0.1:3389”(如果没有修改过远程端口号,也可以省略后面的冒号和端口号)。当然也可以创建BAT文件,里面写上start mstsc /v:10.0.0.1:3389)。

之后只要Win+R 88就可以连接到远程桌面了。

管理网站账户密码

有的网站可能一年半载去不了一次,但是还是需要注册登录(比如csdn下载站-_-)。大多数情况下不同网站下的用户名都会有所不同(比如zhangsan123,zhangsan1986等),一般对这种不重要的网站我们都会使用比较容易输入的短密码,但由于各网站密码规则的不同,最终密码还是会不一样。记忆这些用户名和密码纯粹是浪费脑细胞!

这时最好的方法莫过于建立一个密码本了,在需要登录的时候打开看一眼或者直接Copy & Paste。我的习惯是在Command目录下建一个p目录,然后在里面建立txt文件,文件名为网站域名(注意去掉www.),内容为用户名和密码。

这样当我要登录一个之前注册过的网站时,只要Win+R p,然后输入域名前几位,就可以迅速定位到对应的文件并打开,拿到帐号和密码了。

当然了,你轻松,别人也轻松。比较重要的密码(如qq、邮箱、网银)不能放在这里!

使用StrokeIt提升工作效率

StrokeIt是一款鼠标手势软件,可以将用鼠标右键画出的手势绑定到许多常用的操作,如关闭/最大化窗口、启动程序、触发快捷键等。

下载地址和新手入门可见善用佳软的这篇文章,我就不再重复了。

这里和大家分享一下我使用StrokeIt的一些心得吧。刚接触这款软件时,有点走火入魔,把所有常用软件都绑定到手势,恨不得把所有的内置手势都利用上,甚至还自创了一些手势。结果是大部分的手势都很不常用,加之后来采用了WIN+R法启动常用软件(随后撰文另述),启动软件的手势慢慢就被淘汰了。

最终经过时间的考验,存活下来的手势只有一屏而已:

简单说明一下吧:

C Reversed(从下往上画的C):启动上图中的命令编辑器(Command:StrokeIt – Command Editor)。这在刚开始使用StrokeIt的那段适应期里是使用很频繁的功能。。

C (从上往下画的C):关闭窗口(Command:Keys – Hotkey,Alt+F4)。直接关闭当前窗口,主要用于多标签支持的程序。

\Up(从右下到左上):关闭一个窗口或标签(Command:Keys – Hotkey,Alt+F4)。在单一的程序窗口执行的是Alt+F4,即直接关闭当前窗口。在有多标签支持的程序里(如浏览器、Eclipse、PS等,在tabs分类中进行了重载)执行的是Ctrl+F4,即关闭当前标签。这样省去了鼠标定位关闭按钮(一般都很小)的时间。

\Down(从左上到右下):打开QQ消息(Command:Keys – Send Keystrokes,[F1])。恩没错,我用的是F1,这样左手也可以很方便得启动。你也可以设成Ctrl+Alt+Z或者你自己的快捷键。不用Hotkey的原因是在Hotkey里按F1会弹出帮助,无法记录下按键,下面使用Keystrokes的情况都是这个原因。

/Up(从左下到右上):最大化窗口/将窗口恢复正常(Command:Windows – Maximize or Restore)。这在窗口管理中是使用频率仅次于关闭的功能,就不解释了。

/Down(从右上到左下):最小化所有窗口并显示桌面(Command:Keys – Send Keystrokes,[WIN_DOWN]d[WIN_UP])。相信这个也不用解释了吧。

T(从左上到右上,再到右下):启动记事本(Command:Run -Run Program,C:\Windows\notepad.exe)。这个是我最初绑定的大量启动程序类手势中唯一保留的一个,平时用来快速记点什么东西、格式化文本转纯文本等,很方便快捷。

Left(从右向左):返回父级目录(Command:Keys – Hotkey,Alt + Up)。在Windows的资源管理器里按Backspace或者后退,是到历史记录里的上一条,而不是到当前目录的父级。这样我们通过直接输入目录地址,以及通过“打开文件位置”进入的目录,就要按Alt+Up这个很少有人知道的快捷键。

V(左上到下,再到右上):访问指定目录(Command:Run – Run Program,C:\Windows\explorer.exe)。通过手势打开目录的方法就是启动资源浏览器explorer.exe,并把要打开的目录地址(这里是\\server)通过参数(/e, “目录地址”)传递给它。

最后再说一下怎么给分类增加程序(用来重载)。比如我们有一个支持多标签的新软件要加入到tabs分类中,那么先选中tabs分类,然后点击右边的Add按钮:

启动你要添加的程序,把Finder Tool下面的那个图标拖动到你要添加的程序窗口上(如果是全屏运行的程序,那就只能通过File Name进行添加了,需要到程序安装目录下找出主程序文件名)。

获取到Window Class后按OK,在Application Identifiers里出现了新的CLASS,这个程序就成功地添加到分类里了。如果要从分类中移除该程序,将CLASS删除即可。如果忘了是哪个CLASS,可以通过Finder Tool重新查看。

Saolei.net域名从新网转出到Godaddy的过程记录

Saolei.net这个域名是我在2006年在新网的一家代理商注册的,最近由于众所周知的原因,我需要将域名转移到Godaddy。下面就分享一下我和新网进行的交涉以及和ICANN沟通的过程。

2012-3-8

在参考了很多朋友通过在ICANN投诉转移域名的帖子后,我决定还是走正规渠道,先和新网进行联系。果不其然,新网坚持要求提供身份证扫描件,话说我注册的时候你也没问我要啊?我向工作人员表明按照ICANN的规定,域名转出是不需要提供身份证的。工作人员坚持说是公司的规定,也拒绝出示任何法律法规。

解释不通只好去ICANN投诉,内容是已经准备好的: Continue reading Saolei.net域名从新网转出到Godaddy的过程记录

我所信奉的编程哲学

从去年到今年,陆陆续续看完了《代码大全》《重构》《代码整洁之道》《程序员修炼之道》以及《The Art of Readable Code》,获益匪浅。下面就分享几条我赞同并信奉的编程哲学,顺便废话几句。

本文适合有一定编程经验的读者阅读,高手请轻喷:)

一、代码是写给人看的(Coding for Reading)

请先思考,评价一段代码优劣最重要的标准是什么?

有个著名的图,相信大家都见过,讲的是Code Review时被骂WTF的次数越少,代码的质量就越高。这虽然有点无厘头,但是却不无道理。

《The Art of Readable Code》中告诉我们,评价一段代码的质量的最佳标准是可读性,即别人理解代码意图所需要的时间。

可读性有什么用,我写出一段代码,能完成目标,能通过测试不就行了吗?

不管你是团队开发,还是一个人单干,只要项目还在运作,代码总是要有人来维护的。如果有一天你不在或者离开了,别人应该能很轻松的看懂你的代码,而不是猜来猜去,最后还要来问你,甚至弃用整段代码重新再写。作为一个负责任的开发者,应该尊重自己的劳动成果,也尊重别人的时间。

当你写下一段代码时,脑子里有清晰的逻辑(比如这里必须这么做,因为……这里不能那么做,因为……)。而别人看这段代码时,脑中是一片空白(这个变量是干什么的?为什么要多加一层判断?这个数为什么是 2 不是 3 ?),除非能完整复现你当时脑中的逻辑,否则就不能理解这段代码。

所以我们应该做的是,把写代码时脑中想到的逻辑的每一个细节,尽可能地写到代码以及注释中,从而帮助后来的阅读者快速复原整个逻辑。简单来说可以有以下的方法:

用常量代替魔术数

在一段代码中出现 if ( level > 3 ) …的时候,也许你会想:为什么是 3 不是 4 呢?这就是所谓的魔术数。通过上下文也许你可以判断出这个 3 是指最高等级,但是可能这段代码中 3 出现了好几次。你会迷惑:它们是不是都是一个意思?当我要把最高等级改成 4 的时候,是不是应该修改所有的 3 ?

如果代码的作者定义一个常量MAX_LEVEL = 3,同时还有一个常量USERS_PER_PAGE = 3,并在不同的地方使用不同的常量,就不会有这样的混淆了。

使用富含信息的类名、变量名和函数名


doit();
$return = $str2 . ':' . $str3;
return $return;

这样的代码,简直就是人工混淆过的。你会发现这些代码根本不能帮助你理解代码的含义。

也许你该写成这样?


handleError();
$error_message = $error_code . ':' . $error_status;
return $error_message;

在注释中说明一段代码存在的原因,而不是行为

$('#item').html(''); //清空item的内容

这样的注释有意义么?用自然语言重新描述一次代码的行为,除了徒增维护时的工作量外没有任何价值。你应该说明为什么这样做,以供别人看到这段代码时明白你是怎么想的,并决定如何修改或者对待这段代码。

$('#item').html(''); //先清空容器的内容,否则可能导致内容重复

二、写得越少越好(Less is More)

这个规则的使用性太强了,我简单说说减少逻辑层次和缩小函数体这两个方面吧。

减少逻辑层次

当逻辑层次超过三层时,理解这段代码的难度会急剧上升。我相信谁也不喜欢去读一个n层括号的表达式,或者面对n层缩进的条件判断/循环。

对于复杂的表达式,通过提取中间变量来降低表达式的逻辑层次,保证每个表达式的逻辑层次不超过二层。

对于多层条件判断,大多数情况可以用防御式编程将其简化成单层的条件判断,尽早return或者exit。此外,单行的if-else判断往往可以用三元操作符替换。如果判断实在太多,也许你该重新设计一下结构了。

缩小函数体

记得有一位语言的创始人说过:“我不喜欢比我的头还大的函数”。

事实上,大家都喜欢短小精干、一眼就能看到底的代码。简洁明快的代码有助于别人迅速理解代码的意图,也方便快速定位问题。如果一个函数要滚动屏幕才能看全,那你往往要不断地来回滚动,并强迫自己记住一些信息,再返回去看另一部分,这样做会非常累。

随着函数体不断膨胀,理解它所需要的时间随之增加,出错的几率也会大大提升。而且越大的函数,可维护性和复用性越差。当部分代码逻辑需要修改时,不能快速定位到要修改的位置,也难以确定函数体其他位置是否也需要对应的修改。

当函数尺寸失控时,首先要想到的是,有没有其他方法,用更少的代码完成这个任务?能不能用正则表达式?能不能用查表法?有没有内置的库函数可以利用?

面对一个无法再简化的流程,将其拆分成细粒度的步骤,将每个步骤的相关代码分离出来,提取成子函数,再给子函数起一个漂亮的名字。这样可以降低理解主流程的难度,在做修改时也可以通过函数名快速定位,而且因为相关的代码都在一起,不容易漏改。

也许你会怀疑调用函数所造成的性能损失,我想说现在这个时代,手机都马上四核了……

三、不要重复(Don’t Repeat Yourself)

看过《重构》一书后,我看到代码中任何重复的地方都如见眼中钉。

重复是万恶之源,当你发现你在对代码的不同部分进行同样的修改时就要警惕了。改的地方越多,就越可能出错。也许忘了改一个地方,也许错改或者删除了周边的代码……永远不要让这种事情发生!

将重复的代码提炼成子函数


$('#count').text( + $('#count').text() + 1 );
...
$('#count').text( + $('#count').text() + 1 );
...

如果一段相同的代码出现两次,基本上你还会第三次用到它,所以很有必要将其提炼成子函数。这样不仅可以减少代码量,还可以降低维护的难度。


countPlusOne();
...
countPlusOne();
...
function countPlusOne() {
$('#count').text( + $('#count').text() + 1 ); //以后修改只用改这里就好了
}

如果有几段代码很相似,往往可以提取其共性逻辑,使用不同的调用参数进行区分。


countChange( +1 );
...
countChange( -1 );
...
function countChange( change ) {
$('#count').text( + $('#count').text() + change );
}

用循环减少重复


$item[ 'id' ] = $_POST[ 'id' ];
$item[ 'name' ] = $_POST[ 'name' ];
$item[ 'mail' ] = $_POST[ 'mail' ];
$item[ 'qq' ] = $_POST[ 'qq' ];

如果有大块逻辑雷同只有一两个地方更改的代码,往往可以用循环来解决:


foreach ( array( 'id', 'name', 'mail', 'qq' ) as $key ) {
$item[ $key ] = $_POST[ $key ];
}

说说qwerty、dvorak、colemak三种键盘布局

【qwerty布局】


qwerty布局大家应该都很熟悉了,全世界最普及的键盘布局。
截止到去年接触并使用dvorak布局之前,我使用了十几年qwerty布局,在http://speedtest.10fastfingers.com/测试的最高CPM(每分钟击键数)为475。
相信阅读本文的读者中,有99%以上都在使用qwerty布局。

热区图


本热区图是使用http://www.patrick-wied.at/projects/heatmap-keyboard/对apache2的license.txt(36k)进行分析的结果,下同

优点

1、普及率和兼容性接近100%
2、有史以来的各种软件的快捷键都默认为此布局设计
3、最常用的快捷键(^a, ^s, ^c, ^v, ^x, ^z, ^w)都可用左手完成

缺点

1、高频键大多不在中排,都需要移动手指才能按到,导致需要大量的手指移动
2、高频键左右分布不均衡,左手负担比右手重
3、经常出现单手连续击键(尤其是左手)的情况,容易疲劳也容易出错
4、常用标点符号;/’都要用小指输入,容易疲劳也容易出错

【dvorak布局】


这个布局知道的人就很少了,和qwerty布局相比,它将元音字母aoeui移到左边,将最常用的辅音字母移到右边,同时调整了一下标点符号的键位。
自从去年接触到它后,我用了一个月的时间适应,然后就抛弃qwerty布局了。不仅输入速度得到了提升(在http://speedtest.10fastfingers.com/测试的最高CPM为535),而且长时间coding也很少出现疲劳的情况了。

热区图

使用

Windows:在语言设置里添加“美国英语-Dvorak”,推荐使用http://code.google.com/p/dvorak-qwerty/
Linux:在终端输入loadkeys dvorak(GUI请在键盘设置里找),推荐使用http://code.google.com/p/dvorak-qwerty/
Mac:在语言设置里选择“Dvorak-标准”
更多系统下启用Dvorak布局请见:http://dvorak.mwbrooks.com/support.html

优点

1、将高频键都分布在中排,大大降低手指移动距离
2、尽可能使左右手交替击键,均衡负担
3、布局优雅,精心设计了右手负责区域的键位,使辅音字母组合(如th nt gh wh rn)输入非常顺手
4、将常用的标点符号’ , . ; = – 移到更舒服的位置,输入更方便(对程序员来说巨爽)。

缺点

1、布局变化过大,几乎所有的字母和标点符号都改变了,上手困难
2、到qwerty布局的电脑上丧失盲打能力
3、别人很难再使用你的电脑了,可以再装一个qwerty布局切换
4、本来单手可以操作的快捷键要两手操作。不过MacOS下有天然的“Dvorak-标准”布局,Windows和Linux下可以用这个http://code.google.com/p/dvorak-qwerty/来使用原有键位的快捷键,但是还有一些BUG(不支持ALT快捷键、有个别字母如s w v z在开启Capslock时输入仍是小写等)
5、部分跳过键盘布局直接取键盘码的软件仍然是qwerty布局,比如QQ拼音和搜狗输入法(经测试紫光和谷歌输入法可以正常使用,只是可惜了我的QQ同步词库),还有QQ和部分网银的密码输入框(解决办法是看着键盘按qwerty布局输入),还有一些远程桌面软件,还有一些游戏(比如魔兽,这点挺好,DOTA无障碍了,哈哈)
6、高频键 r 和 i 仍需要移动才能按到,而 u 和 h 不是很高频的键却放在了本位(不需要移动就能按到)

【dvorak programmer布局】


估计某个程序员发现用dvorak布局很爽,就将之变得更加极限。于是出来这么一个布局。
这个布局大胆的用常用符号替换了数字,同时考虑到在程序中;比”出现得更频繁,调换了两者之间的位置。

热区图

 

优点

1、包括上述dvorak键盘的所有缺点
2、优化了程序中常用符号如$ ; ( ) { } [ ] =等,用来coding巨爽

缺点

1、包括上述dvorak布局的所有缺点
2、输入数字只能按住shift进行-_-

【colemak布局】


这个布局比dvorak更激进一些,通过热区图可以看到,8个高频键完美地安排在了本位。
坚持使用colemak数日后,实在无法接受别扭的标点输入进行coding,只好放弃colemak,用回dvorak了,也许colemak对普通人来说更适合一些。

热区图

使用

Windows:http://colemak.com/wiki/index.php?title=Windows
Linux:http://colemak.com/wiki/index.php?title=Unix
Mac:http://colemak.com/wiki/index.php?title=Mac
更多资料请见:http://colemak.com/

优点

1、高频键真正做到了完美分布,手指移动距离更小
2、qwzxcvbm以及标点符号键都没有移动,而且除了e和p外,字母键都在原来的手控制之下,更容易上手
3、常用的快捷键(^a, ^c, ^v, ^x, ^z, ^w)仍能正常使用
4、万年不用的capslock被换成了高频键backspace,巨爽
5、有资料详尽的官方网站http://colemak.com/,甚至针对各种打字练习软件设计了练习包

缺点

1、键分布没有逻辑,不如dvorak优雅
2、没有优化常用标点符号

在MongoDB的shell中显示服务器当前IP

不久前发生一起严重的事故,误删了生产MongoDB服务器上的一个collection,由于没有定时备份,导致几天的数据丢失。认真反省之后,写下这篇文章,希望能给大家一些警示。

过程

当时我正双开两个终端窗口,分别用mongo连接开发环境和生产环境的MongoDB。由于本地的数据库因为不断的开发测试已经被污染了,我从生产环境dump了最新的数据并下载到本地。接下来要做的是把本地MongoDB中的对应collection给drop掉,然后restore回去。

这时我不知道被什么事情打断了,当我继续这个过程时,由于Mongo Shell中没有像Redis那样显示服务器的IP,我并没有注意到自己点开的是生产服务器的终端,并执行了drop命令……

反省

1、在对生产数据库做删除之类的危险操作时,一定要两个人double check;
2、明确区分生产环境和开发环境,在执行各种删除操作前对所在的环境进行确认;
3、在执行重要操作时,不接受其他事务的打断;

措施

在生产环境和开发环境都建立一个~/.mongorc.js文件,内容如下:

var prompt = function ( ) {
var host = db.getMongo().toString().replace( 'connection to ', '' );
var database = db.getName();
return host + '/' + database + '> ';
}

然后连接到Mongo Shell时就会显示服务器IP了,如:

[zhangshenjia@mac: ~]$mongo
MongoDB shell version: 2.4.4
connecting to: test
127.0.0.1/test>

防止在iOS设备中的Safari将数字识别为电话号码

在测试中发现iPad上的Safari总会把长串数字识别为电话号码,文字变成蓝色,点击还会弹出菜单添加到通讯录。

别的地方倒也罢了,如果在用户名中出现数字(手机注册新浪微博的话用户名就是“手机用户xxxxxxxx”),版式会很恶心。

经过测试在a标签中的长串数字不会识别为电话,于是给出现用户名但没有链接的地方嵌套一个无动作的a标签,临时解决了这个问题。

但是这样增加了额外的标签,代码的语义性变得很差,而且对大段文字不能用这个方法。

今天无意中撞进Safari的官网,发现了safari有个私有meta属性可以解决这个问题:


官网的说明如下:

How do I disable automatic detection of phone numbers in webpages?

In Safari on iPhone, phone numbers are automatically detected and transformed into links that dial the phone number when tapped. If you have strings of numbers in your webpage that should not be automatically detected as phone numbers, you can choose to disable this feature on the entire page by adding the <meta> tag shown in Listing 12.

取得URL相对于另一个URL的相对路径

今天群里灰大出了个题:

function getRelativeURL(url, baseURL) {
   // 获取url相对baseURL的相对路径
   // url和baseURL都是绝对路径或都是相对路径的情况下,有可能计算出结果,否则扔Error
   // 如果都是绝对路径,但不在同一个域、同一个协议、同一个端口下,即无法计算相对路径,扔Error
}

用了点时间写了一下:

function getRelativeURL ( url, baseUrl ) {

    var path, 
        basePath,
        i = 0,
        compare = {},
        r = {    'proto' : /(^[a-zA-Z]{1,4}):\/\/(.*)/,
                'domain' : /(^[-_a-zA-Z.]+)((?:\/|:|$)?.*)/,
                'port' : /(?:^:)(\d+)((?:\/|$).*)/,
                'word' : /[^, ]+/g,
        };

    compare[ 'url' ] = parseUrl( url );
    compare[ 'baseUrl' ] = parseUrl( baseUrl );

    if ( different( 'proto' ) || different( 'domain' ) || different( 'port' ) ) return false;    //协议、域名、端口不同

    path = compare.url.path;
    basePath = compare.baseUrl.path;

    while ( path.length && path[ 0 ] == basePath[ 0 ] ) { //去除相同父目录
        path.shift();
        basePath.shift();
    }

    if ( path.length == 0 && basePath.length == 0 ) return './';     //两个url相同
    
    if ( path.length == 0 ) return parent( basePath.length );        //baseUrl是url的子目录

    if ( basePath.length == 0 ) return path.join( '/' ) + '/';        //url是baseUrl的子目录

    return parent( basePath.length ) + path.join( '/' ) + '/';        //url和baseUrl互不包含

    function different ( name ) {
        return compare[ 'url' ][ name ] != compare[ 'baseUrl' ][ name ];
    }

    function notValidUrl () {
        return compare[ 'url' ][ 'proto' ] == '' || compare[ 'baseUrl' ][ 'proto' ] == '';
    }

    function parseUrl ( url ) {
        var parsed = {};
        'proto,domain,port'.replace( r.word, function( name ){
            var match, reg = r[ name ];
            if ( !reg.test( url ) ) {
                parsed[ name ] = '';
                return;
            }
            match = url.match( reg );
            url = match[ 2 ];
            parsed[ name ] = match[ 1 ];
        });
        parsed[ 'path' ] = url.replace(/\/+$/,'').split('/');
        return parsed;
    }

    function parent ( level ) {
        console.log(level);
        var result = [];
        while ( level-- ) result.push( '../' );
        return result.join('');
    }
};

使用单元测试如下:

test("url和baseURL并非都是绝对路径或都是相对路径,没有结果", function() {
    expect(4);
    ok(!getRelativeURL('http://aoeu/ao','/aoeu'),'绝对,相对');
    ok(!getRelativeURL('/aoeu','http://aoeu/ao'),'相对,绝对');
    ok(getRelativeURL('http://aoeu','http://aoeu/ao'),'绝对,绝对');
    ok(getRelativeURL('/aoeu','/ao'),'相对,相对');
});
 
test("不在同一个域、同一个协议、同一个端口下,没有结果", function() {
    expect(3);
    ok(!getRelativeURL('http://aoc.com','http://aoeu.com'),'不同域');
    ok(!getRelativeURL('https://aoc.com','ftp://aoeu.com'),'不同协议');
    ok(!getRelativeURL('https://aoc.com:88','ftp://aoc.com:89'),'不同端口');
});

test("是否以/结尾不影响结果",function() {
    expect(3);
    equal(getRelativeURL('http://aoeu.com/aoeu/','http://aoeu.com/'),getRelativeURL('http://aoeu.com/aoeu','http://aoeu.com'),'都以/结尾');
    equal(getRelativeURL('http://aoeu.com/aoeu/','http://aoeu.com'),getRelativeURL('http://aoeu.com/aoeu','http://aoeu.com'),'url以/结尾');
    equal(getRelativeURL('http://aoeu.com/aoeu','http://aoeu.com/'),getRelativeURL('http://aoeu.com/aoeu','http://aoeu.com'),'baseUrl以/结尾');
})

test("相同目录",function(){
    expect(3);
    equal(getRelativeURL('http://aoeu.com','http://aoeu.com/'),'./','根目录');
    equal(getRelativeURL('http://aoeu.com/aoeu','http://aoeu.com/aoeu'),'./','单级');
    equal(getRelativeURL('http://aoeu.com/ao/eu','http://aoeu.com/ao/eu/'),'./','多级');
})

test("url和baseUrl中有一个为根目录",function() {
    expect(4);
    equal(getRelativeURL('http://aoeu.com/aoeu','http://aoeu.com'),'aoeu/','url为baseUrl的单级子目录');
    equal(getRelativeURL('http://aoeu.com/ao/eu','http://aoeu.com'),'ao/eu/','url为baseUrl的多级子目录');
    equal(getRelativeURL('http://aoeu.com','http://aoeu.com/ao'),'../','baseUrl为url的单级子目录');
    equal(getRelativeURL('http://aoeu.com','http://aoeu.com/ao/eu'),'../../','baseUrl为url的多级子目录'); 
!
})

test("其他",function() {
    expect(2);
    equal(getRelativeURL('http://aoeu.com/aoeu','http://aoeu.com/ueoa'),'../aoeu/','单级');
    equal(getRelativeURL('http://aoeu.com/ao/eu','http://aoeu.com/eu/ao'),'../../ao/eu/','多级');
})

如有更好解法或发现错误,请不吝赐教:)

aoeu.sh 让你 type less, do more

Github: https://github.com/shenjia/aoeu.sh

这是一个为 Linux / MacOS 用户设计的alias集合。

 作为开发人员,我们每天都要在终端敲很多重复性的命令。一些大段重复的命令(比如部署,安装,备份等)我们会写shell脚本来避免重复性的键入,却忽视了还有很多使用频率极高的命令。 Continue reading aoeu.sh 让你 type less, do more

解决google maps api阻塞页面渲染的问题

google maps的api使用很方便,只要在用使用google maps的页面引入http://maps.google.com/maps/api/js?sensor=false就可以了。


但是在项目中这样使用后,发现domReady事件被严重阻塞(甚至会延迟十几秒)

因为domReady只有页面中所有的script都运行完后才会触发,而google的服务器往往很慢……直接用script标签来加入这个壳,会使domReady变得不可控。

为了防止阻塞domReady,对于不是必须在渲染前执行的js代码,一般使用document.createElement创建script标签,这样浏览器会在domReady后再下载这些script并执行。我一般使用这样的代码:

$.loadJs = function ( src ) {
    var script = document.createElement( 'script' );
    script.type = 'text/javascript';
    script.src = src;
    document.body.appendChild( script );
}

在使用$.loadJs加载http://maps.google.com/maps/api/js?sensor=false后,domReady正常了,但是google maps却不能正常使用了。

审查元素发现,壳虽然被引入了,但是依赖的子模块都没有引入进来,于是我们检查壳里加载子模块的代码:

window.google = window.google || {};
google.maps = google.maps || {};
(function() {
    function getScript(src) {
        document.write('<' + 'script src="' + src + '"' +
                   ' type="text/javascript"><' + '/script>');
    }
    .....

乖乖,居然用document.write。我们知道document.write只有在输出流还没有闭合的时候才能输出内容,而我们用$.loadJs方法加载壳的时候,输出流早就关闭了。

这个怎么解决呢,总不能改google的代码吧?曾经想过把这个壳存到本地,修改后使用,但是谁知道google哪天修改了什么东东呢?

仔细分析了一下,这个壳实际上只是设定一些参数,然后用document.write加载另一个壳http://maps.gstatic.com/intl/zh_cn/mapfiles/api-3/7/11/main.js,实际加载模块的动作是在后者中进行。

万幸,后者加载子模块使用的是document.createElement方法……

冥思苦想后,想出一个hack的方法:在调用第一个壳之前将原生的document.write方法保存起来,将其改写为调用$.loadJs,调用之后恢复原有的方法(因为write只是用了一次)。

$.writeListener = function ( ) {
  var write = document.write;
  document.write = function ( html ) {
    var scriptPattern = new RegExp( ']*src=[\'"]([^\'"<>]*)["\'][^>]*>', 'i' );
    if ( scriptPattern.test( html ) ) {
      src = html.match( scriptPattern )[1];
      $.loadJs( src );
      document.write = write;
    } else {
      write.call( document, html );
    }
  }
}
$.loadJs( 'http://maps.google.com/maps/api/js?sensor=false' );

暂时只能想到这里,哪位有更好的解决思路,请不吝赐教。

2011.12.12北京WCA冬季赛亚军

很久没有参加比赛了……

这次主要是冲着中岛来的,顺便测试一下我们公司的app(微拍)。

中岛果然强势,练习时我超水平发挥sub10都被他8秒干掉。纯被虐了一下午……

决赛的结果很意外,各路高手纷纷发挥失常,中岛到决赛才sub10,自认发挥更烂的我居然拿到第二。

最大的收获就是拍了一堆视频,包括练习和参访中岛的,详见我的微拍视角:http://www.weipai.cn/home/4e64df54677c27fa24000003(翻到2011年12月)

2010.12.27沈阳魔方公开赛,9.69/11.70刷新个人记录

感谢熊天煜的孤鸿魔方!感谢小圆同志的努力!感谢天平同志组织的比赛!

初赛第二次大概在9.00左右,结果计时器BUG了,悲剧。最后平均12+

复赛也平均12+

决赛人品爆发,单次9.69破PB,最后一次跳P,幸以平均11.70破PB,哈哈。

【俄罗斯方块速成】系列

注意:本系列主要针对联众俄罗斯方块! ­

2001~2002年时曾痴迷过联众俄罗斯方块(ID为【小桥】天高),于2003年写下此系列文章的第一篇。后被誉为史上最强技术贴,还被某人写进了小说……

写作此系列文章过程中得到了俄罗斯方块爱好者金优的大力支持,他为我专门编写了定制的客户端供我研究,在此表示诚挚的感谢!

————————————————————————————————————————————

【俄罗斯方块速成】[基础篇] ­

本篇主要讲解了基本概念和术语、流派,以及废材处理的概念。 ­

【俄罗斯方块速成】[提高篇] ­

本篇主要讲解了键盘设置、各种开局、建设模样,并重点介绍了“桥”的概念及应用。 ­

【俄罗斯方块速成】[实战篇] ­

本篇主要讲解了对战心态的把握、速度的练习,突击和爆发的概念及应用。­

【俄罗斯方块速成】[开局篇] ­

本篇展示了本人对七大系列开局的研究,以及理论上的最佳开局摆法。­

【俄罗斯方块速成】[双键篇] ­

本篇展示了本人自己开发的双键玩法,可以达到理论最高速度。­

【俄罗斯方块速成】[双键篇]

DOC版本下载:【俄罗斯方块速成】双键篇

双键打法实战的录像:http://v.youku.com/v_show/id_XNDIxMjc3MDI0.html

————————————————————————————————————————

【前言】

我们都知道,方块要想打的好,速度和摆法,一样都不能少。

我们都知道,有的高手摆法不怎么样,但硬是靠速度把对方活活砍死。

我们都知道,有的高手速度慢别人十几块,却能凭出神入化的摆法以柔克刚。

我们都知道……

【概念普及】

  键盘速度:键盘在1分钟内的重复频率,测试方法一般是打开一个记事本,按住某个键一分钟,然后保存,再看文件有多少字节,比如4500字节,那么我们就称这块键盘是4500键盘。

键程:按下和放开一个键时,键帽上下运动的距离。

【改键盘的时代】

记得在那原始蛮荒的年代,一个碌碌之辈突然在一夜之间脱胎换骨,在联众所向披靡,无往不胜……这个不知在何等机缘巧合之下,发现了键盘电阻与键盘速度关系的天才,就是杨过。

随着一篇“二麻教你改键盘”的文章在联众论坛发布,越来越多的人开始修改自己的键盘,我也经不住诱惑拿起了电烙铁……把50欧姆的电阻换成25欧姆之后,键盘果然奇快无比,立马level up!但很快又发现比自己快好多的人还是满地都是,真是人外有人天外有天。一不做二不休,再改!这次换上15欧姆的电阻,玩了两局果然是爽,不料突然之间键盘就死了,按什么都没反映,仔细一闻还有股淡淡的焦味……

就这样,前前后后我一共改坏了三块键盘。 事后总结了一下:

1、要找本来速度就挺快的键盘改。

2、新电阻的电阻值最多不能低于原来电阻的一半。

改键盘有一大弊病,就是这块键盘基本上是不能用来打字了。

【加速器的时代】

在加速键盘大行其道很长一段时间之后,不知哪位高人开发了键盘加速器,从此揭开了一个全新的篇章。加速器是如此的好用,以至于联众都在新版客户端里集成了加速功能。

加速器的好处就是让普通键盘也能有高速键盘的效果,不用改电阻,同时在需要时可以关闭加速功能,不影响其他使用(比如聊天)。有了加速器后,就不用整天抱块键盘到网吧去打方块了。

我们一般使用的都是名为“AcceleratorV2.0”的加速器(也有用1.0的)。

使用方法很简单,选中“全局加速”,再点击“开启”就行了。点“取消”就能关闭加速功能。

第一个输入框用来定义从一个键按下到开始重复的延迟时间(以毫秒为单位),不同的键盘适合不同的值,普通键盘一般设置在100~125之间,笔记本键盘因为键程短可以设得更低一些。

第二个输入框是开始重复后每次重复的延迟时间(以微秒为单位),个人不建议低于2000,否则很容易卡。

用了加速器后移动是变快了,但是经常有时候按落下时松开慢了,就连续落下很多块,基本上就成自杀了。还有按旋转的时候松开慢了,当前块会原地疯转好久,既影响节奏又容易失误。相信很多朋友为此而困恼:难道速度和稳定性不能兼得吗?

现在通用2.0的强大之处就体现出来了:它给我们提供了一个特殊按键功能,可以单独增加几个键的延迟。

点击主界面的“特殊按键设置”:



一共可以设置三个特殊按键,推荐设置旋转键和落下键这两个不需要加速的键(如图中我设置了R和空格),然后延迟比例设成500,勾选“启用特殊按键”,然后点“确定”,再重新开启一下加速功能(先点取消再点开启)。

现在再进入游戏试试吧,你会发现移动依旧飞快,而旋转和落下却不会因为松开过慢而重复了。

【双键的时代】

接下来要介绍由本人自创并完善的玩法:双键玩法!

所谓双键玩法,是指通过一系列键盘映射,将移动操作和旋转操作分别简化为一个按键,每放一个方块只需要按两下键,从而将速度提升到极限的一种玩法。

  〖操作对比〗

为了演示双键玩法比常规玩法的优势,让我们来看下面这个比较极端的操作实例:

常规玩法:(按键6~7次)先按三下旋转(联众默认旋转是逆时针旋转,如果你是用顺转的,你可以想象相反的例子),然后先按住右不放再按一下左(如果你用点移,那就按三下右),最后按落下键来完成入位。

双键玩法:(按键2次)只按一个键就完成了旋转,再按一个键完成入位。

 〖数据对比〗

我们知道每摆一个方块,需要先旋转、再移动,最后落下。

旋转阶段有四种情况:不转、90度、180度、270度。让我们来看看常规玩法和双键玩法在这四种情况下分别所需要的击键次数:

假设四种旋转的出现几率是平均的,那么常规玩法每块平均需要击键 1.5次。而双键玩法每块平均只需要击键0.75次。

假设我们的极限击键速度为8次/秒,即每次击键需要0.125秒,那么在旋转阶段平均每块所需时间如下(单位为毫秒):

在旋转阶段,常规玩法每块需要188毫秒的平均时间,而双键玩法每块只需要93毫秒的平均时间

移动阶段有10种可能:不移、左移1、左移2、左移3、左移到边回1格、左移到边、右移1、右移2、右移到边回1格、右移到边。(有左移3没有右移3的原因是棍子竖起来后偏右,要插到左边第三列时必须用左移3)

常规玩法在移动完后还需要再按一个落下键,而双键玩法是一键完成移动+落下。让我们来看看击键次数对比:

假设各种移动出现的几率相同,那么常规玩法平均需要击键2.5次,而双键玩法每块平均只需要击键1次

接下来要统计时间了。因为移动时按键有长按的情况(平移和回放),而长按需要的时间是单键的1.5倍。大多数人在实战中会提前按落下键,让方块移动到位的同时就落下,所以按落下键的时间会比较短(估且算作单键的一半)。让我们看看需要时间的对比:

在移动+落下阶段,常规玩法平均需要297毫秒的时间,而双键玩法只需要125毫秒。

这样统计下来常规玩法每处理一个块平均要击键4次,平均耗时485毫秒,而双键玩法每处理一个块平均击键1.75次,平均耗时218毫秒。

 〖双键玩法的优点〗

当然,以上只是理论数据。但是双键每块平均少击键2.25次这个优势,是不可动摇的。

在我之前的方块文章里有讲到,为了提升速度,我们经常会选择按键较少的旋转和移动,这样往往是牺牲摆法去换速度。采用双键玩法后,你可以放心地采用自己能想到的高效摆法,而不必担心速度的限制。

此外,在进入高层(15层以上)后,方块初始位置上移一行,这时候通常都要在方块出现时按一下慢降,然后再旋转,而双键玩法直接将慢降加入旋转操作中,节省了这一个必按的键。这样进入高层时不会卡节奏,更容易拉开块数上的差距。

双键所带来的好处还不止如此,常规玩法中操作耗时存在不稳定性,任何一个环节出现问题(自己失误、对手攻击)都会拖慢节奏,所以你注意力大部分时间要聚焦在当前块上,直到确定位置和形状都正确为止。而双键玩法在击键后的操作是由加速器几乎在瞬间完成的,被对手攻击打断的机会极小(印象中我还没碰到过),可以将全部精力投入到摆法的思考上,只要思维连贯,双键稳定性的节奏是常规玩法根本无法比拟的。

最后,常规玩法一般只需要使用5根手指(甚至只需要4根、3根),而双键玩法要使用你双手全部十根手指,打起方块来像弹琴一样,不仅美观大方,而且不容易疲劳,还锻炼身体。

 〖双键玩法的缺点〗

当然,双键玩法在对常规玩法拥有压倒性优势的同时,也存在着不可忽视的短板。

1、上手困难:双键玩法至少需要使用13个键的映射(完全版加辅助映射共有20个映射),原有的旋转、慢降、落下、移动键在必要时刻也要使用。要达到熟练掌握很需要一段时间,之前打方块的习惯几乎要完全改变,只有摆法可以保留。

2、高层节奏差:在层高到一定程度后,双键玩法有自杀的风险,此时必须改回常规玩法,节奏会突然降下来,因为使用双键玩法时延迟会设得稍高一些(因为大拇指反映较慢,延迟低了很容易失误),所以此时节奏会比你使用常规玩法时要稍慢一些,出现一个短暂的节奏差。此时是你最虚弱的时候,如果对手抓住这个机会进攻,你一般会很快输掉。不过只要你的摆法不是差对手太多,这种情况是很少出现的。

3、容错性差:双键玩法因为键位密集,在无数次击键中难免会按错。常规玩法按错了键只要没有落下都还可以调整,而双键玩法一旦按错就已经落下了,所以失误基本上是毁灭性的,一次失误通常需要五六块甚至更多才能补救,如果中盘出现失误会非常危险。更可怕的是因为同时击两键或者键粘连出现的连续失误,一旦发生基本上就可以准备死了。为了减少失误只能放慢击键的速度,在速度和稳定中找一个平衡点。

好了,对双键玩法和常规玩法的分析比较就到此为止。接下来进入双键的教学部分,如果你对掌握双键玩法已经失去了信心,那么你可以跳过该部分阅读:)

【双键玩法必备软件及设置】

〖必备软件〗

联众世界          下载地址:http://www.ourgame.com

联众俄罗斯方块    下载地址:http://www.ourgame.com/download/index.html#d3

通用加速器2.0    下载地址:AcceleratorV2.0

移花接木v4.0     下载地址:移花接木v4.0

〖联众键盘设置〗

左移:小键盘/

右移:小键盘-

落下:小键盘*

旋转:字母R

慢降:字母C

不启用“声音效果”、“方块消失的渐变效果”,这两个功能会使游戏变卡。

不启用“调节键盘速度”,此功能会和通用加速器冲突。

〖通用2.0设置〗



首次延迟必须设置在110以上,勾选“全局加速”、“软变速”和“超级映射”。

点击“开启”后映射生效,点击“取消”后失效。如果游戏过程中映射失效,可以取消后重新开启。



不启用特殊按键(会和超级映射功能冲突)。

Null代表没有设置,如果想清空某个键,可以选中对应的输入框后按Esc键。

*左移:小键盘 /

*右移:小键盘 –

*丢下:小键盘 *

*左旋(逆旋):字母R

以上四个带*的键必须设置和联众的一样,因为超级映射的实现原理就是重复这四个基本键。

左旋和右旋只能设置一个,请让右旋(顺旋)保持Null。

以下映射键位均由我个人研究得出,经长期推敲已经定型,各位朋友有兴趣的话可以自行更改:

丢下:小键盘 5

左三旋:字母W

左平移丢下:小键盘 7

左回放:空格

左移3丢下:小键盘8

左移2丢下:字母A

左移1丢下:小键盘4

左倒旋:字母E

右回放:小键盘0

右平移丢下:小键盘9

右移1丢下:小键盘6

右移2丢下:小键盘+

〖移花接木设置〗



点击“激活”则所有映射生效,窗口最小化到系统托盘,在系统托盘双击图标弹出主窗口,点“取消激活”即可使所有映射失效。可以在“设置”面板里设置激活/取消激活的快捷键(默认Alt+1激活,Alt+2取消激活)。

下面示范一下添加单个映射的流程:

1、在第一个下拉框里选择要映射的键(如Num 1)

2、在第二个下拉框里选择“模拟多个按键”

3、在弹出的窗口里通过下拉框选择按键(如字母C),然后点击“添加”,即可添加一个键(由“按下”和“放开”两个动作组成)

4、连续添加五次字母C之后,点击“确定”

5、提示“已成功转换!激活热键后即可生效”后,添加映射成功

掌握添加映射的流程后,添加以下映射:

小键盘1(快速下落):五次字母C

字母F(逆转):字母C、字母R

字母D(180转):字母C、字母E

字母S(顺转):字母C、字母W

字母G(快速开始):F2、字母Y、字母C、回车

字母X(左插空):五次小键盘/、十四次字母C

小键盘3(右插空):五次小键盘-、十四次字母C

【双键手型】

〖常规手型〗

左手放在正常打字时的位置(拇指在空格上,食指在F上,中指在D上,无名指在S上,小指在A上),右手放在小键盘的位置(拇指在0上,食指在4上,中指在5上,无名指在6上,小指在+上)

〖旋转应急手型〗

左手食指、中指、无名指向上移动一个键位,分别放在R、E、W上(放弃慢降)

〖移动应急手型〗

右手整体向右上方移动一个键位,食指、中指、无名指分别放在小键盘/、*、-上(恢复常规)

常规手型可以贯穿游戏全程,一般不做变动。

如出现下列情况时,则考虑使用旋转应急手型和移动应急手型中的一种或者两种。

1、 一次旋转不到位:补充旋转,因为默认转一次会慢降一行,高度过半后容易自杀,所以要使用旋转应急手型。

2、 中盘插空:需要精确调整左右移动,此时要使用移动应急手型。

3、  中间高度过高:因为双键玩法是先转后移,而且还带慢降,所以中间一定要留出4~5行的空间才可以安全使用双键玩法(尤其是出现棍子时)。如果条件不符合,就要同时使用旋转应急手型和移动应急手型。

4、 边坑高度过高:还是因为先转后移的缘故,容易被卡住无法到位,此时要同时使用旋转应急手型和移动应急手型。

【双键指法】

〖辅助〗

快速开始:左手小指按G(自动开始、自动接受开始)

〖旋转〗

顺转(自动慢降):左手无名指按S

180度转(自动慢降):左手中指按D

逆转(自动慢降):左手食指按F

顺转(应急,无慢降):左手食指按R

180度转(应急,无慢降):左手中指按E

逆转(应急,无慢降):左手无名指按W

〖插空〗

慢降:左手食指按C

加速慢降:右手食指按小键盘1

开局左插空:左手无名指按X

开局右插空:右手无名指按小键盘3

〖移动〗

直接下落:右手中指按小键盘5

左移1格落:右手食指按小键盘4

右移1格落:右手无名指按小键盘6

左移2格落:左手小拇指按字母A

右移2格落:右手小指按小键盘+

左移3格落:右手中指按小键盘8

左移到边回1格落:左手大拇指按空格

右移到边回1格落:右手大拇指按小键盘0

左移到边落:右手食指按小键盘7

右移到边落:右手无名指按小键盘9

左移(应急):右手食指按小键盘/

右移(应急):右手无名指按小键盘-

下落(应急):右手中指按小键盘*

大家可能会问,为什么有左移3格落而没有右移3格落?因为存在这样的特殊情况,在棍子和L竖起来后要放到左边第三列时,必须用左移3格落来完成,而右边则没有这个问题。

【上手指南】

一、养成旋转的条件反射

每个方块有四种状态:不转、顺90度转、180度转、逆90度转。在单机版开始一盘新游戏,第一块出现后,先思考需要旋转成什么状态,然后按下对应的旋转键,如果转对了就用应急移动键移动到位落下,如果转错了就按F2重新开始游戏。

田:只有一种状态,不需要旋转。

左S、右S、棍子:只有两种状态,只要使用一个旋转键就够,都用食指来完成。

山:需要平摆的时候按中指,山头要向左就按食指,向右就按无名指,很好记。

左L:需要平摆的时候按中指,要竖起来平铺的话按食指,要竖起来攻击的话按无名指。

右L:需要平摆的时候按中指,要竖起来平铺的话按无名指,要竖起来攻击的话按食指。

(旋转操作全部由左手来完成,以上提到的手指都是指左手手指)

需要180度转和逆转的只有左L、右L和山这三种方块,多加练习很快就可以掌握。

二、养成移动的条件反射

 1、掌握不移动直接落下:右手中指按小键盘5。开一盘新游戏,连续按5直到自杀。

2、掌握左右平移到边的移动:右手食指按小键盘7,右手无名指按小键盘9。开一盘新游戏,食指和无名指交替按小键盘7和小键盘9直到自杀,多来几局以加深键位印象。

3、掌握左右移1的移动:右手食指按小键盘4,右手无名指按小键盘6。开一盘新游戏,食指和无名指交替按小键盘4和小键盘6直到自杀,多来几局以加深键位印象。

4、掌握左右移2的移动:左手小拇指按字母A,右手小拇指按小键盘+。开一盘新游戏,左右手小拇指交替按直到自杀,多来几局以加深键位印象。在内心建立起这个意识:移动2格=按小拇指。

5、掌握左右回放的移动:左手大拇指按空格,右手大拇指按小键盘0。开一盘新游戏,左右手大拇指交替按直到自杀,多来几局以加深键位印象。在内心建立起这个意识:回放=按大拇指。

6、掌握左移3的移动:右手中指按小键盘8。开一盘新游戏,等到出现棍子、左L、右L、山时,先将它们转成竖的,然后想象要把它们插到左边第三列,然后伸直中指按小键盘8,在内心建立起这个意识:左边第三列=按中指。

三、大量练习,形成连续条件反射

基本掌握旋转和移动条件反射后,开始新游戏,将速度调为1开始练习。先想好摆法,然后先按旋转键,再仔细观察容器底部,判断出要插到第几列,再按下对应的手指。熟练后慢慢提升速度,直到判断出摆法后旋转键和移动键可以连续按下。

可以连续按下旋转键和移动键后,在确定当前块的摆法后先不要操作,观察提示块的摆法。两块的摆法都想好后,连续按四个键来一次性摆好。就这样一次放两块的练习。

可以一次放两块后,尝试连续放块,在第一块放下后,根据新的提示块来决定是否更改原先决定的摆法。然后大量练习,直到可以连续性的条件反射。

【进阶经验】

一、慢降和插孔

插孔主要是用来修复“天灾人祸”的。所谓“天灾”,就是开局或者局势一马平川的时候来一个S或Z,无论怎么摆都会有个洞要补。所谓“人祸”,就是各种失误造成的洞。采用双键打法后失误是难免的,所以掌握慢降插孔是非常重要的。

如果使用的是普速键盘,我们一般会按住慢降键,然后目测方块移动的速率,提前松开慢降键,再通过单点慢降键到达位置。然而当使用极速键盘或加速器时,往往按住慢降键后还没来得及松开,方块已经沉底了。所以很多选手要么彻底放弃了插孔,要么就用疯狂单点慢降来插孔。

双键打法推荐用移花接木设置一个加速慢降键(我用的是Num 1),映射为5次慢降。这样需要慢降插孔的时候可以先评估一下大致需要慢降的行数(0~5、5~10、10~15、15+),先用加速慢降到达差不多的高度,在通过单点慢降到达最终位置。

常规打法插孔还存在一个问题,到位后不敢按落下键,怕掉第二个块。要么按慢降键,要么等第二个块出现,总之节奏会受到影响。而双键打法在下降到正确的高度后,可以直接按左右平移来到达位置。

二、开局插孔

除了开局失误外,开局插孔主要针对的是s开局和z开局。第一块是s或z的话出现洞是必然的,需要用慢降插孔来补。由于上面提到的原因,插孔会影响节奏,而开局时的节奏十分重要,于是很多选手为了保持节奏放弃了插孔这种打法。

但是,如果不用插孔补上这个洞,第一行的资源就无法用于攻击,只有等第二行消开后才能挖开这个洞。而之后发展的局势无法预测,往往这个洞挖不出来,下面对方顶过来的行也借不到。

双键打法推荐设置两个映射,1、左插孔(我用的x)映射为5次左移,14次慢降;2、右插孔(我用的Num3)映射为5次右移,14次慢降。

比如开局出现的是s,那么落下后洞开在右边。这时出现棍子、山、L等可以插孔的块后,先旋转到位再按右插孔,方块会先移到最右边(躲开s块,防止落在上面),然后慢降到靠近底层(没有直接到底是因为要留出缓冲时间,否则如果按插孔键的时机慢了,会直接落地),然后再根据离底层的距离点击慢降键0~2次,当块落到底层的瞬间按左平移。

因为开局插孔情况就那么几种,建议开单机多练习s和z开局,把各种情况要按的键序列记忆下来,熟练之后开局插孔应该是完全连贯的。

【后记】

终于把双键的完整教程写出来,从此不必对每个人都费半天口舌解释双键打方块是怎么一回事了。

很多人觉得双键打法是外挂,我不这样认为。

俄罗斯方块是智慧的游戏,拼的是思考的速度和摆法的优劣。而繁多的操作给人制造了一个瓶颈,使人的操作速度跟不上思维速度。最终拼的是手的力量,而不是智慧的力量。

双键玩法突破了玩家的操作瓶颈(能将极限块速提升到4以上),让玩家真正能够追求思维的极限。是俄罗斯方块游戏历史上的里程碑,相信日后也将是在高级玩家中主流玩法。

随着科技的发展,我相信在不远的将来,打方块连手都不必动了,只要想就可以控制方块。到那时就可以完全放飞玩家的思维了,俄罗斯方块也将到达一个全新的境界。我会期待那一天的早日到来。

最后再说一句:我要玩游戏,不要游戏玩我。