算法与Python

算法与Python 知识量:10 - 40 - 100

3.4 猜词游戏><

问题- 3.4.1 -

猜词游戏的玩法是这样的:一个人写下几个数字让另外一人猜,当每次答题方猜完之后,出题方会给答题方一个提示,告诉他刚才的猜测中有多少位数字和确切位置都猜对了(称为“Bulls”,公牛),还有多少位数字猜对了但是位置不对(称为“Cows”,奶牛)。答题方将会根据出题方的提示继续猜,直到猜出秘密数字为止。

问题求解1- 3.4.2 -

这是一个经典的数字猜测游戏,通常被称为“牛和奶牛”游戏。以下提供一个基本的Python实现,玩家可以猜测数字,并根据提示进行更新。

首先,定义一个函数来计算公牛和奶牛的数量:

def count_bulls_and_cows(secret, guess):  
    bulls = 0  
    cows = 0  
    secret_digits = set(str(secret))  
    guess_digits = set(str(guess))  
    for digit in secret_digits:  
        if digit in guess_digits:  
            bulls += 1  
            secret_digits.remove(digit)  
            guess_digits.remove(digit)  
    for digit in guess_digits:  
        if digit in secret_digits:  
            cows += 1  
            guess_digits.remove(digit)  
            secret_digits.remove(digit)  
    return bulls, cows

接下来,可以实现游戏的逻辑:

def game():  
    secret = input("请输入一个四位数的秘密数字:")  
    while len(set(str(secret))) != 4:  # 检查是否是四位数  
        secret = input("请重新输入一个四位数的秘密数字:")  
    while True:  
        guess = input("请猜一个数字:")  
        bulls, cows = count_bulls_and_cows(secret, guess)  
        print(f"公牛:{bulls},奶牛:{cows}")  
        if bulls == 4:  # 如果全部数字都猜对了,结束游戏  
            print("恭喜,猜对了!")  
            break  
        elif cows == 4:  # 如果所有数字位置都猜错了,重新开始  
            print("很遗憾,全部猜错了。请重新开始。")  
            game()  
        else:  # 否则继续猜数字  
            print("请继续猜数字。")

现在,可以运行game()函数来开始游戏。玩家将输入一个四位数作为秘密数字,然后开始猜测数字。每次猜测后,程序将告诉玩家有多少位数字完全正确(公牛)和有多少位数字位置不正确(奶牛)。如果玩家猜测的数字全部正确,程序将恭喜玩家并结束游戏。如果玩家猜测的数字全部不正确,程序将告诉玩家并重新开始游戏。

问题求解2- 3.4.3 -

要使用哈希表(在Python中通常使用字典实现)来解决“公牛和奶牛”游戏的问题,需要一个方法来跟踪猜测中哪些数字是正确的,并且是在正确的位置上(公牛),以及哪些数字是正确的但位置不正确(奶牛)。

下面是一个使用哈希表的Python实现:

def count_bulls_and_cows(secret, guess):  
    if len(secret) != len(guess) or not secret.isdigit() or not guess.isdigit():  
        raise ValueError("Secret and guess must be of equal length and consist of digits only.")  
      
    bulls = 0  # 公牛数  
    cow_dict = {}  # 用来计算奶牛的哈希表,存储猜测中每个数字出现的次数  
    for s, g in zip(secret, guess):  
        if s == g:  
            bulls += 1  
        elif g in cow_dict:  
            cow_dict[g] += 1  
        else:  
            cow_dict[g] = 1  
      
    cows = 0  # 奶牛数  
    for s in secret:  
        if s in cow_dict and cow_dict[s] > 0:  
            cows += 1  
            cow_dict[s] -= 1  # 已经计算过的奶牛数需要减去  
      
    return bulls, cows  
  
def game():  
    secret = input("请输入一个四位数的秘密数字:")  
    while len(secret) != 4 or not secret.isdigit():  # 检查是否是四位数且只包含数字  
        secret = input("请重新输入一个四位数的秘密数字:")  
      
    while True:  
        guess = input("请猜一个四位数:")  
        while len(guess) != 4 or not guess.isdigit():  # 检查猜测是否是四位数且只包含数字  
            guess = input("请重新输入一个四位数:")  
          
        bulls, cows = count_bulls_and_cows(secret, guess)  
        print(f"公牛:{bulls},奶牛:{cows}")  
        if bulls == 4:  # 如果公牛数为4,则猜对了  
            print("恭喜,你猜对了!")  
            break

上述实现中的count_bulls_and_cows函数在计算奶牛数时有一个问题:它可能会错误地计算那些既是公牛又是奶牛的数字。为了解决这个问题,需要稍微调整算法,确保在计算奶牛之前排除掉公牛。下面是修正后的实现:

def count_bulls_and_cows(secret, guess):  
    if len(secret) != len(guess) or not secret.isdigit() or not guess.isdigit():  
        raise ValueError("Secret and guess must be of equal length and consist of digits only.")  
      
    bulls = 0  # 公牛数  
    cows = 0  # 奶牛数  
    secret_counts = {}  # 存储秘密数字中每个数字出现的次数  
    guess_counts = {}  # 存储猜测中每个数字出现的次数(不考虑位置)  
      
    # 统计秘密数字和猜测中每个数字的出现次数  
    for s, g in zip(secret, guess):  
        if s == g:  # 公牛,数字和位置都匹配  
            bulls += 1  
        else:  # 更新数字的出现次数(奶牛候选)  
            secret_counts[s] = secret_counts.get(s, 0) + 1  
            guess_counts[g] = guess_counts.get(g, 0) + 1  
      
    # 计算奶牛数(只考虑那些位置不匹配的数字)  
    for digit, count in guess_counts.items():  
        cows += min(count, secret_counts.get(digit, 0))  # 取两个计数的最小值作为匹配的奶牛数  
    cows -= bulls  # 从总奶牛数中减去公牛数,因为公牛已经被计算过了  
      
    return bulls, cows if cows >= 0 else 0  # 确保奶牛数不会为负数(理论上不应该发生,但作为一个安全措施)

现在,count_bulls_and_cows函数应该能够正确地计算公牛和奶牛的数量了。可以调用game()函数来开始游戏。