Water Bucket Puzzle
In this solitaire puzzle game, you must use three buckets (three-liter, five-liter, and eight-liter buckets) to collect exactly four liters of water in one of the buckets. Buckets can only be emptied, completely filled, or poured into another bucket. For example, you can fill the five-liter bucket and then pour its contents into the three-liter bucket, leaving you with a full three-liter bucket and two liters of water in the five-liter bucket.
With some effort, you should be able to solve the puzzle. But can you figure out how to solve it with the minimal number of moves?
water_bucket_puzzle.py
1"""Water Bucket Puzzle, by Al Sweigart al@inventwithpython.com
2A water pouring puzzle.
3More info: https://en.wikipedia.org/wiki/Water_pouring_puzzle
4This code is available at https://nostarch.com/big-book-small-python-programming
5Tags: large, game, math, puzzle"""
6
7import sys
8
9
10print('Water Bucket Puzzle, by Al Sweigart al@inventwithpython.com')
11
12GOAL = 4 # The exact amount of water to have in a bucket to win.
13steps = 0 # Keep track of how many steps the player made to solve this.
14
15# The amount of water in each bucket:
16waterInBucket = {'8': 0, '5': 0, '3': 0}
17
18while True: # Main game loop.
19 # Display the current state of the buckets:
20 print()
21 print('Try to get ' + str(GOAL) + 'L of water into one of these')
22 print('buckets:')
23
24 waterDisplay = [] # Contains strings for water or empty space.
25
26 # Get the strings for the 8L bucket:
27 for i in range(1, 9):
28 if waterInBucket['8'] < i:
29 waterDisplay.append(' ') # Add empty space.
30 else:
31 waterDisplay.append('WWWWWW') # Add water.
32
33 # Get the strings for the 5L bucket:
34 for i in range(1, 6):
35 if waterInBucket['5'] < i:
36 waterDisplay.append(' ') # Add empty space.
37 else:
38 waterDisplay.append('WWWWWW') # Add water.
39
40 # Get the strings for the 3L bucket:
41 for i in range(1, 4):
42 if waterInBucket['3'] < i:
43 waterDisplay.append(' ') # Add empty space.
44 else:
45 waterDisplay.append('WWWWWW') # Add water.
46
47 # Display the buckets with the amount of water in each one:
48 print('''
498|{7}|
507|{6}|
516|{5}|
525|{4}| 5|{12}|
534|{3}| 4|{11}|
543|{2}| 3|{10}| 3|{15}|
552|{1}| 2|{9}| 2|{14}|
561|{0}| 1|{8}| 1|{13}|
57 +------+ +------+ +------+
58 8L 5L 3L
59'''.format(*waterDisplay))
60
61 # Check if any of the buckets has the goal amount of water:
62 for waterAmount in waterInBucket.values():
63 if waterAmount == GOAL:
64 print('Good job! You solved it in', steps, 'steps!')
65 sys.exit()
66
67 # Let the player select an action to do with a bucket:
68 print('You can:')
69 print(' (F)ill the bucket')
70 print(' (E)mpty the bucket')
71 print(' (P)our one bucket into another')
72 print(' (Q)uit')
73
74 while True: # Keep asking until the player enters a valid action.
75 move = input('> ').upper()
76 if move == 'QUIT' or move == 'Q':
77 print('Thanks for playing!')
78 sys.exit()
79
80 if move in ('F', 'E', 'P'):
81 break # Player has selected a valid action.
82 print('Enter F, E, P, or Q')
83
84 # Let the player select a bucket:
85 while True: # Keep asking until valid bucket entered.
86 print('Select a bucket 8, 5, 3, or QUIT:')
87 srcBucket = input('> ').upper()
88
89 if srcBucket == 'QUIT':
90 print('Thanks for playing!')
91 sys.exit()
92
93 if srcBucket in ('8', '5', '3'):
94 break # Player has selected a valid bucket.
95
96 # Carry out the selected action:
97 if move == 'F':
98 # Set the amount of water to the max size.
99 srcBucketSize = int(srcBucket)
100 waterInBucket[srcBucket] = srcBucketSize
101 steps += 1
102
103 elif move == 'E':
104 waterInBucket[srcBucket] = 0 # Set water amount to nothing.
105 steps += 1
106
107 elif move == 'P':
108 # Let the player select a bucket to pour into:
109 while True: # Keep asking until valid bucket entered.
110 print('Select a bucket to pour into: 8, 5, or 3')
111 dstBucket = input('> ').upper()
112 if dstBucket in ('8', '5', '3'):
113 break # Player has selected a valid bucket.
114
115 # Figure out the amount to pour:
116 dstBucketSize = int(dstBucket)
117 emptySpaceInDstBucket = dstBucketSize - waterInBucket[dstBucket]
118 waterInSrcBucket = waterInBucket[srcBucket]
119 amountToPour = min(emptySpaceInDstBucket, waterInSrcBucket)
120
121 # Pour out water from this bucket:
122 waterInBucket[srcBucket] -= amountToPour
123
124 # Put the poured out water into the other bucket:
125 waterInBucket[dstBucket] += amountToPour
126 steps += 1
127
128 elif move == 'C':
129 pass # If the player selected Cancel, do nothing.