Bisakah Anda memecahkan teka-teki delapan ratu pada waktu kompilasi?
Pilih format output yang cocok.
Saya sangat tertarik dengan solusi metaprogramming template C ++, tetapi Anda dapat menggunakan bahasa yang memiliki konstruksi serupa, seperti, misalnya, sistem tipe Haskell.
Idealnya metaprogram Anda akan menampilkan semua solusi. Tidak ada hardcoding.
puzzle-solver
compile-time
R. Martinho Fernandes
sumber
sumber
Jawaban:
Program-meta saya menemukan semua 92 solusi. Mereka dicetak sebagai pesan kesalahan:
Ini berarti ratu pertama harus ditempatkan pada y = 1, yang kedua di y = 5, yang ketiga di y = 8 dan seterusnya.
Pertama, beberapa fungsi meta yang berguna:
Kemudian, dua fungsi meta yang menarik (perhatikan bentuk tunggal dan jamak):
Variabel
queens
menyimpan koordinat y dari ratu yang ditempatkan di papan sejauh ini. Tiga variabel berikut menyimpan baris dan diagonal yang sudah ditempati oleh ratu.x
dany
harus jelas.Argumen pertama untuk
if_then_else
memeriksa apakah posisi saat ini diblokir. Jika ya, rekursi berhenti dengan mengembalikan hasil (yang tidak berarti) 0. Jika tidak, ratu ditempatkan di papan tulis, dan proses berlanjut dengan kolom berikutnya.Ketika x mencapai 8, kami telah menemukan solusi:
Karena
print
templat tidak memiliki anggotasolution
, kompiler menghasilkan kesalahan.Dan akhirnya, untuk memulai proses, kami memeriksa
value
anggota dewan yang kosong:Program lengkap dapat ditemukan di ideone .
sumber
Saya datang dengan solusi yang menggunakan sistem tipe Haskell. Saya mencari sedikit Google untuk solusi yang ada untuk masalah di tingkat nilai , mengubahnya sedikit, dan kemudian mengangkatnya ke tingkat tipe. Butuh banyak penemuan kembali. Saya juga harus mengaktifkan banyak ekstensi GHC.
Pertama, karena bilangan bulat tidak diperbolehkan pada level tipe, saya perlu menemukan kembali bilangan alami sekali lagi, kali ini sebagai tipe:
Algoritma yang saya adaptasikan membuat penambahan dan pengurangan pada naturals, jadi saya harus menemukan kembali ini juga. Fungsi pada level tipe didefinisikan dengan kelas resort to type. Ini membutuhkan ekstensi untuk beberapa kelas tipe parameter dan dependensi fungsional. Tipe kelas tidak dapat "mengembalikan nilai", jadi kami menggunakan parameter tambahan untuk itu, dengan cara yang mirip dengan PROLOG.
Rekursi diimplementasikan dengan pernyataan kelas, sehingga sintaks terlihat agak terbelakang.
Selanjutnya adalah boolean:
Dan fungsi untuk melakukan perbandingan ketidaksetaraan:
Dan daftar ...
if
s juga hilang pada tingkat tipe ...Dan dengan itu, semua mesin pendukung yang saya gunakan ada di tempatnya. Saatnya mengatasi masalah itu sendiri!
Dimulai dengan fungsi untuk menguji apakah menambahkan ratu ke papan yang ada sudah ok:
Perhatikan penggunaan asersi kelas untuk mendapatkan hasil antara. Karena nilai pengembalian sebenarnya merupakan parameter tambahan, kami tidak bisa langsung memanggil pernyataan satu sama lain secara langsung. Sekali lagi, jika Anda telah menggunakan PROLOG sebelum Anda mungkin menemukan gaya ini agak akrab.
Setelah saya membuat beberapa perubahan untuk menghilangkan kebutuhan lambda (yang bisa saya terapkan, tetapi saya memutuskan untuk pergi untuk hari lain), inilah yang tampak seperti solusi aslinya:
map
adalah fungsi urutan yang lebih tinggi. Saya pikir menerapkan meta-fungsi tingkat tinggi akan terlalu merepotkan (sekali lagi lambda) jadi saya hanya pergi dengan solusi yang lebih sederhana: karena saya tahu fungsi apa yang akan dipetakan, saya dapat mengimplementasikan versi khususmap
untuk masing-masing, sehingga tidak fungsi tingkat tinggi.Dan meta-fungsi terakhir dapat ditulis sekarang:
Yang tersisa hanyalah beberapa jenis driver untuk membujuk mesin pengecekan tipe untuk mencari solusinya.
Program-meta ini seharusnya dijalankan pada pemeriksa tipe, sehingga orang dapat menjalankan
ghci
dan menanyakan jenisqueens eight
:Ini akan melebihi batas rekursi default agak cepat (ini sangat sedikit 20). Untuk meningkatkan batas ini, kita perlu memanggil
ghci
dengan-fcontext-stack=N
pilihan, di manaN
adalah kedalaman tumpukan yang diinginkan (N = 1000 dan lima belas menit tidak cukup). Saya belum melihat ini berjalan sampai selesai, karena itu membutuhkan waktu yang sangat lama, tetapi saya sudah berhasil berlari hinggaqueens four
.Ada program lengkap tentang ideone dengan beberapa mesin untuk mencetak tipe hasil yang cantik, tetapi hanya ada yang
queens two
bisa berjalan tanpa melebihi batas :(sumber
C, melalui preprocessor
Saya pikir komite ANSI membuat pilihan sadar untuk tidak memperpanjang C preprocessor ke titik Turing-lengkap. Bagaimanapun, itu tidak cukup kuat untuk menyelesaikan masalah delapan ratu. Tidak dengan cara umum.
Tapi itu bisa dilakukan, jika Anda mau melakukan hard-code pada counter loop. Tidak ada cara nyata untuk mengulang, tentu saja, tetapi Anda dapat menggunakan inklusi diri (via
#include __FILE__
) untuk mendapatkan jenis rekursi terbatas.Terlepas dari jumlah konten berulang yang mengerikan, izinkan saya meyakinkan Anda bahwa itu benar-benar menyelesaikan masalah delapan ratu secara algoritmik. Sayangnya satu hal yang saya tidak bisa lakukan dengan preprocessor adalah menerapkan struktur data stack push-down umum. Hasilnya adalah bahwa saya harus meng-hard-code nilai di
i
mana pun ia digunakan untuk memilih nilai lain untuk ditetapkan. (Berbeda dengan mengambil nilai, yang bisa dilakukan sepenuhnya secara umum. Itu sebabnya#if
di bagian atas file, yang memutuskan apakah seorang ratu dapat ditambahkan pada posisi saat ini, tidak perlu diulang delapan kali.)Dalam kode preprocessor,
i
danj
menunjukkan posisi saat ini sedang dipertimbangkan, sementarar
,p
dann
keep track yang pangkat dan diagonal saat ini tidak tersedia untuk penempatan. Namun,i
juga berfungsi sebagai penghitung yang menandai kedalaman rekursi saat ini, sehingga benar-benar semua nilai lain benar-benar menggunakan i sebagai semacam subskrip, sehingga nilainya dipertahankan saat melanjutkan dari rekursi. (Dan juga karena kesulitan serius dalam memodifikasi nilai simbol preprosesor tanpa sepenuhnya menggantinya.)Program yang dikompilasi mencetak semua 92 solusi. Solusi tertanam langsung ke dalam executable; output preprocessor terlihat seperti ini:
Itu bisa dilakukan, meskipun jelas tidak seharusnya.
sumber
Inilah solusi C ++ 11 tanpa templat apa pun:
Solusinya dikodekan sebagai angka desimal, seperti dalam jawaban FredOverflow. GCC 4.7.1 mengkompilasi file di atas ke sumber rakitan berikut dengan
g++ -S -std=c++11 8q.cpp
:Nilai simbolnya
places
adalah 84136275, yaitu ratu pertama pada a8, yang kedua pada b4 dll.sumber
c ++ template, dengan hanya satu kelas template yang didefinisikan:
jadi pesan kesalahan akan terlihat seperti:
error C2440: 'type cast': tidak dapat mengonversi dari 'int' ke 'char [15863724]'
sumber