อัลกอริทึมเพื่อสร้างคำไขว้


123

เมื่อพิจารณาถึงรายการคำคุณจะจัดเรียงคำเหล่านี้ให้เป็นตารางคำไขว้ได้อย่างไร

มันไม่จำเป็นต้องเป็นเหมือนปริศนาอักษรไขว้ที่ "เหมาะสม" ซึ่งเป็นแบบสมมาตรหรืออะไรทำนองนั้น: โดยพื้นฐานแล้วเพียงแค่แสดงตำแหน่งเริ่มต้นและทิศทางสำหรับแต่ละคำ

คำตอบ:


62

ฉันคิดวิธีแก้ปัญหาซึ่งอาจไม่ได้มีประสิทธิภาพมากที่สุด แต่ก็ใช้ได้ดีพอ โดยทั่วไป:

  1. เรียงคำทั้งหมดตามความยาวจากมากไปหาน้อย
  2. เอาคำแรกมาวางบนกระดาน
  3. ใช้คำถัดไป
  4. ค้นหาคำทั้งหมดที่มีอยู่แล้วบนกระดานและดูว่ามีทางแยกที่เป็นไปได้ (ตัวอักษรทั่วไป) ที่มีคำนี้หรือไม่
  5. หากมีตำแหน่งที่เป็นไปได้สำหรับคำนี้ให้วนซ้ำคำทั้งหมดที่อยู่บนกระดานและตรวจสอบว่ามีคำใหม่รบกวนหรือไม่
  6. ถ้าคำนี้ไม่ทำลายกระดานให้วางไว้ตรงนั้นแล้วไปที่ขั้นตอนที่ 3 มิฉะนั้นให้ค้นหาสถานที่ต่อไป (ขั้นตอนที่ 4)
  7. วนต่อไปเรื่อย ๆ จนกว่าจะวางทุกคำหรือวางไม่ได้

สิ่งนี้ทำให้คำไขว้ที่ใช้งานได้ แต่มักจะค่อนข้างแย่ มีการปรับเปลี่ยนหลายอย่างกับสูตรพื้นฐานด้านบนเพื่อให้ได้ผลลัพธ์ที่ดีขึ้น

  • ในตอนท้ายของการสร้างคำไขว้ให้คะแนนตามจำนวนคำที่วางไว้ (ยิ่งมากยิ่งดี) กระดานมีขนาดใหญ่เพียงใด (ยิ่งเล็กยิ่งดี) และอัตราส่วนระหว่างความสูงและความกว้าง (ยิ่งใกล้ เป็น 1 ยิ่งดี) สร้างปริศนาอักษรไขว้จำนวนหนึ่งจากนั้นเปรียบเทียบคะแนนและเลือกสิ่งที่ดีที่สุด
    • แทนที่จะเรียกใช้การทำซ้ำตามจำนวนที่กำหนดฉันได้ตัดสินใจที่จะสร้างปริศนาอักษรไขว้ให้มากที่สุดในเวลาที่กำหนด หากคุณมีรายการคำศัพท์เพียงเล็กน้อยคุณจะได้รับปริศนาอักษรไขว้ที่เป็นไปได้หลายสิบรายการใน 5 วินาที คำไขว้ที่ใหญ่กว่าอาจเลือกได้จาก 5-6 ความเป็นไปได้เท่านั้น
  • เมื่อวางคำใหม่แทนที่จะวางทันทีเมื่อพบตำแหน่งที่ยอมรับได้ให้คะแนนตำแหน่งคำนั้นตามจำนวนที่เพิ่มขนาดของเส้นตารางและจำนวนทางแยก (คุณต้องการให้แต่ละคำเป็นอย่างไร ข้ามด้วยคำอื่น 2-3 คำ) ติดตามตำแหน่งและคะแนนทั้งหมดจากนั้นเลือกตำแหน่งที่ดีที่สุด

7
ฉันบังเอิญเขียนโปรแกรมนี้ในขณะที่เราพูดและนี่คืออัลกอรอ ธ ที่เหมือนกันที่ฉันเลือกด้วย สำหรับคำจำนวนน้อย (10 หรือน้อยกว่า) โปรแกรมไม่มีปัญหาในการคำนวณโซลูชันที่เป็นไปได้ทั้งหมดในหน่วยมิลลิวินาที algoritm เป็นเลขชี้กำลัง ส่วนที่ง่ายคือการเขียนอัลกอริธึมพื้นฐานที่บังคับดุร้ายผ่านชุดค่าผสมที่เป็นไปได้ทั้งหมด ส่วนที่ยากคือ 'ทางลัด' โหลหรือมากกว่านั้นคุณต้องป้องกันไม่ให้โปรแกรมลองใช้วิธีแก้ปัญหาทางตันทั้งหมด
user31586

2
"5. ... และตรวจสอบว่าคำใหม่นั้นรบกวนหรือไม่" คุณจะอธิบายสถานการณ์ที่มีการวางคำใหม่ควบคู่ไปกับคำที่มีอยู่ได้อย่างไรซึ่งทำให้เกิดการพูดพล่อยๆในที่ที่มีช่องสี่เหลี่ยมติดกัน เช่น LEMON ERASE ถ้า "LE", "ER" และ "MA" เป็นต้นไม่ใช่คำในรายการของคุณถือว่าผิด ในทางกลับกันการปฏิเสธคำสั่งดังกล่าวโดยสิ้นเชิงอาจทำให้กริดที่ดีจริงๆเช่น W LEMON ERASE NEXUS TT
George Armhold

4
@Kaffeine ใช่ฉันรู้ว่าคุณหมายถึงอะไร - ฉันต้องทิ้งตัวเลือกเหล่านี้ออกไปเพราะแม้ว่าพวกเขาจะสร้างกริดที่ดีได้ แต่ก็ยากที่จะตรวจสอบ(อ่าน: ฉันไม่ใส่ใจ)และโอกาสที่มันจะเป็นเพียงการรบกวนอยู่ดี .
nickf

4
สร้างด้วย jQuery / Javascript โดยใช้คำแนะนำข้างต้นและบางส่วนของฉันเอง ... mlewiscs.com/crossword
MLewisCodeSolutions

@MLewisCodeSolutions ดูน่ากลัว คุณเปิดแหล่งที่มานี้หรือไม่?
GKS

23

ฉันเพิ่งเขียนของตัวเองใน Python คุณสามารถค้นหาได้ที่นี่: http://bryanhelmig.com/python-crossword-puzzle-generator/ มันไม่ได้สร้างปริศนาอักษรไขว้สไตล์ NYT ที่หนาแน่น แต่เป็นรูปแบบของปริศนาอักษรไขว้ที่คุณอาจพบในหนังสือปริศนาสำหรับเด็ก

ซึ่งแตกต่างจากอัลกอริทึมบางอย่างที่ฉันพบที่นั่นซึ่งใช้วิธีการสุ่มแบบเดรัจฉานบังคับในการวางคำอย่างที่สองสามคนแนะนำฉันพยายามใช้วิธีการบังคับแบบเดรัจฉานที่ชาญฉลาดกว่าเล็กน้อยในการจัดวางคำ นี่คือกระบวนการของฉัน:

  1. สร้างตารางขนาดใดก็ได้และรายการคำ
  2. สลับรายการคำจากนั้นเรียงลำดับคำตามยาวไปหาสั้นที่สุด
  3. วางคำแรกและยาวที่สุดที่ตำแหน่งบนซ้ายสุด 1,1 (แนวตั้งหรือแนวนอน)
  4. เลื่อนไปที่คำถัดไปวนซ้ำตัวอักษรแต่ละตัวในคำนั้นและแต่ละเซลล์ในตารางเพื่อค้นหาตัวอักษรที่ตรงกัน
  5. เมื่อพบการจับคู่เพียงเพิ่มตำแหน่งนั้นในรายการพิกัดที่แนะนำสำหรับคำนั้น
  6. วนรอบรายการพิกัดที่แนะนำและ "ให้คะแนน" ตำแหน่งคำตามจำนวนคำอื่น ๆ ที่ข้ามไป คะแนน 0 แสดงถึงตำแหน่งที่ไม่ถูกต้อง (อยู่ติดกับคำที่มีอยู่) หรือไม่มีคำใด ๆ ข้าม
  7. กลับไปที่ขั้นตอน # 4 จนกว่ารายการคำจะหมด บัตรผ่านที่สองไม่บังคับ
  8. ตอนนี้เราควรมีคำไขว้ แต่คุณภาพสามารถตีหรือพลาดได้เนื่องจากตำแหน่งสุ่มบางตำแหน่ง ดังนั้นเราจึงบัฟเฟอร์คำไขว้นี้และกลับไปที่ขั้นตอนที่ 2 หากคำไขว้ถัดไปมีคำอื่น ๆ วางอยู่บนกระดานคำไขว้จะแทนที่คำไขว้ในบัฟเฟอร์ เวลานี้ จำกัด (ค้นหาคำไขว้ที่ดีที่สุดใน x วินาที)

ในตอนท้ายคุณมีปริศนาอักษรไขว้ที่ดีหรือปริศนาค้นหาคำศัพท์เนื่องจากเป็นปริศนาเดียวกัน มีแนวโน้มที่จะทำงานได้ค่อนข้างดี แต่โปรดแจ้งให้เราทราบหากคุณมีข้อเสนอแนะเกี่ยวกับการปรับปรุง กริดที่ใหญ่กว่าจะทำงานช้าลงอย่างทวีคูณ คำที่ใหญ่กว่าแสดงรายการเชิงเส้น รายการคำที่ใหญ่กว่ายังมีโอกาสสูงกว่ามากที่จะได้หมายเลขตำแหน่งคำที่ดีกว่า


@Neil N: น่าจะเป็นความเป็นไปได้ในการจับคู่ตัวอักษรที่ดีกว่าสำหรับคำอื่น ๆ อาจเป็นแนวทางในการจัดเรียงตามจำนวนตัวอักษรที่แตกต่างกันที่มีอยู่ต่อคำซึ่งส่วนใหญ่จะนำไปสู่ผลลัพธ์เดียวกัน
Karl Adler

@NeilN Python array.sort(key=f)มีเสถียรภาพซึ่งหมายความว่า (เช่น) การจัดเรียงรายการคำตามตัวอักษรตามความยาวจะทำให้คำ 8 ตัวอักษรทั้งหมดเรียงตามตัวอักษร
Lynn

4
@ ไบรอันลิงก์เว็บไซต์ของคุณใช้ไม่ได้สำหรับฉันและโดเมนหลักเพิ่งเปลี่ยนเส้นทางไปที่ Twitter คุณมีลิงก์ที่อัปเดตไปยังรหัสของคุณหรือไม่?
Michael A

2
นี่คือ (เห็นได้ชัด) โคลนของเครื่องกำเนิดไฟฟ้าของไบรอัน: github.com/jeremy886/crossword_helmig
lvictorino

20

จริงๆแล้วฉันเขียนโปรแกรมสร้างคำไขว้เมื่อสิบปีที่แล้ว (มันเป็นความลับ แต่กฎเดียวกันจะใช้กับปริศนาอักษรไขว้ปกติ)

มีรายการคำ (และเบาะแสที่เกี่ยวข้อง) เก็บไว้ในไฟล์โดยเรียงลำดับตามการใช้งานจากมากไปหาน้อยจนถึงปัจจุบัน (เพื่อให้คำที่ใช้น้อยอยู่ที่ด้านบนของไฟล์) เทมเพลตซึ่งโดยพื้นฐานแล้วเป็นรูปแบบบิตที่แสดงถึงสี่เหลี่ยมสีดำและฟรีนั้นถูกเลือกแบบสุ่มจากพูลที่ลูกค้าให้มา

จากนั้นสำหรับแต่ละคำที่ไม่สมบูรณ์ในปริศนา (โดยทั่วไปให้ค้นหาช่องสี่เหลี่ยมว่างแรกและดูว่าคำที่อยู่ทางขวา (ข้ามคำ) หรือคำที่อยู่ด้านล่าง (คำลง) ว่างเปล่าเช่นกัน) จะทำการค้นหา ไฟล์ที่มองหาคำแรกที่พอดีโดยคำนึงถึงตัวอักษรที่มีอยู่แล้วในคำนั้น หากไม่มีคำใดที่เหมาะสมคุณเพียงทำเครื่องหมายว่าทั้งคำไม่สมบูรณ์และดำเนินการต่อไป

ในตอนท้ายจะเป็นคำที่ยังไม่สมบูรณ์ซึ่งคอมไพเลอร์จะต้องกรอก (และเพิ่มคำและเบาะแสลงในไฟล์หากต้องการ) หากพวกเขาไม่สามารถคิดแนวคิดใด ๆ ได้พวกเขาสามารถแก้ไขคำไขว้ด้วยตนเองเพื่อเปลี่ยนข้อ จำกัด หรือเพียงแค่ขอการสร้างใหม่ทั้งหมด

เมื่อไฟล์ word / clue มีขนาดที่กำหนด (และเพิ่ม 50-100 เบาะแสต่อวันสำหรับลูกค้ารายนี้) ไม่ค่อยมีกรณีที่ต้องแก้ไขด้วยตนเองมากกว่าสองหรือสามรายการสำหรับคำไขว้แต่ละคำ .


สิ่งนี้ไม่ได้ช่วยฉันในสถานการณ์ของฉันจริงๆเนื่องจากฉันมีรายการคำประมาณ 6-12 คำเท่านั้น Mine เป็นเหมือนแบบฝึกหัดการเรียนรู้สำหรับผู้ใช้มากกว่าปริศนาคำศัพท์ +1 สำหรับอัลกอริทึมที่น่าสนใจอย่างไรก็ตาม!
nickf

1
คำอธิบายที่ดี ฉันคิดถึงเรื่องนี้สองสามครั้งในอดีต แต่ไม่เคยลองเลย ตอนนี้สำหรับคำถามมหัศจรรย์: มันทำงานได้ดีแค่ไหน? สำหรับปริศนาที่เบาบางหรือสำหรับปริศนาที่หนาแน่น (เช่นในกระดาษ)? และคุณต้องการเบาะแสสำหรับปริศนาที่หนาแน่นมากแค่ไหน?
dmckee --- อดีตผู้ดูแลลูกแมว

1
@dmckee เมื่อสักครู่ที่ผ่านมา แต่จากความทรงจำแม้แต่ปริศนาที่หนาแน่นก็ค่อนข้างดี หลายคนเสร็จสมบูรณ์โดยไม่มีการแทรกแซง แต่คุณอาจจะยังคงได้หนึ่งในห้าที่ต้องเพิ่มหนึ่งหรือสองคำเพิ่มเติม และเรากำลังพูดถึงคำหลายพันคำในไฟล์ ไม่ต้องสงสัยเลยว่าการย้อนรอยสามารถช่วยได้ แต่มันง่ายกว่าสำหรับลูกค้าที่จะปฏิเสธคำที่มี (เช่น) 5 คำที่ยังไม่เสร็จดีกว่าไม่ต้องกังวลกับการพยายามหาเบาะแสเพิ่มเติม ห้าเป็นเรื่องเกี่ยวกับขีด จำกัด ภายนอกที่ฉันเห็นสำหรับคำที่ยังไม่เสร็จ
paxdiablo

16

อัลกอริทึมนี้สร้างปริศนาอักษรไขว้ลูกศร 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)

11

แม้ว่านี่จะเป็นคำถามที่เก่ากว่า แต่ก็จะพยายามหาคำตอบจากงานที่คล้ายกันที่ฉันเคยทำ

มีหลายวิธีในการแก้ปัญหาข้อ จำกัด (ซึ่ง Generallay อยู่ในระดับความซับซ้อนของ NPC)

สิ่งนี้เกี่ยวข้องกับการเพิ่มประสิทธิภาพคอมบิเนเตอร์และการเขียนโปรแกรมข้อ จำกัด ในกรณีนี้ข้อ จำกัด คือเรขาคณิตของเส้นตารางและข้อกำหนดที่ว่าคำไม่ซ้ำกันเป็นต้น

วิธีการสุ่ม / การหลอมยังสามารถใช้งานได้ (แม้ว่าจะอยู่ในการตั้งค่าที่เหมาะสมก็ตาม)

ความเรียบง่ายอย่างมีประสิทธิภาพอาจเป็นภูมิปัญญาขั้นสูงสุด!

ข้อกำหนดมีไว้สำหรับคอมไพเลอร์คำไขว้ที่สมบูรณ์มากขึ้นหรือน้อยลงและตัวสร้าง (วิชวล WYSIWYG)

ออกจากส่วนตัวสร้าง WYSIWYG โครงร่างของคอมไพเลอร์คือ:

  1. โหลดรายการคำที่มีอยู่ (เรียงตามความยาวของคำเช่น 2,3, .. , 20)

  2. ค้นหาช่องคำ (เช่นคำในตาราง) บนเส้นตารางที่ผู้ใช้สร้างขึ้น (เช่นคำที่ x, y ที่มีความยาว L แนวนอนหรือแนวตั้ง) (ความซับซ้อน O (N))

  3. คำนวณจุดตัดกันของคำในตาราง (ที่ต้องเติม) (ความซับซ้อน O (N ^ 2))

  4. คำนวณการตัดกันของคำในรายการคำด้วยตัวอักษรต่างๆของตัวอักษรที่ใช้ (ซึ่งช่วยให้สามารถค้นหาคำที่ตรงกันโดยใช้เทมเพลตเช่นวิทยานิพนธ์ Sik Cambon ที่ใช้โดย cwc ) (ความซับซ้อน O (WL * AL))

ขั้นตอนที่. 3 และ. 4 อนุญาตให้ทำงานนี้:

การตัดกันของคำในตารางด้วยตัวมันเองทำให้สามารถสร้าง "แม่แบบ" สำหรับพยายามค้นหาคำที่ตรงกันในรายการคำที่เกี่ยวข้องของคำที่มีอยู่สำหรับคำตารางนี้ (โดยใช้ตัวอักษรของคำที่ตัดกันอื่น ๆ กับคำนี้ซึ่งเติมเต็มแล้วในบางคำ ขั้นตอนของอัลกอริทึม)

ข จุดตัดของคำในรายการคำที่มีตัวอักษรช่วยให้สามารถค้นหาคำที่ตรงกัน (ตัวเลือก) ที่ตรงกับ "แม่แบบ" ที่กำหนด (เช่น 'A' ในอันดับที่ 1 และ 'B' ในอันดับที่ 3 เป็นต้น)

ดังนั้นด้วยโครงสร้างข้อมูลเหล่านี้จึงใช้อัลกอริทึมที่ใช้จึงเป็นดังนี้:

หมายเหตุ: หากกริดและฐานข้อมูลของคำคงที่ขั้นตอนก่อนหน้านี้สามารถทำได้เพียงครั้งเดียว

  1. ขั้นตอนแรกของอัลกอริทึมคือเลือกช่องคำว่าง (คำตาราง) โดยการสุ่มและเติมด้วยคำที่เป็นตัวเลือกจากรายการคำที่เกี่ยวข้อง (การสุ่มช่วยให้สามารถสร้างตัวทำละลายที่แตกต่างกันในการดำเนินการต่อเนื่องกันของอัลกอริทึม) (ความซับซ้อน O (1) หรือ O ( N))

  2. สำหรับช่องคำที่ยังว่างแต่ละช่อง (ที่มีจุดตัดกับช่องคำที่เติมไว้แล้ว) ให้คำนวณอัตราส่วนข้อ จำกัด (ซึ่งอาจแตกต่างกันไป sth แบบง่ายคือจำนวนโซลูชันที่มีอยู่ในขั้นตอนนั้น) และจัดเรียงช่องคำว่างตามอัตราส่วนนี้ (ความซับซ้อน O (NlogN ) หรือ O (N))

  3. วนรอบช่องคำว่างที่คำนวณในขั้นตอนก่อนหน้าและลองใช้วิธีแก้ปัญหา cancdidate จำนวนหนึ่ง (ตรวจสอบให้แน่ใจว่า "คงความสอดคล้องของส่วนโค้งไว้" กล่าวคือกริดมีวิธีแก้ปัญหาหลังจากขั้นตอนนี้หากใช้คำนี้) และเรียงลำดับตาม ความพร้อมใช้งานสูงสุดสำหรับขั้นตอนต่อไป (เช่นขั้นตอนต่อไปมีวิธีแก้ปัญหาสูงสุดที่เป็นไปได้หากมีการใช้คำนี้ในเวลานั้นในสถานที่นั้นเป็นต้น) (ความซับซ้อน O (N * MaxCandidatesUsed))

  4. เติมคำนั้น (ทำเครื่องหมายว่าเติมแล้วไปที่ขั้นตอนที่ 2)

  5. หากไม่พบคำที่ตรงตามเกณฑ์ของขั้นตอนที่ 3 ให้ลองย้อนกลับไปยังโซลูชันอื่นของขั้นตอนก่อนหน้า (เกณฑ์อาจแตกต่างกันไปที่นี่) (ความซับซ้อน O (N))

  6. หากพบแบ็กแทร็กให้ใช้ตัวเลือกอื่นและรีเซ็ตคำที่เติมไปแล้วซึ่งอาจต้องรีเซ็ต (ทำเครื่องหมายว่ายังไม่ได้เติมอีกครั้ง) (ความซับซ้อน O (N))

  7. หากไม่พบ backtrack จะไม่พบวิธีแก้ปัญหาใด ๆ (อย่างน้อยก็มีการกำหนดค่านี้ initial seed เป็นต้น)

  8. อื่น ๆ เมื่อเติมคำศัพท์ทั้งหมดคุณจะมีทางออกเดียว

อัลกอริทึมนี้จะทำการเดินแบบสุ่มที่สอดคล้องกันของแผนผังวิธีการแก้ปัญหา หากในบางจุดมีทางตันมันจะย้อนกลับไปยังโหนดก่อนหน้าและไปตามเส้นทางอื่น จนกว่าโซลูชันที่พบหรือจำนวนผู้สมัครสำหรับโหนดต่างๆจะหมดลง

ส่วนที่สอดคล้องกันทำให้แน่ใจว่าโซลูชันที่พบเป็นโซลูชันจริงและส่วนที่สุ่มช่วยให้สามารถสร้างโซลูชันที่แตกต่างกันในการดำเนินการที่แตกต่างกันและโดยเฉลี่ยแล้วมีประสิทธิภาพที่ดีขึ้น

PS ทั้งหมดนี้ (และอื่น ๆ ) ถูกนำไปใช้ใน JavaScript บริสุทธิ์ (พร้อมการประมวลผลแบบขนานและความสามารถ WYSIWYG)

PS2 อัลกอริทึมสามารถขนานกันได้อย่างง่ายดายเพื่อสร้างโซลูชันมากกว่าหนึ่ง (ที่แตกต่างกัน) ในเวลาเดียวกัน

หวังว่านี่จะช่วยได้


1
นี่คือการสร้างเลย์เอาต์ที่หนาแน่น (NY Times like) หรือเลย์เอาต์แบบเบาบาง?
จิม

1
@ Jim นี่เป็นส่วนใหญ่สำหรับเลย์เอาต์ที่หนาแน่น แต่สามารถปรับให้เบาบางได้เช่นกัน ความแตกต่างอยู่ในรูปแบบที่หนาแน่น (เช่นคลาสสิกสแกนดินาวิคเป็นต้น) หนึ่งมีกริดและค้นหาคำในขณะที่เลย์เอาต์รูปแบบอิสระ (เบาบาง) บนมีคำและค้นหาตาราง
Nikos M.

1
คุณจะมีแหล่งตัวอย่างบางแห่งที่ดำเนินการตามขั้นตอนข้างต้นหรือไม่ ยกตัวอย่างเช่นผมกับคุณมากที่สุดของมัน (และมีอยู่แล้วนำมาใช้มากที่สุดของมันอิสระ) แต่เมื่อมันมาถึง "คำนวณอัตราส่วน จำกัด ..." ผมต้องยอมรับคุณสูญเสียผม การค้นหาสิ่งต่างๆในเว็บเช่น "STH Ratio" ก็ไม่ได้ช่วยอะไรฉันมากนักเช่นกัน ปัญหาในการใช้งานของฉันคือการพยายามค้นหาคำที่จะเติมนั้นไม่มีประสิทธิภาพมากและใช้เวลานานเกินไป
จิม

1
@ จิมฉันมีตามที่ใช้ไปแล้ว แต่สิ่งนี้ทำได้โดยเฉพาะสำหรับงานที่ฉันมีเป็นไปได้ฉันจะโพสต์เวอร์ชันที่มีน้ำหนักเบาในโครงการโอเพ่นซอร์สของฉันหากคุณต้องการความช่วยเหลือเพิ่มเติมโปรดติดต่อฉัน (ps แน่นอนที่ บางกรณีอัลกอริทึมที่ฉันโพสต์อาจใช้เวลานานเกินไป แต่โดยเฉลี่ยแล้วไม่ได้)
Nikos M.

1
@ Jim ดูไซต์ปริศนาอักษรไขว้นี้ (ยังอยู่ระหว่างดำเนินการ) istavrolexo.gr (ในภาษากรีก) ที่มีปริศนาอักษรไขว้ (หนาแน่น) (เช่นสแกนดินาวิคคลาสสิกซูโดกุ) ซึ่งสร้างขึ้นโดยอัลกอริทึมที่คล้ายกัน ( คำไขว้สแกนดิเนวิกขนาดใหญ่ )
Nikos M.

9

ทำไมไม่ใช้วิธีการสุ่มที่น่าจะเป็นเริ่มต้นด้วย เริ่มต้นด้วยคำจากนั้นเลือกคำสุ่มซ้ำ ๆ และพยายามทำให้พอดีกับสถานะปัจจุบันของปริศนาโดยไม่ทำลายข้อ จำกัด เรื่องขนาด ฯลฯ หากคุณล้มเหลวให้เริ่มต้นใหม่ทั้งหมดอีกครั้ง

คุณจะแปลกใจว่าวิธีการแบบมอนติคาร์โลแบบนี้ได้ผลบ่อยแค่ไหน


2
ใช่นี่คือแนวทางที่ฉันเลือก คุณไม่จำเป็นต้องพยายามและฉลาดมาก เรียงลำดับคำจากยาวที่สุดไปหาสั้นที่สุด ในการวนรอบให้เลือกเซลล์แบบสุ่ม (พิกัดคอลัมน์และแถว) และวางคำบนการทดสอบบนกระดานเพื่อดูว่ามันวิ่งออกจากจุดสิ้นสุดหรือรบกวนคำอื่น (ก่อนที่คุณจะเขียนคำลงในตารางให้ตรวจสอบว่าแต่ละเซลล์เป็นอย่างใดอย่างหนึ่ง ว่างเปล่าหรือถ้ามีตัวอักษรตัวอักษรนั้นจะตรงกับตัวอักษรที่คุณพยายามเขียน) มีตรรกะอื่น ๆ ในการตรวจสอบขอบเขตและสิ่งต่างๆ ฉันกำลังเดรัจฉานสร้างเส้นกริดที่เล็กลงและเล็กลงจากนั้นจัดอันดับที่เล็กที่สุดตามคำที่ตัดกัน
Max Hodges

6

นี่คือโค้ด 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();
}

สคีมาออบเจ็กต์คำขาดหายไปโปรดระบุ wordArray
เช่น

แท้จริงแล้วเป็นเพียงคำต่างๆเช่น ['apple', 'orange', 'pear']
FascistDonut

สวัสดี FYI การแก้ไขของฉันไม่ได้เปลี่ยนรหัสมากนักมันแค่จัดรูปแบบ ฉันรู้ว่ามันดูยุ่งมากเมื่อดู "แบบอินไลน์" แต่ถ้าคุณต้องการเห็นการเปลี่ยนแปลงที่แท้จริงของโค้ดให้คลิก 'side-by-side-markdown' อืม ... ฉันควรจะเขียน "Formatted code" ในคำอธิบายการแก้ไข แต่ฉัน
เสียงบี๊บสองครั้ง

วิธีนี้ทำงานอย่างไร? คุณสามารถจัดเตรียมไฟล์ html ที่มี javascript นี้ได้หรือไม่?
GKS

5

ฉันจะสร้างตัวเลขสองตัว: ความยาวและคะแนน Scrabble สมมติว่าคะแนน Scrabble ต่ำหมายความว่าง่ายต่อการเข้าร่วม (คะแนนต่ำ = ตัวอักษรทั่วไปจำนวนมาก) จัดเรียงรายการตามความยาวจากมากไปหาน้อยและคะแนน Scrabble จากน้อยไปมาก

จากนั้นไปที่รายการ ถ้าคำนั้นไม่ข้ามกับคำที่มีอยู่ (ตรวจสอบแต่ละคำตามความยาวและคะแนน Scrabble ตามลำดับ) จากนั้นใส่ลงในคิวและตรวจสอบคำถัดไป

ล้างและทำซ้ำและควรสร้างคำไขว้

แน่นอนฉันค่อนข้างมั่นใจว่านี่คือ O (n!) และไม่รับประกันว่าจะเติมคำไขว้ให้คุณจนเสร็จ แต่อาจมีใครสามารถปรับปรุงได้


3

ฉันคิดเกี่ยวกับปัญหานี้ ความรู้สึกของฉันคือการสร้างคำไขว้ที่หนาแน่นอย่างแท้จริงคุณไม่สามารถหวังว่ารายการคำที่ จำกัด ของคุณจะเพียงพอ ดังนั้นคุณอาจต้องการใช้พจนานุกรมและวางไว้ในโครงสร้างข้อมูล "trie" วิธีนี้จะช่วยให้คุณค้นหาคำที่เติมช่องว่างที่เหลือได้อย่างง่ายดาย ใน Trie มีประสิทธิภาพพอสมควรในการใช้การส่งผ่านที่ให้คำทั้งหมดในรูปแบบ "c? t"

ดังนั้นความคิดทั่วไปของฉันคือสร้างแนวทางการบังคับที่ค่อนข้างดุร้ายตามที่บางคนอธิบายไว้ที่นี่เพื่อสร้างกากบาทที่มีความหนาแน่นต่ำและเติมคำในพจนานุกรมลงในช่องว่าง

หากใครใช้แนวทางนี้อีกโปรดแจ้งให้เราทราบ


3

ฉันเล่นกับเครื่องมือสร้างปริศนาอักษรไขว้และฉันพบว่าสิ่งนี้สำคัญที่สุด:

0!/usr/bin/python

  1. allwords.sort(key=len, reverse=True)

    ข สร้างรายการ / วัตถุบางอย่างเช่นเคอร์เซอร์ซึ่งจะเดินไปรอบ ๆ เมทริกซ์เพื่อการวางแนวที่ง่ายเว้นแต่คุณต้องการทำซ้ำโดยตัวเลือกแบบสุ่มในภายหลัง

  2. อันดับแรกหยิบคู่แรกและวางขวางและลงจาก 0,0; จัดเก็บอันแรกเป็น 'ผู้นำ' คำไขว้ปัจจุบันของเรา

  3. เลื่อนเคอร์เซอร์ตามลำดับในแนวทแยงหรือสุ่มโดยมีความน่าจะเป็นในแนวทแยงมากกว่าไปยังเซลล์ว่างถัดไป

  4. ย้ำคำเช่นและใช้ความยาวพื้นที่ว่างเพื่อกำหนดความยาวของคำสูงสุด: 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 )

  5. เพื่อเปรียบเทียบคำกับพื้นที่ว่างที่ฉันใช้เช่น:

    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
    
  6. หลังจากใช้คำแต่ละคำสำเร็จแล้วให้เปลี่ยนทิศทาง วนซ้ำในขณะที่เซลล์ทั้งหมดเต็มไปหมดหรือคุณหมดคำหรือด้วยการ จำกัด การวนซ้ำแล้ว:

# CHANGE ALL WORDS LIST inexOf1stWord = allwords.index( leading_w ) allwords = allwords[:inexOf1stWord+1][:] + allwords[inexOf1stWord+1:][:]

... และย้ำอีกครั้งคำไขว้ใหม่

  1. สร้างระบบการให้คะแนนด้วยความง่ายในการกรอกข้อมูลและการคำนวณการประมาณค่าบางส่วน ให้คะแนนสำหรับคำไขว้ปัจจุบันและ จำกัด ตัวเลือกในภายหลังโดยผนวกเข้าในรายการปริศนาอักษรไขว้ที่สร้างขึ้นหากคะแนนเป็นที่พอใจของระบบการให้คะแนนของคุณ

  2. หลังจากเซสชันการทำซ้ำครั้งแรกให้วนซ้ำอีกครั้งจากรายการปริศนาอักษรไขว้ที่สร้างไว้เพื่อทำงานให้เสร็จ

โดยการใช้พารามิเตอร์ความเร็วมากขึ้นสามารถปรับปรุงได้โดยปัจจัยใหญ่


2

ฉันจะได้รับดัชนีของตัวอักษรแต่ละตัวที่ใช้โดยแต่ละคำเพื่อทราบเครื่องหมายกากบาทที่เป็นไปได้ จากนั้นฉันจะเลือกคำที่ใหญ่ที่สุดและใช้เป็นฐาน เลือกขนาดใหญ่ถัดไปและข้ามมัน ล้างและทำซ้ำ มันน่าจะเป็นปัญหา NP

อีกแนวคิดหนึ่งคือการสร้างอัลกอริทึมทางพันธุกรรมโดยที่เมตริกความแรงคือจำนวนคำที่คุณสามารถใส่ลงในตารางได้

ส่วนที่ยากที่ฉันพบคือเมื่อรู้ว่ารายการบางรายการไม่สามารถข้ามได้


1
ฉันยังคิดถึงขั้นตอนวิธีทางพันธุกรรม ฟังก์ชั่นการออกกำลังกายอาจเป็นคำที่บรรจุลงในตารางได้แน่นแค่ไหน
Adrian McCarthy

2

สิ่งนี้ปรากฏเป็นโครงการในหลักสูตร AI CS50จาก Harvard แนวคิดคือการกำหนดปัญหาการสร้างคำไขว้เป็นปัญหาความพึงพอใจที่มีข้อ จำกัด และแก้ปัญหาด้วยการย้อนกลับด้วยการวิเคราะห์พฤติกรรมที่แตกต่างกันเพื่อลดพื้นที่ในการค้นหา

ในการเริ่มต้นเราต้องมีไฟล์อินพุตสองสามไฟล์:

  1. โครงสร้างของปริศนาอักษรไขว้ (ซึ่งมีลักษณะเหมือนตัวต่อไปนี้เช่นโดยที่ '#' หมายถึงอักขระที่ไม่ต้องเติมและ '_' หมายถึงอักขระที่จะเติม)

`

###_####_#
____####_#
_##_#_____
_##_#_##_#
______####
#_###_####
#_##______
#_###_##_#
_____###_#
#_######_#
##_______#    

`

  1. คำศัพท์ที่ป้อน (รายการคำศัพท์ / พจนานุกรม) ซึ่งจะเลือกคำที่เป็นตัวเลือก (เช่นเดียวกับที่แสดงต่อไปนี้)

    a abandon ability able abortion about above abroad absence absolute absolutely ...

ตอนนี้ CSP ได้รับการกำหนดและจะแก้ไขดังนี้:

  1. ตัวแปรถูกกำหนดให้มีค่า (เช่นโดเมน) จากรายการคำ (คำศัพท์) ที่ระบุเป็นอินพุต
  2. ตัวแปรแต่ละตัวจะแสดงด้วย 3 ทูเปิล: (grid_coordinate, ทิศทาง, ความยาว) โดยที่พิกัดแสดงถึงจุดเริ่มต้นของคำที่เกี่ยวข้องทิศทางอาจเป็นแนวนอนหรือแนวตั้งและความยาวจะถูกกำหนดเป็นความยาวของคำที่ตัวแปรจะเป็น ได้รับมอบหมายให้.
  3. ข้อ จำกัด ถูกกำหนดโดยอินพุตโครงสร้างที่ให้ไว้: ตัวอย่างเช่นหากตัวแปรแนวนอนและแนวตั้งมีอักขระร่วมกันข้อ จำกัด นั้นจะแสดงเป็นข้อ จำกัด ที่ทับซ้อนกัน (ส่วนโค้ง)
  4. ตอนนี้ความสอดคล้องของโหนดและอัลกอริธึมความสอดคล้องของส่วนโค้ง AC3 สามารถใช้เพื่อลดโดเมนได้
  5. จากนั้นย้อนรอยเพื่อรับโซลูชัน (ถ้ามี) ไปยัง CSP ด้วย MRV (ค่าที่เหลือต่ำสุด) องศา ฯลฯ สามารถใช้การวิเคราะห์พฤติกรรมเพื่อเลือกตัวแปรที่ไม่ได้กำหนดถัดไปและการวิเคราะห์พฤติกรรมเช่น LCV (ค่า จำกัด น้อยที่สุด) สามารถใช้สำหรับโดเมน - การสั่งซื้อเพื่อให้อัลกอริทึมการค้นหาเร็วขึ้น

ต่อไปนี้แสดงผลลัพธ์ที่ได้รับจากการใช้อัลกอริทึมการแก้ 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█

`

ภาพเคลื่อนไหวต่อไปนี้แสดงขั้นตอนการย้อนรอย:

ใส่คำอธิบายภาพที่นี่

นี่คืออีกคำหนึ่งที่มีรายการคำภาษาบางลา (เบงกาลี):

ใส่คำอธิบายภาพที่นี่


+1 สำหรับคำอธิบายที่น่าสนใจจริงๆ อย่างไรก็ตามบริบทของปัญหาที่ฉันพยายามแก้ไขที่นี่คือมีคำชุดเล็ก ๆ ที่ต้องใช้ทั้งหมดและฉันพยายามหาเค้าโครงที่เหมาะสมที่สุดสำหรับคำไขว้แทนที่จะเริ่มต้นด้วยเค้าโครงและค้นหาคำ ที่พอดี
nickf

1

jQuery Crossword Puzzle Generator และเกม

ฉันได้เขียนโค้ดวิธีแก้ปัญหา JavaScript / jQuery สำหรับปัญหานี้:

ตัวอย่างการสาธิต: http://www.earthfluent.com/crossword-puzzle-demo.html

รหัสที่มา: https://github.com/HoldOffHunger/jquery-crossword-puzzle-generator

วัตถุประสงค์ของอัลกอริทึมที่ฉันใช้:

  1. ลดจำนวนสี่เหลี่ยมที่ใช้ไม่ได้ในตารางให้มากที่สุด
  2. มีคำผสมระหว่างกันให้มากที่สุด
  3. คำนวณในเวลาที่รวดเร็วมาก

การสาธิตปริศนาอักษรไขว้ที่สร้างขึ้น

ฉันจะอธิบายอัลกอริทึมที่ฉันใช้:

  1. จัดกลุ่มคำเข้าด้วยกันตามคำที่ใช้อักษรทั่วไป

  2. จากกลุ่มเหล่านี้ให้สร้างชุดของโครงสร้างข้อมูลใหม่ ("บล็อกคำ") ซึ่งเป็นคำหลัก (ที่วิ่งผ่านคำอื่น ๆ ทั้งหมด) และคำอื่น ๆ (ที่วิ่งผ่านคำหลัก)

  3. เริ่มไขปริศนาอักษรไขว้ด้วยบล็อกคำศัพท์ตัวแรกในตำแหน่งซ้ายบนสุดของปริศนาอักษรไขว้

  4. สำหรับส่วนที่เหลือของบล็อกคำเริ่มจากตำแหน่งขวาล่างสุดของปริศนาอักษรไขว้เลื่อนขึ้นไปทางซ้ายจนกว่าจะไม่มีช่องว่างให้เติม หากมีคอลัมน์ว่างมากกว่าด้านซ้ายให้เลื่อนขึ้นและในทางกลับกัน


@holdoffhunger คุณมีวิธีการแสดงคีย์เวิร์ดหรือไม่? กล่องที่เต็มไปด้วยตัวอักษร?
Jon Glazer

@ จอนเกล: โดยปกติแล้วคุณส่งคีย์ไขว้กับการทำงานของตัวเอง แต่คุณสามารถเข้าสู่ระบบไขว้เป็น 2d-array var crosswords = generateCrosswordBlockSources(puzzlewords);ของตัวอักษรขวาหลังจากที่ เพียงคอนโซลบันทึกค่านี้ อย่าลืมว่ามี "โหมดโกง" ในเกมซึ่งคุณสามารถคลิก "เปิดเผยคำตอบ" เพื่อรับมูลค่าได้ทันที
HoldOffHunger

สิ่งนี้ทำให้เกิดปริศนาที่มีคำที่ไม่เหมาะสม "ข้าม" ในสถานที่ที่มีช่อง "ลง" ที่อยู่ติดกันและในทางกลับกัน ปริศนาคำไขว้มาตรฐานไม่ทำงานเช่นนี้แม้ว่าจะเพิ่มความหนาแน่นสูงสุด
Beejor
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.