Skip to content

Latest commit

 

History

History
206 lines (160 loc) · 7 KB

File metadata and controls

206 lines (160 loc) · 7 KB

八十一、水桶谜题

原文:http://inventwithpython.com/bigbookpython/project81.html

在这个纸牌益智游戏中,您必须使用三个水桶(三升、五升和八升的水桶)在其中一个水桶中收集正好四升水。桶只能被清空、完全装满或倒入另一个桶中。例如,你可以装满一个 5 升的桶,然后把里面的东西倒入 3 升的桶,这样你就有了一个满满的 3 升桶,5 升桶里有 2 升水。

经过一些努力,你应该能解决这个难题。但是你能想出如何用最少的步数解决它吗?

运行示例

当您运行waterbucket.py时,输出将如下所示:

Water Bucket Puzzle, by Al Sweigart email@protected

Try to get 4L of water into one of these
buckets:

8|      |
7|      |
6|      |
5|      |  5|      |
4|      |  4|      |
3|      |  3|      |  3|      |
2|      |  2|      |  2|      |
1|      |  1|      |  1|      |
 +------+   +------+   +------+
    8L         5L         3L

You can:
  (F)ill the bucket
  (E)mpty the bucket
  (P)our one bucket into another
  (Q)uit
> f
Select a bucket 8, 5, 3, or QUIT:
> 5

Try to get 4L of water into one of these
buckets:

8|      |
7|      |
6|      |
5|      |  5|WWWWWW|
4|      |  4|WWWWWW|
3|      |  3|WWWWWW|  3|      |
2|      |  2|WWWWWW|  2|      |
1|      |  1|WWWWWW|  1|      |
 +------+   +------+   +------+
    8L         5L         3L
`--snip--`

工作原理

waterInBucket变量存储了一个代表水桶状态的字典。这个字典的关键字是字符串'8''5''3'(代表水桶),它们的值是整数(代表水桶中的水的公升数)。

第 48 到 59 行使用这个字典在屏幕上呈现水桶和水。waterDisplay列表包含'WWWWWW'(代表水)或' '(代表空气),并被传递给format()字符串方法。waterDisplay列表中的前八串填充八升桶,接下来的五串填充五升桶,最后的三串填充三升桶。

"""Water Bucket Puzzle, by Al Sweigart email@protected
A water pouring puzzle.
More info: https://en.wikipedia.org/wiki/Water_pouring_puzzle
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: large, game, math, puzzle"""

import sys


print('Water Bucket Puzzle, by Al Sweigart email@protected')

GOAL = 4  # The exact amount of water to have in a bucket to win.
steps = 0  # Keep track of how many steps the player made to solve this.

# The amount of water in each bucket:
waterInBucket = {'8': 0, '5': 0, '3': 0}

while True:  # Main game loop.
   # Display the current state of the buckets:
   print()
   print('Try to get ' + str(GOAL) + 'L of water into one of these')
   print('buckets:')

   waterDisplay = []  # Contains strings for water or empty space.

   # Get the strings for the 8L bucket:
   for i in range(1, 9):
       if waterInBucket['8'] < i:
           waterDisplay.append('      ')  # Add empty space.
       else:
           waterDisplay.append('WWWWWW')  # Add water.

   # Get the strings for the 5L bucket:
   for i in range(1, 6):
       if waterInBucket['5'] < i:
           waterDisplay.append('      ')  # Add empty space.
       else:
           waterDisplay.append('WWWWWW')  # Add water.

   # Get the strings for the 3L bucket:
   for i in range(1, 4):
       if waterInBucket['3'] < i:
           waterDisplay.append('      ')  # Add empty space.
       else:
           waterDisplay.append('WWWWWW')  # Add water.

   # Display the buckets with the amount of water in each one:
   print('''
8|{7}|
7|{6}|
6|{5}|
5|{4}|  5|{12}|
4|{3}|  4|{11}|
3|{2}|  3|{10}|  3|{15}|
2|{1}|  2|{9}|  2|{14}|
1|{0}|  1|{8}|  1|{13}|
+------+   +------+   +------+
   8L         5L         3L
'''.format(*waterDisplay))

   # Check if any of the buckets has the goal amount of water:
   for waterAmount in waterInBucket.values():
       if waterAmount == GOAL:
           print('Good job! You solved it in', steps, 'steps!')
           sys.exit()

   # Let the player select an action to do with a bucket:
   print('You can:')
   print('  (F)ill the bucket')
   print('  (E)mpty the bucket')
   print('  (P)our one bucket into another')
   print('  (Q)uit')

   while True:  # Keep asking until the player enters a valid action.
       move = input('> ').upper()
       if move == 'QUIT' or move == 'Q':
           print('Thanks for playing!')
           sys.exit()

       if move in ('F', 'E', 'P'):
           break  # Player has selected a valid action.
       print('Enter F, E, P, or Q')

   # Let the player select a bucket:
   while True:  # Keep asking until valid bucket entered.
       print('Select a bucket 8, 5, 3, or QUIT:')
       srcBucket = input('> ').upper()

       if srcBucket == 'QUIT':
           print('Thanks for playing!')
           sys.exit()

       if srcBucket in ('8', '5', '3'):
           break  # Player has selected a valid bucket.

   # Carry out the selected action:
   if move == 'F':
       # Set the amount of water to the max size.
       srcBucketSize = int(srcBucket)
        waterInBucket[srcBucket] = srcBucketSize
        steps += 1

    elif move == 'E':
        waterInBucket[srcBucket] = 0  # Set water amount to nothing.
        steps += 1

    elif move == 'P':
        # Let the player select a bucket to pour into:
        while True:  # Keep asking until valid bucket entered.
            print('Select a bucket to pour into: 8, 5, or 3')
            dstBucket = input('> ').upper()
            if dstBucket in ('8', '5', '3'):
                break  # Player has selected a valid bucket.

        # Figure out the amount to pour:
        dstBucketSize = int(dstBucket)
        emptySpaceInDstBucket = dstBucketSize - waterInBucket[dstBucket]
        waterInSrcBucket = waterInBucket[srcBucket]
        amountToPour = min(emptySpaceInDstBucket, waterInSrcBucket)

        # Pour out water from this bucket:
        waterInBucket[srcBucket] -= amountToPour

        # Put the poured out water into the other bucket:
        waterInBucket[dstBucket] += amountToPour
        steps += 1

    elif move == 'C':
        pass  # If the player selected Cancel, do nothing. 

在输入源代码并运行几次之后,尝试对其进行实验性的修改。你也可以自己想办法做到以下几点:

  • 通过使游戏可配置来增加多样性,这样你可以为三个桶指定任何大小,为目标数量指定任何数量。
  • 添加“提示”,检查每个水桶中的水量,并提供下一步要采取的措施。如果程序不知道下一步该做什么,它可以简单地显示“我不知道你下一步该做什么。也许重新开始?”

探索程序

试着找出下列问题的答案。尝试对代码进行一些修改,然后重新运行程序,看看这些修改有什么影响。

  1. 如果把 104 行的waterInBucket[srcBucket] = 0改成waterInBucket[srcBucket] = 1会怎么样?
  2. 如果把第 16 行的{'8': 0, '5': 0, '3': 0}改成{'8': 0, '5': 4, '3': 0}会怎么样?
  3. 如果把第 16 行的{'8': 0, '5': 0, '3': 0}改成{'8': 9, '5': 0, '3': 0}会怎么样?