Làm thế nào tôi có thể tìm thấy các từ hợp lệ trong một lưới các ký tự?


12

Tôi đang tạo ra một trò chơi tương tự như Tetris, với hai điểm khác biệt chính: màn hình đã bắt đầu được lấp đầy bằng các ô (như trong Puzzle Quest cho Nintendo DS và PC) và mỗi ô riêng lẻ có một chữ cái trong đó. Mục tiêu của người chơi là loại bỏ các ô bằng cách tạo thành các từ hợp lệ với chúng. Các từ được hình thành bằng cách đặt các chữ cái cạnh nhau, theo bất kỳ hướng nào, ngoại trừ theo đường chéo.

Người chơi có thể di chuyển toàn bộ một hàng gạch sang trái hoặc sang phải hoặc toàn bộ một cột gạch lên hoặc xuống, trong bao nhiêu khoảng trống mà anh ta muốn (nếu chuyển động của một hàng / cột vượt quá giới hạn của bảng, chữ cái vượt quá giới hạn sẽ "chu kỳ", xuất hiện ở đầu kia của hàng / cột). Sau hành động của người chơi, trò chơi nên kiểm tra toàn bộ bảng để tìm các từ hợp lệ và xóa các chữ cái tạo thành các từ đó khỏi bảng. Các chữ cái phía trên những chữ cái đã bị xóa sẽ rơi xuống vị trí của những chữ cái đã bị xóa và các chữ cái mới sẽ rơi từ trên cùng của màn hình cho đến khi bảng được lấp đầy trở lại.

Tôi đã viết một thuật toán tuyến tính, đưa ra một chuỗi các ký tự, xác định xem đó có phải là một từ tiếng Anh hợp lệ hay không. Vấn đề tôi đang gặp phải là: làm thế nào tôi có thể kiểm tra các từ hợp lệ trên bảng? Là vũ phu là cách duy nhất? Kiểm tra tất cả các kết hợp có thể từ bảng để xem chúng có hợp lệ hay không là rất chậm, ngay cả đối với một bảng nhỏ (5x5). Bất kỳ trợ giúp sẽ được đánh giá rất cao, cảm ơn!


Thật không may, bạn đã đúng. Nó rất chậm, vì các số (tất cả các kết hợp của 3, 4, 5, ... 25 chữ cái). Có lẽ hạn chế nó thành "các từ phải được xếp theo chiều ngang hoặc chiều dọc" để cải thiện hiệu suất (và không nhận được các từ ngẫu nhiên mà người chơi không nhìn thấy)?
tro999

Tôi nghĩ rằng bạn cần phải xem lại thuật toán của mình khớp chuỗi ký tự với từ. Theo tính toán của tôi, một lưới 5x5 sẽ có 2700 từ tiềm năng, thuật toán của bạn sẽ thông qua, xem ví dụ câu trả lời của Josh.
Taemyr

Tôi đến 2700 từ theo cách sau; bắt đầu với các từ trái sang phải trên hàng đầu tiên. Có 1 vị trí là một từ 5 chữ cái, 2 4 chữ cái, 3 3 chữ cái, 4 2 chữ cái và 5 1 chữ cái. Chúng ta có thể trao đổi một trong các chữ cái trong từ để lấy một chữ cái từ một cột khác. Chúng ta có thể không mất tính tổng quát cho rằng không có chữ cái nào được trao đổi cho 1 chữ cái và chữ cái đầu tiên không được trao đổi cho 2 chữ cái. Điều này cho; 5 * 5 * 1 + 4 * 5 * 2 + 3 * 5 * 3 + 1 * 5 * 4 + 1 = 135. Nhân với số lượng hàng và hướng; 135 * 5 * 4 = 2700
Taemyr

Tôi nghĩ rằng tôi đã không làm rõ điều này, nhưng các từ có thể được hình thành theo bất kỳ hướng nào, ngoại trừ theo đường chéo và thậm chí tạo các góc (ví dụ: ô đầu tiên từ hàng đầu tiên, sau đó đến ô thứ hai ở bên phải trên hàng đầu tiên, tiếp theo là gạch từ bên dưới trên hàng thứ hai).
Tavio

@Tavio Một số suy nghĩ: việc kiểm tra nên đi từ dài hơn trước (nếu tôi bỏ "sang một bên" tôi không muốn "là". Ngoài ra, các từ đơn có thể được bỏ qua tốt hơn, nếu không bạn sẽ không bao giờ có thể sử dụng bất kỳ từ nào. Khi kết thúc, tôi muốn biết tên bạn đặt cho trò chơi này để tôi có thể kiểm tra nó.
David Starkey

Câu trả lời:


22

Lực lượng vũ phu không phải là cách duy nhất.

Giải quyết bảng trò chơi của bạn tương tự như giải quyết một bảng Boggle , ngoại trừ đơn giản hơn. Bạn muốn kiểm tra từng ô trong bảng, tìm xem có từ nào có thể được thực hiện theo các hướng thích hợp không.

Bạn vẫn muốn tinh chỉnh không gian tìm kiếm của mình hơn nữa để bạn không phải tìm kiếm theo hướng nếu bạn biết bạn không thể tạo từ. Ví dụ: nếu bạn tìm thấy hai qs liên tiếp, bạn nên hủy bỏ. Cuối cùng, bạn sẽ muốn một số loại cấu trúc dữ liệu cho phép bạn biết nếu một bộ ký tự nhất định là tiền tố của một từ hợp lệ. Đối với điều này, bạn có thể sử dụng cây trie hoặc cây tiền tố; một cấu trúc dữ liệu hữu ích khi giải quyết các vấn đề như thế này.

Cây tiền tố là một cấu trúc dựa trên nút phân cấp, trong đó mỗi nút đại diện cho một số tiền tố của con của nó và các nút lá (nói chung) đại diện cho các giá trị cuối cùng. Ví dụ: nếu từ điển các từ hợp lệ của bạn có chứa "cat", "car" và "cell", một bộ ba có thể trông giống như:

    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

Do đó, bắt đầu bằng cách điền vào một cây tiền tố với mỗi từ hợp lệ trong trò chơi của bạn.

Quá trình thực tế tìm từ hợp lệ trên bảng tại bất kỳ thời điểm nào sẽ liên quan đến việc bắt đầu tìm kiếm đệ quy từ mỗi ô trên bảng. Bởi vì mỗi tìm kiếm thông qua không gian bảng bắt đầu tại một số ô cụ thể là độc lập, chúng có thể được song song nếu cần. Khi bạn tìm kiếm, bạn "theo dõi" cây tiền tố dựa trên giá trị của chữ cái theo hướng bạn đang tìm kiếm.

Cuối cùng, bạn sẽ đạt đến một điểm mà không có chữ cái nào xung quanh là con của nút cây tiền tố hiện tại của bạn. Khi bạn đạt đến điểm đó, nếu đúng là nút hiện tại là một chiếc lá, bạn đã tìm thấy một từ hợp lệ. Nếu không, bạn đã không tìm thấy một từ hợp lệ và bạn có thể hủy bỏ tìm kiếm.

Mã ví dụ và thảo luận về kỹ thuật này (và các kỹ thuật khác, chẳng hạn như giải pháp lập trình động có thể nhanh hơn bằng cách "đảo ngược" không gian tìm kiếm sau thời trang) có thể được tìm thấy trên blog của người bạn này ở đây ; anh ta thảo luận về việc giải quyết Boggle, nhưng việc điều chỉnh các giải pháp cho trò chơi của bạn ít nhiều là vấn đề thay đổi hướng mà bạn cho phép tìm kiếm xảy ra.


Brute force không phải là cách duy nhất như bạn tự giải thích. :) Có rất nhiều tiền tố gợi ý rằng không có điểm nào để tiếp tục tìm kiếm. (Hầu hết các chuỗi [ngẫu nhiên] không phải là từ. +1
AturSams

Câu trả lời chính xác. Một "từ" là bất cứ điều gì trong từ điển của trò chơi dừng lại hoàn toàn.
Adam Eberbach

OP tuyên bố rằng anh ta có một thuật toán để ghép từ với chuỗi ký tự. Vì vậy, tôi không nghĩ rằng điều này trả lời câu hỏi.
Taemyr

OTOH Tôi nghĩ OP sẽ muốn một thuật toán khớp chuỗi hiệu quả hơn so với những gì anh ta hiện có.
Taemyr

1
@Taemyr sử dụng trie đơn giản, vâng. Nhưng người ta có thể sử dụng thuật toán Aho-Corasick, sử dụng bộ ba được sửa đổi một chút sẽ hiệu quả hơn (tuyến tính). Với thuật toán Aho-Corasick, người ta có thể tìm thấy tất cả các từ hợp lệ trong ma trận nxn trong thời gian O (n ^ 2).
el.pescado

3

Bạn có thể đã thử điều này, đã thực hiện điều này, có thể tốt hơn kèm theo câu trả lời khác, v.v. Nhưng tôi không thấy chúng được đề cập (chưa), vì vậy đây là:

Bạn có thể loại bỏ rất nhiều kiểm tra bằng cách theo dõi những gì đã thay đổi và những gì không. Ví dụ:

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.

hoặc, trong mã 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)
}

Và những câu hỏi tầm thường:

Bạn có cài đặt tối ưu hóa tốc độ trình biên dịch không? (nếu bạn sử dụng một)

Thuật toán tìm kiếm từ của bạn có thể được tối ưu hóa ở tất cả? Bằng cách nào?


Ngoại trừ việc người chơi được phép xoay hàng, vì vậy việc tìm một từ trong cột thứ ba sẽ ảnh hưởng đến các cột khác.
Taemyr

@Taemyr IF(rowMoved){ checkColumns(); checkMovedRow(); } IF(columnMoved){ checkRows() checkMovedColumn();} Nếu người dùng chỉ có thể di chuyển một lần, thì vào cuối di chuyển đó, không có chữ cái song song nào được di chuyển và do đó không cần phải kiểm tra lại chúng.
David Starkey

2

Hãy nhớ rằng mỗi nhân vật là một giá trị. Vì vậy, sử dụng điều đó để lợi thế của bạn. Có một số hàm băm có thể được tính toán nhanh khi lặp trên các chuỗi con. Chẳng hạn, giả sử chúng tôi cung cấp cho mỗi chữ cái một mã 5 bit (chỉ cần thực hiện c - 'a' + 1trong C):

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

Hơn bạn có thể nhanh chóng chạy trên tất cả các chuỗi con có kích thước nhất định:

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

Chúng ta có thể kiểm tra các chuỗi con lên đến 12 chữ cái theo cách này trên hầu hết các kiến ​​trúc phổ biến hiện nay.

Nếu mã băm tồn tại trong từ điển của bạn, bạn có thể lấy từ đó từ đó nhanh chóng khiến mã băm như thế này là duy nhất. Khi bạn đạt tối đa 12 chữ cái, bạn có thể muốn thêm một cấu trúc dữ liệu khác cho các từ bắt đầu bằng 12 chữ cái đó. Nếu bạn tìm thấy một từ bắt đầu bằng 12 chữ cái cụ thể, chỉ đơn giản là tạo một danh sách hoặc một bảng băm nhỏ khác cho các hậu tố của mỗi từ bắt đầu bằng tiền tố đó.

Lưu trữ một từ điển của tất cả các mã từ hiện có không nên chiếm nhiều hơn một vài megabyte bộ nhớ.


0

Bạn chỉ bị giới hạn trong các hình dạng Tetris cổ điển khi hình thành từ, hoặc bất kỳ hình thành sẽ làm gì? Từ ngữ có thể uốn cong vô thời hạn hoặc chỉ một lần? Một từ có thể được miễn là nó muốn? Điều này khá phức tạp nếu bạn có thể thực hiện bao nhiêu lần uốn cong tùy thích, thực sự làm cho các từ dài nhất có thể dài 25 ký tự. Tôi sẽ giả sử bạn có một danh sách các từ được chấp nhận. Với giả định đó, tôi khuyên bạn nên thử một cái gì đó như thế này:

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

Điều này sẽ tạo ra một bản đồ trên mỗi ô với thông tin về cách ô này được kết nối với các từ xung quanh nó trong lưới. Khi một cột hoặc hàng được di chuyển, hãy kiểm tra tất cả các ô đã được hoặc liền kề với chuyển động và tính toán lại thông tin. Khi bạn tìm thấy một từ, và không có thêm gạch nào có thể được thêm vào từ đó; gỡ bỏ nó. Tôi không chắc liệu điều này sẽ nhanh hơn hay không, nó thực sự hiểu rõ có bao nhiêu từ được tạo ra một nửa. Lợi ích của việc này là người dùng rất có thể đang cố gắng tạo ra một từ từ một nửa hoàn thành trên bảng. Bằng cách giữ tất cả các từ này được lưu trữ, thật dễ dàng để kiểm tra nếu một từ đã được hoàn thành.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.