Gruselige Korridore

8

Diese Herausforderung ist inspiriert von einem Brettspiel, das ich vor einiger Zeit gespielt habe.
Die Geschichte dieser Herausforderung muss nicht unbedingt gelesen werden, das Ziel des Herausforderungsabschnitts sollte alles Notwendige erklären.

Die Geschichte

Die Menschen sind in einem großen Raum mit einem menschenfressenden Monster eingesperrt. Die Wände des Raumes sind verzaubert und teleportieren Objekte durch den Raum, wenn sie berührt werden. Das Monster marschiert durch den Raum und sucht nach Fleisch. Der erste Mensch in seinen Augen wird von seinen scharfen Zähnen verzehrt.

Das Ziel der Herausforderung

Sie erhalten die Karte des Raums, einschließlich des Standorts der Menschen und des Monsters.

%%%KLMNOPQRSTA%
%%J           B
%I       %    C
H             D
G   %%        E
F             F
E      %      G
D             H
C   %        I%
B           J%%
%ATSRQPONMLK%%%

Lassen Sie uns die Komponenten der Karte aufschlüsseln.

  • Buchstaben von Abis T: Wenn das Monster auf eines dieser Buchstaben tritt, wird es zum zweiten Erscheinen dieses Buchstabens teleportiert und ändert nicht seine Richtung. Es werden immer nur null oder zwei Buchstaben auf der Tafel sein.
  • %: Wandfliesen. Nur zur Formatierung und zum schönen Aussehen.
  • #: Der Startort des Monsters.
  • *: Die Standorte der Menschen.
  •  : Leere Kacheln, das Monster kann sich frei darauf bewegen.

Einige zusätzliche Dinge, die Sie über die Karte beachten sollten:

  • Die Kartenabmessungen und die Objektposition sind nicht konstant, daher muss sich Ihr Code dynamisch daran anpassen.

Das Monster bewegt sich immer in die Richtung, in die es gerade zeigt (zu Beginn nach Westen), es sei denn, es entdeckt einen Menschen. In diesem Fall wendet es sich dem nächsten Menschen zu.
Das Monster entdeckt einen Menschen, wenn sich keine Wand- oder Teleporterplättchen in einer geraden horizontalen oder vertikalen Linie zwischen ihm und dem Menschen befinden.

Eine andere Sache, die zu beachten ist, ist, dass wenn sich das Monster vor einer festen Wand befindet ( %) oder sich zwischen zwei Menschen entscheiden muss, es immer rechts vor links priorisiert .

Wenn das Monster aus irgendeinem Grund nicht nach rechts abbiegen und einen Schritt nach vorne machen kann , wird es stattdessen nach links abbiegen .

Am Ende würde die Reihenfolge, in der das Monster Richtungen priorisiert, vorwärts, rechts, links, rückwärts gehen.

Eingang

  • Die Karte, einschließlich des Startorts des Monsters und der Positionen der Leute als ihre jeweiligen Charaktere. Es sollte keine andere Eingabe als die Map-Zeichenfolge oder das Array von Zeichenfolgen oder Zeichen geben.

Die Eingabe kann in jedem vernünftigen Format empfangen werden; eine einzelne Zeichenfolge oder ein Array von Zeichenfolgen für die Karte.

Ausgabe

Die Koordinate der Person, die zuerst vom Monster gefressen wird.

Die Koordinaten beginnen in der oberen linken Ecke und sind 0-indiziert, sodass die erste Kachel die Koordinaten (0 | 0) enthält. Wenn Sie die 1-Indizierung verwenden, geben Sie dies bitte in Ihrer Antwort an.

Regeln

  • Dies ist , der kürzeste Code in Bytes in einer Sprache gewinnt.
  • Standardlücken sind verboten.
  • Sie können davon ausgehen, dass das Monster immer einen Menschen erreichen kann.

Testfälle

Eingang:

%%%KLMNOPQRSTA%
%%J           B
%I       %*   C
H   *         D
G   %%        E
F       #     F
E      %      G
D      *      H
C   %        I%
B           J%%
%ATSRQPONMLK%%%

Ausgabe: (10,2)Da das Monster die beiden anderen Personen nicht sehen kann, wenn es an ihnen vorbeirennt, wird es zur anderen FWand teleportiert , wo es dann die letzte Person sieht.

Eingang:

%%%KLMNOPQRSTA%
%%J           B
%I      *     C
H     %%%   * D
G      #%     E
F     %%%   % F
E             G
D       %     H
C       *    I%
B       *   J%%
%ATSRQPONMLK%%%

Ausgabe: (12,3)

Eingang:

%%%KLMNOPQRSTA%
%%J           B
%I     %%%    C
H     *%#%    D
G             E
F             F
E       %     G
D             H
C            I%
B           J%%
%ATSRQPONMLK%%%

Ausgabe: (6, 3)

Eingang:

%%%%%%%%%%%%%%%
%#%       %%% %
%A%ABCD   %*% %
%*F     G %%% %
% %BC% FD     %
% %   %    %%%%
% %  %       %%
%   % %%   G  %
%             %
%*%    %    % %
%%%%%%%%%%%%%%%

Ausgabe: (1,9)


Viel Glück!

Ian H.
quelle
Sie sollten explizit und früh in der Beschreibung angeben, dass sich die Menschen nicht bewegen. Mir war zunächst nicht klar, dass sie stationär sind. Wenn ich in dieser Situation ein Mensch wäre, würde ich mich sicherlich bewegen!
DLosc

Antworten:

6

Python 2 , 565 .. 422 445 1 .. 444 463 2 .. 468 467 463 Bytes

u,U='*%'
G=lambda s:u==s.strip('# ')[0]and len(N)-s.find(u)
b=input()
D=3;j=''.join;N,w,P,t,B=j(b),len(b[0]),[0,1,0,-1],{},map(j,zip(*b))
for c in N:
 l,r=N.find(c),N.rfind(c)
 if u<c:t[l]=r;t[r]=l
 if'#'==c:x,y=l%w,l/w
while u!=b[y][x]:
 O=[B[x][y-1::-1],b[y][x+1:],B[x][y+1:],b[y][x-1::-1]];L,R=O[D-1],O[~D]
 if u<b[y][x]:X=t[x+w*y];x,y=X%w,X/w
 elif(G(O[D])<1)*(G(R)+G(L)+(U==O[D][0])):D-=0<G(L)>G(R)or(U==R[0])*-~(U==L[0])or-1;D%=4
 x+=P[D];y+=P[~D]
print x,y

Probieren Sie es online aus!

Dank Halvard , Ian und Jonathan wurden viele Bytes gespeichert

1: Wurde länger, um den Fall des zweimaligen Wenden zu beheben und den Ort des Monsters zu finden.
2: Noch länger. Monster sollte beim Teleportieren nicht die Richtung ändern.

TFeld
quelle
Etwas auf 482 Bytes golfen . Verkürzte Verbindung wegen zu langer TIO
Halvard Hummel
@Halvard Ein kleiner Golf, nur 1 Byte: 481
1
l.replace('#',' ')-> l.replace(*"# ").
Jonathan Frech
Behoben, aber jetzt ist es die gleiche Länge wie deine, 434 Bytes
2
@ KevinCruijssen Ich weiß, Ian sagte, meine Antwort gilt als gültig, aber ich werde sie trotzdem ändern.
TFeld
5

Perl 6 ,343 334 333 328 322 308 Bytes

{my \m=%((^@^a X ^@a[0]).map:{.[0]i+.[1]=>@a[.[0]][.[1]]});my \a=m<>:k.classify
({m{$_}});my$m=a<#>[0];my$d=-1;{$d=($d,i*$d,-i*$d,-$d).min({$^q;first ?*,map
{(((my \u=m{$m+$_*$q})~~"%")*(1+!($_-1))+(u~~"A".."Z"))*m+(u~~"*")*$_},^m});
$m+=$d;$m=$d+(a{m{$m}}∖~$m).pick while m{$m}~~"A".."Z"}...{m{$m}~~"*"};$m}

Probieren Sie es online aus!

(Der eigentliche Code enthält keine Zeilenumbrüche. Ich habe sie nur eingefügt, um die Zeilen zum leichteren Lesen umzubrechen.)

Dies ist nicht in der Lage, Karten zu verarbeiten, bei denen es möglich ist, außerhalb der Kartengrenzen zu sehen. (D. H. Karten mit Leerzeichen an der Grenze.) Wenn dies wichtig ist, +5 Bytes. Aber da die Teleporter LoS jetzt blockieren, sollte es nicht.

Erläuterung : Diese Funktion verwendet die Karte als Liste von Zeichenlisten. Lassen Sie es uns in Aussagen aufteilen:

my \m=%((^@^a X ^@a[0]).map:{.[0]i+.[1]=>@a[.[0]][.[1]]});: Lassen Sie uns einen Hash ("Wörterbuch" für Pythonisten) mit dem Namen m(es ist eine sigillose Variable, daher müssen wir explizit einen Hash zuweisen) zuweisen, %(...)der komplexe Formschlüssel x+iymit Zeichen in der ydritten und dritten xSpalte verknüpft der Karte.

my \a=m<>:k.classify({m{$_}});: Dies macht ein "inverses Wörterbuch" aus m, genannt a: Es gibt einen Schlüssel, der jedem Wert in entspricht m, und der Wert ist eine Liste komplexer Koordinaten (Schlüssel in m), die dieses Zeichen enthalten. So erhalten Sie beispielsweise a{"#"}eine Liste aller Koordinaten, bei denen sich #auf der Karte eine befindet. (Dies ist auch eine Siegellose Variable, aber wir haben Glück, da sie classifyeinen Hash zurückgibt.)

my$m=a<#>[0];my$d=-1: Stelle die anfängliche Monsterposition ein. Wir schauen uns #den umgekehrten Hash an a. Wir müssen verwenden, [0]da a<#>es sich immer noch um eine Liste handelt, auch wenn sie nur 1 Element enthält. Das $denthält die Richtung des Monsters; Wir setzen es nach Westen. (Die Richtung ist ebenfalls eine komplexe Zahl, ebenso -1wie der Westen.)

OK, die nächste Aussage ist ziemlich böse. Schauen wir uns zunächst Folgendes an: {$^q;first ?*,map {(((my$u=m{my$t=$m+$_*$q})~~"%")*(1+!($_-1))+($u~~"A".."Z"))*m+($u~~"*")*abs($t-$m)},^m}Dies ist eine Routine, die LoS in der angegebenen Richtung bewertet. Befindet sich ein Mensch in dieser Richtung, gibt er die Entfernung zum Menschen zurück. Wenn sich in dieser Richtung eine Wand oder ein Teleport befindet, wird die Gesamtzahl der Quadrate der Karte zurückgegeben. (Es geht darum, eine so hohe Zahl anzugeben, dass sie größer ist als jede legitime Entfernung zu einem Menschen.) Wenn sich die Wand in dieser Richtung und in Entfernung 1 befindet, geben wir schließlich die 2 × Gesamtzahl der Quadrate der Karte zurück. (Wir wollen niemals durch Wände rennen, daher benötigen diese eine noch größere Punktzahl. Wir werden in Kürze das Minimum auswählen.)

Wir verwenden dies im Konstrukt $d=($d,i*$d,-i*$d,-$d).min( LoS deciding block );. Da wir für alles komplexe Zahlen verwenden, können wir leicht Richtungen erhalten, die relativ vorwärts, rechts, links und rückwärts von der ursprünglichen Richtung sind, indem wir sie einfach mit 1, i, -i multiplizieren (denken Sie daran, dass die yAchse in die andere Richtung verläuft verwendet werden, um aus Mathe) bzw. -1. Also bilden wir die Liste der Richtungen in dieser Reihenfolge und finden die Richtung, die den minimalen "Abstand zu einem Menschen" hat (gemäß dem obigen Block), wodurch sichergestellt wird, dass jeder Mensch eine Wand schlägt und alles eine Wand schlägt, die richtig ist unter der Nase des Monsters. Wir nutzen die Tatsache, dass die minFunktion die erste gibtminimaler Wert. Wenn zwischen verschiedenen Richtungen ein Gleichstand besteht, wird das Monster es vorziehen, von rechts nach links nach hinten zu wechseln, was genau das ist, was wir wollen. So bekommen wir eine neue Richtung, die dann zugewiesen wird $d.

$m+=$d; macht das Monster nur einen Schritt in die neue Richtung.

$m=$d+(a{m{$m}}∖~$m).pick while m{$m}~~"A".."Z"kümmert sich um die Teleports. Nehmen wir an, das Monster ist bei einem Teleport A. Zuerst suchen wir Aim inversen Hash %aund das zeigt die beiden Positionen des Teleports auf A, dann verwerfen wir die aktuelle Position mit dem eingestellten Differenzoperator (der wie ein Backslash aussieht). Da es auf der Karte genau 2 Vorkommen jedes Teleports gibt und das Monster sicher auf einem steht, wird der Unterschied ein Satz mit 1 Element sein. Wir .pickwählen dann ein zufälliges Element aus (ob Sie es glauben oder nicht, aber dies ist der kürzeste Weg, um das Element einer 1-Element-Menge zu erhalten :-)). So etwas passiert, bis das Monster irgendwo landet, wo es nicht in einem Portal ist.

Alles in den letzten 4 Absätzen beschreibt eine massive Formkonstruktion {change direction; step; handle teleports}...{m{$m}~~"*"}. Dies ist eine Sequenz, die den Block links von aufruft, ...bis die Bedingung rechts von erfüllt ...ist. Und das ist wahr, wenn sich das Monster mit einem Menschen auf einem Feld befindet. Die Liste selbst enthält Rückgabewerte des großen Blocks auf der linken Seite, der (höchstwahrscheinlich (Any)) Müll ist, da er am Ende den Wert der while-Schleife zurückgibt. Im Wesentlichen verwenden wir es als billigere while-Schleife. Der Wert der Liste wird verworfen (und der Compiler stöhnt über eine "nutzlose Verwendung ...in einem Sink-Wettbewerb", aber wen interessiert das?). Wenn dies alles erledigt ist, kehren wir zurück $m- die Position des Monsters, nachdem es einen Menschen gefunden hat, immer noch als komplexe Zahl (also geben wir für den ersten Test 10+2iund so weiter).

Ramillies
quelle
Schöne Erklärung! :)
Ian H.
3

JavaScript (ES6), 258 245

g=>eval("m=g[I='indexOf']`#`,D=[w=g[I]`\n`+1,-1,-w,k=t=1],g=[...g];for(n=1/0;n;(o=g[m+=d=D[k]])>'@'?g[g[u=m]=t=1,m=g[I](o),u]=o:o<'%'?t=1:o<'*'&&(m-=d,k=k+t++&3))D.map((d,j)=>{for(q=0,u=m;g[u+=d]<'%';++q);g[u]=='*'&n>q&&(n=q,k=j)});[m%w,m/w|0]")

Weniger Golf gespielt

g=>{
    var u, // temp current position 
        q, // distance so far scanning for a human
        o, // value of grid at current position
        d, // offset to move given current direction
        n = 1/0 // current distance from human
        m = g.indexOf(`#`), // monster position
        w = g.indexOf(`\n`)+1, // grid width + 1 (offset to next row)
        D = [w,-1,-w,1], // offset for moves, clockwise
        k = 1, // current direction, start going west
        t = 1; // displacement for turn
    g=[...g]; // string to array
    while (n) // repeat while not found (distance > 0)
    {
      // look around to find humans
      D.forEach( (d,j) => { // for each direction
        // scan grid to find a human
        for(q=0, u=m; g[u+=d]<'$'; ++q); // loop while blank space
        if ( g[u] == '*' // human found at position u
             & n>q ) // and at a shorter distance than current
        {
           n = q; // remember min distance
           k = j; // set current direction
        }
      })
      // if human found, the current direction is changed accordingly
      d = D[k] // get delta
      m += d // move
      o = g[m] // current cell in o
      if (o > '@') // check if letter (teleporter)
      {
        t = 1 // keep current direction, next turn will be right
        u = m // save current position in u
        g[u] = 1 // clear current cell, so I can find only the other teleporter
        m = g.indexOf(o) // set current position to other teleporter
        g[u] = o // reset previous cell content
      }
      else if (o > '%') // check if '*'
      {
        // set result, so we can exit the loop
        r = [ m%w, m/w|0 ] // x and y position 
      }
      else if (o == '%') // check if wall
      {
        // turn
        m -= d // current position invalid, go back
        k = (k+t) % 4 // turn right 90° * t
        t = t+1 // next turn will be wider
      }
      else
      {
        t = 1 // keep current direction, next turn will be right
      }
    }
    return r
}

Prüfung

var F=
g=>eval("m=g[I='indexOf']`#`,D=[w=g[I]`\n`+1,-1,-w,k=t=1],g=[...g];for(n=1/0;n;(o=g[m+=d=D[k]])>'@'?g[g[u=m]=t=1,m=g[I](o),u]=o:o<'%'?t=1:o<'*'&&(m-=d,k=k+t++&3))D.map((d,j)=>{for(q=0,u=m;g[u+=d]<'%';++q);g[u]=='*'&n>q&&(n=q,k=j)});[m%w,m/w|0]")

var grid=[`%%%KLMNOPQRSTA%\n%%J           B\n%I       %*   C\nH   *         D\nG   %%        E\nF       #     F\nE      %      G\nD      *      H\nC   %        I%\nB           J%%\n%ATSRQPONMLK%%%`
,'%%%KLMNOPQRSTA%\n%%J           B\n%I      *     C\nH     %%%   * D\nG      #%     E\nF     %%%   % F\nE             G\nD       %     H\nC       *    I%\nB       *   J%%\n%ATSRQPONMLK%%%'
,'%%%KLMNOPQRSTA%\n%%J           B\n%I     %%%    C\nH     *%#%    D\nG             E\nF             F\nE       %     G\nD             H\nC            I%\nB           J%%\n%ATSRQPONMLK%%%'
,'%%%%%%%%%%%%%%%\n%#%       %%% %\n%A%ABCD   %*% %\n%*F     G %%% %\n% %BC% FD     %\n% %   %    %%%%\n% %  %       %%\n%   % %%   G  %\n%             %\n%*%    %    % %\n%%%%%%%%%%%%%%%'
]
$(function(){
  var $tr = $('tr')
  grid.forEach(x=>{
    $tr.eq(0).append("<td>"+x+"</td>")
    $tr.eq(1).append("<td>"+F(x)+"</td>")
  })
})
td {padding: 4px; border: 1px solid #000; white-space:pre; font-family:monospace }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table ><tr/><tr/></table>

edc65
quelle