Tumbangkan tumpukan pasir

12

(Ada pertanyaan terkait tentang tumpukan pasir tak terbatas , dan menemukan elemen identitas tumpukan pasir .)

Diberikan matriks bilangan bulat non-negatif, kembalikan matriks dengan dimensi yang sama, tetapi dijatuhkan :

  1. Jika matriks tidak mengandung nilai lebih dari 4, kembalikan.
  2. Setiap "sel" yang lebih besar dari 3 akan berkurang sebesar 4, dan semua sel yang bertetangga secara langsung (di atas, di bawah, kiri, dan kanan) bertambah, jika ada.
  3. GOTO 1.

Contoh:

0 1 0        0 2 0
2 4 0   ->   3 0 1
0 0 3        0 1 3

1 2 3    2 3 4    2 5 1    4 1 2    0 3 3    0 3 3    0 3 3
4 5 6 -> 2 4 4 -> 4 2 3 -> 0 5 4 -> 3 2 1 -> 3 3 1 -> 3 3 2
7 8 9    5 7 7    2 6 5    4 3 2    0 5 3    1 1 4    1 2 0

(Anda hanya perlu mengembalikan hasil akhir. Jalur yang Anda capai mungkin berbeda dari yang ditunjukkan di sini: tidak masalah dalam urutan mana Anda melakukan operasi penggulingan, semuanya mengarah ke hasil yang sama.)

Untuk penjelasan yang lebih dalam dan motivasi, lihat video Numberphile ini atau artikel Wikipedia tentang model pasir Abelian .

Aturan:

  • Anda dapat mengambil input dan output dengan salah satu cara standar
  • Celah dilarang
  • Input dan output mungkin:
    • daftar bersarang: [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    • daftar sederhana: [1, 2, 3, 4, 5, 6, 7, 8, 9]dan bentuknya
    • semacam jenis matriks asli
    • sebuah string, mis 1 2 3\n4 5 6\n7 8 9
    • atau apa pun yang berfungsi dalam bahasa Anda.
  • Input dan output harus dalam bentuk yang sama
  • Input mungkin berisi angka yang lebih besar daripada yang ditunjukkan di sini, tetapi ukurannya mungkin dibatasi oleh batas bahasa Anda (setara MAXINT, jika ada)
  • Matriks dapat memiliki bentuk apa pun (mis. 1x1, 2x2, 3x3, 4x4, 2x7, 11x3, ...)
  • Anda tidak perlu menangani case di mana bentuknya 0xN atau Nx0.

Testcases

[[2, 5, 4], [8, 6, 4], [1, 2, 3]] -> [[3, 3, 0], [1, 2, 2], [1, 3, 2]]
[[0, 0, 2], [1, 3, 3], [0, 0, 0]] -> [[0, 0, 2], [1, 3, 3], [0, 0, 0]]
[[9, 9, 9], [9, 9, 9], [9, 9, 9]] -> [[1, 3, 1], [3, 1, 3], [1, 3, 1]]
[[4, 5], [2, 3]] -> [[2, 3], [0, 1]]
[[2, 3, 5], [2, 2, 0]] -> [[3, 0, 2], [2, 3, 1]]
[[7]] -> [[3]]

Ini , kode terpendek (per bahasa) menang.

L3viathan
sumber
Apakah boleh untuk menampilkan semua hasil antara?
feersum
@feersum saya kira begitu, selama jelas apa hasil akhirnya.
L3viathan

Jawaban:

8

MATL , 17 byte

tss:"t3>t1Y6Z+w4*-+

Cobalah di MATL Online! Atau verifikasi semua kasus uji .

Penjelasan

Program ini berulang sebanyak jumlah input. Ini adalah batas atas yang longgar pada jumlah iterasi yang diperlukan.

Untuk setiap iterasi, entri dalam matriks sandpile melebihi 3terdeteksi, memberikan matriks 1dan 0, yang berbelit-belit dengan topeng 4-tetangga. Entri yang melebihi 3dalam matriks pasir dikurangi oleh 4, dan hasil konvolusi ditambahkan.

Untuk iterasi terakhir, di mana matriks sandpile tidak memiliki angka melebihi 3, nol dikurangi dan ditambahkan ke dalamnya, sehingga tidak terpengaruh.

t       % Implicit input (matrix). Duplicate
ss      % Sum of matrix entries
:"      % Repeat that many times
  t     %   Duplicate
  3>    %   True for matrix entries that exceed 3
  t     %   Duplicate
  1Y6   %   Push predefined literal [0, 1, 0; 1, 0, 1; 0, 1, 0]
  Z+    %   2D convolution, keeping size
  w     %   Swap
  4*    %   Multiply by 4
  -     %   Subtract
  +     %   Add
        % Implicit end. Implicit display
Luis Mendo
sumber
3
Konvolusi lima tinggi.
Martin Ender
@ MartinEnder Ah, Anda juga menggunakan itu :-) Senang melihat sesama konvoluter! Saya yakin flawr akan segera bergabung dengan kami
Luis Mendo
2
@LuisMendo Convolutionista
Suever
4

Mathematica, 65 byte

#//.s_:>s+ListConvolve[{v={0,1,0},1-v,v},x=UnitStep[s-4],2,0]-4x&

Penjelasan

#//.s_:>...&

Mengubah input berulang kali dengan menjatuhkan semua tumpukan lebih besar dari 3. Proses ini berhenti secara otomatis ketika transformasi gagal mengubah matriks (yaitu ketika tidak ada tumpukan besar lagi). Dalam ekspresi berikut, matriks disebut s.

...x=UnitStep[s-4]...

Buat matriks yang memiliki 1setiap kali matriks saat ini memiliki 4atau lebih besar, dan nol sebaliknya. Ini pada dasarnya adalah topeng yang menunjukkan tumpukan mana yang harus digulingkan. Panggil topengnya x.

ListConvolve[{v={0,1,0},1-v,v},x=UnitStep[s-4],2,0]

Pertama-tama kita menghitung jumlah pasir yang ditambahkan ke setiap tumpukan karena tumpukan tetangga yang jatuh. Ini dilakukan dengan konvolusi dari matriks berikut atas x:

0 1 0
1 0 1
0 1 0

Pada dasarnya, ia menambahkan satu ke sel saat ini untuk masing-masing tetangga von-Neumann di topeng.

s+...-4x

Kami menambahkan hasil sebelumnya sdan kemudian kami mengurangi empat kali topeng dari itu untuk mengurangi tumpukan yang dijatuhkan.

Martin Ender
sumber
3

Oktaf, 65 byte

Ini sepertinya tidak terlalu bagus, saya pasti melewatkan beberapa trik ...

m=input(0);do;m+=conv2(m>3,[0 1 0;1 -4 1;0 1 0],"same")
until m<4
feersum
sumber
Apa versi Oktaf yang Anda gunakan yang memungkinkan input(0)?
Suever
@Suever>> version ans = 4.0.1
feersum
2

JavaScript (ES6), 101 95 byte

Mengambil lebar matriks wdan array nilai adalam sintaks currying (w)(a). Mengembalikan array nilai.

w=>g=a=>(b=a.map((n,i)=>n%4+(F=d=>~m|i%w&&a[i+d]>>2)(m=w)+F(-w)+F(m=-1)+F(!++i)))+0==a+0?a:g(b)

Diformat dan dikomentari

w =>                      // main function: takes w as input, returns g
  g = a =>                // recursive function g: takes a as input
    (                     //
      b = a.map((n, i) => // for each element n at position i in a:
        n % 4 + (         //   keep only n MOD 4
          F = d =>        //   define F(): function that takes d as input
            ~m |          //     if m is not equal to -1
            i % w &&      //     or i MOD w is not null:
            a[i + d] >> 2 //       return a fourth of the value of the cell at i + d
        )(m = w) +        //   test the cell below the current cell
        F(-w) +           //   test the cell above
        F(m = -1) +       //   test the cell on the left
        F(!++i)           //   test the cell on the right
      )                   // end of map(): assign the result to b
    ) + 0 == a + 0 ?      // if b is equal to a:
      a                   //   stop recursion and return a
    :                     // else:
      g(b)                //   do a recursive call with b

Uji kasus

Arnauld
sumber
1

JavaScript (ES6), 118 114 104 byte

Disimpan 2 byte berkat @Neil

f=a=>a.find(b=>++y&&b.find(c=>++x&&c>3,x=0),y=0)?f(a.map(b=>b.map(c=>c+=--i|y?i*i+y*y==1:-4,i=x,--y))):a
Produksi ETH
sumber
Apakah (i-=x)|y-j?i*i+membantu?
Neil
@Neil Memang, terima kasih!
ETHproduk
... Saya sedang menelepon tetapi saya juga mempertimbangkan a.find(...b.find(...c>3&&a.map(...)))&&f(a).
Neil
@Neil Saya tidak berpikir itu akan berhasil, karena .maptidak bermutasi ...
ETHproduksi
Tampaknya membuatnya bermutasi sedikit lebih murah daripada memindahkan peta di dalam find menghemat:f=a=>a.find((b,x)=>b.find((c,y)=>c>3&&a.map(b=>b.map((_,j)=>b[j]+=x|(j-=y)?x*x+j*j==1:-4)&x--)))&&f(a)
Neil
1

C ++, 261 258 250 byte

#import<vector>
#define S size()
void f(std::vector<std::vector<int>>&m){s:int i,j,r;for(i=r=0;i<m.S;++i)for(j=0;j<m[i].S;++j){if(m[i][j]>3){r=1;m[i][j]-=4;j>0&&m[i][j-1]++;i>0&&m[i-1][j]++;j<m[i].S-1&&m[i][j+1]++;i<m.S-1&&m[i+1][j]++;}}if(r)goto s;}

Mengambil input sebagai referensi ke vektor vektor dan memodifikasinya secara langsung.

Cobalah online!

Steadybox
sumber