Koridor menyeramkan

8

Tantangan ini terinspirasi oleh permainan papan yang saya mainkan beberapa waktu lalu.
Kisah tantangan ini tidak harus dibaca, yaitu tujuan dari tantangan- bagian harus menjelaskan semua yang diperlukan.

Cerita

Orang-orang terkunci di dalam ruangan besar dengan monster yang melahap manusia. Dinding ruangan terpesona, memindahkan benda-benda ke seberang ruangan saat disentuh. Kata monster itu berjalan melintasi ruangan, berburu daging. Manusia pertama yang terlihat akan dikonsumsi oleh giginya yang tajam.

Tujuan Tantangan

Anda diberi peta ruangan, termasuk lokasi orang dan monster.

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

Mari kita jabarkan komponen peta.

  • Surat dari Ake T: Jika monster melangkah ke salah satu dari ini, itu akan dipindahkan ke penampilan kedua surat ini dan tidak mengubah arahnya. Hanya akan ada nol atau dua huruf apa pun di papan tulis.
  • %: Ubin dinding. Hanya untuk memformat & terlihat bagus.
  • #: Lokasi awal monster itu.
  • *: Lokasi orang.
  •  : Ubin kosong, monster itu bisa bergerak bebas ke sana.

Beberapa hal tambahan yang perlu diperhatikan tentang peta:

  • Dimensi peta dan lokasi objek tidak akan konstan, jadi kode Anda harus beradaptasi secara dinamis dengannya.

Monster itu akan selalu pergi ke arah yang saat ini dihadapinya (menghadap ke barat di awal) kecuali jika ia melihat manusia, dalam hal ini ia akan berbalik ke arah manusia terdekat .
Monster itu melihat manusia jika tidak ada ubin dinding atau teleporter dalam garis horizontal atau vertikal lurus antara manusia dan manusia.

Hal lain yang perlu diperhatikan adalah bahwa jika monster itu berada di depan dinding yang kokoh ( %) atau harus memutuskan antara dua manusia, itu akan selalu memprioritaskan tepat di sebelah kiri.

Jika monster itu tidak dapat berbelok ke kanan dan membuat langkah ke depan untuk beberapa alasan, itu akan berbelok ke kiri sebagai gantinya.

Jadi, pada akhirnya, urutan monster yang memprioritaskan arah adalah kita maju, kanan, kiri, mundur.

Memasukkan

  • Peta, termasuk lokasi awal monster dan posisi orang-orang sebagai karakter masing-masing. Seharusnya tidak ada input selain string peta, atau larik string, atau karakter.

Input dapat diterima dalam format apa pun yang wajar; string tunggal atau array string untuk peta.

Keluaran

Koordinat orang yang pertama kali dimakan monster itu.

Koordinat mulai dari sudut kiri atas dan diindeks 0, sehingga ubin pertama akan memiliki koordinat (0 | 0). Jika Anda menggunakan pengindeksan 1, harap sebutkan dalam jawaban Anda.

Aturan

  • Ini adalah , kode terpendek dalam byte yang menang dalam bahasa apa pun.
  • Celah standar dilarang.
  • Anda mungkin berasumsi bahwa monster itu akan selalu dapat mencapai manusia.

Uji Kasus

Memasukkan:

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

Keluaran:, (10,2)karena monster itu tidak dapat melihat dua orang lain ketika berlari melewati mereka, ia akan dipindahkan ke Fdinding lain , di mana ia kemudian akan melihat orang terakhir.

Memasukkan:

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

Keluaran: (12,3)

Memasukkan:

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

Keluaran: (6, 3)

Memasukkan:

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

Keluaran: (1,9)


Semoga berhasil!

Ian H.
sumber
Anda harus menyatakan, secara eksplisit dan awal dalam deskripsi, bahwa manusia tidak bergerak. Awalnya saya tidak menyadari bahwa mereka diam. Jika saya adalah manusia dalam situasi itu, saya pasti akan bergerak!
DLosc

Jawaban:

6

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

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

Cobalah online!

Menyimpan banyak byte berkat Halvard , Ian dan Jonathan

1: Dapatkan lebih lama, untuk memperbaiki kasus berbalik dua kali, dan untuk menemukan lokasi monster.
2: Lebih lama lagi .. Monster seharusnya tidak mengubah arah saat berteleportasi.

TFeld
sumber
Agak golf hingga 482 byte . Tautan singkat karena TIO terlalu panjang
Halvard Hummel
@Halvard A golf kecil, hanya 1 byte: 481
1
l.replace('#',' ')-> l.replace(*"# ").
Jonathan Frech
Diperbaiki, tetapi sekarang memiliki panjang yang sama dengan milik Anda, 434 byte
2
@KevinCruijssen Saya tahu Ian mengatakan jawaban saya dianggap valid, tetapi saya tetap akan mengubahnya.
TFeld
5

Perl 6 ,343 334 333 328 322 308 byte

{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}

Cobalah online!

(Tidak ada baris baru dalam kode aktual. Saya menyisipkannya hanya untuk membungkus garis agar lebih mudah dibaca.)

Ini tidak dapat menangani peta di mana dimungkinkan untuk melihat di luar batas peta. (I. e. Memetakan dengan ruang kosong di perbatasan.) Jika ini penting, +5 byte. Tapi, karena teleporter memblokir LoS sekarang, seharusnya tidak.

Penjelasan : Ini adalah fungsi yang mengambil peta sebagai daftar daftar karakter. Mari kita bagi menjadi beberapa pernyataan:

my \m=%((^@^a X ^@a[0]).map:{.[0]i+.[1]=>@a[.[0]][.[1]]});: Mari kita membuat hash ("kamus" untuk Pythonists) yang disebut m(ini adalah variabel sigilless, jadi kita perlu secara eksplisit tentang menetapkan hash ke dalamnya dengan %(...)) yang mengaitkan kunci kompleks bentuk x+iydengan karakter yang ada di kolom th ydan xth th dari peta.

my \a=m<>:k.classify({m{$_}});: Ini membuat "kamus terbalik" dari m, disebut a: ada satu kunci yang terkait dengan setiap nilai dalam m, dan nilainya adalah daftar koordinat kompleks (kunci dalam m) yang berisi karakter itu. Jadi, misalnya a{"#"}akan memberikan daftar semua koordinat di mana ada #di peta. (Ini juga merupakan variabel sigilless, tapi kami beruntung karena classifymengembalikan hash.)

my$m=a<#>[0];my$d=-1: Setel posisi monster awal. Kami mencari #di dalam hash terbalik a. Kita harus menggunakan [0]karena a<#>masih daftar, bahkan ketika itu hanya mengandung 1 elemen. The $dberisi arah rakasa; kami mengaturnya ke Barat. (Arahnya adalah bilangan kompleks juga, begitu -1juga barat.)

Oke, pernyataan selanjutnya cukup jahat. Pertama, mari kita lihat ini: {$^q;first ?*,map {(((my$u=m{my$t=$m+$_*$q})~~"%")*(1+!($_-1))+($u~~"A".."Z"))*m+($u~~"*")*abs($t-$m)},^m}Ini adalah rutin yang mengevaluasi LoS dalam arah yang diberikan. Jika ada manusia di arah ini, ia mengembalikan jarak ke manusia. Jika ada dinding atau teleport di arah ini, ia mengembalikan jumlah kuadrat dari peta. (Intinya adalah untuk memberikan angka yang begitu tinggi sehingga lebih besar daripada jarak yang sah untuk manusia.) Akhirnya, jika dinding berada di arah ini dan dalam jarak 1, kita mengembalikan 2 × jumlah kuadrat total dari peta. (Kami ingin tidak pernah berlari menembus dinding, jadi ini membutuhkan skor yang lebih besar. Kami akan segera memilih minimum.)

Kami menggunakan ini dalam konstruk $d=($d,i*$d,-i*$d,-$d).min( LoS deciding block );. Karena kita menggunakan bilangan kompleks untuk semuanya, kita dapat dengan mudah mendapatkan arah yang relatif maju, kanan, kiri dan mundur dari arah semula hanya dengan mengalikannya dengan 1, i, -i (ingat bahwa ysumbu bergerak ke arah lain yang Anda bisa digunakan untuk dari matematika) dan -1, masing-masing. Jadi kita membentuk daftar arah dalam urutan ini, dan menemukan arah yang memiliki "jarak ke manusia" minimal (sesuai dengan blok di atas), yang memastikan bahwa setiap manusia mengalahkan setiap dinding dan apa pun mengalahkan dinding yang benar di bawah hidung monster itu. Kami menggunakan fakta bahwa minfungsi memberi yang pertamanilai minimal. Jika ada ikatan jarak antara beberapa arah, monster itu akan memilih maju ke kanan ke kiri ke belakang, yang persis seperti yang kita inginkan. Jadi kita mendapatkan arahan baru yang kemudian ditugaskan $d.

$m+=$d; hanya membuat monster itu melangkah ke arah yang baru.

$m=$d+(a{m{$m}}∖~$m).pick while m{$m}~~"A".."Z"mengurus bank-bank. Katakanlah monster itu ada di sebuah teleport A. Pertama kita mencari Adi hash terbalik %adan yang muncul dua posisi teleportasi A, kemudian kita membuang posisi saat ini menggunakan operator perbedaan set (yang terlihat seperti garis miring terbalik). Karena ada tepat 2 kejadian dari masing-masing teleport di peta dan monster itu pasti berdiri di atas satu, perbedaannya akan menjadi satu set dengan 1 elemen. Kami kemudian gunakan .pickuntuk memilih elemen acak (percaya atau tidak, tapi ini adalah cara terpendek untuk mendapatkan elemen set elemen 1 :—)). Hal semacam ini terjadi sampai monster itu berakhir di suatu tempat bukan di portal.

Segala sesuatu dalam 4 paragraf terakhir menggambarkan satu konstruksi bentuk besar-besaran {change direction; step; handle teleports}...{m{$m}~~"*"}. Ini adalah urutan yang memanggil blok di sebelah kiri ...sampai kondisi di sebelah kanan ...adalah benar. Dan itu benar ketika monster itu berada di lapangan dengan manusia. Daftar itu sendiri berisi nilai-nilai pengembalian blok besar di sebelah kiri, yang merupakan sampah (kemungkinan besar (Any)) karena mengembalikan nilai loop sementara di akhir. Pada dasarnya, kami menggunakannya sebagai loop sementara yang lebih murah. Nilai daftar dibuang (dan kompiler mengeluh tentang "penggunaan yang tidak berguna ...dalam kontes wastafel", tetapi siapa yang peduli). Ketika semua ini dilakukan, kita kembali $m- posisi monster setelah menemukan manusia, masih sebagai bilangan kompleks (jadi, untuk tes pertama, kita memberi 10+2idan seterusnya).

Ramillies
sumber
Penjelasan yang bagus! :)
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]")

Kurang golf

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
}

Uji

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
sumber