[文字游戏] Quiddler求解器算法

时间:2011-01-17 07:13:16

标签: c++ python c algorithm

Quiddler Solver

我有一个名为Quiddler的纸牌游戏,我正在尝试编写一个算法来解决,但是当我尝试线性地解决它时它非常慢且效率低。

游戏(循序渐进):

  1. 每位玩家可以获得3到10张牌,每张牌上面都有一个或两个字母。
  2. 然后玩家尝试从他们给出的牌中制作一个或多个单词,而不会有多余的牌。
  3. 虽然我尽力使用算法来完成这些看似简单的任务,但即使是中长手也需要20秒才能找到所有答案。

    我使用字典such as this one作为我的单词列表。我线性检查手中的字母数量,并将其与列表中的字词进行比较,假设它们的长度相等或更短。虽然这项工作需要很长时间。

    我希望有人可以帮助我,最好是Perl,Python或C / C ++。

    示例手: 卡= [ 'I', 'd', '0', 'N']

    答案(根据我的算法): 迪不, 迪, 做, 证件号码, id on, 在做, 在外面, 恐龙, nodi

    我在Python中的算法:

    import timeit
    from wordlist import *
    #Quiddler Solver
    print 'Dictionary loaded\n'
    
    #Define our hand
    cards=['i','d','o','n']
    
    #Count the letters in a word
    def cntLetters(word):   #Surely there's a better way?
        lettercnt={97:0,98:0,99:0,100:0,101:0,102:0,103:0,104:0,105:0,106:0,107:0,108:0,109:0,110:0,111:0,112:0,113:0,114:0,115:0,116:0,117:0,118:0,119:0,120:0,121:0,122:0}
        for v in word:
            lettercnt[ord(v)]+=1
        return lettercnt
    
    #Check the letters to make sure our hand has at least what the word has
    def cmpList(list1,list2):
        for k,v in list1.iteritems():
            if list2[k]<=v:
                pass
            else:
                return False
        return True
    
    #Check to make sure cards with more than one letter are together in the word.
    def has(word):
        for v in cards:
            if len(v)>1:
                if v in word:
                    pass
                else:
                    return False
        return True
    
    def solve():
        rawhand=''.join(cards).lower()
        hand=cntLetters(rawhand)
        handl=len(rawhand)
        buff=[]
        for v in dict:  #Add all words that have at least the letters in our hand to buff
            if len(v)<=handl and cmpList(hand,cntLetters(v)):
                if has(v):
                    buff.append(v)
        for v in range(0,int((len(buff)/2)+1)): #Find 2 words that can be used together to make a play
            for n in buff:
                if len(n)==(handl-len(buff[v])):
                    if hand==cntLetters(buff[v]+n):
                        print buff[v],n
        for v in range(0,int((len(buff)/3)+1)): #This is a bit overkill since it finds so much stuff, need to tune it
            for n in buff:
                if (len(n))<=len(buff[v]):
                    for x in buff:
                        if len(x)==(handl-len(buff[v])-len(n)):
                            if hand==cntLetters(buff[v]+n+x):
                                print buff[v],n,x
        for v in buff:  #Print the single words that can be made
            if len(v)==handl:
                print v
    
    t = timeit.Timer(stmt=solve)
    print 'Search took %.2f seconds'%t.timeit(number=1)
    

    我从wordlist导入一个名为dict的预编译列表。

    我希望有人可以帮我解决我的算法设计,因为它需要改进,谢谢。

    有人建议使用DAWG,但我没有进行任何单词查找。在这种情况下,我仍然需要循环检查字母,除非我在想错误的行?

2 个答案:

答案 0 :(得分:4)

您可以尝试将单词列表存储为directed acyclic word graph(DAWG)或trie以进行快速查找。

放置第一个字母并使用DAWG / trie找出第二个字母的所有可能性,依此类推。当没有更多的字母可以放置,或者找到解决方案而你想要下一个字母时,请使用回溯。

此算法应该在解决方案的数量上大致呈线性,如果有效写入应该能够在几毫秒内为10张卡解决您的问题。请注意,随着您添加更多卡片,解决方案的数量会迅速增长。

答案 1 :(得分:1)

从您的问题到设置封面有一个非常简单的减少,这是NP完全的,所以虽然您可以使用DAWG进行微小的改进,但是没有已知的有效解决方案。