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 的判斷去掉即可。
然後就過了。
至此,通關。
真的很好玩的遊戲。說實話。
強烈推薦大家獨立完成。