Bentuk Dot Logis

12

Permainan

Baru-baru ini, sebagian besar waktu saya dihabiskan oleh permainan adiktif di ponsel saya, yang disebut Logic Dots, yang menginspirasi saya untuk menulis tantangan ini. Lebih mudah untuk menjelaskan aturan jika saya menunjukkan tampilan permainan, jadi di sini adalah tangkapan layar dari teka-teki yang belum terpecahkan, dan dipecahkan:

Sekarang di sini, ada tiga hal utama yang perlu diperhatikan.

  1. Papan permainan (kotak 4x4 kotak di tengah)
  2. Bentuk yang diperlukan (titik-titik yang ditautkan di bilah kedua dari atas, di bawah skor dan menu, dll.), Yang semuanya adalah garis, atau adengan 1 persegi panjang
  3. Angka di atas baris dan kolom, yang menunjukkan berapa banyak titik yang harus ada dalam kolom, untuk solusi

Tujuan permainan ini adalah untuk menyesuaikan bentuk yang diperlukan ke dalam kisi. Anda dapat memutar bentuk, tetapi mereka tidak bisa masuk secara diagonal.

Dalam solusinya, perhatikan bahwa semua bentuk dibuat tepat sekali (karena mereka hanya dalam bentuk yang diperlukan sekali), dan dalam hal ini semua bentuk horisontal tetapi juga bisa vertikal. Merah muda yang diisi kotak menunjukkan kotak tidak digunakan.

Berikut ini kisi yang lebih besar, dan sedikit lebih rumit:

Perhatikan bahwa dalam teka-teki yang belum terpecahkan, sudah ada beberapa kotak yang diisi. Kotak berwarna abu-abu menandakan kotak yang diblokir yang tidak dapat Anda tempatkan titik. Titik-titik dengan ekor memberi tahu Anda bahwa ada titik di titik itu, dan titik itu terhubung ke setidaknya satu titik lagi di arah ekor, tetapi tidak ke arah lain (termasuk arah yang berlawanan).

Notasi

Untuk sisa posting ini, saya akan merujuk ke papan menggunakan simbol-simbol berikut:

  • <,>, ^, v - Menandakan titik yang ditempatkan sebelumnya dengan ekor memanjang ke arah titik
  • * - Menandakan titik. Jika diberikan pada grid (input) yang tidak terpecahkan, itu adalah bentuk individual. Jika dalam output, maka terhubung ke titik-titik di sekitarnya.
  • # - Menandakan kotak persegi yang diblokir (tempat Anda tidak dapat menempatkan titik)
  • -, | (tanda hubung dan batang) - Menandakan titik dengan ekor kanan dan kiri, dan titik dengan ekor atas dan bawah
  • ** (karakter spasi) - ** Menandakan ruang kosong

Dengan menggunakan simbol-simbol ini, contoh kasus terakhir (belum terpecahkan) dapat direpresentasikan sebagai berikut:

 <    



    # 
 ^ #

Dan solusinya dapat direpresentasikan sebagai:

*< * *
   *  
     *
 *   *
 * *#*
 ^ # *

Perhatikan bahwa tidak ada dua bentuk yang dapat menyentuh secara horizontal, vertikal atau diagonal , sehingga case berikut ini tidak valid:

 *** 
**   
  ** 

Tantangan

Tantangan Anda adalah menyelesaikan teka-teki titik logika apa pun, mulai dari 4x4 hingga 9x9 inklusif. Anda akan menerima empat baris input, kemudian papan permainan. Barisnya adalah sebagai berikut:

  • Baris pertama, Bentuk - Bentuk yang ditemukan, masing-masing diberikan dalam bentuk sizexquantity(mis. 3x2Untuk dua bentuk dengan panjang tiga) dan dipisahkan oleh spasi. Baris contoh:3x1 2x1 1x1
  • Baris 2, Kolom - Daftar yang dipisahkan spasi dari jumlah titik yang diperlukan untuk setiap kolom. Baris contoh:1 1 2 2
  • Baris ke-3, Baris - Daftar spasi terpisah dari jumlah titik yang diperlukan untuk setiap baris. Baris contoh:3 0 3 0
  • Baris 4, Ukuran papan - Bilangan bulat tunggal, ukuran papan, B

Papan kemudian diberikan, dan Bgaris input mewakili papan menggunakan notasi yang disebutkan di atas. Misalnya, input lengkap untuk contoh kasus terakhir adalah sebagai berikut:

4x1 3x1 2x2 1x2
1 4 0 3 0 5
4 1 1 2 3 2
6
 <    



    # 
 ^ #  

Program Anda kemudian akan menampilkan papan yang diselesaikan, dalam notasi yang sama. Output yang cocok untuk input di atas adalah sebagai berikut:

** * *
   *  
     *
 *   *
 * *#*
 * # *

Perhatikan bahwa papan permainan dapat memiliki beberapa solusi. Dalam hal ini, cukup keluarkan satu solusi yang valid. Selain itu, program Anda harus mengeluarkan solusi yang benar dalam waktu 10 detik pada komputer desktop yang masuk akal untuk kisi 10x10 yang rumit.

Ini adalah kode golf, jadi paling tidak byte menang.


Uji Kasus

Input 1

3x2 1x4
2 2 3 1 2
4 0 3 0 3
5


    #
  #  
    *

Output 1

*** *

 ***#
  #  
* * *

Input 2

3x1 1x6
2 0 4 0 3
3 1 2 1 2
5
*    


   # 

Keluaran 2

* * *
  *  
  * *
*  # 
  * *

Input 3

5x1 4x1 2x1 1x2
1 2 3 3 2 2
0 5 0 4 0 4
6
#     
  -   


 #    
   <  

Keluaran 3

#     
 *****

 **** 
 #    
* ** *
globby
sumber
Ya, itu benar @flawr
globby
@ flawr t no two shapes can touch horizontally, vertically or diagonally(ini seharusnya di awal, tidak hilang hampir mendekati akhir, tapi bagaimanapun ...)
edc65
@globby Bukankah setiap ruang kosong akan diganti dengan #, saya kira # adalah ketika Anda mengetuk satu ruang kosong dalam permainan. Ketika Anda selesai level itu mengisi semua sel kosong.
Teun Pronk
@TeunPronk No. # adalah spasi yang telah ditentukan sebelumnya bahwa Anda tidak dapat menempatkan titik di level, seperti kotak abu-abu dalam contoh kedua.
globby
2
Lebih baik daripada menawarkan hadiah, Anda harus menambahkan lebih banyak test case yang menarik dan memperbaiki kesalahan dalam pertanyaan Anda. Sebagai contoh, output terakhir sebelum test case saat ini masih mengandung <dan ^
edc65

Jawaban:

3

Python 2: 766 739 696 663 633 byte

def f(B,S,o=0):
 if[]==S:print'\n'.join(B);exit()
 s=S[0]
 for i in r:
  for j in R(Z-s+1):
   if(B[i][j]in' '+'>v'[o])*(B[i][j+s-1]in' '+'<^'[o])*({' ','-|'[o]}>=set(B[i][j+1:j+s-1]))*all(B[x][y]in'# 'for x,y in [(x,y)for y in R(j-1,j+s+1)for x in i-1,i+1]+[(i,j-1),(i,j+s)]if 0<=x<Z>y>=0):q=B[:];q[i]=q[i][:j]+'*'*s+q[i][j+s:];q=(q,t(q))[o];any((t(q)+q)[k].count('*')>m[k]for k in R(Z+Z))or f(q,S[1:])
 o or f(t(B),S,1)
y=raw_input;S=[];s=str.split
for i in s(y()):u,v=map(int,s(i,'x'));S+=[u]*v
m=map(int,s(y())+s(y()));Z=input();R=range;r=R(Z);B=[y()for _ in r];J=''.join;t=lambda x:map(J,zip(*x))
f(B,S[:len(S)-J(B).count('*')])

Lihat berfungsi online: Ideone.com (Versi online mungkin terlalu lambat untuk kisi besar dan sulit, offline seharusnya baik-baik saja)

Input melalui stdin, cukup salin dan lewati baris dari OP (tapi hati-hati, stackexchange terkadang menghapus spasi atau garis).

Beberapa ide dasar kode ini: Menggunakan fungsi rekursif f. fmencoba menempatkan satu bentuk di papan tulis. Untuk setiap lokasi yang memungkinkan ia memanggil dirinya sendiri dengan papan yang dimodifikasi. Ada 3 loop di dalamnya. omenentukan orientasi (2 - horizontal, 3 - vertikal). Itu akan selalu menempatkan bentuk horizontal, oleh karena itu pada akhir o=2, itu akan mengubah posisi papan dengan fungsi t. iadalah baris dan jsemuanya adalah kolom awal yang memungkinkan. Kemudian banyak pemeriksaan terjadi, jika ujung-ujungnya memiliki karakter yang valid, jika bagian tengahnya memiliki karakter yang valid dan jika sekitarnya kosong.

Jakube
sumber
Saya sedang berjuang untuk memotong 6 byte terakhir, ketika saya melihat suntingan terakhir Anda (-30) dan menyerah ... Anda memiliki suara saya untuk apa nilainya
edc65
3

JavaScript (ES6) 661 667 695 702 745 755 786 790 784 798

Pekerjaan yang sedang berjalan, bisa dipersingkat. Mungkin terlalu lambat pada kisi yang rumit. Mungkin tidak.

Edit sedikit lebih lama, jauh lebih cepat.
Edit 2 Bug fix, periksa kolom / baris. Kebetulan, sekarang lebih cepat

Fungsi M adalah yang utama. Parameter w adalah string multiline dengan semua input. Fungsi mem-parsing input dan menyiapkan papan awal. Karakter <>^v|-*di papan awal diganti dengan ,, masing-masing ,harus diganti dengan *dalam solusi yang benar.

Fungsi R mencoba secara rekursif untuk menempatkan semua bentuk di papan tulis. Ketika suatu bentuk ditempatkan, ia menyebut dirinya melewati daftar bentuk yang lebih pendek dan papan yang dimodifikasi. Ketika semua bentuk ditempatkan, solusi masih bisa tidak valid jika tidak ada yang ,diganti *.

Tes fungsi P jika suatu bentuk dapat ditempatkan pada posisi dan orientasi tertentu. Ia memeriksa semua costrains (di dalam papan, tidak ada tumpang tindih, tidak ada sentuhan, jumlah baris dan kolom yang valid)

M=w=>(
  [x,c,r,z]=w=w[S='split'](n='\n'),
  (b=[...w.slice(4).join(n)])
  .map((c,p)=>~(k='*<>-*^v|'.indexOf(c))&&[(q=k>3?z:1,0),k&1&&-q,k&2&&q].map(o=>b[p+o]=0),
    c=c[S](e=' '),r=r[S](e),w=z++,f='*',s='',x[S](e).map(v=>s+=v[0].repeat(v[2]))),
  R=(s,b,x=0,y=0,n=s[0],V=i=>b[i]>'#',
    P=(p,o,q,t,g,l,d=[...b])=>{
        if(l<z-n&!V(p+o*l-o)&!V(p+o*l+o*n))
        {
          for(i=-1;v=d[p],++i<w;p+=o,t-=v==f)
            if(i>=l&i-n<l)
              for(v!=e&v!=0|[q,w,~z].some(w=>V(p+w)|V(p-w))?t=0:d[p]=f,j=o*i,u=k=0;
                  ++k<z;(u+=d[j]==f)>g[i]?t=0:j+=q);
          return t>=n&&d.join('')
        }
    })=>{
    if(b){
      if(!n)return~b.search(0)?0:b;
      for(s=s.slice(1);y<w||(y=0,++x<w);++y)
        if(h=R(s,P(y*z,1,z,r[y],c,x))||n>1&&R(s,P(x,z,1,c[x],r,y)))return h
    }
  })(s,b)

Uji di konsol FireFox / FireBug

;['3x2 1x4\n2 2 3 1 2\n4 0 3 0 3\n5\n     \n     \n    #\n  #  \n    *\n'
,'3x1 1x6\n2 0 4 0 3\n3 1 2 1 2\n5\n*    \n     \n     \n   # \n     \n'
,'5x1 4x1 2x1 1x2\n1 2 3 3 2 2\n0 5 0 4 0 4\n6\n#     \n  -   \n      \n      \n #    \n   <  \n'
,'4x1 3x1 2x2 1x2\n1 4 0 3 0 5\n4 1 1 2 3 2\n6\n <    \n      \n      \n      \n    # \n ^ #  \n']
.forEach(x=>console.log(x,M(x).replace(/ /g,'`'))) // space replaced with ` for clarity

Output (total waktu eksekusi <1sec)

3x2 1x4
2 2 3 1 2
4 0 3 0 3
5


    #
  #  
    *

***`*
`````
`***#
``#``
*`*`*

3x1 1x6
2 0 4 0 3
3 1 2 1 2
5
*    


   # 


*`*`*
``*``
``*`*
*``#`
``*`*

5x1 4x1 2x1 1x2
1 2 3 3 2 2
0 5 0 4 0 4
6
#     
  -   


 #    
   <  

#`````
`*****
``````
`****`
`#````
*`**`*

4x1 3x1 2x2 1x2
1 4 0 3 0 5
4 1 1 2 3 2
6
 <    



    # 
 ^ #  

**`*`*
```*``
`````*
`*```*
`*`*#*
`*`#`*
edc65
sumber
Sepertinya @globby lupa tentang karunia itu. Ngomong-ngomong, bersenang-senang di balapan ini.
Jakube