ฉันจะหาคำที่ถูกต้องในตารางตัวละครได้อย่างไร


12

ฉันกำลังสร้างเกมที่คล้ายคลึงกับ Tetris โดยมีความแตกต่างที่สำคัญสองประการ: หน้าจอเริ่มเต็มไปด้วยกระเบื้อง (เช่นใน Puzzle Quest สำหรับ Nintendo DS และพีซี) และแต่ละไพ่มีตัวอักษรอยู่ในนั้น เป้าหมายของผู้เล่นคือการกำจัดไพ่โดยสร้างคำที่ถูกต้องกับพวกเขา คำที่เกิดขึ้นโดยการวางตัวอักษรติดกันในทิศทางใด ๆ ยกเว้นแนวทแยงมุม

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

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


น่าเสียดายที่คุณพูดถูก มันช้ามากเนื่องจากตัวเลข (รวมกันทั้งหมด 3, 4, 5, ... 25 ตัวอักษร) อาจ จำกัด ไว้ที่ "คำต้องเรียงตามแนวนอนหรือแนวตั้ง" เพื่อปรับปรุงประสิทธิภาพ (และไม่ได้คำสุ่มที่ทำให้ผู้เล่นไม่เห็น)?
ashes999

ฉันคิดว่าคุณต้องดูอัลกอริทึมของคุณอีกครั้งซึ่งตรงกับลำดับของอักขระกับคำ โดยการนับของฉันตาราง 5x5 จะมี 2700 คำที่เป็นไปได้ซึ่งอัลกอริทึมของคุณควรจะผ่านดูตัวอย่างเช่นคำตอบของ Josh
Taemyr

ฉันมาที่ 2700 คำในลักษณะดังต่อไปนี้ เริ่มด้วยคำซ้ายไปขวาในแถวแรก มี 1 ตำแหน่งที่คำ 5 ตัวอักษร, 2 4 คำตัวอักษร, 3 3 คำตัวอักษร, 4 2 คำตัวอักษรและ 5 1 คำตัวอักษร เราสามารถแลกเปลี่ยนตัวอักษรตัวใดตัวหนึ่งในคำสำหรับตัวอักษรจากคอลัมน์อื่น เราสามารถทำได้โดยไม่สูญเสียความคิดทั่วไปว่าไม่มีการแลกเปลี่ยนตัวอักษรสำหรับคำ 1 ตัวอักษรและตัวอักษรตัวแรกไม่ได้แลกเปลี่ยนสำหรับคำ 2 ตัวอักษร สิ่งนี้จะช่วยให้; 5 * 5 * 1 + 4 * 5 * 2 + 3 * 5 * 3 + 1 * 5 * 4 + 1 = 135 คูณด้วยจำนวนแถวและเส้นทาง 135 * 5 * 4 = 2700
Taemyr

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

@Tavio ความคิดบางอย่าง: การตรวจสอบควรไปอีกคำก่อน (ถ้าฉันทำ "กัน" ฉันไม่ต้องการ "เป็น" นอกจากนี้คำตัวอักษรเดียวอาจจะดีกว่าละเว้นมิฉะนั้นคุณจะไม่สามารถใช้ของใด ๆ เมื่อเสร็จแล้วฉันต้องการทราบชื่อที่คุณให้กับเกมนี้เพื่อให้ฉันสามารถตรวจสอบได้
David Starkey

คำตอบ:


22

กำลังดุร้ายไม่ใช่วิธีเดียว

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

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

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

    0        The root of the trie is the empty string here, although you 
    |        can implement the structure differently if you want.
    c
   / \ 
  a   e
 / \   \
t  r    l
         \
          l

ดังนั้นเริ่มต้นด้วยการเติมคำนำหน้าต้นไม้ด้วยคำที่ถูกต้องทุกคำในเกมของคุณ

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

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

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


กำลังดุร้ายไม่ใช่วิธีเดียวที่คุณอธิบายตัวเอง :) มีคำนำหน้ามากมายที่บอกเป็นนัย ๆ ว่าไม่มีจุดที่จะมองต่อไป (ส่วนใหญ่ [สุ่ม] สตริงไม่ใช่คำ +1
AturSams

คำตอบที่ดี "คำว่า" คืออะไรก็ได้ในพจนานุกรมของเกม
Adam Eberbach

OP ระบุว่าเขามีอัลกอริทึมเพื่อจับคู่คำกับสตริงอักขระ ดังนั้นฉันไม่คิดว่านี่จะตอบคำถามได้
Taemyr

OTOH ฉันคิดว่า OP จะต้องการอัลกอริทึมการจับคู่สตริงที่มีประสิทธิภาพมากกว่าสิ่งที่เขามีอยู่ในปัจจุบัน
Taemyr

1
@Taemyr ใช้ trie ธรรมดาแล้วใช่ แต่สามารถใช้อัลกอริทึม Aho-Corasick ซึ่งใช้ trie ที่ปรับเปลี่ยนเล็กน้อยมีประสิทธิภาพมากขึ้น (เชิงเส้น) ด้วยอัลกอริทึม Aho-Corasick เราสามารถค้นหาคำที่ถูกต้องทั้งหมดในเมทริกซ์ nxn ในเวลา O (n ^ 2)
el.pescado

3

คุณอาจลองทำสิ่งนี้แล้วนำไปใช้แล้วอาจมีคำตอบอื่นดีกว่า ฯลฯ แต่ฉันไม่เห็นพวกเขาพูดถึง (ยัง) ดังนั้นนี่คือ:

คุณสามารถยกเลิกการตรวจสอบจำนวนมากได้โดยการติดตามสิ่งที่เปลี่ยนแปลงและสิ่งที่ไม่ได้ทำ ตัวอย่างเช่น:

On a 5x5 field, A vertical word is found on base of the third column,
All the rows change. However, the first, second, fourth, and fifth,
columns do not change, so you dont need to worry about them (the third did change.)

On a 5x5 field, A 3 letter word is found horizontally on row 2, column 3, to column 5.
So you need to check row 1 and 2 (row 1 because the words on that one
fell down and where replaced), as-well as columns 3, 4, and 5.

หรือในรหัส psudo

// update the board

// and check
if (vertical_word)
{
    check(updated_column)

    for (i in range 0 to updated_row_base)
        check(i)
}
else // horizontal word
{
    for (i in range 0 to updated_row)
        check(i)

    for (i in range 0 to updated_column_start)
        check(i)

    for (i in range updated_column_end+1 to final_column)
        check(i)
}

และคำถามเล็ก ๆ น้อย ๆ :

คุณได้ตั้งค่าการปรับแต่งความเร็วของคอมไพเลอร์แล้วหรือยัง? (ถ้าคุณใช้)

อัลกอริทึมการค้นหาคำของคุณสามารถปรับให้เหมาะสมได้ทั้งหมดหรือไม่? ในทางใดทางหนึ่ง?


ยกเว้นว่าผู้เล่นจะได้รับอนุญาตให้หมุนเวียนแถวดังนั้นการค้นหาคำในคอลัมน์ที่สามจะส่งผลต่อคอลัมน์อื่น ๆ
Taemyr

@Taemyr IF(rowMoved){ checkColumns(); checkMovedRow(); } IF(columnMoved){ checkRows() checkMovedColumn();} หากผู้ใช้สามารถย้ายทีละครั้งเท่านั้นเมื่อสิ้นสุดการย้ายนั้นจะไม่มีการเคลื่อนย้ายตัวอักษรคู่ขนานดังนั้นจึงไม่จำเป็นต้องตรวจสอบอีกครั้ง
David Starkey

2

จำไว้ว่าตัวละครทุกตัวมีค่า ดังนั้นใช้เพื่อประโยชน์ของคุณ มีฟังก์ชันแฮชบางอย่างที่สามารถคำนวณได้อย่างรวดเร็วเมื่อทำซ้ำในสตริงย่อย ตัวอย่างเช่นสมมติว่าเราให้รหัสตัวอักษร 5 บิต (ทำc - 'a' + 1ใน C) ทุกตัวอักษร:

space = 00000;
a = 00001;
c = 00011;
e = 00101;
t = 01100;

กว่าคุณจะสามารถเรียกใช้วัสดุพิมพ์ที่มีขนาดที่กำหนดได้อย่างรวดเร็ว:

a b [c a t] e t h e = 00011 00001 01100;
//Now we just remove the 5 msb and shfit the rest 5 bits left and add the new character.
a b  c [a t e] t h e = (([c a t] & 0xffff) << 5) | e; // == a t e

เราสามารถตรวจสอบวัสดุพิมพ์ได้ถึง 12 ตัวอักษรด้วยวิธีนี้กับสถาปัตยกรรมทั่วไปส่วนใหญ่ในปัจจุบัน

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

การจัดเก็บพจนานุกรมของรหัสคำที่มีอยู่ทั้งหมดไม่ควรใช้หน่วยความจำเกินสองสามเมกะไบต์


0

คุณ จำกัด เฉพาะรูปร่าง Tetris แบบคลาสสิกเมื่อสร้างคำหรือการก่อตัวใด ๆ จะทำอย่างไร คำสามารถโค้งงอไม่ จำกัด หรือเพียงครั้งเดียว? คำสามารถยาวได้เท่าที่ต้องการหรือไม่? การทำเช่นนี้ค่อนข้างซับซ้อนหากคุณสามารถโค้งได้มากเท่าที่คุณต้องการและทำให้คำที่ยาวที่สุดยาว 25 ตัวอักษร ฉันจะถือว่าคุณมีรายการคำที่ยอมรับได้ จากสมมติฐานนั้นฉันแนะนำให้คุณลองทำสิ่งนี้:

At the start of the game:
  Iterate tiles:
    Use tile as starting letter
      Store previous tile
      Check the four adjacent tiles
      If a tile can continue a word started by the previous tile, carry on
      Store the next tile
      Move check to next tile

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

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