Untrusted是个非常好的游戏。。
原来编程还可以这么玩,这么有趣~~
游戏地址: http://alexnisnevich.github.io/untrusted/
下面是1-21关的分析和答案....
-----------------------------------------
01 - CellBlockA
没什么好说的。。这关过不去后面都别想玩了。。
把可编辑部分都删掉就好了。
-----------------------------------------
02 - theLongWayOut
比第一关难一点。但还是没得做。。
既然删不掉那就注释掉吧。
把中间的红色部分给注释掉即可。
-----------------------------------------
03 - validationEngaged
也很简单。。好像删不掉了。。要求至少有numBlocks个。。
那既然至少啊,就多一点不过分吧。。。
于是乎,将方框扩大扩大,直到同时包括了起点和出口。
代码如下:
for (y = 2; y <= map.getHeight() - 3; y++) {
map.placeObject(5, y, 'block');
map.placeObject(map.getWidth() - 5, y, 'block');
}
for (x = 5; x <= map.getWidth() - 5; x++) {
map.placeObject(x, 2, 'block');
map.placeObject(x, map.getHeight() - 3, 'block');
}
-----------------------------------------
04 - multiplicity
不好!限制更大了!
只能修改中间一部分,也就是说你不可能去改整个方框了!。。
怎么办? 注意到上面的提示:Level filenames can be hints, by the way. Have I mentioned that before?
这一关的名称是提示。多样性?什么的多样性?总不可能是方块吧。。
没错!就是出口!再定义一个出口就ok~
加上
map.placeObject(map.getWidth() - 5, map.getHeight()-6, 'exit');
即可
-----------------------------------------
05 - minesweeper
扫雷啊。我们看中间的一行。。这一行是在设置雷的过程中的。
我们的目标是,躲开所有的雷,也就是,将雷都标记上。
怎么标记?背景颜色咯。。加上如下代码即可。
map.setSquareColor(x, y, '#000000');
之后躲开黑色的部分,就顺利过关了。
-----------------------------------------
06 - drones101
从这题开始才真正有难度。题目定义了一个d,这个d每次你行动时都会向你走近一格。
我们想法是,拦住这个d,让它不能碰到你。我们注意到,d的移动条件的是,canMove()为true,那就想办法让不能canMove就行了
所以要自己定义一个物品。。这个物品需要能拦住d,但又是安全的,也就是碰到不会挂。
代码如下:
map.defineObject('safeDrone', {
'type': 'dynamic',
'symbol': 'h',
'color': 'blue',
'onCollision': function (player) { // nothing here!
},
'behavior': function (me) {
moveToward(me, 'player');
}
});
map.placeObject(map.getWidth()-3, 12, 'safeDrone');
然后自己想办法走一走,躲一躲d,很容易的。
-----------------------------------------
07 - colors
要求人物和方块颜色相同才能通过。那就设置呗。。
捡到phone后可以设置callback的回调函数。每经过一个方块,调用一次,改变颜色,再经过下一个。
代码如下:
if (player.atLocation(23, 12)){ player.setColor('#f00');} // 23: 第一个绿色方块后一个。以下同。
if (player.atLocation(26, 12)){ player.setColor('#ff0');}
if (player.atLocation(29, 12)){ player.setColor('#0f0');}
if (player.atLocation(32, 12)){ player.setColor('#f00');}
if (player.atLocation(35, 12)){ player.setColor('#ff0');}
-----------------------------------------
08 - intoTheWoods
额,好像没什么可说的。。方框中填上:"generateForest"
然后,尽量朝终点走吧。。走死了就按Q重新生成森林就好了。水。
-----------------------------------------
09 - fordingTheRiver
过河。多几个raft就好了。但是后面规定了raft只能有一个啊。好难办,,,
既然raft只能有一个。。。那我自己重新定义一个raft没问题吧?这不就可以很多个了么。。
map.defineObject('raftt', {
'type': 'dynamic',
'symbol': '▓',
'color': '#420',
'transport': true, // (prevents player from drowning in water)
'behavior': function (me) {
}
});
for (var y = 5; y < 15; y++) {
map.placeObject(22, y, 'raftt');
}
-----------------------------------------
10 - ambush
也很简单。。自己定义一下行为不阻拦到你就好了。if (me.getY()==12)
{
if (me.getX()==23)
me.move('left');
else me.move('down');
}
黄的不填。
绿的:
if (me.getY()==12)
{
if (me.getX()==27)
me.move('right');
else me.move('down');
}
-----------------------------------------
11 - robot
随便定义,只要机器人能走到出口即可。if (me.getX()!=map.getWidth()-2)
me.move('right');
else me.move('down');
-----------------------------------------
12 - robotNav
一样随便定义。。下--右--上--右--下 的顺序if (me.getX()<=map.getWidth()/2)
{
if (me.canMove('down')) me.move('down');
else me.move('right');
}
else if (me.getX()==map.getWidth()-2) me.move('down');
else
{
if (me.canMove('up')) me.move('up');
else me.move('right');
}
-----------------------------------------
13 - robotMaze
这是少见的几道难题之一。机器人走迷宫。迷宫是随机生成的。我们需要给机器人制定一个策略,使其走出来。
问题的关键在于:在机器人的每一步,怎么去判断该怎么去走?
这题我花了挺久的,最后灵机一动:
我想到了很久以前win98的屏保,就是那个3D迷宫的屏保。
一个人人走迷宫的策略是:
按照当前方向直走。只要能左拐那么就左拐。
换句话说,策略如下:
1. 判断当前能否左拐。如果可以,左拐,当前方向旋转90度。
2. 若不能左拐,判断能否直走。
3. 若1、2都不行,判断能否右拐。
4. 若1、2、3都不行,那么转身180度,即后退。
这样一定可以走出迷宫。
现在,问题的关键在于:如何判断某一步是机器人的当前方向?(是正在向右,向上,向左,还是向下?)
所以我们需要做标记。
标记的方法有很多种。我这里采用的是,玩家的颜色进行标记。
当颜色为#0f0时代表向右,#ff0代表向上,#f00代表向左,#0ff代表向下。
那么,每次,取当前颜色,得到当前方向,判断能否左转等。如果方向改变,随之改变颜色。
代码如下。
// player color:
// #0f0: right
// #ff0: up
// #f00: left
// #0ff: down
// turn left - go ahead - turn right - turn back
if (me.getX()==map.getWidth()-2 && me.getY()>=8) // has get the key
me.move('down');
if (player.getColor()=='#0f0') { // now: right
if (me.canMove('up'))
{
player.setColor('#ff0');
me.move('up');
}
else if (me.canMove('right')) {
player.setColor('#0f0');
me.move('right');
}
else if (me.canMove('down'))
{
player.setColor('#0ff');
me.move('down');
}
else if (me.canMove('left'))
{
player.setColor('#f00');
me.move('left');
}
}
else if (player.getColor()=='#ff0') { // now: up
if (me.canMove('left'))
{
player.setColor('#f00');
me.move('left');
}
else if (me.canMove('up'))
{
player.setColor('#ff0');
me.move('up');
}
else if (me.canMove('right')) {
player.setColor('#0f0');
me.move('right');
}
else if (me.canMove('down'))
{
player.setColor('#0ff');
me.move('down');
}
}
else if (player.getColor()=='#f00') { // now: left
if (me.canMove('down'))
{
player.setColor('#0ff');
me.move('down');
}
else if (me.canMove('left'))
{
player.setColor('#f00');
me.move('left');
}
else if (me.canMove('up'))
{
player.setColor('#ff0');
me.move('up');
}
else if (me.canMove('right')) {
player.setColor('#0f0');
me.move('right');
}
}
else if (player.getColor()=='#0ff') { // now: down
if (me.canMove('right')) {
player.setColor('#0f0');
me.move('right');
}
else if (me.canMove('down'))
{
player.setColor('#0ff');
me.move('down');
}
else if (me.canMove('left'))
{
player.setColor('#f00');
me.move('left');
}
else if (me.canMove('up'))
{
player.setColor('#ff0');
me.move('up');
}
}
-----------------------------------------
14 - crispsContest
看题目描述,貌似和3-SAT有关系的一道题?管他那么多,能做出来就ok,嗯!
我们要看,过绿门的时候,需要消耗什么钥匙。显然不可能是绿钥匙。
那么只可能是红色钥匙或者蓝色钥匙。
蓝色钥匙挺多的,看起来靠谱点,事实上,就是蓝色钥匙。
填写 blueKey 然后按照如下策略通过:
过蓝门进左边的房间(得黄钥匙)——过绿门进左上房间(得蓝钥匙)——过蓝门回到中间——过红门进入右上房间(得红钥匙)——过绿门进入右边的房间(得蓝钥匙)——过黄门进左下房间(得A)——过蓝门进右下房间(得黄钥匙)——回到中间
-----------------------------------------
15 - exceptionalCrossing
很贱的一个题!我们发现,你要过河,但是你不能定义任何东西。也就是只能硬着头皮想办法过。
而 onCollision 中已经定义了,当和水相撞时,调用 killedBy 函数,也就是只能自定义被挂的字符串。
看似无解了,怎么办?
我们发现,要过的话,onCollision 必须得调用。而调用 onCollision 就会调用 killedBy 函数,然后就会挂掉。
这中间可以做文章! 我们调用 onCollision 的时候,能否不调用 killedBy 呢?
可以的。 onCollision 重载掉。
于是这个很贱的方法就出来了。
将第31-33行补全为如下:
'onCollision': function (player) {
player.killedBy('');},'onCollision':function(){a(1);
}
然后就可以过了。
这方法真的很贱。。
-----------------------------------------
16 - lasers
这题也挺难的。我们要想办法,让人物接近一个激光的时候,变成这个激光的颜色。
很自然要想到,需要自己定义object,然后将相撞条件设置为,当碰到object的时候,改变玩家的颜色为object的颜色。
我的做法是,取每条激光正中心的点(x,y),然后将(x-1,y-1), (x-1,y+1), (x+1, y-1), (x+1, y+1) 放置自定义object,颜色为激光颜色,相撞条件为,将玩家颜色改成此颜色。
注意一:
object 只能在函数里定义,且只能定义一次。因此只能在第一次循环的时候进行定义。
要判断是不是第一次循环,只能用全局变量。 还好javascript是面向对象的。也就是变量的声明可以放在函数之后。
所以在函数结束后再声明变量也是可以的。
注意二:
centerX和centerY是像素坐标,要将其转化成格子的坐标。
依照 width:length=600:500 进行放缩即可。
函数内的代码如下:
if (xxx!=1) // Is the first time?
{
xxx=1;
map.defineObject('r', {
'type': 'dynamic',
'symbol': 'R',
'color': 'red',
'onCollision': function (player, me) {
player.setColor("red");
}});
map.defineObject('y', {
'type': 'dynamic',
'symbol': 'Y',
'color': 'yellow',
'onCollision': function (player, me) {
player.setColor("yellow");
}});
map.defineObject('t', {
'type': 'dynamic',
'symbol': 'T',
'color': 'teal',
'onCollision': function (player, me) {
player.setColor("teal")
}});
}
var ctx = map.getCanvasContext();
ctx.beginPath();
ctx.strokeStyle = color;
ctx.lineWidth = 5;
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
var cx=Math.floor(centerX*map.getWidth()/600);
var cy=Math.floor(centerY*map.getHeight()/500);
if (color=="red") {
map.placeObject(cx-1, cy-1, 'r');
map.placeObject(cx+1, cy+1, 'r');
map.placeObject(cx-1, cy+1, 'r');
map.placeObject(cx+1, cy-1, 'r');
}
else if (color=="yellow") {
map.placeObject(cx-1, cy-1, 'y');
map.placeObject(cx+1, cy+1, 'y');
map.placeObject(cx-1, cy+1, 'y');
map.placeObject(cx+1, cy-1, 'y');
}
else {
map.placeObject(cx-1, cy-1, 't');
map.placeObject(cx+1, cy+1, 't');
map.placeObject(cx-1, cy+1, 't');
map.placeObject(cx+1, cy-1, 't');
}
而函数外代码仅一行,是对xxx的声明:
var xxx;
-----------------------------------------
17 - pointers
陷阱&传送门。传送门之间只完全随机连接,一些传送门会直接连到陷阱上。
要填的那一部分,是传送门互相连接的时候的部分。
我们可以在传送门上做标记。
当传送门之间连到陷阱的话,将传送门和陷阱都变红,代表危险。那么得到的不是红色的传送门就不会连到陷阱,是安全的。
然后自己走吧。由于地图随机生成,可能会无解,多走几次碰碰运气就出来了。挺简单的。
要填写的代码如下:
if (t1.getType()=='trap' || t2.getType()=='trap')
{
map.setSquareColor(t1.getX(), t1.getY(), 'red');
map.setSquareColor(t2.getX(), t2.getY(), 'red');
}
-----------------------------------------
18 - superDrEvalBros
重力都出来了。我们看到,player下落的条件是,player下方为empty
那么我们就让它不会empty就好了呗。也就是自己建object然后把桥给补全。
代码如下:
map.defineObject('r', {
'type': 'none',
'symbol': 'A',
'color': 'red'
});
for (var x=fl(w/2)-5;x<=fl(w/2)+4;x++)
map.placeObject(x,fl(h/2),'r');
-----------------------------------------
19 - documentObjectMadness
我也没搞清楚这个题是要干嘛。好像是。绿色是你控制的,红色是随机的,然后只要红色和绿色碰到一起就好了。
随便按一按就过了,真的。相信我。
-----------------------------------------
20 - bossFight
这个题很有意思。我们要打败boss才行。怎么打败?
看API,里面提供了object.projectile这一项,若其为true,那么它会摧毁它【主动碰到】的同为dynamic的物品。
boss也是dynamic啊。
所以,我们要创建object,将其projectile设置为true,然后让它主动去碰boss,之后就可以干掉所有的boss了。
注意不能在一开始就生成object。也就是只能在获得电话后进行callback回调生成object。
于是,首先躲过枪林弹雨(好像也不是太麻烦的样子。挺容易过的呢。),获得电话。之后生成object,干掉boss
代码如下:
map.defineObject('bomb', {
'type': 'dynamic',
'symbol': 'o',
'color': 'gray',
'projectile': true,
'interval': 100,
'behavior': function (me) {
me.move("up");
}
});
map.getPlayer().setPhoneCallback(function(){
for (var x=0;x<=map.getWidth()-1;x++) {
map.placeObject(x,7,'bomb');}
});
-----------------------------------------
21 - endOfTheLine
可以直接修改源代码了。和前面比较,发现不能过的原因是多了一个 map.finalLevel = true;
所以我们找到exit时对于finalLevel的判断。
进 Menu/scripts/object.js
将第28-30行对于 game.map.finalLevel 的判断去掉即可。
然后就过了。
至此,通关。
真的很好玩的游戏。说实话。
强烈推荐大家独立完成。