【大赞!】 Geek游戏 - Untrusted 1-21关分析及解答^_^

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 的判断去掉即可。

然后就过了。



至此,通关。



真的很好玩的游戏。说实话。

强烈推荐大家独立完成。

你可能感兴趣的:(【大赞!】 Geek游戏 - Untrusted 1-21关分析及解答^_^)