CoolShell博主陳皓做了一個在線的puzzle很有意思,鏈接在這里,這里記錄一下解題的一些步驟。
Puzzle 0
++++++++[>+>++>+++>++++>+++++>++++++>+++++++>++++++++>+++++++++>++++++++++>+++++++++++>++++++++++++>+++++++++++++>++++++++++++++>+++++++++++++++>++++++++++++++++<<<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>>-.+<<<<<<<<<<<<<<<>>>>>>>>>>>>>---.+++<<<<<<<<<<<<<>>>>>>>>>>>>>>----.++++<<<<<<<<<<<<<<>>>>>>>>>>>>+++.---<<<<<<<<<<<<>>>>>>>>>>>>>>-.+<<<<<<<<<<<<<<>>>>>>>>>>>>>>---.+++<<<<<<<<<<<<<<>>>>>>>>>>>>>---.+++<<<<<<<<<<<<<>>>>>>--.++<<<<<<>>>>>>>>>>>>>.<<<<<<<<<<<<<>>>>>>>>>>>>>>>----.++++<<<<<<<<<<<<<<<>>>>>>>>>>>>>>---.+++<<<<<<<<<<<<<<>>>>>>>>>>>>>>----.++++<<<<<<<<<<<<<<.
如果之前沒有聽說過變態的編程語言,就讓你見識一下。BrainFuck也稱BF,是一門只有8個指令構成的圖靈完備的語言。CoolShell博主陳皓寫過一篇簡單的介紹在這里
具體的指令解釋不多說了,直接打長這里,把上面的指令粘進去,運行得到下一關的地址:welcome.html
。
Puzzle welcome.html
X * Y
2, 3, 6, 18, 108, ?
What is the meaning of life, the universe and everything?
生命、宇宙以及任何事情的終極答案
這題有兩個線索,首先是這串數字,其次是生命、宇宙以及任何事情的終極答案
。數字序列找規律並不復雜,每個數字是前兩個數字之積,那么直接用18 * 108
的結果1944
嘗試進入下一關,發現只找到了一個答案。第二個答案很有意思,或者說很極客
很宅
,直接google發現和《銀河系漫游指南》有關,wiki地址在這里。
用1944 * 42
的答案81648
進入下一關。
Puzzle 81648.html
macb() ? lpcbyu(&gbcq/_\021%ocq\012\0_=w(gbcq)/_dak._=}_ugb_[0q60)s+
放眼望去是Dvorak
鍵盤,點圖片可以看到詳細信息。那么意圖很明顯了,Dvorak
和QWERTY
鍵盤轉換一下看看會怎么樣?這里有個在線的轉換工具,然后:
main() { printf(&unix["\021%six\012\0"],(unix)["have"]+"fun"-0x60);}
WTF……搜了一下,這是87年國際C語言混亂大賽的一段代碼。C語言了解不多,趁這個機會了解了解戳這里,還有這里,列一些解此題的關鍵知識點。
- unix關鍵字相當於
#define unix 1
- 數組的引用,array[num]和num[array]效果相同,所以(unix)["have"] 等於"have"[unix],結果是
a
,ASCII是0x61 0x61 + "fun" - 0x60
相當於對fun
右移0x61
指針再左移0x60
指針,也就是說fun
右稱一位,結果是un
- \021是換頁,於是
&unix["\021%six\012\0"]
約為&unix["\n%six\n\0"]
,%s
被替為前面的un
,&unix
再跳過了第一個\n
,所以結果是unix
使用unix
,進入下一題。
Puzzle unix.html
微信掃碼,得到:
[abcdefghijklmnopqrstuvwxyz] <=> [pvwdgazxubqfsnrhocitlkeymj]
看來是一個簡單的替代,請出大shell
echo 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. | tr "pvwdgazxubqfsnrhocitlkeymj" "abcdefghijklmnopqrstuvwxyz"
得到:
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.
這里我腦抽了一下,沒看仔細以為是用shell命令,嘗試各種tr
以及tr xxx xxx
都不行,后來出去跑了個步,回來再讀一遍發現是用rot13
轉換一下shell
這個字符串,wtf……
echo "shell" | tr "[A-Za-z]" "[N-ZA-Mn-za-m]"
順利得到下一關地址:furyy
Puzzle furyy.html
啊回文,差點一口老血死在這里……
剛開始思路有點歪,總以為是用cat
再加上什么關鍵字得出一個單詞,cat
的規律其實已經注意到了,只是在糾結於怎么找到后續字母的規律……媽的走的有點遠扯着蛋了。
后來又是認真讀了下揭示語The answer has been lost in the source
,咦……
Ctrl + Shift + I
打開Chrome的源代碼查看工具(IE F12),看見一坨亂碼躺在那里,就是它了,很明確,正則表達式。把亂碼扔到一個文本文件里,然后執行:
cat data.txt | grep -E "([A-Z])(\d{1})[a-z](\2)(\1)|(\d{1})([A-Z])[a-z](\6)(\5)" -o
輸出
E1v1E
4FaF4
9XrX9
O3i3O
0MaM0
4GbG4
M5l5M
0WeW0
Y0s0Y
使用所有中間的字母variables
過關。
Puzzle variables.html
點圖片,進入http://fun.coolshell.cn/n/2014
,顯示了一個數字,這時候我腦殘的用顯示的數據作為answer,顯然不行。
看到url里的2014
了嗎?用網頁里的數字替換2014
,然后又出現一個新數據,哦原來是這樣……接下來就簡單多了,上bash腳本。
#!/bin/bash
baseUrl="http://fun.coolshell.cn/n"
result="2014"
while [[ $result -ne "" ]]; do
result=$(curl -s $baseUrl/$result)
echo "=> $result"
done
輸出片斷:
=> 32722
=> 13310
...
=> 16626
=> 20446
=> Cool! the next level is "tree"
run.sh: line 6: [[: Cool! the next level is "tree": syntax error in expression (error token is "! the next level is "tree"")
雖然腳本不完美,但是沒辦法,因為不知道最后會輸出什么,這樣看來搞出error也是不錯的選擇……使用tree
過關。
Puzzle tree.html
這道題很直白,純考功底。先還原二叉樹,然后找出最深路徑,使用此關鍵字解密字符串U2FsdGVkX1+gxunKbemS2193vhGGQ1Y8pc5gPegMAcg=
。
由於只有中序的后序的遍歷序列,所以需要先從后序序列倒着取出根節點,然后再通過中序序列和后序序列來確立左子樹和右子樹,此過程遞歸完成。用js寫了一段代碼來還原二叉樹:
var inOrderSeq = ["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"];
var postOrderSeq = ["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"];
function parseTree(inOrder, postOrder) {
if (inOrder.length == 0 || postOrder.length == 0) {
return null;
}
var root = postOrder[postOrder.length - 1];
var inOrderIndex = inOrder.indexOf(root);
var leftTreeInOrder = inOrder.slice(0, inOrderIndex);
var leftTreePostOrder = postOrder.slice(0, inOrderIndex);
var rightTreeInOrder = inOrder.slice(inOrderIndex + 1);
var rightTreePostOrder = postOrder.slice(inOrderIndex, -1);
var node = {
node: root,
left: parseTree(leftTreeInOrder, leftTreePostOrder),
right: parseTree(rightTreeInOrder, rightTreePostOrder)
};
return node;
}
var tree = parseTree(inOrderSeq, postOrderSeq);
OK,樹還原出來了,還需要進行最深路徑查找腦中瞬間閃出DFS,完全由於深度優先
四個字。
,這個和深度優先搜索有點像但並不是搜索,通過遞歸的方式得到最長的路徑。順便提一嘴,BFS(廣度優先)借助隊列實現,DFS(深度優先)借助棧實現。好了,大學課程回憶完畢,上代碼:
function findDeepestPath(selfNode) {
if (selfNode == null) {
return [];
}
if (selfNode.left == null || selfNode.right == null) {
return [selfNode];
}
var leftPathSeq = findDeepestPath(selfNode.left);
var rightPathSeq = findDeepestPath(selfNode.right);
if (leftPathSeq.length > rightPathSeq.length) {
return [selfNode].concat(leftPathSeq);
} else {
return [selfNode].concat(rightPathSeq);
}
}
得到結果zWp8LGn01wxJ7
,保留這個結果,因為下道題還用的到。
echo U2FsdGVkX1+gxunKbemS2193vhGGQ1Y8pc5gPegMAcg= | openssl enc -aes-128-cbc -a -d -pass pass:zWp8LGn01wxJ7
nqueens
,進入下一題。
Puzzle nqueens.html
這個倒是簡單粗暴,考回溯算法,求解n后,然后暴力窮舉出答案。寫求n后解。本想用C#寫個小程序,然后生成一個帶有所有解txt文件,后來想想何必呢,還是繼續用js吧,有node呢……
var crypto = require('crypto');
var passwd = "zWp8LGn01wxJ7";
var target = "e48d316ed573d3273931e19f9ac9f9e6039a4242";
function writeResult(results) {
var resultStr = results.map(function (v) {
return v + 1;
}).join("");
var hashString = passwd + resultStr + "\n";
var sha1 = crypto.createHash('sha1');
sha1.update(hashString)
var digest = sha1.digest('hex') ;
if(digest == target) {
console.log(resultStr);
}
}
function conflict(results, theLocation) {
for (var row = 0; row < results.length; row++) {
var queenLoction = results[row];
if (queenLoction == theLocation) {
return true;
}
var rowDiff = results.length - row;
var locationDiff = Math.abs(theLocation - queenLoction);
if (rowDiff == locationDiff) {
return true;
}
}
return false;
}
function solveQueens(size, results) {
if (typeof results === "undefined") { results = []; }
for (var pos = 0; pos < size; pos++) {
if (conflict(results, pos)) {
continue;
}
// pos is good.
var newResults = results.slice(0);
if (newResults.length == size - 1) {
newResults.push(pos);
writeResult(newResults);
} else {
newResults.push(pos);
solveQueens(size, newResults);
}
}
}
調用solveQueens(9)
並在node下運行即可。
最終的代碼合並了計算sha1的部分,注意sha1字符串的最后一定要加\n
,否則是算不出結果的。
順利拿到下一關入口953172864
。
Puzzle 953172864.html
通過對第一列的觀察,發現這是一個26進制/10進制的對應表。那么接下來的總是就是如果將COOLSHELL / SHELL
轉化為10進制並轉換回26進制對應的字母的問題。
首先COOLSHELL對應的10進制數字分別為3 15 15 12 19 8 5 12 12
,計算公式如下:
3*26^8+15*26^7+15*26^6+12*26^5+19*26^4+8*26^3+5*26^2+12*26^1+12*26^0
使用Excel或Google計算結果為751743486376
。同理,SHELL
結果為8826856
。
接下來將兩個數相除的結果85165
(這個數是帶小數,但是因為除數和被除數都是整數所以結果也是整數)轉回26進制,即輾轉相除法
,重復模
26並取余數,得到15 25 21 4
,對應的字母為DUYO
,Bingo進入最后一題。
Puzzle DUYO.html
最后一關是最輕松的一關,從圖片得出線索是豬圈密碼,然后通過一幅簡單的圖可輕松逆向出答案:helloworld
.
ps: 通過圖形的形狀找圖中該圖形所對應的字母。
pps: 昨天答完的時候通過Top100看到是六十多名,今天再打開發現自己的成績不見了很奇怪,耗子叔叔我沒作弊啊……
=============================
UPDATES:
今天才知道有隱藏劇情……
最后helloworld.html頁面填完信息后,會出現一個大大的shutdown圖標,查看頁面源代碼發現:
<span style="color:white">Did you even think vi a image file?
</span>
OK,不要點圖片,直接把圖片存到本地。然后本能的想到圖片里藏有信息。使用文本工具打開,亂碼一片。簡單粗暴一些,將后綴名改為.zip
,然后解壓,會發現有個helloworld.txt
文件,打開,閱讀,通過……