一、前言周末在微博上看到 coolshell 博主陈皓搞了一个编程小游戏的页面,过关制的。感觉很有趣,就打开看了看。有空没空搞了3天才算搞定,感觉眼界开阔了一些,但是对每一关涉及到的知识都了解的太浅,这里仅仅记录一下通关过程,至于涉及到的知识会在最近学习一下:)首先,游戏地址是:coolshell 大闯关。游戏规则很简单。每一关都需要得到一个结果,把这个结果填进 url 即可进入下一关。下面是通关攻略(强烈建议自己先试试,每一关如果20分钟都没思路就可以看看攻略了)二、通关过程0. first.html这一关由两部分组成:一段乱七八糟的符号一个提示语:My brain has been fucked当我打开这个页面的时候,感觉这啥玩意啊。难道是正则表达式提取?于是看了看+号,依次是1个,2个,3个……然后又找了各种规律找不到,很是郁闷。于是就去干别的了。等我无聊的时候打开了这个页面的源代码,灵光一现发现上面不是纯文本,而是一段 code,那提示语应该跟 code 相关吧?于是就在网上开始搜,百度必应不出意料的呵呵呵(原谅我一直黑,但这是事实啊。。),于是用 google 开始搜,(⊙o⊙)…然后发现 fuck 被 google 过滤了,和简单,把安全过滤去掉就好了(中文版 google 是不能去掉安全过滤的,你懂的。所以切换到中文繁体,然后在右下方的设置里面去掉安全过滤之后拉到最下面保存即可)。然后看了几个网页,进了英文版的 wikipedia,然后答案就很明显了。原来有门编程语言叫做 brainfuck。之后就很 easy 了,可以看看这是静态还是动态的,静态的就找个编译器和解释器,动态的直接在网上找个解释器就好。我随手搜了个在线运行的网站,把代码贴进去。执行结果是welcome,于是下一关就被打开了。总结一下:brainfuck wiki找一个在线执行 brainfuck 代码的网站,比如这个brainfuck贴进去点击 Run,看输出就哦了1. welcome.html这关很简单的其实,根据等比数列,可以首先得到一个数字:18 * 108=1944。然后试一下,发现这个1944对了。但是还有其他答案,应该是在那句话里。这次聪明了直接 google,然后直接知道是42。然后发现也对了,但是没有进入下一关。从 X * Y 那个来看,难道是求一下乘积?尝试着 1944 * 42 = 81648。然后就过关了= =总结一下:生命、宇宙以及任何事情的终极答案——42,为什么?你丫不会 google 啊2. 81648.html一个硕大的键盘,鼠标滑过图片发现可以点击。然后会进入一个 wiki,大概看看介绍,这个布局是为了提高打字速度设计的,跟目前的布局也是一一对应的,然后自己人肉翻译一下即可,得到下面的代码:1 main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}发现原来是一段 C 代码,用 gcc 编译执行后,输出 unix,得解。总结一下:为打字出现的Dvorak Simplified Keyboard和目前使用的QWERTY键盘布局那段代码很有厉害,可自行 google 一下3. unix.html出来一个二维码,用微信扫一下发现是一个字典。结合二维码下面那一段话,就非常简单了。写段程序翻译一下即可。随手写了一个: 1 #include2 #include3 #include4 #include5 6 #define N 1000 7 char a[] = "abcdefghijklmnopqrstuvwxyz"; 8 char b[] = "pvwdgazxubqfsnrhocitlkeymj"; 9 char ci[N];10 11 char find(char c) {12 int i;13 for(i = 0; i < 26; i++) {14 if(c == b[i]) {15 break;16 }17 }18 return a[i];19 }20 21 int main() {22 char *str = "Wxgcg txgcg ui p ixgff, txgcg ui p epm. I gyhgwt mrl lig txg ixgff wrsspnd tr irfkg txui hcrvfgs, nre, hfgpig tcm liunz txg crt13 ra \"ixgff\" tr gntgc ngyt fgkgf.";23 24 int len = strlen(str);25 for(int i = 0; i < len; ++i) {26 char c = str[i];27 if(isalpha(c) && islower(c)) {28 ci[i] = find(c);29 } else {30 ci[i] = c;31 }32 }33 34 printf("%s\n", ci);35 return 0;36 }/*output:37 Where there is a shell, there is a way. I expect you use the shell command to solve this problem, now, please try using the rot13 of "shell" to enter next level.38 */发现输出需要用到 rot13,这是啥?!google 一下就知道了,原来就是一个简单的加密工具,因为英文字母有26个,13对,所以正好可以一一对应。然后 google 一下使用方法就可以了,或者懒得直接找一个在线 rot13转换的工具,输入 shell 后得到结果:furyy总结一下:学习一下 rot13这种加密方式:rot-13 wiki4. furyy.html因为以前在玩正则表达式的游戏时遇到个这个模式,瞬间就知道这个是考察正则的了。根据那个单词,知道是回文字符串。根据图示知道需要找出能匹配左边8个单词的模式,然后提示语说在源码中有东西。打开源代码拉到最下面有一大段文本,保存到一个文件中。这时候思路已经很明显了,用找出来的模式去匹配这段文本。那么,首先就需要找出这个模式,如果以前学过正则表达式的话,应该是很 easy 的。如果不太会,在下面总结的时候我会推荐一个讲解正则表达式很好的地方,配套有一个练习的地方(额,难度略高)。找出来这个模式也很简单,人肉看下就是:第一个字符是大写或者数字第二个字符是大写或者数字第三个字符是小写第二个字符第一个字符所以,考察的就是最简单的正则表达式,其中回文也可以用正则中的()来匹配。这样答案就出来了:([A-Z])([0-9])[a-z]\2\1|([0-9])([A-Z])[a-z]\4\3然后有输入了,有处理过程了,执行一下即可得到输出:egrep -o '([A-Z])([0-9])[a-z]\2\1|([0-9])([A-Z])[a-z]\4\3' palindrome然后就可以得到答案:E1v1E4FaF49XrX9O3i3O0MaM04GbG4M5l5M0WeW0Y0s0Y这几个都是回文串,我们根据 cat 是最中间小写字母的原则拿出来,得到答案:variables总结一下:正则表达式学习正则表达式游戏5. variables.html妈蛋这个页面让我困了大半天,不知道想表达什么意思。我以为是那个数字有特殊的含义,google 了半天找到看起来靠谱的英文。好像是美国哪个州的 zipcode 啥的,填进去各种404,让我很是崩溃。。。 最后也没搞定,是看了网上已经出来的攻略才知道。。(这次写攻略才发现那句提示有点作用,让你 keep try...)原来需要拿那个数字替换 url 中的2014,于是我就替换了,大概替换了10多次,还是需要替换。。估计要写个程序的样子,于是用 shell 写了个 while 循环,里面就是一个简单的 curl 命令,最后得到了答案:tree总结一下:善于观察,这道题如果仔细看说不定会找到思路,,,,不过嘛,,,,,,,,,,遇到我这种智商的就,,,,,,,不说了,擦泪去6. tree.html这道题就简单了,就是一个树。扫了一眼就知道题意是由中序和后序还原树,然后求得最深路径。于是写了一段代码,特么由于好久没碰指针,各种凌乱,吭哧吭哧花了将近1个小时才搞定,,,真是弱爆了。。。。 1 #include2 #include3 #include4 #include5 using namespace std; 6 7 struct Node 8 { 9 char value;10 Node *left;11 Node *right;12 };13 14 string t_in, t_post;15 char in[100], post[100];16 char deep[100], final[100];17 int maxlen;18 19 void init() {20 int p = 0;21 for(int i = 0; i < t_in.length(); i++) {22 if(isalnum(t_in[i]))23 in[p++] = t_in[i];24 }25 26 p = 0;27 for(int i = 0; i < t_post.length(); i++) {28 if(isalnum(t_post[i]))29 post[p++] = t_post[i];30 }31 }32 33 Node* build(char *in, char *post, int len) {34 if(len == 0)35 return NULL;36 37 Node *cur = new Node;38 cur->value = post[len - 1];39 int lenp = strchr(in, cur->value) - in;40 cur->left = build(in, post, lenp);41 cur->right = build(in + lenp + 1, post + lenp, len - 1 - lenp);42 43 return cur;44 }45 46 void pre_order(Node *root) {47 if(root == NULL) {48 return ;49 }50 51 cout
52 pre_order(root->left);
53 pre_order(root->right);
54 }
55
56 void find(Node *root, int depth) {
57 if(root == NULL) {
58 if(depth - 1 > maxlen) {
59 maxlen = depth - 1;
60 memcpy(final, deep, sizeof(deep));
61 }
62 return ;
63 }
64
65 deep[depth] = root->value;
66 find(root->left, depth + 1);
67 find(root->right, depth + 1);
68 }
69
70 int main(void) {
71 Node *root = new Node;
72 t_in = "T, b, H, V, h, 3, o, g, P, W, F, L, u, A, f, G, r, m, 1, x, J, 7, w, e, 0, i, Q, Y, n, Z, 8, K, v, q, k, 9, y, 5, C, N, B, D, 2, 4, U, l, c, p, I, E, M, a, j, 6, S, R, O, X, s, d, z, t";
73 t_post = "T, V, H, o, 3, h, P, g, b, F, f, A, u, m, r, 7, J, x, e, w, 1, Y, Q, i, 0, Z, n, G, L, K, y, 9, k, q, v, N, D, B, C, 5, 4, c, l, U, 2, 8, E, I, R, S, 6, j, d, s, X, O, a, M, p, W, t, z";
74 init();
75 cout<