Skip to content

Instantly share code, notes, and snippets.

@quietlynn
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save quietlynn/e162d0ee924d125af22b to your computer and use it in GitHub Desktop.
Save quietlynn/e162d0ee924d125af22b to your computer and use it in GitHub Desktop.
JavaScript 入门第四次作业

零、请继续复习控制语句

请复习或补习JS的所有控制语句。活动的时候没讲到的 switch 语句等,也请查阅相关书籍 或网络来学习。

对于没有学习过编程或者不了解控制语句的各位,建议在 codecademy 进行简单的训练。

提示

这次的作业题目描述很长……真的很长。如果有看不懂的地方,请不要迟疑,第一时间怀疑出题者的语文水平。没错,出题者的语文就是体育老师教的!

遇到题目没解释清楚的地方,请马上在环聊提问,应该很快就能得到解答了。然后,题目文字可能会更新,增加一些解释。

一、输家洗牌

请编写一个函数 shuffle(array),这个函数接受一个参数 array,是一个数组。

这个函数应该将 array 中的元素进行随机排序,就像洗牌一样。

可以上网搜索洗牌(随机排序)的实现思路,也可以自己考虑。但是不用上网搜索现成的代码了,那会很无聊的。

如果自己考虑了很久也没有思路的话……那用最简单的方法,随机交换多次就行了。

测试一下吧。做这种复杂的逻辑,就一定会需要很多测试。

二、争论?参数!

请自学 arguments 。 JavaScript 中 arguments 变量允许动态访问参数列表,主要用于多个可变参数的使用。

参考资料: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments

题目背景:关于JS语言本身的设计,有很多很多争论。编程语言学家们分成两派或更多派别,互相争吵不休。而这一切争吵的起因,就在于 JS 语言中有 arguments 这个特殊变量。现在,你需要设计一个函数,来消除一切争论(arguments)。

题目要求:写一个函数clearArgs,这个函数接受任意数量的参数,每个参数是一个争论。如果参数数量为零,那么表示没有争论,很和谐,直接返回字符串"harmony"。 如果参数数量不为零,则需要依次解决每一个争论,最后返回一个数组。

  • 如果某个参数是一个字符串,则表示争论的主题。返回结果的数组中添加元素"不能打架,不能打架,JKL好处都有啥,谁说对了就给他!"这里JKL替换成争论的主题。
  • 如果某个参数是一个数组,则表示该争论分为多种观点,每个元素是一种观点。这时返回数组中对应添加"你们说的都很有道理,但是你们说了都不算!"字符串。
  • 如果某个参数是一个函数,说明这是一个很复杂的问题,需要通过进一步争论(arguments)解决。此时应调用这个函数,并且通过参数(arguments)传递之前的所有争论,并将结果返回。
  • 如果参数是其他类型(比如对象),则说明这个争论无法正常解决。这时候要不懂装懂,在资历上鄙视他们,返回"你们呐,太幼稚!"
  • 如果争论数量太多(大于8个),一个一个解决太费事,应该直接快刀斩乱麻,返回一个数组,内容全是"拉出去枪毙十分钟",重复次数与争论数量相同。

样例输入: clearArgs("金珂拉", ["美国圣地亚哥", "中国科学院"], function () { return "亩产" + 900 * arguments.length; }, {})

返回结果: ["不能打架,不能打架,金珂拉好处都有啥,谁说对了就给他!", "你们说的都很有道理,但是你们说了都不算!", "亩产1800", "你们呐,太幼稚!"]

提示:

需要动态传递参数,则需要使用函数的 .apply() 函数。调用时,第一个参数为null,第二个参数为参数列表。如:

(function () { return arguments.length; }).apply(null, [5, 6, 7]) 返回结果为3。相当于 (function () { return arguments.length; })(5, 6, 7)

三、汝可识得此阵?

军师诸葛暗和敌军约定斗阵法,为此需要一个函数来打印阵法图。阵法图是八卦阵的一种变化,由8行8列一共64个字符组成。现在你作为诸葛暗的弟子姜某,需要协助诸葛暗完成这一函数。

诸葛暗已经写好了一个函数bagua(x, y),可以生成八卦阵的基本阵图。这个函数只返回在 (x, y) 处的字符。

一个示例的 bagua 实现: 请注意:之前的函数有问题,现在已经做了一定的修改。

    var bagua = function (x, y) { return String.fromCharCode(48 + x * 8 + y) };

首先,你需要编写一个函数printBagua(bagua),来打印阵法图。参数bagua是诸葛暗写好的那个函数作为参数传入(需要调用64次)。 实现很简单,每行依次 console.log 输出即可。

然后,你需要编写一个函数getVariedBagua(bagua, transform)

其中bagua是诸葛暗写好的那个函数,而 transform 是另一个函数,用于控制换位(后述)。

返回值是一个函数,而不是阵形。返回的函数与bagua大致相同,只返回 (x, y) 处的字符。这样测试的时候可以用 printBagua(getVariedBagua(bagua, transform)) 来测试。

为了让阵形更难破解,诸葛暗决定使用一个 transform(x, y) 函数来控制换位。如果 transform(1, 2) 返回 [3, 4],说明 (1, 2) 位置应该变成原先 (3, 4) 位置的字符。

测试用 transform 函数:

    var transform = function (x, y) { return [7 - x, 7 - y]; };

例: getVariedBagua(bagua, transform)(1, 2) 应该返回 bagua(6, 5)。计算方式是先计算 transform(1, 2) 结果为 [6, 5],根据这个结果选取 bagua(6, 5) 来代替 (1, 2) 位置。 所以返回的实际上是原先阵形 (6, 5) 位置的结果。

有了这个实现以后,就可以利用不同的 tranform 函数来实现阵形的变化,可以做出旋转、交换行列等简单的变换,也可以有更复杂的计算方法。试着做几种吧。

军师诸葛暗觉得只是有这点功夫的话,斗阵法还有些勉强。光列阵还不够,还需要识破对方阵形方可完胜。

编写一个 inspect(original, varied) 函数,这个函数用来判断对方的阵形进行了怎样的变化。

其中 original 是原来的阵形函数, varied 是变化后的阵形函数。(这两个函数与bagua用法相同,但返回结果可能不同)

假设 original 返回的所有字符都不重复,且 varied 中返回的字符都和 original 相同。

请注意:之前的示例bagua函数有问题,现在已经做了一定的修改,不会返回重复字符了。

函数返回一个函数,这个函数相当于对方所用的 tranform 函数。但是注意:返回的函数不是一个简单的变换(比如 7-x),而是由 original 和 varied 决定的一个相当复杂的变换。

提示:这并不是一个数学变换,而是通过对于某个 origial(x, y),寻找与其字符相等的 varied(x2, y2) 所得出的结果。然后返回 [x2, y2].

测试时,先破解自己的阵形:

var varied = getVariedBagua(bagua, transform);
printBagua(varied); // 变化的阵形
var inspectedTransform = inspect(bagua, varied);
printBagua(getVariedBagua(bagua, inspectedTransform));
// 结果应该和 printBagua(varied) 相同
var reverse = inspect(varied, bagua); // 反演阵形变换
printBagua(getVariedBagua(varied, reverse));
// 结果应该和 printBagua(bagua) 相同

测试通过后,诸葛暗就已经做好了上战场的准备。而在战场上总少不了情报通信和加密。诸葛暗自然使用自己最擅长的八卦来进行加密解密。

先准备好一个最长64字符的原文,然后可以用这个加密:

// 加密
var text = "(64字符长的原文)";
var getText = function (x, y) { return text[x * 8 + y]; };
var varied = getVariedBagua(getText, transform);
printBagua(varied);
// 打印出加密过的文本,然后8行可以依次连在一起发送。
// 解密
var message = "(64字符长的加密过的结果,不含换行)";
var varied = function (x, y) { return message[x * 8 + y]; };
var key = getVariedBagua(bagua, transform);
var reverse = inspect(key, bagua);
printBagua(getVariedBagua(varied, reverse));
// 打印出的就是原文

双方都知道 transform 的情况下,就可以进行加密和解密了。

但是如果 transform 只是简单的函数,还不够安全。最好用一个密钥:

// 生成密钥
keyText = "";
for (var i = 0; i < 64; i++) keyText += bagua(Math.floor(i / 8), i % 8);
keyText = shuffle(keyText.split("")).join("");
// 然后事先约定好 keyText.
// 加密
var key = function (x, y) { return ruleText[x * 8 + y]; }
var transform = inspect(bagua, key);
// 解密
var key = function (x, y) { return ruleText[x * 8 + y]; }
var reverse = inspect(key, bagua);

这里先取了 bagua 的所有字符,然后用之前的 shuffle 函数随机排列了一下。

作业要求:

作业并不是必须的,不做也可以。但是,如果做了作业,建议用 https://gist.github.com 把你的解答分享出来,和大家交流。当然,也可以用 jsfiddle 做简单的演示。

做完作业的话,建议马上将作业的网址发到环聊里供讨论。也可以请别人帮忙调试或者解决 问题。记得多看看别人的代码,也许会有更多收获。答案不唯一,只要能达到目的,而且代码 风格不是很差的,都是可以接受的。

只做作业是不够的。请利用空余时间继续自学。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment