如何生成像boggle这样的游戏板

时间:2013-10-18 18:07:24

标签: algorithm boggle

Google Play,Apple Store和Facebook平台上有许多类似Boggle的游戏。如何生成像这些游戏一样的可玩板?

2 个答案:

答案 0 :(得分:4)

最简单的方法是生成统一选择的随机字符网格。但这不会给你很多的话:

from random import randint

N = 4

def display(letters):
    for row in letters:
        print('+%s+' % '+'.join('-' * N))
        print('|%s|' % '|'.join(row))
    print('+%s+' % '+'.join('-' * N))

def uniform_char():
    return chr(ord('A') + randint(0, 25))

def to_array(fn):
    return [[fn() for _ in range(N)] for _ in range(N)]

display(to_array(uniform_char))

给予

+-+-+-+-+
|B|G|C|Z|
+-+-+-+-+
|G|B|T|K|
+-+-+-+-+
|I|R|O|Q|
+-+-+-+-+
|G|A|S|W|
+-+-+-+-+

这方面的改进是通过英语发生的频率来加权(假设这是你想要的语言):

from collections import Counter

def letters():
    with open('/usr/share/dict/words', 'r') as words:
        for word in words:
            for letter in word.upper():
                if letter >= 'A' and letter <= 'Z':
                    yield letter

letter_scores = Counter(letters())
print(letter_scores)

# http://stackoverflow.com/questions/14992521/python-weighted-random/14992648
def weighted_random(pairs):
    total = sum(pair[1] for pair in pairs)
    r = randint(1, total)
    for (value, weight) in pairs:
        r -= weight
        if r <= 0: return value

display(to_array(lambda: weighted_random(letter_scores.items())))

Counter({'E': 301968, 'S': 274630, 'I': 241084, 'A': 225091, 'R': 191386,
'N': 191320, 'O': 184143, 'T': 177237, 'L': 151341, 'C': 111066, 
'U': 90838, 'D': 89014, 'M': 80645, 'P': 79507, 'G': 71689, 'H': 71423, 
'B': 52921, 'Y': 47941, 'F': 32114, 'V': 27918, 'K': 26797, 'W': 22635,  
'Z': 14022, 'X': 7861, 'J': 5130, 'Q': 4722})

+-+-+-+-+
|L|E|S|T|
+-+-+-+-+
|O|A|C|P|
+-+-+-+-+
|A|I|L|L|
+-+-+-+-+
|N|G|S|I|
+-+-+-+-+

更好的是使用n-gram(例如普通字母对)和马尔可夫链或只是某种随机抽样。这里我从以概率加权的字母(如上所述)开始,然后将几个邻居设置为热门对(在mix中我选择一个随机点,找到一个通常跟在那里的字母后面的字母,并设置一个相邻的方格到即):

def pairs():
    with open('/usr/share/dict/words', 'r') as words:
        for word in words:
            prev = None
            for letter in word.upper():
                if letter >= 'A' and letter <= 'Z':
                    if prev: yield (prev, letter)
                    prev = letter

pair_scores = Counter(pairs())
#print(pair_scores)                                                             
start = to_array(lambda: weighted_random(letter_scores.items()))

def mix(array):
    x, y = randint(0, N-1), randint(0, N-1)
    a = array[y][x]
    neighbours = [(pair[1], score)
                  for (pair, score) in pair_scores.items()
                  if pair[0] == a]
    if neighbours:
        b = weighted_random(neighbours)
        # print(a, b, neighbours)                                               
        array[(y+randint(-1,1))%N][(x+randint(-1,1))%N] = b
    else:
        print('no neighbours for', a)

for _ in range(N*(N-1)//2): mix(start)
display(start)

+-+-+-+-+
|L|T|H|P|
+-+-+-+-+
|S|S|S|O|
+-+-+-+-+
|S|O|O|L|
+-+-+-+-+
|E|S|A|E|
+-+-+-+-+

不确定这是一个很大的改进,但请注意双S,TH等。

最后,当然,您可以只注意晃动中使用的骰子上的字母,并随机选择每个骰子,完全模仿游戏。

linux上的所有代码python 3.

答案 1 :(得分:1)

您可以在骰子上谷歌搜索“Boggle letter distribution”。 4x4和5x5板的分布不同。同样大小的电路板也有变化。其中一些是Wikipedia's Boggle talk page给出的(这不是永久性的,所以现在抓住它们)。请注意,字母Q计为两个字母QU,但在分发表中写为单个字母。