Minesweeper adalah permainan puzzle yang populer di mana Anda harus menemukan ubin mana yang merupakan "ranjau" tanpa mengklik ubin itu. Sebagai gantinya, Anda mengeklik ubin terdekat untuk mengungkap jumlah tambang yang berdekatan. Satu kelemahan tentang permainan ini adalah kemungkinan untuk berakhir dalam skenario di mana ada beberapa jawaban yang valid dan Anda hanya bisa menebak. Misalnya, ambil papan berikut:
1110
2*31
3*??
2*4?
112?
Dalam format ini, angka mewakili jumlah tambang yang berdekatan, sebuah *
mewakili tambang yang diketahui, dan "?" mewakili potensi tambang. Hal yang disayangkan tentang teka-teki khusus ini adalah bahwa ada empat solusi potensial yang berbeda dan valid :
1110 1110 1110 1110
2*31 2*31 2*31 2*31
3*4* 3*5* 3**2 3**1
2*42 2*4* 2*4* 2*42
112* 1121 1121 112*
Ini berarti papan tidak terpecahkan . Berikut adalah contoh papan yang dapat dipecahkan :
1121
1??*
12?*
0122
Board ini dapat dipecahkan karena hanya ada satu solusi yang valid:
1121
1*4*
12**
0122
Tugas Anda adalah menulis baik program atau fungsi yang menggunakan papan kapal penyapu ranjau yang valid dan menentukan apakah dapat dipecahkan atau tidak. Dengan "papan kapal penyapu ranjau yang valid", maksud saya bahwa input akan selalu persegi panjang, memiliki setidaknya satu solusi, dan tidak mengandung karakter yang tidak valid.
Input Anda mungkin berupa array karakter, array string, string yang berisi baris baru, dll. Outputnya harus berupa nilai yang benar jika dapat dipecahkan dan nilai yang salah jika tidak. Saya tidak terlalu khawatir tentang kinerja, tetapi solusi Anda secara teoritis harus bekerja untuk input ukuran apa pun.
Seperti biasa, celah standar berlaku dan solusi terpendek dalam byte menang!
Contoh:
Contoh-contoh berikut semuanya dapat dipecahkan:
1121
1??*
12?*
0122
1110
1???
1110
0000
1110
3???
??20
*310
****
****
****
****
0000
0000
0000
0000
1100
*100
2321
??*2
13*2
1221
1*10
1110
1121
2*??
2*31
2220
1*10
Semua contoh berikut tidak dapat dipecahkan:
1110
2*31
3*??
2*4?
112?
01??11*211
12??2323*1
1*33*2*210
12?2122321
13?3101**1
1***101221
1***
3*52
2*31
12??
02??
01??
00000111
000012*1
00001*21
22101110
**100111
?31123*1
?311**31
**113*20
sumber
2?
tidak memiliki solusi, yang berarti tidak dapat berasal dari permainan Minesweeper yang sebenarnya. Oleh karena itu tidak dianggap sebagai "papan Minesweeper" ... ya?)Jawaban:
GNU Prolog, 493 bytes
Predikat tambahan yang mungkin berguna untuk pengujian (bukan bagian dari pengiriman):
Prolog jelas merupakan bahasa yang tepat untuk menyelesaikan tugas ini dari sudut pandang praktis. Program ini cukup banyak hanya menyatakan aturan Minesweeper dan memungkinkan pemecah kendala GNU Prolog memecahkan masalah dari sana.
z
dani
adalah fungsi utilitas (z
melakukan semacam operasi lipatan tetapi pada himpunan tiga elemen yang berdekatan, bukan 2;i
mentranspos 3 daftar elemen n ke dalam daftar n 3-tupel). Kami secara internal menyimpan sel sebagai , di mana x adalah 1 untuk tambang dan 0 untuk bukan tambang, dan y adalah jumlah tambang yang berdekatan; mengungkapkan kendala ini di papan tulis. berlaku untuk setiap baris papan; dan jadi memeriksa untuk melihat apakah papan yang valid.x/y
c
r
c
z(r,M)
M
Sayangnya, format input yang diperlukan untuk membuat pekerjaan ini secara langsung tidak masuk akal, jadi saya juga harus menyertakan parser (yang mungkin menyumbang lebih banyak kode daripada mesin aturan aktual, dan sebagian besar waktu yang dihabiskan untuk debugging; mesin aturan Minesweeper cukup banyak bekerja pertama kali, tetapi parser itu penuh dengan thinkos).
q
mengkonversi sel tunggal antara kode karakter dan format kami . mengonversi satu baris papan (meninggalkan satu sel yang diketahui bukan tambang, tetapi dengan sejumlah ranjau yang berdekatan, di setiap tepi garis sebagai perbatasan);x/y
l
p
mengkonversi seluruh papan (termasuk batas bawah, tetapi tidak termasuk yang paling atas). Semua fungsi ini dapat dijalankan baik maju atau mundur, sehingga dapat menguraikan dan mencetak papan. (Ada beberapa yang mengganggu dengan argumen ketigap
, yang menentukan lebar papan; ini karena Prolog tidak memiliki jenis matriks, dan jika saya tidak membatasi papan menjadi persegi panjang, program akan masuk ke loop tak terbatas mencoba semakin perbatasan yang lebih luas di sekitar papan.)m
adalah fungsi pemecahan Minesweeper utama. Ini mem-parsing string input, menghasilkan papan dengan perbatasan yang benar (melalui menggunakan kasus rekursifp
untuk mengkonversi sebagian besar papan, kemudian memanggil kasing langsung untuk menghasilkan perbatasan atas, yang memiliki struktur yang sama dengan perbatasan bawah). Maka itu panggilanz(r,[R|M])
untuk menjalankan mesin aturan Minesweeper, yang (dengan pola panggilan ini) menjadi generator yang hanya menghasilkan papan yang valid. Pada titik ini, dewan masih dinyatakan sebagai serangkaian kendala, yang berpotensi canggung bagi kita; kita mungkin dapat memiliki satu set kendala yang dapat mewakili lebih dari satu papan. Selain itu, kami belum menentukan di mana saja bahwa setiap kotak berisi paling banyak satu tambang. Dengan demikian, kita perlu secara eksplisit "menciutkan bentuk gelombang" dari setiap kotak, yang mengharuskannya untuk menjadi tambang (tunggal) atau bukan tambang, dan cara termudah untuk melakukannya adalah dengan menjalankannya melalui parser mundur (var(V)
pada kasingq(63,V)
dirancang untuk mencegah?
kasing mundur, dan dengan demikian merentang papan memaksa agar diketahui sepenuhnya). Akhirnya, kami mengembalikan papan yang diurai darim
;m
dengan demikian menjadi generator yang mengambil papan yang sebagian tidak dikenal dan menghasilkan semua papan yang diketahui konsisten dengannya.Itu benar-benar cukup untuk menyelesaikan Minesweeper, tetapi pertanyaannya secara eksplisit meminta untuk memeriksa apakah ada satu solusi, daripada menemukan semua solusi. Karena itu, saya menulis predikat tambahan
s
yang hanya mengubah generatorm
menjadi satu set, dan kemudian menyatakan bahwa set tersebut memiliki tepat satu elemen. Ini berarti bahwas
akan mengembalikan kebenaran (yes
) jika memang ada satu solusi, atau falsey (no
) jika ada lebih dari satu atau kurang dari satu.d
bukan bagian dari solusi, dan tidak termasuk dalam bytecount; itu adalah fungsi untuk mencetak daftar string seolah-olah itu adalah matriks, yang memungkinkan untuk memeriksa papan yang dihasilkan olehm
(secara default, GNU Prolog mencetak string sebagai daftar kode ASCII, karena itu memperlakukan keduanya secara sinonim; format ini cukup sulit dibaca). Ini berguna selama pengujian, atau jika Anda ingin menggunakanm
sebagai pemecah Minesweeper praktis (karena menggunakan pemecah kendala, ini sangat efisien).sumber
Haskell,
193169168 bytesContoh penggunaan:
g "1121 1??* 12?* 0122"
->True
.Cara kerjanya: buat daftar semua papan yang mungkin dengan
?
diganti dengan salah satu*
atau!
(!
artinya abaikan nanti). Ini dilakukan melaluimapM c
, tetapi sebelum kita menambahkan dan menambahkan sekelompok spasi ke string input sehingga pengindeksan kami tidak akan keluar dari jangkauan. Untuk setiap papan seperti itu periksa apakah itu papan yang valid dengan mengulang semua elemen (indeksj
) dan jika itu angka (d>'/'
) juga atas tetangganya (indeksn
,m
), hitung*
dan bandingkan dengan angka. Akhirnya periksa panjang daftar papan yang valid.sumber
Mathematica,
214192190180176174168165 byteBerisi U + F4A1 (Penggunaan pribadi). Fungsi tanpa nama ini menemukan semua kombinasi yang mungkin untuk
"?"
(yaitu mengganti semua"?"
dengan"*"
atau0
) dan memeriksa apakah hanya ada satu solusi yang valid.Penjelasan
Setel
b
ke"*"
.Setel
q
ke string"?"
. Periksa apakah ada"?"
di input.Jika
True
...Ganti kemunculan pertama dari
q
(="?"
) denganb
(="*"
) atau0
(yaitu dua output), dan terapkan kembali seluruh fungsi.Jika
False
...Pad input dengan satu layer
0
.Partisi input ke dalam matriks 3 x 3 dengan offset 1. Untuk setiap partisi, terapkan fungsi sedemikian rupa sehingga jika nilai tengahnya adalah
b
(="*"
), outputnya adalahb
(="*"
), dan jika nilai tengahnya tidakb
(="*"
), output adalah jumlahb
(="*"
) pada input. Langkah ini mengevaluasi kembali semua sel angka.Dari semua hasil, cari yang cocok dengan input
Periksa apakah input panjang 1.
sumber
Perl, 215 byte
213 byte kode +
-p0
bendera (2 byte).Gagasan kode adalah untuk menguji setiap kemungkinan dan melihat apakah ada satu dan hanya satu yang mengarah ke papan penuh yang valid.
Lebih mudah dibaca, kode ini terlihat seperti:
Tentang regex di tengah:
Perhatikan bahwa
[^V]
kepanjangan dari "karakter apa saja, termasuk \ n".Jadi idenya adalah: 3 char pada satu baris, kemudian 3 pada berikutnya (dengan
$i
di tengah), kemudian 3 pada berikutnya. 3 kelompok dari 3 angka tersebut disejajarkan, terima kasih[^V]{$c}
dan nomor yang kami minati berada di tengah.Dan kemudian,
"$1$2$3"=~y%*%%
hitung jumlah*
(bom) di antara 9 karakter tersebut: jika berbeda dari itu$i
, kami menambahkan string kosong untuk mencocokkan (""
=> pencocokan instan, regex mengembalikan true), jika tidak, kami memaksakan kegagalan dengan mencoba mencocokkanR
( yang tidak bisa berada di string).Jika pertandingan regex, maka dewan tidak valid, jadi kami mengatur
$r
untuk0
dengan$r&=!/.../
.Dan itu sebabnya kami menambahkan beberapa
A
di mana-mana di sekitar setiap baris: jadi kita tidak perlu khawatir tentang tepi kasus angka-angka yang berada di dekat tepi papan: mereka akan memilikiA
tetangga, yang bukan tambang (tentu saja, kira-kira arang mana pun bisa bekerja, Saya memilihA
).Anda dapat menjalankan program dari baris perintah seperti itu:
Kompleksitasnya tidak mungkin terburuk: itu adalah di
O(m*9^n)
manan
jumlah?
di papan tulis, danm
jumlah sel di papan tulis (tanpa menghitung kompleksitas regex di tengah, yang mungkin sangat buruk). Di mesin saya, ini bekerja cukup cepat hingga 4?
, dan mulai lebih lambat 5, butuh beberapa menit selama 6, dan saya tidak mencoba untuk jumlah yang lebih besar.sumber
JavaScript (ES6), 221
229Jika semua masukan diharapkan berlaku - yang dengan setidaknya 1 solusi - maka saya dapat menyimpan byte berubahs==1
dengans<2
Kurang golf
Uji
sumber
JavaScript (Node.js) , 167 byte
Cobalah online!
Meskipun op mengatakan "input akan selalu persegi panjang, memiliki setidaknya satu solusi", sampel 3 tidak cocok, jadi saya masih membutuhkan 1 solusi, bukan <2 solusi
sumber