Roguelike Wegfindung

21

Roguelike Wegfindung

Ihre Aufgabe ist es, anhand einer zweidimensionalen Anordnung der unten beschriebenen Elemente, die ein Verlies darstellen, eine einzelne Zahl auszugeben oder zurückzugeben, die die Menge der Goldstücke darstellt, die der Schurke sammeln kann, ohne Monster zu wecken.

Die Elemente des Arrays lauten wie folgt:

  1. Leerzeichen werden durch entweder .ein Leerzeichen oder ein Leerzeichen dargestellt.
  2. Rogues Ausgangsposition ist natürlich vertreten durch @;
  3. Ein Goldstück wird dargestellt durch $;
  4. Wände werden dargestellt durch #;
  5. Monster werden von Zeichen aus dem folgenden regulären Ausdruck dargestellt wird : [a-zA-Z*&].

Das Array darf keine Zeichen enthalten, die nicht oben aufgeführt sind. Sie können also davon ausgehen, dass alles, was keine Mauer, kein leerer Raum, kein Schurke oder kein Goldstück ist, ein Monster ist.

Die Regeln für die Wegfindung sind:

  1. Der Schurke kann nur durch leere oder goldhaltige Zellen gehen;
  2. Es dauert eine Runde, um zu einer benachbarten oder diagonal benachbarten Zelle zu gelangen.
  3. Das Gold zu holen ist augenblicklich;
  4. Der Schurke kann nicht länger als eine Runde neben oder diagonal neben einem Monster bleiben, ohne es aufzuwecken, was verboten ist.
  5. Der Schurke kann das Bewusstseinsgebiet eines Monsters beliebig oft betreten. Das Monster wacht nur auf, wenn der Schurke zwei aufeinanderfolgende Runden in der Nähe des Monsters verbringt .

Eingabe- und Ausgaberegeln

Sie können die Eingabe in jedem vernünftigen Format abrufen, einschließlich eines zweidimensionalen Arrays, eines flachen Arrays, einer Zeichenfolge oder was auch immer. Wenn es Ihnen das Leben erleichtert, können Sie auch die Abmessungen des Arrays bestimmen.

Es ist garantiert, dass der Schurke am Anfang nicht in der Nähe eines Monsters ist.

Ein volles Programm oder eine Funktion ist in Ordnung.

Wertung

Dies ist , die Punktzahl ist die Anzahl der Bytes Ihrer Einreichung, wobei weniger besser ist.

Testfälle

Ich verwende hier Punkte für Leerzeichen, um die Lesbarkeit zu verbessern. Wenn Sie dies wünschen, können Sie Leerzeichen verwenden (siehe oben). Beachten Sie auch, dass dies ein reiner Zufall ist, dass sich der Schurke immer in der oberen linken Ecke befindet und Ihr Code auch jede andere gültige Position verarbeiten sollte.

1)
@..
.$.
...  -> 1

Nur ein Gesundheitstest.

2)
@....
...g$
.....  -> 0

Wieder ein Gesundheitstest.

3)
@....
...$g
.....  -> 1

Der Schurke kann das Gold greifen, indem er von links einrückt.

4)
@....g..
.......$
........
.....h..  -> 1

Der Schurke kann zwischen den Monstern im Zick-Zack verkehren und sich nie länger als eine Runde in der Nähe aufhalten.

5)
@....z..
.......$
.....b..  -> 0

Die Taktik aus dem vorherigen Testfall funktioniert hier nicht - die Monsterempfindlichkeitsbereiche überlappen sich.

6)
@$#.
###$
....  -> 1

Gesundheitstest.

7)
@..#..
$.$g.$
...#..  -> 2

Dito.

8)
@#.d#$
$...##
e.....
..$...
##..$b
.#..g$  -> 3

Von all dem Gold sind hier nur drei sicher zu erreichen: Das Gold in der Nähe der Startposition kann durch Herunterschieben um eins und dann zurück in die Startposition erhalten werden. Um aus der oberen linken Ecke zu entkommen, muss sich der Schurke zweimal diagonal nach rechts unten bewegen. Das Gold in der Mitte ist keine Herausforderung. Das äußere Gold wird von bewacht gund bkann erhalten werden, indem man diagonal von der Stelle rechts neben dem mittleren Gold und dann zurück zieht. Der Rest ist nicht zu bekommen: Das Gold oben rechts ist durch Wände blockiert, und das Gold unten rechts erfordert zwei Runden in den empfindlichen Bereichen der Monster.

Die folgenden Testfälle wurden von mbomb007 großzügig gespendet.

9)
  12345678
a @....g.D
b .......$
c ......#.
d .....h..  -> 1

Dieser ist schwierig. Ein Weg ist b4-b5-c6-b7-c8-b8(grab).

10)
  12345678
a @....g.D
b .......$
c .......#
d .....h..  -> 1

Ein Weg ist [bc]4-c5-b6-c7-b8(grab).

11)
  12345678
a @....g.D
b ......#$
c .......#
d .....h..  -> 1

Die zusätzliche Wand ändert eigentlich nichts, [bc]4-c5-b6-c7-b8(grab)ist immer noch eine Lösung.

Michail
quelle
Sie sollten ein größeres und komplexeres Beispiel hinzufügen. Was sind die minimalen und maximalen Dimensionen des Dungeons? Ist der 1x1-Dungeon @eine gültige Eingabe?
mbomb007
@ mbomb007 Ich habe ein neues Beispiel hinzugefügt. In Bezug auf die Größe des Rasters halte ich es für angemessen, es auf mindestens 3x3 zu beschränken.
Michail
@ mbomb007 Stört es mich, wenn ich deine Beispiele bearbeite? Einmal verstanden, zeigen sie die Logik sehr gut.
Michail
Fühlen Sie sich frei. Dafür habe ich sie gemacht. Es könnte auch angemerkt werden, dass das Drehen eines Testfalls keinen Einfluss auf sein Ergebnis haben sollte.
mbomb007

Antworten:

5

frühere lösungen (teil davon) sind im footer container im tio link zu finden (diese sind wahrscheinlich besser lesbar)

JavaScript (Node.js) , 883 436 411 360 345 311 Byte

g=>g.map((r,y)=>[...r].map((c,x)=>A+=c=="$"&&P(g,x,y)),A=0)|A
P=(g,x,y,m={},p={},I=i=9,M={})=>{if(/[.$]/.test(c=(g[y]||0)[x])){for(;i--;)if(/^[^.@$#]$/.test(C=(g[y+~-(i/3)]||0)[x+i%3-1])){if(m[C])return
M[C]=1}for(;I--;)if(!p[(X=x+~-(I/3))+","+(Y=y+I%3-1)]&&P(g,X,Y,M,{...p,[x+","+y]:1}))return 1}return c=="@"}

Probieren Sie es online!

Erklärung -

anstatt vom Spieler zum Geld zu gehen, ging ich vom Fall zum @. Ich denke, ich sollte schneller sein, weil ich weiß, wann ich aufhören muss zu suchen (erreichen Sie das @), und wenn Sie nach Bargeld suchen, müssen Sie immer in Bewegung bleiben, bis Sie alle Stellen abgedeckt haben (und die Wege, um zu ihnen zu gelangen). so ist das algo ziemlich einfach - die hauptfunktion g.map((r,y)=>[...r].map((c,x)=>A+=c=="$"&&P(g,x,y)),A=0)|A: geld finden -> wenn du es gefunden hast -> suche nach dem spieler -> wenn du ihn gefunden hast -> inkrementiere A jetzt lass uns zum wegfinder aka P gehen, if(/[.$]/.test(c=(g[y]||[])[x]))überprüfe einfach ob Die aktuelle Zelle ist "speziell" -> wenn ja, möchten wir zurückkehren, wenn es sich um einen Spieler handelt. Sonderfälle: @ # (Monster)

for(;i--;) if(/^[a-zA-Z*&]$/.test(C=(g[y+~-(i/3)]||0)[x+i%3-1])) -> if my neighbor is a monster {if(m[C])return false -> and it already was in the previous turn - this path is not value M[C]=1} -> if not just add it to the neighbors monsters for(;I--;) if(!p[(X=x+~-(I / 3))+","+(Y=y+I%3-1)]&&P(g,X,Y,M,{...p,[x+","+y]:1}))return true wieder Nachbarn iterieren - wenn ich nicht schon da war (p ist der genommene Pfad) Pfad fortsetzen (P aufrufen)

DanielIndie
quelle
Schönes Golfen! Ein paar Dinge, die mir aufgefallen sind: (1) Ihr Code hat überflüssige Leerzeichen in der 2. und 7. Zeile, und die meisten Zeilenumbrüche sind unnötig (nur die Zeilen 1 und 6 benötigen einen Umbruch) und I / 3haben unnötigen Platz. Beseitigen Sie dieses Leerzeichen und Ihre Punktzahl ist tatsächlich 324! (2) return true kann return 1(a truthy Wert) und return falsekann einfach sein return(implizit undefined, einen Falsey - Wert). (3) Der reguläre Ausdruck ^[^.@$#]$, um nach Nicht-Monstern zu suchen , ist kürzer als ^[a-zA-Z*&]$nach Monstern zu suchen. Gute Arbeit!
Apsillers
Ja, ich weiß, ich kann es viel kürzer machen :)
DanielIndie
@apsillers auf die Leerzeichen freie Lösung aktualisiert :)
DanielIndie