Dinamitli Fare


23

Sen bir faresin. Fare arkadaşların hepsi yakalandı ve bilinçsiz ve tek bir giriş / çıkışa sahip bir labirentte kaldılar. Labirentin mükemmel bir haritasına sahip olursunuz, böylece acele edip hepsini güvenli bir yere taşıyabileceğiniz bir çözüm çizebilirsiniz. Bununla birlikte, labirent, eşik değerine 1000ulaşıldığında bir alarmı tetikleyecek ve yakalanmanıza ve kurtarma görevinizde başarısız olmanıza neden olacak bir güvenlik sistemi ile korunmaktadır .

Labirent hakkındaki önceki araştırmalarınızdan, adım attığınız her kare (yani, her yatay veya dikey hareket - fareler çapraz olarak hareket edemez ) 1güvenlik sisteminin sayacına ekler . Bununla birlikte, bir ağırlık taşıyorsanız (bir dinamit bloğu veya bilinçsiz bir fare arkadaşı), bunun yerine 2ek basıncı tespit ettiğinden ekler . Giriş / çıkış meydanında bu güvenlik sistemi yoktur ve bu yüzden tezgahın içine ekleme yapmaz.

Girişte getirdiğiniz sınırsız bir dinamit kaynağınız var, böylece arkadaşlarınızı özgür bırakmak için tüm duvarları havaya uçurabilirsiniz . Ancak, her patlamada 50sarsıcı baskıdan dolayı tezgahı eklediği için bunu yaparken dikkatli olmalısınız . Ek olarak, bir seferde yalnızca bir şey taşıyabilir, bir fare veya bir dinamit bloğu. Her dinamit bloğu yalnızca bir duvar alanını patlatabildiğinden, arka arkaya birden fazla duvar varsa, daha fazla kapmak için girişe boş elle yapılan bir yolculuk yapmanız gerekeceği anlamına gelir.

Çalışılan örnek

Labirentimizin aşağıdaki gibi göründüğünü varsayalım:

######
#M# E#
######

cSayaç için kullanacağım . Biz başlayacak E, ntrance dinamit taşırken bir kare sola hareket c=2. Duvarı patlatmak için dinamiti patlatıyoruz c=52. İki kareyi sola hareket ettirdik, eli boş, almak için c=54, ve şimdi farenin karesinde duruyoruz. Arkadaşımızı kaldırıyoruz ve 3 kareyi tekrar Exit'e taşıyoruz, ancak son kare sayma sensörleri olmadığı için sayılmaz, bu yüzden sırtımızda bir şey olan sadece 2 kare var. Bu, son fare ile çıkışa ulaştığımızda c=58, bundan daha az olan 1000ve dolayısıyla görevin başarılı olduğu anlamına gelir.

Meydan okuma

Bir giriş labirentine bakıldığında, fare kahramanı olarak, yukarıda belirtilen kısıtlamalar dahilindeki kapana kısılmış tüm fareleri başarıyla kurtarabilir veya görevin başarısız olup olmadığını çıkarabilirsiniz.

Giriş

  • Kabul edilebilir herhangi bir formatta 2D labirent (çok satırlı dize, dizi dizisi, vb.).
  • Bu meydan okuma #için hem iç hem dış duvarlarda, Mfare arkadaşlarında ve Egirişlerde kullanacağım .
  • Giriş hiçbir zaman bir iç duvara bitişik olmayacak (her zaman serbestçe hareket edebilecek en az bir alan olacak).
  • Tutarlı olduğu sürece, yazdırılabilir ASCII karakterlerinin yerine kullanabilirsiniz . Bu mu çok uzun örn tutarlılık (, kullanmak seçerseniz korumak gibi, sen dış duvarlar vs iç duvarlar için iki farklı semboller kullanmasına izin @yerine iç duvarlar için ve izin #dış için, her iç duvar olmalı @ve her dış duvar #).
  • Labirent her zaman duvarlarla tamamen sınırlanır, ancak mutlaka dikdörtgen değildir. İstenirse, labirentin dikdörtgen giriş yapmak için boşluklarla doldurulduğunu varsayalım (isteğe bağlı).
  • Labirent, dinamit olmadan erişilemeyen bölümlere sahip olabilir.
  • Labirentin dış duvarlarını dinamit edemezsiniz.

Çıktı

Bir truthy / falsey değeri. "Evet, fare diğer fareleri kurtarabilir" ya da "Hayır, alarm sistemi açılacak" için Truthy.

Kurallar

  • Tam bir program veya bir işlev kabul edilebilir.
  • Standart boşluklar yasaktır.
  • Bu olduğundan, tüm normal golf kuralları geçerlidir ve en kısa kod (bayt cinsinden) kazanır.

Örnekler

Boş çizgilerle ayrılmış gerçek örnekleri.

#####
#M E#
#####

######
#M# E#
######

########
#E  # M#
#   #  #
#   #  #
#      #
########

#############################
#    ##      #       #      #
#  M ## M    #       #      #
#    ##      #   M   #    E #
#M   ##      #       #      #
#############################

###############
#MMMMMMMMMMMMM#
#MMMMMMMMMMMMM#
#MMMMMMMMMMMMM#
#MMMMMMMMMM MM#
#MMMMMMMMMMMME#
###############

Boş satırlarla ayrılmış Falsey örnekleri

#############################
#M   ##      ##      ##     #
#  M ## M    ##      ##     #
#    ##      ##  M   ##   E #
#M   ##      ##      ##     #
#############################
#############################
                     ########
                     ########
                     #   #  #
                     # M # M#
                     ########

              #####
              # M #
              #####
              #####
              #####
              #####
###################
# # # ##   ## # # #
#M#M#M## E ##M#M#M#
# # # ##   ## # # #
###################
#######
######
#####
####
# M#
####

###############
#MMMMMMMMMMMMM#
#MMMMMMMMMMMMM#
#MMMMMMMMMMMMM#
#MMMMMMMMMMMMM#
#MMMMMMMMMMMME#
###############

3

3
@AlexA. İnternetteki bir yabancıdan öğrendiğin için üzgünüm. ;-)
AdmBorkBork

2
Çoğu insanın golf oynamayı bırakıp düzenli kodlarla çözmekte zorlanacağını düşünüyorum. Şu anda üzerinde çalışmak için zamanım olmadığından maalesef bu çok zor.
Moshe Katz

2
Dış duvarlar için farklı bir karaktere sahip olmak kabul edilebilir mi (yok edilemez oldukları için)?
Tensibai

2
@ Moshe Katz , zamanınız olmadığından emin olun . Sadece Mäuse’u kurtarmak istemiyorsun.
msh210

Yanıtlar:


19

Perl, 216 215 bayt

İçin +2 içerir -0p

STDIN'e giriş verin. Kullanım %, dış duvarlarda #, iç duvar 0, boş alanlar için 8olan fareler ve rbaşlangıç pozisyonu için. Bütün tahtalar bir dikdörtgen oluşturacak şekilde doldurulmalıdır. Örnekleri aşağıdaki gibi dönüştürebilir ve çalıştırabilirsiniz:

cat dynamite.txt | perl -p0e 's/.+/$a^=$&/egr;s//sprintf"%-*s",length$a,$&/eg;1while/\n/,s/^ *\K#|#(?= *$)|^ *.{@{-}}\K#|\A[^\n]*\K#|#(?=[^\n]*\n\z)|#(?=.{@{-}} *$)/%/sm;y/ EM/0x2/' | dynamite.pl

dynamite.pl:

#!/usr/bin/perl -0p
sub f{@a{@_}||=push@{$%+($&?$1?50:$&=~8?0:$&&"5"?2:1:0)},@_}f$_;for(@{$%}){f y/xr|/ytx/r;{f s/\pL\d/$&^(E&$&)x2/er}{f s/(q|s|y)#/$&^"\x01\x13"/er}my$o;{$\|=/x/>/2/;$o.="
"while s/.$/$o.=$&,""/meg}f$o}$%++>999|$\||redo}{

\xhhTalep edilen puan için kaçışları değiştir .

Program, karmaşık durumları gerçekçi bir şekilde ele alamıyor. Özellikle başarısızlık durumlarının hiçbiri ile başa çıkamaz. Bunun nedeni, iç duvarları havaya uçurmanın ya da fareleri toplamanın çok farklı yollarının bulunmasıdır, böylece arama çok geniş olur ve aynı hatayı birden fazla kez işleyemeyecek kadar akıllı olsa da çok fazla bellek kullanır. Bir 100miktar katlanılabilir çalışma süreleri ve hafıza kullanımı için basınç sınırının düşürülmesi gerekir .

açıklama

Bir alanın durumunu göstermek için karakterin bit desenini kullanırım:

contains victim: 0000 0010
has hero:        0100 0000
carry dynamite   0000 0001
carry mouse      0000 0100
home             0000 1000
walkable         0001 0000 (not really needed but results in shorter regexes)
make printable   0010 0000
wall             0010 xxxx (bit patterns not very important,
permawall        0010 xxxx  just avoid letters and digits)

Örneğin, 01000000dinamit ( ) taşıyan kahraman ( ) 00000001yürüyebileceği bir yerde olmalı ( 00010000) ve tüm değerlerin yazdırılabilir ASCII ( 00100000) olmasını istiyoruz . orTüm bu bit maskelerinin bit yönünde alınması, 01110001ASCII kodunun hangisi olduğunu verir q. Toplamda bu olur ::

p: hero                     r hero on victim
q: hero carrying dynamite   s hero carrying dynamite on victim
t: hero carrying mouse      v hero carrying mouse on victim

x : hero at home
y : hero at home carrying dynamite
| : hero at home carrying mouse

0: empty  without hero
8: home   without hero
2: victim without hero

%: permanent wall
#: normal wall

Program sadece kahramanın sağa doğru hareket ettiğini düşünecektir (daha sonra açıklanacak olan rotasyon diğer yönlere dikkat edecektir). Bit maskeleri, kahramanın her zaman bir harfle ve bir rakamla hareket edebileceği bir yerle temsil edileceği şekilde özenle seçildi (evdeki bir kurban taşıyan kahraman hariç), ancak yine de bu kasıtlı, kahramanın tek hareketi düşecek kurban). Yani ilerleyebilecek bir kahraman tarafından eşleştirilir /\pL\d/. Eşleşen alt dize, kahraman ve taşıdığı şey ilk karakterden çıkarılıp ikinciye eklenecek ve xorher iki karakter için de aynı değerde bit değeriyle yapılabilecek şekilde değiştirilmelidir . Xor değeri kahraman bitinden ( 01000000), dinamit bitinden ( 00000001) ve fare faresinden ( 00000100) oluşur. Birlikte onlar oriçin01000101hangisi ASCIIE. Böylece kahramanı harekete geçirir:

s/\pL\d/$&^(E&$&)x2/e

Kahraman tam önünde duruyorsa ve dinamit taşıyorsa bir duvarı havaya uçurabilir ( q, sveya y). Kahraman dinamitini ( xorile birlikte 00000001) kaybedecek ve duvar #bir geçide 0(xor ile 00010011) dönüşecek ,

s/(q|s|y)#/$&^"\x01\x13"/e

Diğer yönleri ele almak için tüm tahta döndürülür (döndürülen tahta içeri girer $o):

my$o;$o.="\n"while s/.$/$o.=$&,""/meg

Kahramanı hareket ettirmenin yanı sıra yapabileceği çok sayıda başka seçenek de var:

When at home, pick up dynamite:                   x -> y
When on victim not carrying anything pick him up: r -> t
When at home carrying a victim, drop him off:     | -> x

Bu tarafından yapılır

y/xr|/ytx/

Kahraman evde hiçbir şey taşıyorsa ( x) ve kurtarılacak kurban yoksa (tahta) kurul kurulur 2. Bu uygun kullanarak test edilebilir

/x/>/2/

Tahta çözüldükten sonra bu durumu hatırlamak ve sonunda yazdırmak istiyorum. Ben de "çözüldü" bayrağını taşıdıkları için $\ve yazdırmadan program sonunda o yazdırmak $_böylece,

$\|=/x/>/2/  ...   }{

0 basıncında işlenecek olan durumlar @0, 1 üzerinde @1vb. Basınçta tutulur $%. Kullanılması $nveya değişken bir şeye başlatılmadı, autovivification aksi değişecek çünkü böyle bir şey kısa olacağını ancak kod işi değil $nbelli basınçta devletler üzerinde ARRAY reference.Looping bir kullanılarak yapılır forve bir mapnedeni a ile forhala çevrilirken diziyi genişletebilir ve yeni elemanları seçebilirsin. Buna ihtiyaç var, çünkü kahramanın dönüşleri ve tek saha seçimleri 0 zamanında oluyor ve aynı basınç dizisinde sonuçlanıyor. Yani verilen bir basınç için döngü tarafından yapılır

for(@{$%}){...}

Bu, basınç 1000'e ulaşana veya bir çözelti bulunana kadar tekrar edilir:

$%++>999|$\||redo

Geriye kalan tek şey, yeni keşfedilen durumları kendi baskı dizilerine eklemek. Bu alt rutin tarafından yapılacaktır f. Sadece henüz görülmediyse bir devlet eklemek istiyoruz. Daha önce görülen devletler şu şekilde tutulur %a:

sub f{@a{@_}||=push@$n, @_}

$nbir devlet için yeni baskıyı temsil eder. Regex değişkenlerinin hâlâ kahramanın bu çağrıya yol açan eyleminin bir sonucu olduğu durumundan türeyeceğim:

if $1 is set it was from s/(q|s|y)#/$&^"\x01\x13"/e which blows a wall -> 50
else if $& is set it was from s/\pL\d/$&^(E&$&)x2/e, so the hero moves.
    if $& contains 8 the hero went home -> 0
    else if the hero has carry bits (5) -> 2
    else                                   1
else ($& was not set) it was from y/xr|/ytx/r -> 0

Bu, aşağıdaki formüle götürür $n:

$%+($&?$1?50:$&=~8?0:$&&"5"?2:1:0)

Tüm oyuncu değişikliği bir rdeğiştirici alır, böylece değiştirilen durumu döndürür ve mevcut durumu $_yalnız bırakır . fdaha sonra bu değişmiş durumda çağrılır, böylece

f y/xr|/ytx/r;

$nİhtiyaçların hesaplanması , regex değişkenlerine ihtiyaç duyduğundan, değişikliklerin hiçbir şeyi değiştirmemesi durumunda kümelemek için varsayılan olmalıdır (çünkü onları tetikleme koşulu yerine getirilmediğinden). Ayrıca önceki bir döngüden herhangi bir regex değişkenini almamalıyım. Bu nedenle ikameler {}, regex durumunu kaydetmek ve geri yüklemek için bloklara sarılır . Böyle ifadeler böyle olsun

{f s/\pL\d/$&^(E&$&)x2/er}

Özellikle rotasyon öyle sarılır ki öyle çağırır ki f regex değişkenleri olmadan ve 0'a basınç katkısı alır.

Hala yapılacak tek şey @0, başlangıçtaki ilk durumla baş etmek.

f$_

Bu ana döngüde olduğu $_için daha sonraki basınç dizilerine de eklemeye çalışır , ancak başlangıçtaki durum zaten%a hiçbir şeyde olmayacağından.

Bütün bunlar, temel olarak Dijkstra'nın algoritmasını kullanarak en kısa çözümü bulur . Yine de potansiyel bir sorun var. Geçerli kod, ilk keşiften daha düşük bir basınçla yeniden keşfedilirse bir durum eklemez. Bunu tetikleyecek bir tahta kuramadım, ancak bunun imkansız olduğunu ispatlayamadım.


3
Ooo, merak uyandırıcı. Bu, cevap beklediğimden çok daha kısa. Biraz açıklama ekleyebilir misiniz? Ben gerçekten Perl'i takmadım.
AdmBorkBork

3
@TimmyD Tamam, açıklama perl olmayan bir programcının bile en azından nasıl çalıştığıyla ilgili bir izlenim alması için yeterli detayda eklendi
Ton Hospel

1
Çok etkileyici!
Emigna

Harika golf, gerçekten etkileyici ... Perl ile golf oynamakta o kadar da kötü olmadığımı düşündüğümde, golflerine bir göz atıyorum ve bu duygu oldukça hızlı gidiyor!
Dada

13

JavaScript, 863 834 785 781 bayt

ETHproductions sayesinde 29 bayt
kaydedildi Jordan ile 53 bayt kaydedildi

L=[]
f=(S,r="",R="",p=0,s=S.replace(RegExp(r),R),l=`((.|\n){${s.split`
`[0].length}})`,q=p+1,o=p+2,n=p+50)=>s in L|p>999?1e3:!/M/.test(s,L[s]=0)&/E/.test(s)?p:Math.min(...[[/ E/,"me",q],[/ E/,"de",o],[/ME/,"ce",q],[/E /,"em",q],[/E /,"ed",o],[/EM/,"ec",q],[`E${l} `,"e$1m",q],[`E${l} `,"e$1d",o],[`E${l}M`,"e$1c",q],[` ${l}E`,"m$1e",q],[` ${l}E`,"d$1e",o],[`M${l}E`,"c$1e",q],[/ m/,"m ",q],[/m /," m",q],[`m${l} `," $1m",q],[` ${l}m`,"m$1 ",q],[/ (d|c)/,"$1 ",o],[/(d|c) /," $1",o],[`(d|c)${l} `," $2$1",o],[` ${l}(d|c)`,"$3$1 ",o],[/d#/,"m ",n],[/#d/," m",n],[`#${l}d`," $1m",n],[`d${l}#`,"m$1 ",n],[/mM/," c",q],[/Mm/,"c ",q],[`M${l}m`,"c$1 ",q],[`m${l}M`," $1c",q],[/[mc]e/," E",p],[/e[mc]/,"E ",p],[`e${l}[mc]`,"E$1 ",p],[`[mc]${l}e`," $1E",p]].map(a=>f(s,...a)))
F=s=>f(s)<1e3

Girdiyi çok satırlı bir dize olarak alır.

Bu, ftüm fareleri almadan önce alarmı devre dışı bırakıp bırakmadığınızı belirlemek için özyinelemeli bir işlev kullanan anonim bir işlevi tanımlar . fdöner 1000basınç 1000 üzerindeyse, kurtarma için artık fareler ve çıkış fare ve döner aksi mevcut durumdan tüm olası hamle minimum basınç varsa basınç döndürür (sonsuz özyinelemeye önlemek için). LZaten ziyaret L[pos]==0edilmişse ziyaret edildiği yerleri izlemek için bir dizi kullanır ve ziyaret edilmemişse tanımsızdır. Bu gerekli olmayabilir, ancak farenin işe yaramaz hareketler yapmasını ve özyineleme hatalarını en azından fırlatmasını önler. (Bu yeniden tanımlamanız gerektiği anlamına gelirL bunu birden çok kez test ediyorsanız )

Bu, dış duvarlar için farklı bir karakter kullanmanızı gerektirdiğinden başka bir sorudaki formatı kullanır. (Dışında herhangi bir şey # MEmecd)

Daha okunabilir sürüm:

stateList = []
f=(s,regex="",replacement="",pressure=0,state=s.replace(regexp(regex),replacement),line=`((.|\n){${state.split("\n")[0].length}})`)=>{
    if (state in stateList || pressure > 999) return 1e3
    if (!/M/.test(state) && /E/.test(state)) return pressure

    stateList[state] = 0

    return [
        [/ E/,"me",pressure+1],
        [/ E/,"de",pressure+2],
        [/ME/,"ce",pressure+1],
        [/E /,"em",pressure+1],
        [/E /,"ed",pressure+2],
        [/EM/,"ec",pressure+1],
        [`E${line} `,"e$1m",pressure+1],
        [`E${line} `,"e$1d",pressure+2],
        [`E${line}M`,"e$1c",pressure+1],
        [` ${line}E`,"m$1e",pressure+1],
        [` ${line}E`,"d$1e",pressure+2],
        [`M${line}E`,"c$1e",pressure+1],
        [/ m/,"m ",pressure+1],
        [/m /," m",pressure+1],
        [`m${line} `," $1m",pressure+1],
        [` ${line}m`,"m$1 ",pressure+1],
        [/ ([dc])/,"$1 ",pressure+2],
        [/([dc]) /," $1",pressure+2],
        [`([dc])${line} `," $2$1",pressure+2],
        [` ${line}([dc])`,"$3$1 ",pressure+2],
        [/d#/,"m ",pressure+50],
        [/#d/," m",pressure+50],
        [`#${line}d`," $1m",pressure+50],
        [`d${line}#`,"m$1 ",pressure+50],
        [/mM/," c",pressure+1],
        [/Mm/,"c ",pressure+1],
        [`M${line}m`,"c$1 ",pressure+1],
        [`m${line}M`," $1c",pressure+1],
        [/[mc]e/," E",pressure],
        [/e[mc]/,"E ",pressure],
        [`e${line}[mc]`,"E$1 ",pressure],
        [`[mc]${line}e`," $1E",pressure]
    ].map(a=>f(state,...a)).reduce((a,b)=>a-b<0?a:b) //reduce used for support in more browsers.
}
s=>f(s)>1e3

Yararsız boşluklarda s in L|p > 999.
Yytsi

@TuukkaX Bana bunu hatırlattığın için teşekkürler, bytecount zaten boşluksuz sürümdeydi.
DanTheMan

Eğer kod sararak bayt kaydetmek varsa görün evalve değiştirilmesi @ile $1(Emin bu çalışacaktır değilse, fakat yazım $1çok)
Cyoce

fTek bir astar yaparak bir f=(...)=>s in L|p>999?1e3:!/M/.test(s,L[s]=0)&/E/.test(s)?p:Math.min(...
demetden

@Cyoce Ben $118 kez kullanıyorum ve .replace("@","$1")18 bayt. Çıkarmanın bir yolunu görmüyorum.
DanTheMan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.