Yangın yayılma simülatörü


28

Diyelim ki böyle bir matrisimiz var:

11111
12221
12321
12221
11111

Bu matris bir alanı temsil eder ve her hücre bir arazinin bir bölümünü temsil eder. Her bir hücredeki sayı, arazinin bir kısmının yanıcılığına bağlı olarak (bir ölçüm biriminin gerekli olması halinde dakikalar içinde) tamamen yanması gereken zamanı gösterir . Eğer herhangi bir pozisyonda (hücre) bir ateş başlarsa, ateş bitişik hücrelere yayılmadan önce o hücrenin tamamen yanması gerekir (sadece yatay ve dikeydir, diyagonal değildir). Bu nedenle, eğer bir yangın merkezden başlatılıyorsa, yangının ihtiyacı:

11111        11111        11111        11011        10001        00000
12221  3 m.  12221  2 m.  12021  1 m.  11011  1 m.  00000  1 m.  00000
12321 -----> 12021 -----> 10001 -----> 00000 -----> 00000 -----> 00000
12221        12221        12021        11011        00000        00000
11111        11111        11111        11011        10001        00000

Açıklama:

  • Ateş, yanma süresi 3 olan [2,2] 'de (0-tabanlı) başlar.
  • 3 dakika sonra, [1,2], [2,1], [2,3], [3,2] yanmaya başlar.
  • 2 dakika sonra, bu hücreler yanmaya başlar ve tüm bitişik hücrelere yayılır, ancak [0,2], [2,0], [2,4], [0,4] yakmak için sadece 1 dakika daha gerekir,
  • 1 dakika sonra, bu hücreler yanar ve hücre, bitişik hücrelerine yayılır.
  • 1 dakika sonra, 3. adımdaki hücrelerin geri kalanı yanmaya başlar ve ateş bitişik hücrelerine yayılır (zaten yanmış, yani hiçbir şey olmuyor).
  • Son 1 dakika sonra, ateş tüm araziyi yakıyor.

Yani bu durumda çözüm 8 dakikadır. Ateş en üstteki hücrede başlarsa [0,0]:

11111     01111     00111     00011     00001     00000
12221  1  12221  1  02221  1  01221  1  00121  1  00011   1
12321 --> 12321 --> 12321 --> 02321 --> 01321 --> 00321  -->
12221     12221     12221     12221     02221     01221
11111     11111     11111     11111     11111     01111

00000     00000     00000     00000     00000
00000  1  00000  1  00000  1  00000  1  00000
00221 --> 00110 --> 00000 --> 00000 --> 00000
00221     00121     00020     00010     00000
00111     00011     00001     00000     00000

Yani şimdi toplam süre 10 dakikadır.

Meydan okuma

Her hücrenin tamamen tüketilmesi gereken zamanı temsil eden bir tamsayı değerine sahip bir NxM matrisi (N> 0, M> 0) göz önüne alındığında, bu matrisi alan en kısa program / işlevi ve ateşin başladığı konumda bir çift tamsayı yazın. ve yangının tüm araziyi tamamen tüketmesi için gereken süreyi döndürür / yazdırır.

  • Her hücre pozitif (sıfır olmayan) bir yanma süresine sahip olacaktır. Hücreler için maksimum bir değer alamazsınız.
  • Matrisin kare veya simetrik olması gerekmez.
  • Matris, istediğiniz gibi 0 indeksli veya 1 indeksli olabilir.
  • Konum, bir tamsayı dizisi içeren tek bir parametre, diğer makul formatta iki ayrı parametre olarak verilebilir.
  • Matrisin boyutları giriş parametreleri olarak belirtilemez.
  • Her ara basamağı, sadece istenen süreyi göstermeniz gerekmez. Ancak, adımların herhangi bir şekilde görselleştirildiğinden şikayet etmeyeceğim.

Başka bir örnek:

Fire starts at [1,1] (a '>' represents a minute):

4253   4253   4253   4153   4043   3033   2023    0001   0000
2213 > 2113 > 2013 > 1003 > 0002 > 0001 > 0000 >> 0000 > 0000 
1211   1211   1211   1111   1001   0000   0000    0000   0000

Output: 9

Bu , yani her dil için en kısa programı kazanabilir!


1
@LeanderMoesinger herhangi bir matrisle çalışmak zorunda. Demek istediğim, programınızın veya işlevinizin matrisin boyutlarını giriş parametreleri olarak kabul edemeyeceği, ancak elbette bu boyutları kodunuzun içinde hesaplayabilirsiniz.
Charlie

Sütun ana emriyle giriş tek bir sayı olarak alınabilir mi? Yani, matris girişleri aşağıya doğru numaralandırılır, sonra genelinde
Luis Mendo

1
@LuisMendo evet, elbette. Ancak, "tek sayı" kısmı için önemliyse, her hücrenin yanma süresinin 9'dan büyük olabileceğini unutmayın.
Charlie

Teşekkürler. Hayır, önemli değil. Tek bir numarayı kastetmiştim, ancak muhtemelen birkaç rakamı vardı. Sayı aralığı olacaktır 1içinM*N
Luis Mendo

Yanıtlar:


12

Matlab, 235 257 190 182 178 bayt

Giriş: Matris A, pbaşlangıç ​​koordinatlarını içeren 1x2 vektör .

function t=F(A,p)
[n,m]=size(A);x=2:n*m;x(mod(x,n)==1)=0;B=diag(x,1)+diag(n+1:n*m,n);k=sub2ind([n m],p(1),p(2));t=max(distances(digraph(bsxfun(@times,((B+B')~=0),A(:))'),k))+A(k)

Açıklama:

Yangın yayılımını simüle etmek yerine, bunu "en kısa yolu bul" sorunu olarak da anlayabiliriz. Matris ağırlıklı yönlendirilmiş grafiğe dönüştürülür. Yolların tek bir düğüme olan ağırlıkları, söz konusu düğümü yakma zamanına karşılık gelir. Bir matris için

5   7   7   10
5   2   2   10
4   5   2   6

bağlı grafiği alıyoruz:

grafik

Düğüm 1, sol üst matris elemanı ve düğüm 12 sağ alt elemandır. Başlangıç ​​koordinatları pverilen tüm diğer düğümlere giden en kısa yol hesaplanır. Daha sonra bu en kısa yolların en uzun yolunun uzunluğu + ilk düğümü yakma süresi tüm matrisi yakma zamanına eşittir.

Ungolfed ve yorumlanmış versiyon örnek başlangıç ​​değerleri ile:

% some starting point
p = [3 2];
% some random 5x6 starting map, integers between 1:10
A = randi(10,5,6); 

function t=F(A,p)
% dimensions of A
[n,m] = size(A);
% create adjacency matrix
x=2:n*m;
x(mod(x,n)==1)=0;
B = diag(x,1)+diag(n+1:n*m,n);
B = B+B';
B = bsxfun(@times,(B~=0),A(:))';
% make graph object with it
G = digraph(B);
% starting node
k = sub2ind([n m], p(1), p(2));
% calculate the shortest distance to all nodes from starting point
d = distances(G,k);
% the largest smallest distance will burn down last. Add burntime of initial point
t = max(d)+A(k);

1
PPCG'ye Hoşgeldiniz!
Stephen

Çok güzel bir yaklaşım ve çok iyi açıkladı!
Charlie

Hey, bu benim ilk golf oyunum olduğundan, ;her satırdan sonra atlamamın uygun olup olmadığını sormam gerekiyor . Matlab'da bunlar, her komutun sonuçlarının konsolda görüntülenmesini önler. Şu anda kod ÇOK konuşkan ve konsolu spam. Ama bu kesin bir başarısızlık hali olmadığından, bu şekilde tuttum. Ama çok da önemli değil, sadece 4 bayt
Leander Moesinger

1
@ LeanderMoesinger spam, program çıktınızla aynı çıktı alanına mı giriyor? Örneğin spam, STDERR veya eşdeğerine gider ve çıktı STDOUT veya eşdeğerine giderse, bunları kaldırmanız iyi olur. İkisi de aynı noktada çıktılarsa bilmem.
Stephen

@ Farklı bir çıktı alanı, ancak her şeyi bir satıra koyarak onu tamamen önleyebilirim. Açıklama için teşekkürler!
Leander Moesinger

9

JavaScript (ES6), 156 152 146 144 143 bayt

Kevin Cruijssen sayesinde 1 bayt kaydedildi

Oldukça saf bir uygulama. Kizartma sözdiziminde girdi a(a)(s) , burada a 2B dizidir ve s , başlangıç ​​konumunun 0 temelli koordinatlarını temsil eden iki tamsayıdan [ x, y ] oluşan bir diziden oluşur .

a=>s=>(g=t=>(a=a.map((r,y)=>r.map((c,x)=>(z=(h,v)=>(a[y+~~v]||[])[x+h]<1)(-1)|z(1)|z(0,-1)|z(0,1)|x+','+y==s&&c?u=c-1:c),u=-1),~u?g(t+1):t))(0)

Biçimlendi ve yorumlandı

a => s => (                                // given a and s
  g = t => (                               // g = recursive function with t = time counter
    a = a.map((r, y) =>                    // for each row r of the input array:
      r.map((c, x) =>                      //   for each cell c in this row:
        (                                  //     z = function that takes
          z = (h, v) =>                    //         2 signed offsets h and v and checks
            (a[y + ~~v] || [])[x + h] < 1  //         whether the corresponding cell is 0
        )(-1) | z(1) |                     //     test left/right neighbors
        z(0, -1) | z(0, 1) |               //     test top/bottom neighbors
        x + ',' + y == s                   //     test whether c is the starting cell
        && c ?                             //     if at least one test passes and c != 0:
          u = c - 1                        //       decrement the current cell / update u
        :                                  //     else:
          c                                //       let the current cell unchanged
      ),                                   //   end of r.map()
      u = -1                               //   start with u = -1
    ),                                     // end of a.map() --> assign result to a
    ~u ?                                   // if at least one cell was updated:
      g(t + 1)                             //   increment t and do a recursive call
    :                                      // else:
      t                                    //   stop recursion and return t
  )                                        // end of g() definition
)(0)                                       // initial call to g() with t = 0

Test durumları


==0yanılmıyorsam golf oynayabilir <1.
Kevin Cruijssen

1
@KevinCruijssen Bu gerçekten de undefined<1sahte olduğu gibi güvenlidir. Teşekkürler!
Arnauld,

8

Octave, 67 bayt

function n=F(s,a)n=0;do++n;until~(s-=a|=imdilate(~s,~(z=-1:1)|~z')

Çevrimiçi deneyin!

Ara sonuçları görselleştirmek için Bunu deneyebilirsiniz!

Arazinin giriş matrisi ave başlangıç ​​koordinatını, 0 & 1 matrisi olarak alan ve aynı boyutta bir fonksiyon.

Aslında endfunction, örneği çalıştırmak için eklenmesine gerek yoktur.

Açıklama:

Araziye tekrar tekrar morfolojik görüntü dilasyonu uygulayın ve yanık alanları çıkartın.

Ungolfed cevap:

function n = Fire(terrain,burned)
    n = 0;
    mask = [...
            0  1  0
            1  1  1
            0  1  0];
    while true
        n = n + 1;
        propagation = imdilate(~terrain, mask);
        burned = burned | propagation;
        terrain = terrain - burned;
        if all(terrain(:) == 0)
            break;
        end
    end
end

Bu güzel bir cevap, ancak belki de algoritma ilk durumu bir adım olarak sayıyor ve örneğinizde 10 yerine 11 döndürüyor. İlk hücreyi [3 3] olarak değiştirirsem sonuç 8 yerine 9 olur.
Charlie

@CarlosAlejo OH, benim hatam. Cevap değişti güncelleme n=1için n=0.
rahnema1

7

Matl , 26 25 bayt

Buradaki en golfçü dilleri kullanarak daha fazla cevap görmek istedim.

`yy)qw(8My~1Y6Z+fhy0>z}@&

Giriş formatı:

  • İlk giriş ;satır ayırıcı olarak kullanılan bir matristir .

  • İkinci girdi, matrisin girişine 1 temelli sütun ana düzeninde hitap eden tek bir sayıdır (mücadelenin izin verdiği şekilde). Örneğin, 3 × 4 matrisindeki her bir girişin sütun ana koordinatı

    1  4  7 10
    2  5  8 11
    3  6  9 12
    

    Dolayısıyla, örneğin 1 tabanlı koordinatlar (2,2) karşılık gelir 5.

Çevrimiçi deneyin! Veya tüm test durumlarını doğrulayın .

açıklama

Kod, yanan girişlerin listesini tutar. Her yinelemede, bu listenin tüm girişleri azaltılır. Bir giriş sıfıra ulaştığında, komşu girişleri listeye eklenir. Baytları kaydetmek için sıfıra ulaşan girişler listeden kaldırılmaz; bunun yerine, negatif değerlerle "yanmayı" tutarlar. Girdilerden hiçbiri pozitif değere sahip olmadığında döngüden çıkar.

Hafifçe değiştirilmiş kodla adım adım çalışan programa bakın .

Yorumlanan kod:

`      % Do...while
  yy   %   Duplicate top two arrays (matrix and array of positions to be decremented)
       %   In the first iteration this implicitly takes the two inputs
  )    %   Reference indexing. This gives the values that need to be decremented
  q    %   Decrement
  w    %   Swap. This brings the array of positions that have been decremented to top
  (    %   Assignment indexing. This writes the decremented values back into their
       %   positions
  8M   %   Push array of positions again
  y    %   Duplicate decremented matrix
  ~    %   Negate. This replaces zeros by 1, and nonzeros by 0
  1Y6  %   Push predefined literal [0 1 0; 1 0 1; 0 1 0] (4-neighbourhood)
  Z+   %   2D convolution, maintaining size
  f    %   Find: gives column-major indices of neighbours of totally burnt entries
  h    %   Concatenate. This updates the array of positions to be decremented
  y    %   Duplicate decremented matrix
  0>   %   This gives 1 for positive entries, and 0 for the rest
  z    %   Number of nonzeros. This is the loop condition (*)
}      % Finally (execute before exiting loop)
  @    %   Push iteration number. This is the output
  &    %   Specify that the final implicit display function will display only the top
       %   of the stack
       % Implicit end. If the top of the stack (*) is not 0 (i.e. there are entries
       % that have not been totally burnt) the loop proceeds with the next iteration.
       % Else the "finally" branch is executed and the loop is exited
       % Implicit display (only top of the stack)

2
Şimdi buna kısa kod derim! :-)
Charlie

4

Python 2 , 170 bayt

s,m=input()
t={s}
r=0
while max(sum(m,[]))>0:
 r+=1
 for a,b in t|t:
	try:a<0<x;b<0<x;m[a][b]-=1;t|=m[a][b]==0and{(a+1,b),(a-1,b),(a,b+1),(a,b-1)}or t^t
	except:0
print r

Çevrimiçi deneyin!


4

Python 3 , 277 266 bayt

def f(m,s):
 p={s};w=len(m);t=0
 while sum(sum(m,[])):
  t+=1;i=0
  for x,y in p:
   try:m[x][y]=max(0,m[x][y]-1)
   except:0
  for v in sum(m,[]):
   if v<1:
    for l in[(1,0),(-1,0),(0,1),(0,-1)]:a,b=max(0,i%w+l[0]),max(0,i//w+l[1]);p.add((a,b))
   i+=1
 print(t)

Çevrimiçi deneyin!

f2B matris ve bir puan kesimi alan bir işlevi tanımlar . İşlevin yaptığı ilk şey, içinde iletilen ilk başlangıç ​​değerini içeren bir grup kümesi tanımlamaktır p={s}. İşlev daha sonra sıfır olan tüm nokta pdiziliminden geçer mve o noktadaki matristen bir sayı çıkarır . Daha sonra mtekrar sıfır değerine sahip tüm noktaları bulmak ve bu noktanın dört komşusunu sete eklemek için tekrar dolaşır p. Bu yüzden bir set kullanmayı seçtim, çünkü Python'daki setler yinelenen değerlere izin vermiyor (bu da çıkarma işlemini çok mahveder). Ne yazık ki, liste dizini sarma list[-1] == list[len(list)-1]işleminden dolayı (örneğin :) endekslerin kısıtlanması gerekir, bu yüzden negatif olmazlar ve yanlış koordinatlar eklerler p.

Özel bir şey yok, hala golf oynamaya alışmak. Kesinlikle burada iyileştirme için yer açılmalı, ben de çatlamaya devam edeceğim.


Kodunuzu test edebilmemiz için Çevrimiçi deneyin bölümüne bir yürütme örneği yazabilir misiniz ?
Charlie

@CarlosAlejo Elbette, gönderiye ekledi.
MooseOnTheRocks

4

APL (Dyalog) , 93 66 57 bayt

{⍵{^/,0≥⍺:0⋄1+x∇⍵∨{∨/,⍵∧⍲/¨2|⍳3 3}⌺3 30=x←⍺-⍵}(⊂⍺)≡¨⍳⍴⍵}

Çevrimiçi deneyin! veya Çevrimiçi görselleştirin!


Bu fonksiyon, arazi matrisini sağ argüman ve ilk ateşin koordinatlarını (1-tabanlı) sol argüman olarak alır. Her şeyi yakmak için gereken dakika sayısını döndürür.


Güncellemeler

Sonunda yayılma işlevini aşağı golf etmenin bir yolunu buldum.
* Sigh * dünya toroidal olsaydı çok daha kolay olurdu .


TIO az önce Dyalog 16.0'a yükseldi , bu da şimdi parlak yeni şablon operatörümüze sahip olduğumuz anlamına geliyor


Çok güzel cevap! Ara çıktı, ilerlemeyi görselleştirmeye yardımcı olur!
Charlie

2

Python 2,268 bayt

def f(m,y,x):t,m[y][x]=m[y][x],0;g(m,t)
def g(m,t):
	n,h,w=map(lambda r:r[:],m),len(m),len(m[0])
	for l in range(h*w):r,c=l/h,l%h;n[r][c]-=m[r][c]and not all(m[r][max(c-1,0):min(c+2,w+1)]+[m[max(r-1,0)][c],m[min(r+1,h-1)][c]])
	if sum(sum(m,[])):g(n,t+1)
	else:print t

Çevrimiçi deneyin!

Her döşemenin sayısının Kardinal olarak 0'a bitişik olması durumunda düşürüldüğü zaman adımlarında yinelemeli olarak yineleyin, inanıyorum ki hala boolean verimlilik için golf oynayabildiğini düşünüyorum ...

* not: 'Çevrimiçi deneyin!' kod altbilgide günlük hata ayıklama günlüğünü içerir. Algoritma ilerlemesini izlemeyi seviyorum.


2

Haskell , 138 133 bayt

u#g|all((<=0).snd)g=0|2>1=1+(u:[[(x+1,y),(x-1,y),(x,y-1),(x,y+1)]|((x,y),0)<-n]>>=id)#n where n=d<$>g;d p|elem(fst p)u=pred<$>p|2>1=p

Çevrimiçi deneyin!

Girişin ((x, y), cell) listesi olduğunu varsayar. Ungolfed:

type Pos = (Int, Int)

ungolfed :: [Pos] -> [(Pos, Int)] -> Int
ungolfed burning grid
  | all ((<=0).snd) grid = 0 
  | otherwise = 1 + ungolfed (burning ++ newburning) newgrid
 where
  newgrid = map burn grid
  burn (pos,cell) | pos `elem` burning = (pos, cell - 1)
                  | otherwise = (pos, cell)
  newburning = do
    ((x,y),cell) <- newgrid
    guard (cell <= 0)
    [(x+1,y),(x-1,y),(x,y-1),(x,y+1)]
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.