0

Google Play、Apple Store 和 Facebook 平台上有许多类似 Boggle 的游戏。我如何生成像那些游戏一样的可玩棋盘?

4

2 回答 2

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 等。

最后,当然,您可以只记下 boggle 中使用的骰子上的字母,然后从每个字母中随机选择,完全模仿游戏。

linux上的所有代码python 3。

于 2013-10-18T21:08:26.747 回答
1

您可以在骰子上搜索“Boggle letter distribution”。4x4 和 5x5 板的分布不同。同样尺寸的板也有变化。其中一些是在Wikipedia 的 Boggle 讨论页上给出的(这不是永久性的,所以现在就抓住它们)。请注意,字母 Q 算作两个字母 QU,但在分配表中写为单个字母。

于 2013-10-19T13:31:03.053 回答