共计 4282 个字符,预计需要花费 11 分钟才能阅读完成。
残缺的地图
今天在微信群里面看到一张招聘图片,如下
寻找钥匙
被玷污的残缺的婀娜多汁姿的二维码,蕴藏着通往神秘国度大门的钥匙。利用微信自带截图工具,凭借着我手绘天赋,很快就还原了二维码。
然后查看图片,长按。居然是可以识别的二维码,扫一扫,得到下面的摩斯密码
.–..-……
找到答案
于是,百度摩斯密码对照表。
由于我们得到摩斯密码没有空格隔开,所以解密后有可能不止一种。这个时候,身为攻城虱当然想到是用程序解决了。
既然,图片中说到是 4 个字的单词,等于这段密码可以分为 4 段。
[part1][part2][part3][part4]
如果 4 段密码分别都能匹配上,那么连起来整个密码也能匹配上(废话)。最先想到是用 4 层循环穷举法
for(){
for(){
for(){
for(){
}
}
}
}
可是如何把这段密码分成四段呢?很简单,如果电码符号与密码前几个字符能完全匹配,这里就分一段,然后继续匹配下一段。
for(){
// 匹配成功
if([part1][part2][part3][part4].indexOf(xcode[i]) === 0 ){
for(){
if([part2][part3][part4].indexOf(xcode[j]) === 0 ){
}
}
}
}
第四段,也就是最后一段匹配不能再用 [indexOf],而是用 [===]。
核心匹配代码
for(i = 0; i < morseCodeNum; i ++){
if(mission1.indexOf(morseCodeMap[i]) === 0 ){
firstMatchPart = morseCodeMap[i];
mission2 = secretCode.slice(firstMatchPart.length);
for(j = 0; j < morseCodeNum; j ++){
if(mission2.indexOf(morseCodeMap[j]) === 0 ){
secondMatchPart = morseCodeMap[j];
mission3 = secretCode.slice(firstMatchPart.length+secondMatchPart.length);
for(k = 0; k < morseCodeNum; k ++){
if(mission3.indexOf(morseCodeMap[k]) === 0 ){
thirdMatchPart = morseCodeMap[k];
mission4 = secretCode.slice(firstMatchPart.length+secondMatchPart.length+thirdMatchPart.length);
for(n = 0; n < morseCodeNum; n ++){
if(mission4 === morseCodeMap[n]){
fourthMatchPart = morseCodeMap[n];
console.log([firstMatchPart, secondMatchPart, thirdMatchPart, fourthMatchPart].join(”));
result.push([letters[i], letters[j], letters[k], letters[n]].join(”));
}
}
}
}
}
}
}
}
注: mission1 表示处于匹配第一段密码,以此类推。
完整的代码
var morseCodeMap = [
‘.-‘, ‘-…’, ‘-.-.’, ‘-..’,
‘.’, ‘..-.’, ‘–.’, ‘….’,
‘..’, ‘.—‘, ‘-.-‘, ‘.-..’,
‘–‘, ‘-.’, ‘—‘, ‘.–.’,
‘–.-‘, ‘.-.’, ‘…’, ‘-‘,
‘..-‘, ‘…-‘, ‘.–‘, ‘-..-‘,
‘-.–‘, ‘–..’
],
secretCode = ‘.–..-……’,
morseCodeNum = morseCodeMap.length,
letters = ‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’;
var result = [],
firstMatchPart,
secondMatchPart,
thirdMatchPart,
fourthMatchPart,
mission1,
mission2,
mission3,
mission4;
function deCodeMorse(){
var i, j, k, n;
mission1 = secretCode;
for(i = 0; i < morseCodeNum; i ++){
if(mission1.indexOf(morseCodeMap[i]) === 0 ){
firstMatchPart = morseCodeMap[i];
mission2 = secretCode.slice(firstMatchPart.length);
for(j = 0; j < morseCodeNum; j ++){
if(mission2.indexOf(morseCodeMap[j]) === 0 ){
secondMatchPart = morseCodeMap[j];
mission3 = secretCode.slice(firstMatchPart.length+secondMatchPart.length);
for(k = 0; k < morseCodeNum; k ++){
if(mission3.indexOf(morseCodeMap[k]) === 0 ){
thirdMatchPart = morseCodeMap[k];
mission4 = secretCode.slice(firstMatchPart.length+secondMatchPart.length+thirdMatchPart.length);
for(n = 0; n < morseCodeNum; n ++){
if(mission4 === morseCodeMap[n]){
fourthMatchPart = morseCodeMap[n];
console.log([firstMatchPart, secondMatchPart, thirdMatchPart, fourthMatchPart].join(”));
result.push([letters[i], letters[j], letters[k], letters[n]].join(”));
}
}
}
}
}
}
}
}
}
deCodeMorse();
console.log(result);
得到结果如下,根据图片中的提示,该单词与面试有关,那么应该是 pass 无疑。
上面的代码我们用了 4 层 for 嵌套循环,确实有点多,但是只有 if 条件成立,才会进入深层的循环。因为要求所有解,是避免不了的.
延伸
假如,我们得到的密码可能不是 4 段,不确定是几段,这个时候就不能用嵌套 for 循环了,可以用递归。核心代码逻辑
function deCodeMorse(mission[j]){
for (var i = 0; i < morseCodeNum; i++) {
if(morseCode.indexOf(morseCodeMap[i]) === 0 ){
if(morseCode === morseCodeMap[i]){
// 输出匹配结果
}else{
deCodeMorse(mission[j+1]);
}
}
}
}
使用递归的完整代码
var morseCodeMap = [
‘.-‘, ‘-…’, ‘-.-.’, ‘-..’,
‘.’, ‘..-.’, ‘–.’, ‘….’,
‘..’, ‘.—‘, ‘-.-‘, ‘.-..’,
‘–‘, ‘-.’, ‘—‘, ‘.–.’,
‘–.-‘, ‘.-.’, ‘…’, ‘-‘,
‘..-‘, ‘…-‘, ‘.–‘, ‘-..-‘,
‘-.–‘, ‘–..’
],
secretCode = ‘.–..-……’,
morseCodeNum = morseCodeMap.length,
letters = ‘ABCDEFGHIJKLMNOPQRSTUVWXYZ’,
result = [],
function deCodeMorse(morseCode, deCodeResult, stack){
stack = stack || [];
for (var i = 0; i < morseCodeNum; i++) {
if(morseCode.indexOf(morseCodeMap[i]) === 0 ){
if(morseCode === morseCodeMap[i]){
deCodeResult.push(stack.concat(letters[i]).join(”));
}else{
deCodeMorse(morseCode.slice(morseCodeMap[i].length), deCodeResult, stack.concat(letters[i]));
}
}
}
}
deCodeMorse(secretCode, result);
console.log(result);
我们还可以传一个数字参数给函数 deCodeMorse,表示密码由几段组成,不传则没有限制。那么 deCodeMorse 函数可以这样写
function deCodeMorse(morseCode, deCodeResult, limit, stack){
stack = stack || [];
for (var i = 0; i < morseCodeNum; i++) {
if(morseCode.indexOf(morseCodeMap[i]) === 0 ){
if(morseCode === morseCodeMap[i]){
if(limit){
stack.length +1 === limit && deCodeResult.push(stack.concat(letters[i]).join(”));
}else{
deCodeResult.push(stack.concat(letters[i]).join(”));
}
}else{
if(limit){
if(stack.length < limit){
deCodeMorse(morseCode.slice(morseCodeMap[i].length), deCodeResult, limit, stack.concat(letters[i]));
}
}else{
deCodeMorse(morseCode.slice(morseCodeMap[i].length), deCodeResult, limit, stack.concat(letters[i]));
}
}
}
}
}
deCodeMorse(secretCode, result, 4);