Susuzluktan ölmeni izlemek istiyorum


12

Siz iki kasaba arasındaki çölü geçen bir gezginsiniz. Durmadan geçebilecek kadar su taşıyamazsınız. Bu klasik bir bulmacanın bir çeşididir.

Kurallar

Bir çöl şöyle görünür: çoğunlukla boş alanlardan oluşan bir Gxy ızgarası. İşaretli Salan başladığınız Eyerdir, bitirmek istediğiniz yerdir ve N ile işaretlenmiş bir kare N birim su tutar. .Sıfır su ile işaretlenmiş kareler .

.....................................
........S............................
.....................................
.........7...........................
.....................................
.......................3.............
.....5...............................
................................2....
.....................................
.....................................
.....................................
...............................E.....
.....................................
....................7................
.....................................
.....................................

S'den 5 birim su ile başlıyorsunuz.

En fazla 5 birim su taşıyabilirsiniz.

Her dönüşte

  1. bir kare yukarı, aşağı, sola veya sağa hareket ettirme,
  2. taşıdığınız 1 birim su tüket,
  3. bir miktar su alın veya bırakın .

A dönüş böylece notated edilir (direction)(+|-)(units of water), +, Suyu toplayıp düzenliyor olabilir -bunu olarak düştüğünü.

Örnek dönüşler:

D+0        Move Down
R+0        Move Right
D+2        Move Down, pick up two units of water.
U-1        Move Up, drop one unit of water.

Yukarıdaki örnekte S'den başlayarak bu hareketleri yaparsanız, çöl daha sonra böyle görünür.

.....................................
........S............................
.........1...........................
.........5...........................
.....................................
.......................3.............
.....5...............................
................................2....
.....................................
.....................................
.....................................
...............................E.....
.....................................
....................7................
.....................................
.....................................

Karenizde olduğundan daha fazla su alamazsınız. Suyu aldığınızda, o sayıda birimi karo sayımından çıkarın.

En fazla 5 ünite tutmak için sadece su alabilirsiniz.

Sonsuzluk birimleri olan S dışında hiçbir döşemede 9'dan fazla birim bulunamaz.

Sadece elinde tuttuğunuz kadar su damlatabilirsiniz.

Yerdeki su siz tekrar alana kadar değişmeden kalır.

S'ye dönerseniz, tüketmeden herhangi bir miktarda suyu alabilirsiniz.

E'ye ulaşırsan kazanırsın . E'deki son su biriminizi tüketirseniz hala kazanırsınız.

Sıranızdan sonra sıfır suyunuz varsa ve E'de değilseniz, ölürsünüz .

Giriş ve çıkış

Programınız, STDINyukarıdaki formatta ASCII sanatı olarak isteğe bağlı boyutta bir başlangıç ​​haritası alacaktır . Dikdörtgen olduğunu varsayabilirsiniz, yani tüm satırlar aynı uzunluktadır, tam olarak bir Sve bir Ekare vardır, tüm satırlar ile sonlandırılır \nve STDIN'in tamamı bu normal ifadeye uyacaktır:/^[SE1-9\.\n]+$/

Programınız STDOUT'a aşağıdaki çıktıyı yazacaktır:

  1. hamle listesi,
  2. haritanın son durumu.

Hareket listesini uygun herhangi bir formatta çıkarabilirsiniz.

Haritanın son durumu, girişle aynı formatta yazdırılacaktır, ancak ek olarak #, eğer çini su içermiyorsa ve S veya E değilse ( ziyaret edilen tüm karoları işaretleyerek çölde geçtiğiniz rotayı gösterecektir. öyle .).

ÖRNEK giriş:

.....S.
.......
.......
E......
....8..

ÖRNEK kazanan çıktı:

D+0
D+0
D+0
D+0
L+5
L+0
L+0
L+0
L+0
U+0
.....S.
.....#.
.....#.
E....#.
####3#.

Nontriviality

Kodunuzu yüklediğinizde, kodunuzun aşağıdaki önemsiz durumları karşılayan bir çözüm bulduğu örnek bir harita girişi gönderin:

  • S ve E birbirinden en az 10 harekettir.
  • Başlangıçta N birim su içeren herhangi bir kare, tüm karelerin bulunduğu N genişliğinde bir kenarlıkla çevrelenmelidir .(su veya S veya E değil)

MİSAL

........2.
..........
..........
S.1..2....
..........
..........
........1.
..3.......
.........E

Herhangi bir karodaki su miktarını artırırsanız, yukarıdakiler önemsiz hale gelir.

Gereksinimler

Muhtemelen programınız, bir çözüm bulmadan önce bir dizi başarısız denemeyle karşılaşacaktır.

  1. Programınız sonunda çözülebilir girdileri çözmelidir.
  2. Ölmene izlemek istiyorum program çıktısı hamle ve idama rotanın son harita - her bir çözüm bulmak için başarısız girişimi.
  3. Kazanan bir çözümle karşılaşırsanız, bunun için tam çıktıyı yazdırın ve sonlandırın.
  4. Bir çözüm bulunana kadar devam edin, ancak aynı çözümü iki kez denemeyin - tüm ölümler ayrı yollardan yapılmalıdır.
  5. Bunu bir test girişi kullanın:

(bazı orta noktalarda su önbelleği bırakmak için en az bir hareket gerekir).

 S........
 .........
 .........
 ........E

Çözdüğü önemsiz bir tanıtım girişi ile gönderilen en kısa kod kazanır.


Programın herhangi bir çözülebilir haritayı çözmesi gerekip gerekmediğini veya yalnızca bir harita için çalışması gerekip gerekmediğini belirlemek için bunun açıklığa kavuşturulması gerekir. Birincisini kesinlikle cesaretlendiririm; bir harita olması durumunda çözümü hesaplamaktan daha kolay kodlamak daha kolay olacaktır.

Netlik için düzenlenmiştir. Evet, sıfırdan fazla suyunuz varsa kazanırsınız ve evet, programınız tüm çözülebilir girdileri çözmelidir.
Kasım'da

A * gibi bir algoritma kullanmanızı ve art arda gittiğiniz her döşemede 5 birim yol bırakmanızı ve 5 su içermeyen bir döşemeye basarsanız başlangıca geri dönmenizi engelleyen nedir?
Mavi

Hiçbir şey değil. Devam et.
16:15

'S'den tüm suyu taşı' stratejisi çok sıkıcı olsa da işe yarayacak. S.,.,.,.,. E .... E'yi burada ele alalım ve e gerçekten nokta. Virgüller, yol boyunca sakladığınız yerdir ve 'e', ​​E için koşmak için 5 suya ihtiyacınız olduğu yerdir. 4 su 1 virgülün ilk virgüle taşınması (E + 0 E-1 W + 0 W + 4). 1 su ikinci virgülün içine taşınmak için 16 adım. 52'den üçüncüye, 160'dan dördüncüye, 484'e 1 su atmak ve S. 1926 adımlarına geri dönmek için ve E'de, 1931 adımlarında çalıştırmak için 5 su, 5 tane daha taşıyorsunuz. Her iki adımda da çözüm uzunluğunuzu etkili bir şekilde üç katına çıkarın.
Sparr

Yanıtlar:


12

Perl, 299 + 1 = 300254 + 1 = 255 bayt

İnsanlar algoritmamı gördüğünde bu kesinlikle golf dillerinden biri tarafından dövülecek :-)

İle koş -n(1 byte ceza).

Önceki sürüm spesifikasyona tam olarak uymadı çünkü haritada ekstra su bıraktı ve haritanın son versiyonunda göstermedi; bu durumla başa çıkmak için algoritmayı değiştirirken, süreçte biraz daha küçük golf oynamayı başardım.

push@a,[split//];($s,$t)=(length$`,$.)if/S/;($e,$f)=(length$`,$.)if/E/}{$_.=$s<$e?($s++,R):$s>$e?($s--,L):$t<$f?($t++,D):($t--,U);$\=reverse$";$".=y/LRUD/RLDU/r.Y.reverse.($"=~y/Y/X/r);$a[$t-1][$s]=~y/./#/;$\.=$s-$e||$t-$f?redo:$_;print map{join'',@$_}@a

Örnek (Kaydırma ve yapıyı gösterme ihtiyacını önlemek için çıktıya satır sonları ekledim):

E .....
# .....
# .....
# .....
##### S
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUXDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUUXDDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUXDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUUUYDDDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUXDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUUYDDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLXRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLUYDRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLXRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLLYRRRRR
 LXR LLXRR LXR LLLXRRR LXR LLXRR LXR LLLLYRRRR
 LXR LLXRR LXR LLLYRRR LXR LLYRR LYR LLLLLUUUU

Program tarafından kullanılan gösterimde, hareket yoluyla temsil edilir L, R, Uve Dsol için, yukarı, sağa, aşağı sırasıyla. Varsayılan olarak, her hareketten sonra 1 birim su alırsınız, ancak bu bir karakter eklenerek değiştirilebilir:

  • X: 1 tane almak yerine 2 birim su bırakın
  • Y: 1 tane almak yerine 1 birim su bırakın
  • (yani boşluk): tamamen su üzerinde doldurun (sadece bir taşınmadan sonra çıktı S; program aynı zamanda önde gelen bir alanla çıkar, bu da su ile dolu olduğunuz için mantıklıdır)

Gördüğünüz gibi, bu (daha kısır) haritayı hiçbir ekstra havuz kullanmadan geçmek mümkündür. Aslında, bu kurallar altında, herhangi bir haritada, önceden yerleştirilmiş su yardımı olmadan herhangi bir mesafe elde etmek mümkündür . Bu nedenle, bu algoritma önceden yerleştirilmiş suları yok sayar, yani onu işlemeye çalışan baytları boşa harcamak zorunda değilim. Bu aynı zamanda botun ölmesini görmeyeceğiniz anlamına da gelir, üzgünüm. Asla hayatta kalmayı garanti ettiğini bildiği aralığın ötesine geçmez.

İkimiz de ihtiyaç nedeni Xile Y(ve biz sağlamak için ekstra bir kod parçasıdır Xstratejisinin en ama ara sıra boyunca Ysonunda) Spec çıkışı olması haritanın son sürümünü gerektirir olmasıdır. Bunu uygulamanın en kolay yolu, haritaya tamamen dokunulmamış olarak bırakmaktır (başlangıçta boş karelerdeki yolumuzun dışında), özellikle de yoldaysa 9su ile başlayan bir kare 10(ASCII sanatını kırmak) ile sonuçlanacağı için ve biz sadeceXve böylece haritaya fazladan su damlamasını önleyen bir çözüm bulmamız gerekiyor. Buradaki algoritma, güzergâh üzerindeki her kareye 1 ekstra su birimi “doğal olarak” düşer; bu nedenle, her bir kareyi ziyaret ettiğimiz sondan bir önceki süre, X yerine Y kullanarak 1 tarafından düşürülen su miktarını azaltıyoruz, böylece son ziyaretimizde kareyi orijinal su miktarına geri döndürüyoruz, başladığımızdan biraz daha ıslak bırakıyor.

Bunu büyük bir haritada çalıştırmaya karşı öneriyorum, çünkü O (2 ^ n) performansı var (bot asla susuzluktan ölmese de, böyle bir strateji kullanarak açlıktan öleceğini düşünmek mantıklı.)

Okunabilir sürüm:

# implicit with -n: read a line of input into $_
push @a, [split //]; #/ split $_ into characters, store at the end of @a
($s,$t) = (length$`,$.) if /S/; # if we see S, store its coordinates
($e,$f) = (length$`,$.) if /E/  # if we see E, store its coordinates
}{ # Due to -n, loop back to start if there are more lines.

# From here onwards, $" stores the partial solution this iteration;
#                    $\ stores the partial solution last iteration;
#                    $_ stores the path from ($s,$t) to S.
# At the start of the program, $" is a space, $\ and $_ are empty.

$_ .=  # Work out the next step on the path:
  $s < $e ? ($s++,R) # if too far left, move right, record that in $_;
: $s > $e ? ($s--,L) # if too far right, move left, record that in $_;
: $t < $f ? ($t++,D) # if too far up,    move down, record that in $_;
: ($t--,U);          # in other cases we must be too far down.
$\ = reverse $";     # Store last iteration; $" is constructed backwards.
$" .=                # Extend $" by appending
  y/LRUD/RLDU/r .    # the path from ($s, $t) back to S;
  Y .                # a literal 'Y';
  reverse .          # $/ backwards (i.e. the path from S to ($s, $t);
  ($"=~y/Y/X/r);     # a copy of $" with all 'Y' changed to 'X'.
$a[$t-1][$s] =~      # At the current path coordinate,
  y/./#/;            # replace any '.' with '#'.
$\ .=                # Start appending to $\;
  $s-$e||$t-$f?redo  # if we're not at E, abort that and jump back to {{,
: $_;                # otherwise append $_ (the path from S to E).
print map            # For each element of some array
  {join'',@$_}       # output its concatenated elements
  @a                 # specifying that array as @a.
# Implicitly: print $\ (which specifies the sort of newline print uses).

Dünyayı bir sarmalla dolduran sel, çıkış arayışına yön vermek için şartlar bloğunuzdan daha az kod olur mu?
Sparr

1
Bunun olacağını düşünmüyorum (görmememin bir yolu olsa da, kesinlikle dikkate değer bir fikir). Hala dört yönle uğraşmanız gerekiyor ve şimdi haritanın kenarıyla da uğraşmanız gerekiyor, bu algoritmanın bu sürümünde sorun olmayan bir şey.

İyi bir nokta, kenarları yeniden. Sanırım sonsuz bir haritada yapılabilirdi.
Sparr
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.