Saya menemukan solusi yang mungkin bukan yang paling efisien, tetapi berhasil dengan cukup baik. Pada dasarnya:
- Urutkan semua kata berdasarkan panjangnya, turun.
- Ambil kata pertama dan letakkan di papan tulis.
- Ambil kata berikutnya.
- Cari semua kata yang sudah ada di papan tulis dan lihat apakah ada kemungkinan persimpangan (huruf umum) dengan kata ini.
- Jika ada kemungkinan lokasi untuk kata ini, ulangi semua kata yang ada di papan tulis dan periksa untuk melihat apakah kata baru tersebut mengganggu.
- Jika kata ini tidak merusak papan, letakkan di sana dan lanjutkan ke langkah 3, jika tidak, lanjutkan mencari tempat (langkah 4).
- Lanjutkan putaran ini sampai semua kata ditempatkan atau tidak dapat ditempatkan.
Ini membuat teka-teki silang yang berhasil, namun seringkali sangat buruk. Ada sejumlah perubahan yang saya lakukan pada resep dasar di atas untuk mendapatkan hasil yang lebih baik.
- Pada akhir pembuatan teka-teki silang, beri skor berdasarkan berapa banyak kata yang ditempatkan (semakin banyak semakin baik), seberapa besar papannya (semakin kecil semakin baik), dan rasio antara tinggi dan lebar (semakin dekat menjadi 1 lebih baik). Hasilkan sejumlah teka-teki silang dan kemudian bandingkan skor mereka dan pilih yang terbaik.
- Alih-alih menjalankan sejumlah iterasi yang sewenang-wenang, saya telah memutuskan untuk membuat sebanyak mungkin teka-teki silang dalam waktu yang sewenang-wenang. Jika Anda hanya memiliki daftar kata kecil, maka Anda akan mendapatkan lusinan kemungkinan teka-teki silang dalam 5 detik. Teka-teki silang yang lebih besar hanya dapat dipilih dari 5-6 kemungkinan.
- Saat menempatkan kata baru, alih-alih menempatkannya segera setelah menemukan lokasi yang dapat diterima, berikan skor lokasi kata tersebut berdasarkan seberapa besar peningkatan ukuran kisi dan jumlah persimpangan yang ada (idealnya Anda ingin setiap kata menjadi disilangkan dengan 2-3 kata lain). Pantau semua posisi dan skor mereka, lalu pilih yang terbaik.
Saya baru saja menulis sendiri dengan Python. Anda dapat menemukannya di sini: http://bryanhelmig.com/python-crossword-puzzle-generator/ . Itu tidak menciptakan teka-teki silang gaya NYT yang padat, tetapi gaya teka-teki silang yang mungkin Anda temukan di buku teka-teki anak.
Tidak seperti beberapa algoritme yang saya temukan di sana yang menerapkan metode brute-force acak untuk menempatkan kata-kata seperti yang disarankan beberapa, saya mencoba menerapkan pendekatan brute-force yang sedikit lebih cerdas pada penempatan kata. Inilah proses saya:
Pada akhirnya, Anda memiliki teka-teki silang atau teka-teki pencarian kata yang bagus, karena keduanya hampir sama. Ini cenderung berjalan cukup baik, tetapi beri tahu saya jika Anda memiliki saran untuk perbaikan. Grid yang lebih besar berjalan lebih lambat secara eksponensial; daftar kata yang lebih besar secara linier. Daftar kata yang lebih besar juga memiliki peluang lebih tinggi pada nomor penempatan kata yang lebih baik.
sumber
array.sort(key=f)
stabil, yang berarti (misalnya) hanya mengurutkan daftar kata menurut abjad akan membuat semua kata 8 huruf diurutkan menurut abjad.Saya sebenarnya menulis program pembuatan teka-teki silang sekitar sepuluh tahun yang lalu (itu samar, tetapi aturan yang sama akan berlaku untuk teka-teki silang biasa).
Ini memiliki daftar kata (dan petunjuk terkait) yang disimpan dalam file yang diurutkan berdasarkan penggunaan menurun hingga saat ini (sehingga kata-kata yang jarang digunakan ada di bagian atas file). Sebuah template, pada dasarnya sebuah bit-mask yang merepresentasikan kotak hitam dan gratis, dipilih secara acak dari sebuah pool yang disediakan oleh klien.
Kemudian, untuk setiap kata yang tidak lengkap dalam teka-teki (pada dasarnya temukan kotak kosong pertama dan lihat apakah yang ada di kanan (kata di seberang) atau yang di bawahnya (kata di bawah) juga kosong), pencarian dilakukan dari file mencari kata pertama yang pas, dengan mempertimbangkan huruf yang sudah ada di kata itu. Jika tidak ada kata yang bisa muat, Anda cukup menandai seluruh kata sebagai tidak lengkap dan melanjutkan.
Pada akhirnya akan ada beberapa kata yang belum selesai yang harus diisi oleh kompilator (dan tambahkan kata dan petunjuk ke file jika diinginkan). Jika mereka tidak dapat menemukan ide apa pun , mereka dapat mengedit teka-teki silang secara manual untuk mengubah batasan atau hanya meminta pembuatan ulang total.
Setelah file kata / petunjuk mencapai ukuran tertentu (dan menambahkan 50-100 petunjuk sehari untuk klien ini), jarang ada kasus lebih dari dua atau tiga perbaikan manual yang harus dilakukan untuk setiap teka-teki silang .
sumber
Algoritma ini membuat 50 teka-teki silang panah 6x9 dalam 60 detik. Ini menggunakan database kata (dengan kata + tips) dan database papan (dengan papan yang telah dikonfigurasi sebelumnya).
Database kata yang lebih besar sangat mengurangi waktu pembuatan dan beberapa jenis papan lebih sulit diisi! Papan yang lebih besar membutuhkan lebih banyak waktu untuk diisi dengan benar!
Contoh:
Papan 6x9 yang Dikonfigurasi Sebelumnya:
(# berarti satu tip dalam satu sel,% berarti dua tip dalam satu sel, panah tidak ditampilkan)
Papan 6x9 yang dihasilkan:
Kiat [baris, kolom]:
sumber
Meskipun ini adalah pertanyaan yang lebih lama, akan mencoba menjawab berdasarkan pekerjaan serupa yang telah saya lakukan.
Ada banyak pendekatan untuk memecahkan masalah kendala (yang umumnya ada di kelas kompleksitas NPC).
Ini terkait dengan optimasi kombinatorial dan pemrograman kendala. Dalam hal ini batasannya adalah geometri grid dan persyaratan bahwa kata-kata itu unik, dll.
Pendekatan pengacakan / anil juga dapat berfungsi (meskipun dalam pengaturan yang tepat).
Kesederhanaan yang efisien mungkin saja merupakan kebijaksanaan tertinggi!
Persyaratannya adalah untuk penyusun teka-teki silang yang kurang lebih lengkap dan pembuat (WYSIWYG visual).
Mengesampingkan bagian pembuat WYSIWYG, garis besar kompilernya adalah ini:
Muat daftar kata yang tersedia (diurutkan berdasarkan panjang kata, yaitu 2,3, .., 20)
Temukan wordlots (yaitu kata grid) pada grid yang dibuat pengguna (misalnya kata pada x, y dengan panjang L, horizontal atau vertikal) (kompleksitas O (N))
Hitung titik potong dari kata-kata grid (yang perlu diisi) (kompleksitas O (N ^ 2))
Hitung perpotongan kata-kata dalam daftar kata dengan berbagai huruf alfabet yang digunakan (ini memungkinkan untuk mencari kata yang cocok dengan menggunakan templat misalnya tesis Sik Cambon seperti yang digunakan oleh cwc ) (kompleksitas O (WL * AL))
Langkah .3 dan .4 memungkinkan untuk melakukan tugas ini:
Sebuah. Perpotongan kata kisi dengan dirinya sendiri memungkinkan untuk membuat "templat" untuk mencoba menemukan kecocokan dalam daftar kata terkait dari kata yang tersedia untuk kata kisi ini (dengan menggunakan huruf dari kata berpotongan lain dengan kata ini yang sudah diisi pada langkah algoritma)
b. Perpotongan kata-kata dalam daftar kata dengan alfabet memungkinkan untuk menemukan kata yang cocok (kandidat) yang cocok dengan "template" yang diberikan (misalnya, 'A' di tempat pertama dan 'B' di tempat ke-3, dll.)
Jadi dengan struktur data ini diimplementasikan, algoritma yang digunakan adalah seperti ini:
CATATAN: jika grid dan database kata konstan, langkah sebelumnya hanya dapat dilakukan satu kali.
Langkah pertama dari algoritme adalah memilih celah kata kosong (kata kisi) secara acak dan mengisinya dengan kata kandidat dari daftar kata yang terkait (pengacakan memungkinkan untuk menghasilkan soluton yang berbeda dalam eksekusi algoritme yang berurutan) (kompleksitas O (1) atau O ( N))
Untuk setiap slot kata yang masih kosong (yang memiliki persimpangan dengan slot kata yang sudah terisi), hitung rasio batasan (ini dapat bervariasi, sth simple adalah jumlah solusi yang tersedia pada langkah tersebut) dan urutkan wordlots kosong dengan rasio ini (kompleksitas O (NlogN) ) atau O (N))
Ulangi kata-kata kosong yang dihitung pada langkah sebelumnya dan untuk masing-masing coba sejumlah solusi cancdidate (pastikan bahwa "konsistensi busur dipertahankan", yaitu kisi memiliki solusi setelah langkah ini jika kata ini digunakan) dan urutkan menurut ketersediaan maksimum untuk langkah berikutnya (yaitu, langkah selanjutnya memiliki solusi maksimum yang mungkin jika kata ini digunakan pada saat itu di tempat itu, dll ..) (kompleksitas O (N * MaxCandidatesUsed))
Isi kata itu (tandai sebagai terisi dan lanjutkan ke langkah 2)
Jika tidak ditemukan kata yang memenuhi kriteria pada langkah .3 coba mundur ke solusi kandidat lain dari beberapa langkah sebelumnya (kriteria dapat bervariasi di sini) (kompleksitas O (N))
Jika jejak mundur ditemukan, gunakan alternatif dan secara opsional setel ulang kata-kata yang sudah terisi yang mungkin perlu diatur ulang (tandai sebagai tidak terisi lagi) (kompleksitas O (N))
Jika tidak ada backtrack yang ditemukan, tidak ada solusi yang dapat ditemukan (setidaknya dengan konfigurasi ini, seed awal, dll ..)
Lain ketika semua slot kata terisi, Anda memiliki satu solusi
Algoritme ini melakukan jalan konsisten acak dari pohon solusi masalah. Jika di beberapa titik ada jalan buntu, ia melakukan backtrack ke node sebelumnya dan mengikuti rute lain. Hingga solusi yang ditemukan atau jumlah kandidat untuk berbagai node habis.
Bagian konsistensi memastikan bahwa solusi yang ditemukan memang merupakan solusi dan bagian acak memungkinkan untuk menghasilkan solusi yang berbeda dalam eksekusi yang berbeda dan juga rata-rata memiliki performa yang lebih baik.
PS. semua ini (dan lainnya) diimplementasikan dalam JavaScript murni (dengan pemrosesan paralel dan kemampuan WYSIWYG)
PS2. Algoritme dapat dengan mudah diparalelkan untuk menghasilkan lebih dari satu solusi (berbeda) pada saat yang bersamaan
Semoga ini membantu
sumber
Mengapa tidak hanya menggunakan pendekatan probabilistik acak untuk memulai. Mulailah dengan sebuah kata, lalu berulang kali memilih kata acak dan mencoba menyesuaikannya dengan status teka-teki saat ini tanpa melanggar batasan ukuran, dll. Jika Anda gagal, mulai dari awal lagi.
Anda akan terkejut betapa sering pendekatan Monte Carlo seperti ini berhasil.
sumber
Berikut adalah beberapa kode JavaScript berdasarkan jawaban nickf dan kode Python Bryan. Hanya mempostingnya jika orang lain membutuhkannya di js.
sumber
Saya akan menghasilkan dua angka: Panjang dan skor Scrabble. Asumsikan bahwa skor Scrabble yang rendah berarti lebih mudah untuk bergabung (skor rendah = banyak huruf umum). Urutkan daftar berdasarkan panjang menurun dan skor Scrabble naik.
Selanjutnya, turunkan daftarnya. Jika kata tersebut tidak bersilangan dengan kata yang sudah ada (periksa setiap kata dengan panjangnya dan skor Scrabble, masing-masing), masukkan ke antrean, dan periksa kata berikutnya.
Bilas dan ulangi, dan ini akan menghasilkan teka-teki silang.
Tentu saja, saya cukup yakin ini adalah O (n!) Dan tidak ada jaminan untuk menyelesaikan teka-teki silang untuk Anda, tetapi mungkin seseorang dapat memperbaikinya.
sumber
Saya sudah memikirkan masalah ini. Pengertian saya adalah bahwa untuk membuat teka-teki silang yang benar-benar padat, Anda tidak dapat berharap bahwa daftar kata Anda yang terbatas akan cukup. Oleh karena itu, Anda mungkin ingin mengambil kamus dan menempatkannya ke dalam struktur data "trie". Ini akan memungkinkan Anda dengan mudah menemukan kata-kata yang mengisi ruang yang tersisa. Dalam percobaan, cukup efisien untuk mengimplementasikan traversal yang, katakanlah, memberi Anda semua kata dalam bentuk "c? T".
Jadi, pemikiran umum saya adalah: buat semacam pendekatan kekerasan yang relatif seperti yang dijelaskan di sini untuk membuat persilangan dengan kepadatan rendah, dan mengisi kekosongan dengan kata-kata kamus.
Jika ada orang lain yang telah mengambil pendekatan ini, beri tahu saya.
sumber
Saya bermain-main dengan mesin generator teka-teki silang, dan saya menemukan ini yang paling penting:
0.
!/usr/bin/python
Sebuah.
allwords.sort(key=len, reverse=True)
b. buat beberapa item / objek seperti kursor yang akan berjalan mengelilingi matriks untuk memudahkan orientasi kecuali jika anda ingin mengulang dengan pilihan acak nanti.
yang pertama, ambil pasangan pertama dan letakkan di seberang dan ke bawah dari 0,0; simpan yang pertama sebagai 'pemimpin' teka-teki silang kita saat ini.
pindahkan kursor dengan urutan diagonal atau acak dengan probabilitas diagonal lebih besar ke sel kosong berikutnya
mengulangi kata-kata seperti dan gunakan panjang ruang kosong untuk menentukan panjang kata maksimal:
temp=[] for w_size in range( len( w_space ), 2, -1 ) : # t for w in [ word for word in allwords if len(word) == w_size ] : # if w not in temp and putTheWord( w, w_space ) : # temp.append( w )
untuk membandingkan kata dengan ruang kosong yang saya gunakan yaitu:
setelah setiap kata berhasil digunakan, ubah arah. Ulangi saat semua sel terisi ATAU Anda kehabisan kata ATAU dengan batas iterasi maka:
# CHANGE ALL WORDS LIST inexOf1stWord = allwords.index( leading_w ) allwords = allwords[:inexOf1stWord+1][:] + allwords[inexOf1stWord+1:][:]
... dan mengulangi teka-teki silang baru lagi.
Membuat sistem penilaian dengan kemudahan pengisian, dan beberapa perhitungan perhitungan. Beri skor untuk teka-teki silang saat ini dan persempit pilihan nanti dengan menambahkannya ke dalam daftar teka-teki silang yang dibuat jika skornya sesuai dengan sistem penilaian Anda.
Setelah sesi iterasi pertama iterasi lagi dari daftar teka-teki silang yang dibuat untuk menyelesaikan pekerjaan.
Dengan menggunakan lebih banyak parameter, kecepatan dapat ditingkatkan dengan faktor yang sangat besar.
sumber
Saya akan mendapatkan indeks dari setiap huruf yang digunakan oleh setiap kata untuk mengetahui kemungkinan persilangan. Kemudian saya akan memilih kata terbesar dan menggunakannya sebagai basis. Pilih yang besar berikutnya dan silangkan. Bilas dan ulangi. Ini mungkin masalah NP.
Ide lainnya adalah membuat algoritma genetika di mana metrik kekuatannya adalah berapa banyak kata yang dapat Anda masukkan ke dalam kisi.
Bagian tersulit yang saya temukan adalah ketika mengetahui daftar tertentu yang tidak mungkin disilangkan.
sumber
Yang ini muncul sebagai proyek dalam kursus AI CS50 dari Harvard. Idenya adalah untuk merumuskan masalah pembuatan teka-teki silang sebagai masalah kepuasan kendala dan menyelesaikannya dengan backtracking dengan heuristik yang berbeda untuk mengurangi ruang pencarian.
Untuk memulainya kita membutuhkan beberapa file input:
`
`
Kosakata masukan (daftar kata / kamus) dari mana kata-kata kandidat akan dipilih (seperti yang ditunjukkan berikut ini).
a abandon ability able abortion about above abroad absence absolute absolutely ...
Sekarang CSP didefinisikan dan diselesaikan sebagai berikut:
Berikut ini adalah keluaran yang diperoleh dengan menggunakan implementasi algoritma penyelesaian CSP:
`
Animasi berikut menunjukkan langkah mundur:
Ini satu lagi dengan daftar kata bahasa Bangla (Bengali):
sumber
Saya telah membuat kode solusi JavaScript / jQuery untuk masalah ini:
Demo Contoh: http://www.earthfluent.com/crossword-puzzle-demo.html
Kode Sumber: https://github.com/HoldOffHunger/jquery-crossword-puzzle-generator
Maksud dari algoritma yang saya gunakan:
Saya akan menjelaskan algoritma yang saya gunakan:
Kelompokkan kata-kata itu menurut kata-kata yang memiliki huruf yang sama.
Dari grup ini, buat kumpulan struktur data baru ("blok kata"), yang merupakan kata utama (yang berjalan melalui semua kata lain) dan kemudian kata lainnya (yang dijalankan melalui kata utama).
Mulailah teka-teki silang dengan yang pertama dari blok kata ini di posisi paling kiri atas teka-teki silang.
Untuk blok kata lainnya, mulai dari posisi paling kanan-bawah teka-teki silang, bergerak ke atas dan ke kiri, hingga tidak ada lagi slot yang tersedia untuk diisi. Jika ada lebih banyak kolom kosong ke atas daripada di kiri, pindahkan ke atas, dan sebaliknya.
sumber
var crosswords = generateCrosswordBlockSources(puzzlewords);
. Konsol saja nilai ini. Jangan lupa, ada "cheat-mode" di dalam game, di mana Anda tinggal mengklik "Reveal Answer", untuk langsung mendapatkan nilainya.