เมื่อพิจารณาถึงรายการคำคุณจะจัดเรียงคำเหล่านี้ให้เป็นตารางคำไขว้ได้อย่างไร
มันไม่จำเป็นต้องเป็นเหมือนปริศนาอักษรไขว้ที่ "เหมาะสม" ซึ่งเป็นแบบสมมาตรหรืออะไรทำนองนั้น: โดยพื้นฐานแล้วเพียงแค่แสดงตำแหน่งเริ่มต้นและทิศทางสำหรับแต่ละคำ
เมื่อพิจารณาถึงรายการคำคุณจะจัดเรียงคำเหล่านี้ให้เป็นตารางคำไขว้ได้อย่างไร
มันไม่จำเป็นต้องเป็นเหมือนปริศนาอักษรไขว้ที่ "เหมาะสม" ซึ่งเป็นแบบสมมาตรหรืออะไรทำนองนั้น: โดยพื้นฐานแล้วเพียงแค่แสดงตำแหน่งเริ่มต้นและทิศทางสำหรับแต่ละคำ
คำตอบ:
ฉันคิดวิธีแก้ปัญหาซึ่งอาจไม่ได้มีประสิทธิภาพมากที่สุด แต่ก็ใช้ได้ดีพอ โดยทั่วไป:
สิ่งนี้ทำให้คำไขว้ที่ใช้งานได้ แต่มักจะค่อนข้างแย่ มีการปรับเปลี่ยนหลายอย่างกับสูตรพื้นฐานด้านบนเพื่อให้ได้ผลลัพธ์ที่ดีขึ้น
ฉันเพิ่งเขียนของตัวเองใน Python คุณสามารถค้นหาได้ที่นี่: http://bryanhelmig.com/python-crossword-puzzle-generator/ มันไม่ได้สร้างปริศนาอักษรไขว้สไตล์ NYT ที่หนาแน่น แต่เป็นรูปแบบของปริศนาอักษรไขว้ที่คุณอาจพบในหนังสือปริศนาสำหรับเด็ก
ซึ่งแตกต่างจากอัลกอริทึมบางอย่างที่ฉันพบที่นั่นซึ่งใช้วิธีการสุ่มแบบเดรัจฉานบังคับในการวางคำอย่างที่สองสามคนแนะนำฉันพยายามใช้วิธีการบังคับแบบเดรัจฉานที่ชาญฉลาดกว่าเล็กน้อยในการจัดวางคำ นี่คือกระบวนการของฉัน:
ในตอนท้ายคุณมีปริศนาอักษรไขว้ที่ดีหรือปริศนาค้นหาคำศัพท์เนื่องจากเป็นปริศนาเดียวกัน มีแนวโน้มที่จะทำงานได้ค่อนข้างดี แต่โปรดแจ้งให้เราทราบหากคุณมีข้อเสนอแนะเกี่ยวกับการปรับปรุง กริดที่ใหญ่กว่าจะทำงานช้าลงอย่างทวีคูณ คำที่ใหญ่กว่าแสดงรายการเชิงเส้น รายการคำที่ใหญ่กว่ายังมีโอกาสสูงกว่ามากที่จะได้หมายเลขตำแหน่งคำที่ดีกว่า
array.sort(key=f)
มีเสถียรภาพซึ่งหมายความว่า (เช่น) การจัดเรียงรายการคำตามตัวอักษรตามความยาวจะทำให้คำ 8 ตัวอักษรทั้งหมดเรียงตามตัวอักษร
จริงๆแล้วฉันเขียนโปรแกรมสร้างคำไขว้เมื่อสิบปีที่แล้ว (มันเป็นความลับ แต่กฎเดียวกันจะใช้กับปริศนาอักษรไขว้ปกติ)
มีรายการคำ (และเบาะแสที่เกี่ยวข้อง) เก็บไว้ในไฟล์โดยเรียงลำดับตามการใช้งานจากมากไปหาน้อยจนถึงปัจจุบัน (เพื่อให้คำที่ใช้น้อยอยู่ที่ด้านบนของไฟล์) เทมเพลตซึ่งโดยพื้นฐานแล้วเป็นรูปแบบบิตที่แสดงถึงสี่เหลี่ยมสีดำและฟรีนั้นถูกเลือกแบบสุ่มจากพูลที่ลูกค้าให้มา
จากนั้นสำหรับแต่ละคำที่ไม่สมบูรณ์ในปริศนา (โดยทั่วไปให้ค้นหาช่องสี่เหลี่ยมว่างแรกและดูว่าคำที่อยู่ทางขวา (ข้ามคำ) หรือคำที่อยู่ด้านล่าง (คำลง) ว่างเปล่าเช่นกัน) จะทำการค้นหา ไฟล์ที่มองหาคำแรกที่พอดีโดยคำนึงถึงตัวอักษรที่มีอยู่แล้วในคำนั้น หากไม่มีคำใดที่เหมาะสมคุณเพียงทำเครื่องหมายว่าทั้งคำไม่สมบูรณ์และดำเนินการต่อไป
ในตอนท้ายจะเป็นคำที่ยังไม่สมบูรณ์ซึ่งคอมไพเลอร์จะต้องกรอก (และเพิ่มคำและเบาะแสลงในไฟล์หากต้องการ) หากพวกเขาไม่สามารถคิดแนวคิดใด ๆ ได้พวกเขาสามารถแก้ไขคำไขว้ด้วยตนเองเพื่อเปลี่ยนข้อ จำกัด หรือเพียงแค่ขอการสร้างใหม่ทั้งหมด
เมื่อไฟล์ word / clue มีขนาดที่กำหนด (และเพิ่ม 50-100 เบาะแสต่อวันสำหรับลูกค้ารายนี้) ไม่ค่อยมีกรณีที่ต้องแก้ไขด้วยตนเองมากกว่าสองหรือสามรายการสำหรับคำไขว้แต่ละคำ .
อัลกอริทึมนี้สร้างปริศนาอักษรไขว้ลูกศร 6x9 หนาแน่น 50 รายการใน 60 วินาที ใช้ฐานข้อมูลคำ (พร้อมคำ + เคล็ดลับ) และฐานข้อมูลบอร์ด (พร้อมบอร์ดที่กำหนดค่าไว้ล่วงหน้า)
1) Search for all starting cells (the ones with an arrow), store their size and directions
2) Loop through all starting cells
2.1) Search a word
2.1.1) Check if it was not already used
2.1.2) Check if it fits
2.2) Add the word to the board
3) Check if all cells were filled
ฐานข้อมูลคำที่ใหญ่ขึ้นจะลดเวลาในการสร้างลงอย่างมากและบอร์ดบางประเภทก็เติมได้ยากขึ้น! กระดานขนาดใหญ่ต้องใช้เวลามากขึ้นในการเติมให้ถูกต้อง!
ตัวอย่าง:
บอร์ด 6x9 ที่กำหนดค่าไว้ล่วงหน้า:
(# หมายถึงเคล็ดลับหนึ่งข้อในเซลล์เดียว% หมายถึงสองเคล็ดลับในเซลล์เดียวไม่แสดงลูกศร)
# - # # - % # - #
- - - - - - - - -
# - - - - - # - -
% - - # - # - - -
% - - - - - % - -
- - - - - - - - -
สร้างบอร์ด 6x9:
# C # # P % # O #
S A T E L L I T E
# N I N E S # T A
% A B # A # G A S
% D E N S E % W E
C A T H E D R A L
เคล็ดลับ [บรรทัดคอลัมน์]:
[1,0] SATELLITE: Used for weather forecast
[5,0] CATHEDRAL: The principal church of a city
[0,1] CANADA: Country on USA's northern border
[0,4] PLEASE: A polite way to ask things
[0,7] OTTAWA: Canada's capital
[1,2] TIBET: Dalai Lama's region
[1,8] EASEL: A tripod used to put a painting
[2,1] NINES: Dressed up to (?)
[4,1] DENSE: Thick; impenetrable
[3,6] GAS: Type of fuel
[1,5] LS: Lori Singer, american actress
[2,7] TA: Teaching assistant (abbr.)
[3,1] AB: A blood type
[4,3] NH: New Hampshire (abbr.)
[4,5] ED: (?) Harris, american actor
[4,7] WE: The first person of plural (Grammar)
แม้ว่านี่จะเป็นคำถามที่เก่ากว่า แต่ก็จะพยายามหาคำตอบจากงานที่คล้ายกันที่ฉันเคยทำ
มีหลายวิธีในการแก้ปัญหาข้อ จำกัด (ซึ่ง Generallay อยู่ในระดับความซับซ้อนของ NPC)
สิ่งนี้เกี่ยวข้องกับการเพิ่มประสิทธิภาพคอมบิเนเตอร์และการเขียนโปรแกรมข้อ จำกัด ในกรณีนี้ข้อ จำกัด คือเรขาคณิตของเส้นตารางและข้อกำหนดที่ว่าคำไม่ซ้ำกันเป็นต้น
วิธีการสุ่ม / การหลอมยังสามารถใช้งานได้ (แม้ว่าจะอยู่ในการตั้งค่าที่เหมาะสมก็ตาม)
ความเรียบง่ายอย่างมีประสิทธิภาพอาจเป็นภูมิปัญญาขั้นสูงสุด!
ข้อกำหนดมีไว้สำหรับคอมไพเลอร์คำไขว้ที่สมบูรณ์มากขึ้นหรือน้อยลงและตัวสร้าง (วิชวล WYSIWYG)
ออกจากส่วนตัวสร้าง WYSIWYG โครงร่างของคอมไพเลอร์คือ:
โหลดรายการคำที่มีอยู่ (เรียงตามความยาวของคำเช่น 2,3, .. , 20)
ค้นหาช่องคำ (เช่นคำในตาราง) บนเส้นตารางที่ผู้ใช้สร้างขึ้น (เช่นคำที่ x, y ที่มีความยาว L แนวนอนหรือแนวตั้ง) (ความซับซ้อน O (N))
คำนวณจุดตัดกันของคำในตาราง (ที่ต้องเติม) (ความซับซ้อน O (N ^ 2))
คำนวณการตัดกันของคำในรายการคำด้วยตัวอักษรต่างๆของตัวอักษรที่ใช้ (ซึ่งช่วยให้สามารถค้นหาคำที่ตรงกันโดยใช้เทมเพลตเช่นวิทยานิพนธ์ Sik Cambon ที่ใช้โดย cwc ) (ความซับซ้อน O (WL * AL))
ขั้นตอนที่. 3 และ. 4 อนุญาตให้ทำงานนี้:
การตัดกันของคำในตารางด้วยตัวมันเองทำให้สามารถสร้าง "แม่แบบ" สำหรับพยายามค้นหาคำที่ตรงกันในรายการคำที่เกี่ยวข้องของคำที่มีอยู่สำหรับคำตารางนี้ (โดยใช้ตัวอักษรของคำที่ตัดกันอื่น ๆ กับคำนี้ซึ่งเติมเต็มแล้วในบางคำ ขั้นตอนของอัลกอริทึม)
ข จุดตัดของคำในรายการคำที่มีตัวอักษรช่วยให้สามารถค้นหาคำที่ตรงกัน (ตัวเลือก) ที่ตรงกับ "แม่แบบ" ที่กำหนด (เช่น 'A' ในอันดับที่ 1 และ 'B' ในอันดับที่ 3 เป็นต้น)
ดังนั้นด้วยโครงสร้างข้อมูลเหล่านี้จึงใช้อัลกอริทึมที่ใช้จึงเป็นดังนี้:
หมายเหตุ: หากกริดและฐานข้อมูลของคำคงที่ขั้นตอนก่อนหน้านี้สามารถทำได้เพียงครั้งเดียว
ขั้นตอนแรกของอัลกอริทึมคือเลือกช่องคำว่าง (คำตาราง) โดยการสุ่มและเติมด้วยคำที่เป็นตัวเลือกจากรายการคำที่เกี่ยวข้อง (การสุ่มช่วยให้สามารถสร้างตัวทำละลายที่แตกต่างกันในการดำเนินการต่อเนื่องกันของอัลกอริทึม) (ความซับซ้อน O (1) หรือ O ( N))
สำหรับช่องคำที่ยังว่างแต่ละช่อง (ที่มีจุดตัดกับช่องคำที่เติมไว้แล้ว) ให้คำนวณอัตราส่วนข้อ จำกัด (ซึ่งอาจแตกต่างกันไป sth แบบง่ายคือจำนวนโซลูชันที่มีอยู่ในขั้นตอนนั้น) และจัดเรียงช่องคำว่างตามอัตราส่วนนี้ (ความซับซ้อน O (NlogN ) หรือ O (N))
วนรอบช่องคำว่างที่คำนวณในขั้นตอนก่อนหน้าและลองใช้วิธีแก้ปัญหา cancdidate จำนวนหนึ่ง (ตรวจสอบให้แน่ใจว่า "คงความสอดคล้องของส่วนโค้งไว้" กล่าวคือกริดมีวิธีแก้ปัญหาหลังจากขั้นตอนนี้หากใช้คำนี้) และเรียงลำดับตาม ความพร้อมใช้งานสูงสุดสำหรับขั้นตอนต่อไป (เช่นขั้นตอนต่อไปมีวิธีแก้ปัญหาสูงสุดที่เป็นไปได้หากมีการใช้คำนี้ในเวลานั้นในสถานที่นั้นเป็นต้น) (ความซับซ้อน O (N * MaxCandidatesUsed))
เติมคำนั้น (ทำเครื่องหมายว่าเติมแล้วไปที่ขั้นตอนที่ 2)
หากไม่พบคำที่ตรงตามเกณฑ์ของขั้นตอนที่ 3 ให้ลองย้อนกลับไปยังโซลูชันอื่นของขั้นตอนก่อนหน้า (เกณฑ์อาจแตกต่างกันไปที่นี่) (ความซับซ้อน O (N))
หากพบแบ็กแทร็กให้ใช้ตัวเลือกอื่นและรีเซ็ตคำที่เติมไปแล้วซึ่งอาจต้องรีเซ็ต (ทำเครื่องหมายว่ายังไม่ได้เติมอีกครั้ง) (ความซับซ้อน O (N))
หากไม่พบ backtrack จะไม่พบวิธีแก้ปัญหาใด ๆ (อย่างน้อยก็มีการกำหนดค่านี้ initial seed เป็นต้น)
อื่น ๆ เมื่อเติมคำศัพท์ทั้งหมดคุณจะมีทางออกเดียว
อัลกอริทึมนี้จะทำการเดินแบบสุ่มที่สอดคล้องกันของแผนผังวิธีการแก้ปัญหา หากในบางจุดมีทางตันมันจะย้อนกลับไปยังโหนดก่อนหน้าและไปตามเส้นทางอื่น จนกว่าโซลูชันที่พบหรือจำนวนผู้สมัครสำหรับโหนดต่างๆจะหมดลง
ส่วนที่สอดคล้องกันทำให้แน่ใจว่าโซลูชันที่พบเป็นโซลูชันจริงและส่วนที่สุ่มช่วยให้สามารถสร้างโซลูชันที่แตกต่างกันในการดำเนินการที่แตกต่างกันและโดยเฉลี่ยแล้วมีประสิทธิภาพที่ดีขึ้น
PS ทั้งหมดนี้ (และอื่น ๆ ) ถูกนำไปใช้ใน JavaScript บริสุทธิ์ (พร้อมการประมวลผลแบบขนานและความสามารถ WYSIWYG)
PS2 อัลกอริทึมสามารถขนานกันได้อย่างง่ายดายเพื่อสร้างโซลูชันมากกว่าหนึ่ง (ที่แตกต่างกัน) ในเวลาเดียวกัน
หวังว่านี่จะช่วยได้
ทำไมไม่ใช้วิธีการสุ่มที่น่าจะเป็นเริ่มต้นด้วย เริ่มต้นด้วยคำจากนั้นเลือกคำสุ่มซ้ำ ๆ และพยายามทำให้พอดีกับสถานะปัจจุบันของปริศนาโดยไม่ทำลายข้อ จำกัด เรื่องขนาด ฯลฯ หากคุณล้มเหลวให้เริ่มต้นใหม่ทั้งหมดอีกครั้ง
คุณจะแปลกใจว่าวิธีการแบบมอนติคาร์โลแบบนี้ได้ผลบ่อยแค่ไหน
นี่คือโค้ด JavaScript บางส่วนตามคำตอบของ nickf และรหัส Python ของ Bryan เพียงโพสต์ไว้เผื่อว่ามีคนอื่นต้องการใน js
function board(cols, rows) { //instantiator object for making gameboards
this.cols = cols;
this.rows = rows;
var activeWordList = []; //keeps array of words actually placed in board
var acrossCount = 0;
var downCount = 0;
var grid = new Array(cols); //create 2 dimensional array for letter grid
for (var i = 0; i < rows; i++) {
grid[i] = new Array(rows);
}
for (var x = 0; x < cols; x++) {
for (var y = 0; y < rows; y++) {
grid[x][y] = {};
grid[x][y].targetChar = EMPTYCHAR; //target character, hidden
grid[x][y].indexDisplay = ''; //used to display index number of word start
grid[x][y].value = '-'; //actual current letter shown on board
}
}
function suggestCoords(word) { //search for potential cross placement locations
var c = '';
coordCount = [];
coordCount = 0;
for (i = 0; i < word.length; i++) { //cycle through each character of the word
for (x = 0; x < GRID_HEIGHT; x++) {
for (y = 0; y < GRID_WIDTH; y++) {
c = word[i];
if (grid[x][y].targetChar == c) { //check for letter match in cell
if (x - i + 1> 0 && x - i + word.length-1 < GRID_HEIGHT) { //would fit vertically?
coordList[coordCount] = {};
coordList[coordCount].x = x - i;
coordList[coordCount].y = y;
coordList[coordCount].score = 0;
coordList[coordCount].vertical = true;
coordCount++;
}
if (y - i + 1 > 0 && y - i + word.length-1 < GRID_WIDTH) { //would fit horizontally?
coordList[coordCount] = {};
coordList[coordCount].x = x;
coordList[coordCount].y = y - i;
coordList[coordCount].score = 0;
coordList[coordCount].vertical = false;
coordCount++;
}
}
}
}
}
}
function checkFitScore(word, x, y, vertical) {
var fitScore = 1; //default is 1, 2+ has crosses, 0 is invalid due to collision
if (vertical) { //vertical checking
for (i = 0; i < word.length; i++) {
if (i == 0 && x > 0) { //check for empty space preceeding first character of word if not on edge
if (grid[x - 1][y].targetChar != EMPTYCHAR) { //adjacent letter collision
fitScore = 0;
break;
}
} else if (i == word.length && x < GRID_HEIGHT) { //check for empty space after last character of word if not on edge
if (grid[x+i+1][y].targetChar != EMPTYCHAR) { //adjacent letter collision
fitScore = 0;
break;
}
}
if (x + i < GRID_HEIGHT) {
if (grid[x + i][y].targetChar == word[i]) { //letter match - aka cross point
fitScore += 1;
} else if (grid[x + i][y].targetChar != EMPTYCHAR) { //letter doesn't match and it isn't empty so there is a collision
fitScore = 0;
break;
} else { //verify that there aren't letters on either side of placement if it isn't a crosspoint
if (y < GRID_WIDTH - 1) { //check right side if it isn't on the edge
if (grid[x + i][y + 1].targetChar != EMPTYCHAR) { //adjacent letter collision
fitScore = 0;
break;
}
}
if (y > 0) { //check left side if it isn't on the edge
if (grid[x + i][y - 1].targetChar != EMPTYCHAR) { //adjacent letter collision
fitScore = 0;
break;
}
}
}
}
}
} else { //horizontal checking
for (i = 0; i < word.length; i++) {
if (i == 0 && y > 0) { //check for empty space preceeding first character of word if not on edge
if (grid[x][y-1].targetChar != EMPTYCHAR) { //adjacent letter collision
fitScore = 0;
break;
}
} else if (i == word.length - 1 && y + i < GRID_WIDTH -1) { //check for empty space after last character of word if not on edge
if (grid[x][y + i + 1].targetChar != EMPTYCHAR) { //adjacent letter collision
fitScore = 0;
break;
}
}
if (y + i < GRID_WIDTH) {
if (grid[x][y + i].targetChar == word[i]) { //letter match - aka cross point
fitScore += 1;
} else if (grid[x][y + i].targetChar != EMPTYCHAR) { //letter doesn't match and it isn't empty so there is a collision
fitScore = 0;
break;
} else { //verify that there aren't letters on either side of placement if it isn't a crosspoint
if (x < GRID_HEIGHT) { //check top side if it isn't on the edge
if (grid[x + 1][y + i].targetChar != EMPTYCHAR) { //adjacent letter collision
fitScore = 0;
break;
}
}
if (x > 0) { //check bottom side if it isn't on the edge
if (grid[x - 1][y + i].targetChar != EMPTYCHAR) { //adjacent letter collision
fitScore = 0;
break;
}
}
}
}
}
}
return fitScore;
}
function placeWord(word, clue, x, y, vertical) { //places a new active word on the board
var wordPlaced = false;
if (vertical) {
if (word.length + x < GRID_HEIGHT) {
for (i = 0; i < word.length; i++) {
grid[x + i][y].targetChar = word[i];
}
wordPlaced = true;
}
} else {
if (word.length + y < GRID_WIDTH) {
for (i = 0; i < word.length; i++) {
grid[x][y + i].targetChar = word[i];
}
wordPlaced = true;
}
}
if (wordPlaced) {
var currentIndex = activeWordList.length;
activeWordList[currentIndex] = {};
activeWordList[currentIndex].word = word;
activeWordList[currentIndex].clue = clue;
activeWordList[currentIndex].x = x;
activeWordList[currentIndex].y = y;
activeWordList[currentIndex].vertical = vertical;
if (activeWordList[currentIndex].vertical) {
downCount++;
activeWordList[currentIndex].number = downCount;
} else {
acrossCount++;
activeWordList[currentIndex].number = acrossCount;
}
}
}
function isActiveWord(word) {
if (activeWordList.length > 0) {
for (var w = 0; w < activeWordList.length; w++) {
if (word == activeWordList[w].word) {
//console.log(word + ' in activeWordList');
return true;
}
}
}
return false;
}
this.displayGrid = function displayGrid() {
var rowStr = "";
for (var x = 0; x < cols; x++) {
for (var y = 0; y < rows; y++) {
rowStr += "<td>" + grid[x][y].targetChar + "</td>";
}
$('#tempTable').append("<tr>" + rowStr + "</tr>");
rowStr = "";
}
console.log('across ' + acrossCount);
console.log('down ' + downCount);
}
//for each word in the source array we test where it can fit on the board and then test those locations for validity against other already placed words
this.generateBoard = function generateBoard(seed = 0) {
var bestScoreIndex = 0;
var top = 0;
var fitScore = 0;
var startTime;
//manually place the longest word horizontally at 0,0, try others if the generated board is too weak
placeWord(wordArray[seed].word, wordArray[seed].displayWord, wordArray[seed].clue, 0, 0, false);
//attempt to fill the rest of the board
for (var iy = 0; iy < FIT_ATTEMPTS; iy++) { //usually 2 times is enough for max fill potential
for (var ix = 1; ix < wordArray.length; ix++) {
if (!isActiveWord(wordArray[ix].word)) { //only add if not already in the active word list
topScore = 0;
bestScoreIndex = 0;
suggestCoords(wordArray[ix].word); //fills coordList and coordCount
coordList = shuffleArray(coordList); //adds some randomization
if (coordList[0]) {
for (c = 0; c < coordList.length; c++) { //get the best fit score from the list of possible valid coordinates
fitScore = checkFitScore(wordArray[ix].word, coordList[c].x, coordList[c].y, coordList[c].vertical);
if (fitScore > topScore) {
topScore = fitScore;
bestScoreIndex = c;
}
}
}
if (topScore > 1) { //only place a word if it has a fitscore of 2 or higher
placeWord(wordArray[ix].word, wordArray[ix].clue, coordList[bestScoreIndex].x, coordList[bestScoreIndex].y, coordList[bestScoreIndex].vertical);
}
}
}
}
if(activeWordList.length < wordArray.length/2) { //regenerate board if if less than half the words were placed
seed++;
generateBoard(seed);
}
}
}
function seedBoard() {
gameboard = new board(GRID_WIDTH, GRID_HEIGHT);
gameboard.generateBoard();
gameboard.displayGrid();
}
ฉันจะสร้างตัวเลขสองตัว: ความยาวและคะแนน Scrabble สมมติว่าคะแนน Scrabble ต่ำหมายความว่าง่ายต่อการเข้าร่วม (คะแนนต่ำ = ตัวอักษรทั่วไปจำนวนมาก) จัดเรียงรายการตามความยาวจากมากไปหาน้อยและคะแนน Scrabble จากน้อยไปมาก
จากนั้นไปที่รายการ ถ้าคำนั้นไม่ข้ามกับคำที่มีอยู่ (ตรวจสอบแต่ละคำตามความยาวและคะแนน Scrabble ตามลำดับ) จากนั้นใส่ลงในคิวและตรวจสอบคำถัดไป
ล้างและทำซ้ำและควรสร้างคำไขว้
แน่นอนฉันค่อนข้างมั่นใจว่านี่คือ O (n!) และไม่รับประกันว่าจะเติมคำไขว้ให้คุณจนเสร็จ แต่อาจมีใครสามารถปรับปรุงได้
ฉันคิดเกี่ยวกับปัญหานี้ ความรู้สึกของฉันคือการสร้างคำไขว้ที่หนาแน่นอย่างแท้จริงคุณไม่สามารถหวังว่ารายการคำที่ จำกัด ของคุณจะเพียงพอ ดังนั้นคุณอาจต้องการใช้พจนานุกรมและวางไว้ในโครงสร้างข้อมูล "trie" วิธีนี้จะช่วยให้คุณค้นหาคำที่เติมช่องว่างที่เหลือได้อย่างง่ายดาย ใน Trie มีประสิทธิภาพพอสมควรในการใช้การส่งผ่านที่ให้คำทั้งหมดในรูปแบบ "c? t"
ดังนั้นความคิดทั่วไปของฉันคือสร้างแนวทางการบังคับที่ค่อนข้างดุร้ายตามที่บางคนอธิบายไว้ที่นี่เพื่อสร้างกากบาทที่มีความหนาแน่นต่ำและเติมคำในพจนานุกรมลงในช่องว่าง
หากใครใช้แนวทางนี้อีกโปรดแจ้งให้เราทราบ
ฉันเล่นกับเครื่องมือสร้างปริศนาอักษรไขว้และฉันพบว่าสิ่งนี้สำคัญที่สุด:
0!/usr/bin/python
allwords.sort(key=len, reverse=True)
ข สร้างรายการ / วัตถุบางอย่างเช่นเคอร์เซอร์ซึ่งจะเดินไปรอบ ๆ เมทริกซ์เพื่อการวางแนวที่ง่ายเว้นแต่คุณต้องการทำซ้ำโดยตัวเลือกแบบสุ่มในภายหลัง
อันดับแรกหยิบคู่แรกและวางขวางและลงจาก 0,0; จัดเก็บอันแรกเป็น 'ผู้นำ' คำไขว้ปัจจุบันของเรา
เลื่อนเคอร์เซอร์ตามลำดับในแนวทแยงหรือสุ่มโดยมีความน่าจะเป็นในแนวทแยงมากกว่าไปยังเซลล์ว่างถัดไป
ย้ำคำเช่นและใช้ความยาวพื้นที่ว่างเพื่อกำหนดความยาวของคำสูงสุด:
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 )
เพื่อเปรียบเทียบคำกับพื้นที่ว่างที่ฉันใช้เช่น:
w_space=['c','.','a','.','.','.'] # whereas dots are blank cells
# CONVERT MULTIPLE '.' INTO '.*' FOR REGEX
pattern = r''.join( [ x.letter for x in w_space ] )
pattern = pattern.strip('.') +'.*' if pattern[-1] == '.' else pattern
prog = re.compile( pattern, re.U | re.I )
if prog.match( w ) :
#
if prog.match( w ).group() == w :
#
return True
หลังจากใช้คำแต่ละคำสำเร็จแล้วให้เปลี่ยนทิศทาง วนซ้ำในขณะที่เซลล์ทั้งหมดเต็มไปหมดหรือคุณหมดคำหรือด้วยการ จำกัด การวนซ้ำแล้ว:
# CHANGE ALL WORDS LIST
inexOf1stWord = allwords.index( leading_w )
allwords = allwords[:inexOf1stWord+1][:] + allwords[inexOf1stWord+1:][:]
... และย้ำอีกครั้งคำไขว้ใหม่
สร้างระบบการให้คะแนนด้วยความง่ายในการกรอกข้อมูลและการคำนวณการประมาณค่าบางส่วน ให้คะแนนสำหรับคำไขว้ปัจจุบันและ จำกัด ตัวเลือกในภายหลังโดยผนวกเข้าในรายการปริศนาอักษรไขว้ที่สร้างขึ้นหากคะแนนเป็นที่พอใจของระบบการให้คะแนนของคุณ
หลังจากเซสชันการทำซ้ำครั้งแรกให้วนซ้ำอีกครั้งจากรายการปริศนาอักษรไขว้ที่สร้างไว้เพื่อทำงานให้เสร็จ
โดยการใช้พารามิเตอร์ความเร็วมากขึ้นสามารถปรับปรุงได้โดยปัจจัยใหญ่
ฉันจะได้รับดัชนีของตัวอักษรแต่ละตัวที่ใช้โดยแต่ละคำเพื่อทราบเครื่องหมายกากบาทที่เป็นไปได้ จากนั้นฉันจะเลือกคำที่ใหญ่ที่สุดและใช้เป็นฐาน เลือกขนาดใหญ่ถัดไปและข้ามมัน ล้างและทำซ้ำ มันน่าจะเป็นปัญหา NP
อีกแนวคิดหนึ่งคือการสร้างอัลกอริทึมทางพันธุกรรมโดยที่เมตริกความแรงคือจำนวนคำที่คุณสามารถใส่ลงในตารางได้
ส่วนที่ยากที่ฉันพบคือเมื่อรู้ว่ารายการบางรายการไม่สามารถข้ามได้
สิ่งนี้ปรากฏเป็นโครงการในหลักสูตร AI CS50จาก Harvard แนวคิดคือการกำหนดปัญหาการสร้างคำไขว้เป็นปัญหาความพึงพอใจที่มีข้อ จำกัด และแก้ปัญหาด้วยการย้อนกลับด้วยการวิเคราะห์พฤติกรรมที่แตกต่างกันเพื่อลดพื้นที่ในการค้นหา
ในการเริ่มต้นเราต้องมีไฟล์อินพุตสองสามไฟล์:
`
###_####_#
____####_#
_##_#_____
_##_#_##_#
______####
#_###_####
#_##______
#_###_##_#
_____###_#
#_######_#
##_______#
`
คำศัพท์ที่ป้อน (รายการคำศัพท์ / พจนานุกรม) ซึ่งจะเลือกคำที่เป็นตัวเลือก (เช่นเดียวกับที่แสดงต่อไปนี้)
a
abandon
ability
able
abortion
about
above
abroad
absence
absolute
absolutely
...
ตอนนี้ CSP ได้รับการกำหนดและจะแก้ไขดังนี้:
ต่อไปนี้แสดงผลลัพธ์ที่ได้รับจากการใช้อัลกอริทึมการแก้ CSP:
`
███S████D█
MUCH████E█
E██A█AGENT
S██R█N██Y█
SUPPLY████
█N███O████
█I██INSIDE
█Q███E██A█
SUGAR███N█
█E██████C█
██OFFENSE█
`
ภาพเคลื่อนไหวต่อไปนี้แสดงขั้นตอนการย้อนรอย:
นี่คืออีกคำหนึ่งที่มีรายการคำภาษาบางลา (เบงกาลี):
ฉันได้เขียนโค้ดวิธีแก้ปัญหา JavaScript / jQuery สำหรับปัญหานี้:
ตัวอย่างการสาธิต: http://www.earthfluent.com/crossword-puzzle-demo.html
รหัสที่มา: https://github.com/HoldOffHunger/jquery-crossword-puzzle-generator
วัตถุประสงค์ของอัลกอริทึมที่ฉันใช้:
ฉันจะอธิบายอัลกอริทึมที่ฉันใช้:
จัดกลุ่มคำเข้าด้วยกันตามคำที่ใช้อักษรทั่วไป
จากกลุ่มเหล่านี้ให้สร้างชุดของโครงสร้างข้อมูลใหม่ ("บล็อกคำ") ซึ่งเป็นคำหลัก (ที่วิ่งผ่านคำอื่น ๆ ทั้งหมด) และคำอื่น ๆ (ที่วิ่งผ่านคำหลัก)
เริ่มไขปริศนาอักษรไขว้ด้วยบล็อกคำศัพท์ตัวแรกในตำแหน่งซ้ายบนสุดของปริศนาอักษรไขว้
สำหรับส่วนที่เหลือของบล็อกคำเริ่มจากตำแหน่งขวาล่างสุดของปริศนาอักษรไขว้เลื่อนขึ้นไปทางซ้ายจนกว่าจะไม่มีช่องว่างให้เติม หากมีคอลัมน์ว่างมากกว่าด้านซ้ายให้เลื่อนขึ้นและในทางกลับกัน
var crosswords = generateCrosswordBlockSources(puzzlewords);
ของตัวอักษรขวาหลังจากที่ เพียงคอนโซลบันทึกค่านี้ อย่าลืมว่ามี "โหมดโกง" ในเกมซึ่งคุณสามารถคลิก "เปิดเผยคำตอบ" เพื่อรับมูลค่าได้ทันที