Al livello 13, il robot si trova in alto a sinistra di un labirinto generato casualmente. Come posso fargli ottenere la chiave blu e darmela?
Al livello 13, il robot si trova in alto a sinistra di un labirinto generato casualmente. Come posso fargli ottenere la chiave blu e darmela?
Piuttosto che creare una semplice IA, è molto più facile fare in modo che il Robot rispecchi i tuoi movimenti utilizzando il seguente codice:
if (me.getY () >map.getPlayer (). getY () -9) me.move ('up'); else if (me.getY () <map.getPlayer (). GetY () - 9) me.move ('down'); else if (me.getX ( ) >map.getPlayer (). GetX ()) me.move ('left'); else if (me.getX () <map.getPlayer (). GetX ()) me.move ('right');
Quindi spostati in alto e a sinistra finché il robot non rispecchia i tuoi movimenti. Guidalo attraverso il labirinto come se lo stessi controllando. Una volta che ha la chiave ed è fuori, spostati a destra e vai fino in fondo per entrare in collisione con la R
e prendere la chiave.
*
* Nota che il tuo labirinto sarà probabilmente diverso, ma guidare il robot è semplice quando i suoi controlli corrispondono ai tuoi.
Non hai bisogno di un'intelligenza artificiale sofisticata per risolvere il problema. Usa una semplice strategia "abbraccia il muro alla tua destra" e puoi sfuggire a qualsiasi labirinto. Ci vuole semplicemente un po 'più di tempo.
var dirs = [' left ',' up ',' right ',' down ']; if (map.rdir === undefined) map.rdir = 0; // Il buon vecchio algoritmo hug-the-wall-to-your-right var trythese = [map.rdir + 1, map.rdir, map.rdir - 1, map.rdir + 2]; for (var i = 0; i<4; i ++) {var d = (trythese [i] + 4)% 4; if (me.canMove (dirs [d])) {me.move (dirs [d]) map.rdir = d; rompere; }}
Nota che sto memorizzando una proprietà extra su map
( map.rdir
) per farlo. Ciò è totalmente consentito poiché JavaScript consente l'uso di proprietà arbitrarie sugli oggetti.
Pensavo che sarebbe stato molto più divertente scrivere un'IA più elaborata, quindi l'ho fatto. Ecco un semplice algoritmo di ricerca del percorso che completerà tutti i labirinti del robot.
var getMoveToward = function (x, y) {var pointsEqual = function (p1, p2) {return p1 [0] == p2 [0] && p1 [1] == p2 [1]; } var curPoint = [me.getX (), me.getY ()]; var targetPoint = [x, y]; var mark = {}; var pointString = function (p) {return p [0] .toString () + ',' + p [1] .toString (); } var markPoint = function (p) {marks [pointString (p)] = true; } var isPointMarked = function (p) {segni di ritorno [pointString (p)] == true; } var getUnmarkedMoves = function (d, p) {var offsetList = {'left': [-1, 0], 'right': [1, 0], 'up': [0, -1], 'down' : [0, 1]} var unmarkedMoves = [] for (var dir in offsetList) {var offset = offsetList [dir]; var movePoint = [p [0] + offset [0], p [1] + offset [1]]; if (map.getObjectTypeAt (movePoint [0], movePoint [1])! = 'block' &&! isPointMarked (movePoint)) {unmarkedMoves.push ([d == null? dir: d, movePoint]); markPoint (movePoint); }} return unmarkedMoves; } markPoint (curPoint); var moveStack = [[null, curPoint]]; while (moveStack.length > 0) {var move = moveStack [0]; moveStack.shift (); if (pointsEqual (move [1], targetPoint)) {return move [0]; } else {moveStack = moveStack.concat (getUnmarkedMoves (move [0], move [1])); }} return null;} var move = getMoveToward (map.getWidth () - 2, 10); if (move! = null) {me.move (move);}
La mia soluzione era ancora un'altra: ho creato una mappa di riempimento alla prima corsa mappando le posizioni nella direzione verso l'uscita.
In questo modo, ottieni il ritardo di calcolo solo al primo movimento e tutte le mosse successive sono veloci e il robot è sicuro di farcela senza dover rigenerare il labirinto.
funzione getMove (me) {if (me.getY () > 9) return '' ; return me.floodPath [[me.getX (), me.getY ()]];} if (! me.floodPath) {me.floodPath = {}; var rcol = map.getWidth () - 2; var direction = ['su', 'giù', 'sinistra', 'destra']; var opposites = {up: 'down', down: 'up', left: 'right', right: 'left'}; var diffs = {su: [0, -1], giù: [0, 1], sinistra: [-1, 0], destra: [1, 0]}; // Inizia floodPath con un percorso attraverso la barriera me.floodPath [[rcol, 10]] = 'down'; me.floodPath [[rcol, 9]] = 'down'; me.floodPath [[rcol, 8]] = 'down'; var iterEdges; // Inizializza i bordi con la chiave var edge = [[rcol, 8]]; funzione addDiff (pos, dir) {var dif = diffs [dir]; ritorno [pos [0] + dif [0], pos [1] + dif [1]]; } console.log ('ciao'); // Questo terminerà non appena il flood-fill raggiungerà la posizione iniziale while (! GetMove (me)) {iterEdges = edge.slice (0); // bordi.clone (); bordi = bordi.slice (bordi.lunghezza); // bordi.clear (); iterEdges.forEach (function (pos) {direction.forEach (function (dir) {var nextPos = addDiff (pos, dir); if (me.floodPath [nextPos]) return; if (map.getObjectTypeAt (nextPos [0], nextPos [1])! = 'vuoto') ritorno; bordi.push (nextPos); me.floodPath [nextPos] = opposites [dir];});}); } console.log (me.floodPath);} me.move (getMove (me));
Disclaimer: molto probabilmente è molto lontano dalla soluzione prevista, ma è ancora una.
Approfitta del fatto che un labirinto viene generato casualmente.
Grazie al modo in cui viene generato il labirinto, c'è una possibilità molto affidabile che riavviando il labirinto solo poche volte, in uno di quei labirinti, il semplice codice
if (me.canMove ('down')) me.move ('down'); else me.move ('right');
è sufficiente per far uscire il robot il labirinto.
Avevo fatto più o meno la stessa soluzione di nneonneo, solo leggermente diversa nella formattazione:
// Implementa la regola della mano destra per maze solving.if (me.facing = == undefined) me.facing = 'right'; var dirs = {'right': ['down', 'right', 'up', 'left'], 'down': ['left', 'down' , "destra", "su"], "sinistra": ["su", "sinistra", "giù", "destra"], "su": ["destra", "su", "sinistra", " down ']} var scelte = dirs [me.facing]; for (var i = 0; i < 4; i ++) if (me.canMove (scelte [i])) {me.move (scelte [i]); me.facing = scelte [i];}
hackeriamo e non disturbiamo il labirinto ...
player.hasItem = function (item) {return true; };
Invece di correre nel labirinto, perché non eliminarlo del tutto? Ho chiuso la chiamata defineObject
, quindi ho ridefinito ROT.Map.DividedMaze
in modo che create
non facesse nulla.
map.defineObject ('robot', {'type': 'dynamic', 'symbol': 'R', 'color': 'gray', 'onCollision': function (player, me) {me.giveItemTo ( player, 'blueKey');}, 'behavior': function (me) {// codice utente inizia}}); ROT.Map.DividedMaze = function () {this.create = function () {}}; (function () {{// fine del codice utente}});
Puoi anche ridefinire defineObject per rendere la barriera passabile prima di chiamare l'originale, quindi vai a prendere la chiave tu stesso.
Ho usato il campo come controller
if (player.atLocation (1, 24)) {
me.move ('down');
} if (player.atLocation (1, 23)) {
me.move ('up');
} if (player.atLocation (1,22)) {
me.move ('right');
}
vai all'uscita e a destra.La terza dal basso è destra, la seconda è in alto e quella più bassa è in basso.
AI? Ah!
'behavior': function (me) {me.move (robodir);}}); var robodir = "right" player.setPhoneCallback (function () {if (robodir = = "right") {robodir = "down";} else if (robodir == "down") {robodir = "left";} else if (robodir == "left") {robodir = "up";} else if (robodir == "up") {robodir = "right";}}) map.defineObject ('null', {'behavior': function () {
Il robot behiavor
ora lo fa muovere lungo la direzione memorizzata in robodir ogni tick. L'attivazione del telefono cambia quella direzione. Banale!
semplicemente, chiedi al robot di trovarlo, puoi sempre valutare prima il percorso e poi camminare, ma questo fa camminare solo il robot:
if (! me.g) {me.g = 0; me.dir = [['destra', 0, -1], ['su', - 1,0], ['sinistra', 0,1], ['giù', 1,0]] ;} move = function () {x = me.getX () + me.dir [me.g] [1]; y = me.getY () + me.dir [me.g] [2]; if ( map.getObjectTypeAt (x, y)! = 'block') me.g = (me.g + 1)% 4; else if (! me.canMove (me.dir [me.g] [0])) me .g = (me.g + 3)% 4; me.move (me.dir [me.g] [0]);} if (me.getY () <10) move ();
la cosa divertente è che puoi eseguire qualsiasi metodo, anche quelli bloccati, usa questo, probabilmente verrà risolto in futuro ma per ora sembra che abbiano lasciato una backdoor per tutti:
map._display.game._setPlayerCodeRunning (false); map._display.game.map._removeItemFromMap (map.getWidth () - 2, 9, 'barrier');
HAHAHA
'behavior': function (me) {player.setPhoneCallback (function () {color = player.getColor (); if (color == "# 0f0") { player.setColor ("# f00");} else if (color == "# f00") {player.setColor ("# 00f");} else if (color == "# 00f") {player.setColor ( "# ff0");} else if (color == "# ff0") {player.setColor ("# 0f0");}}); color = player.getColor (); if (color == "# 0f0") {me.move ("right"); } else if (color == "# f00") {me.move ("left"); } else if (color == "# 00f") {me.move ("up"); } else if (color == "# ff0") {me.move ("down"); }