Python 小型项目大全 46~50

# 四十六、百万骰子投掷统计模拟器

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

当你掷出两个六面骰子时,有 17%的机会掷出 7。这比掷出 2 的几率好得多:只有 3%。这是因为只有一种掷骰子的组合给你 2(当两个骰子都掷出 1 时发生的组合),但许多组合加起来是 7:1 和 6,2 和 5,3 和 4,等等。

但是当你掷出三个骰子呢?还是四个?还是 1000?你可以用数学方法计算理论概率,或者你可以让计算机掷骰子一百万次,凭经验算出它们。这个程序采用了后一种方法。在这个程序中,你告诉计算机掷骰子一百万次并记住结果。然后,它显示每笔金额的百分比机会。

这个程序做了大量的计算,但是计算本身并不难理解。

运行示例

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

Million Dice Roll Statistics Simulator
By Al Sweigart email@protected

Enter how many six-sided dice you want to roll:
> 2
Simulating 1,000,000 rolls of 2 dice...
36.2% done...
73.4% done...
TOTAL - ROLLS - PERCENTAGE
  2 - 27590 rolls - 2.8%
  3 - 55730 rolls - 5.6%
  4 - 83517 rolls - 8.4%
  5 - 111526 rolls - 11.2%
  6 - 139015 rolls - 13.9%
  7 - 166327 rolls - 16.6%
  8 - 139477 rolls - 13.9%
  9 - 110268 rolls - 11.0%
  10 - 83272 rolls - 8.3%
  11 - 55255 rolls - 5.5%
  12 - 28023 rolls - 2.8%

工作原理

我们通过在第 30 行调用random.randint(1, 6)来模拟单个六面骰子的滚动。这将返回一个介于16之间的随机数,无论掷出多少骰子,该随机数都会被添加到累计总数中。random.randint()函数具有均匀分布,这意味着每个数字都像其他数字一样有可能被返回。

程序用results字典存储这次掷骰的结果。这个字典的关键字是每个可能的掷骰子总数,值是这个总数遇到的次数。为了获得频率百分比,我们将总数遇到的次数除以 1,000,000(在该模拟中掷骰子的次数)并乘以 100(以获得 0.0 和 100.0 之间的百分比,而不是 0.0 和 1.0)。通过做一些代数运算,我们可以算出,这与我们在第 37 行所做的将遭遇次数除以 10,000 是一样的。

"""Million Dice Roll Statistics Simulator
By Al Sweigart email@protected
A simulation of one million dice rolls.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: tiny, beginner, math, simulation"""

import random, time

print('''Million Dice Roll Statistics Simulator
By Al Sweigart email@protected

Enter how many six-sided dice you want to roll:''')
numberOfDice = int(input('> '))

# Set up a dictionary to store the results of each dice roll:
results = {}
for i in range(numberOfDice, (numberOfDice * 6) + 1):
    results[i] = 0

# Simulate dice rolls:
print('Simulating 1,000,000 rolls of {} dice...'.format(numberOfDice))
lastPrintTime = time.time()
for i in range(1000000):
    if time.time() > lastPrintTime + 1:
        print('{}% done...'.format(round(i / 10000, 1)))
        lastPrintTime = time.time()

    total = 0
    for j in range(numberOfDice):
        total = total + random.randint(1, 6)
    results[total] = results[total] + 1

# Display results:
print('TOTAL - ROLLS - PERCENTAGE')
for i in range(numberOfDice, (numberOfDice * 6) + 1):
    roll = results[i]
    percentage = round(results[i] / 10000, 1)
    print(' {} - {} rolls - {}%'.format(i, roll, percentage)) 

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

  • 尝试掷出 8 面、10 面、12 面或 20 面骰子。
  • 尝试模拟双面抛硬币。

探索程序

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

  1. 如果把第 24 行的lastPrintTime + 1改成lastPrintTime + 2会怎么样?
  2. 如果删除或注释掉第 31 行的results[total] = results[total] + 1,会导致什么 bug?
  3. 如果用户键入字母而不是数字来表示要掷出的六面骰子的数量,会出现什么错误?

四十七、蒙德里安艺术生成器

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

皮耶·蒙德里安是 20 世纪的荷兰画家,也是抽象艺术运动“新塑料主义”的创始人之一。他最具标志性的画作依赖于原色(蓝、黄、红)、黑色和白色。他采用极简主义的方法,用水平和垂直的元素将这些颜色分开。

这个程序随机生成遵循蒙德里安风格的绘画。你可以在en.wikipedia.org/wiki/Piet_Mondrian找到更多关于皮特·蒙德里安的信息。

运行示例

bext模块允许我们的 Python 程序在文本输出中显示明亮的原色,尽管这本书只显示黑白图像。图 47-1 显示了运行mondrian.py时的输出。

f47001

图 47-1 :蒙德里安艺术程序的计算机生成艺术。程序每次运行都会生成不同的图像。

工作原理

该算法通过创建一个带有随机间隔的垂直线和水平线的数据结构(canvas字典)来工作,如图图 47-2 。

f47002

:蒙德里安艺术算法的第一步是创建一个网格。

接下来,它移除一些线段来创建更大的矩形,如图图 47-3 所示。

f47003

:蒙德里安艺术算法的第二步随机去掉一些线条。

最后,算法用黄色、红色、蓝色或黑色随机填充一些矩形,如图图 47-4 。

f47004

:蒙德里安艺术算法第三步随机选择矩形填充颜色。

你可以在github.com/asweigart/mondrian_art_generator找到这个蒙德里安艺术生成器的另一个版本,还有一些样本图片。

"""Mondrian Art Generator, by Al Sweigart email@protected
Randomly generates art in the style of Piet Mondrian.
More info at: https://en.wikipedia.org/wiki/Piet_Mondrian
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: large, artistic, bext"""

import sys, random

try:
   import bext
except ImportError:
   print('This program requires the bext module, which you')
   print('can install by following the instructions at')
   print('https://pypi.org/project/Bext/')
   sys.exit()

# Set up the constants:
MIN_X_INCREASE = 6
MAX_X_INCREASE = 16
MIN_Y_INCREASE = 3
MAX_Y_INCREASE = 6
WHITE = 'white'
BLACK = 'black'
RED = 'red'
YELLOW = 'yellow'
BLUE = 'blue'

# Setup the screen:
width, height = bext.size()
# We can't print to the last column on Windows without it adding a
# newline automatically, so reduce the width by one:
width -= 1

height -= 3

while True:  # Main application loop.
   # Pre-populate the canvas with blank spaces:
   canvas = {}
   for x in range(width):
       for y in range(height):
           canvas[(x, y)] = WHITE

   # Generate vertical lines:
   numberOfSegmentsToDelete = 0
   x = random.randint(MIN_X_INCREASE, MAX_X_INCREASE)
   while x < width - MIN_X_INCREASE:
       numberOfSegmentsToDelete += 1
       for y in range(height):
           canvas[(x, y)] = BLACK
       x += random.randint(MIN_X_INCREASE, MAX_X_INCREASE)

   # Generate horizontal lines:
   y = random.randint(MIN_Y_INCREASE, MAX_Y_INCREASE)
   while y < height - MIN_Y_INCREASE:
       numberOfSegmentsToDelete += 1
       for x in range(width):
           canvas[(x, y)] = BLACK
       y += random.randint(MIN_Y_INCREASE, MAX_Y_INCREASE)

   numberOfRectanglesToPaint = numberOfSegmentsToDelete - 3
   numberOfSegmentsToDelete = int(numberOfSegmentsToDelete * 1.5)

   # Randomly select points and try to remove them.
   for i in range(numberOfSegmentsToDelete):
       while True:  # Keep selecting segments to try to delete.
           # Get a random start point on an existing segment:
           startx = random.randint(1, width - 2)
           starty = random.randint(1, height - 2)
           if canvas[(startx, starty)] == WHITE:
               continue

           # Find out if we're on a vertical or horizontal segment:
           if (canvas[(startx - 1, starty)] == WHITE and
               canvas[(startx + 1, starty)] == WHITE):
               orientation = 'vertical'
           elif (canvas[(startx, starty - 1)] == WHITE and
               canvas[(startx, starty + 1)] == WHITE):
               orientation = 'horizontal'
           else:
               # The start point is on an intersection,
               # so get a new random start point:
               continue

           pointsToDelete = [(startx, starty)]

           canDeleteSegment = True
           if orientation == 'vertical':
               # Go up one path from the start point, and
               # see if we can remove this segment:
               for changey in (-1, 1):
                   y = starty
                   while 0 < y < height - 1:
                       y += changey
                       if (canvas[(startx - 1, y)] == BLACK and
                           canvas[(startx + 1, y)] == BLACK):
                           # We've found a four-way intersection.
                           break
                       elif ((canvas[(startx - 1, y)] == WHITE and
                              canvas[(startx + 1, y)] == BLACK) or
                              (canvas[(startx - 1, y)] == BLACK and
                               canvas[(startx + 1, y)] == WHITE)):
                            # We've found a T-intersection; we can't
                            # delete this segment:
                            canDeleteSegment = False
                            break
                        else:
                            pointsToDelete.append((startx, y))

            elif orientation == 'horizontal':
                # Go up one path from the start point, and
                # see if we can remove this segment:
                for changex in (-1, 1):
                    x = startx
                    while 0 < x < width - 1:
                        x += changex
                        if (canvas[(x, starty - 1)] == BLACK and
                            canvas[(x, starty + 1)] == BLACK):
                            # We've found a four-way intersection.
                            break
                        elif ((canvas[(x, starty - 1)] == WHITE and
                               canvas[(x, starty + 1)] == BLACK) or
                              (canvas[(x, starty - 1)] == BLACK and
                               canvas[(x, starty + 1)] == WHITE)):
                            # We've found a T-intersection; we can't
                            # delete this segment:
                            canDeleteSegment = False
                            break
                        else:
                            pointsToDelete.append((x, starty))
            if not canDeleteSegment:
                continue  # Get a new random start point.
            break  # Move on to delete the segment.

        # If we can delete this segment, set all the points to white:
        for x, y in pointsToDelete:
            canvas[(x, y)] = WHITE

    # Add the border lines:
    for x in range(width):
        canvas[(x, 0)] = BLACK  # Top border.
        canvas[(x, height - 1)] = BLACK  # Bottom border.
    for y in range(height):
        canvas[(0, y)] = BLACK  # Left border.
        canvas[(width - 1, y)] = BLACK  # Right border.

    # Paint the rectangles:
    for i in range(numberOfRectanglesToPaint):
        while True:
            startx = random.randint(1, width - 2)
            starty = random.randint(1, height - 2)

            if canvas[(startx, starty)] != WHITE:
                continue  # Get a new random start point.
            else:
                break

        # Flood fill algorithm:
        colorToPaint = random.choice([RED, YELLOW, BLUE, BLACK])
        pointsToPaint = set([(startx, starty)])
        while len(pointsToPaint) > 0:
            x, y = pointsToPaint.pop()
            canvas[(x, y)] = colorToPaint
            if canvas[(x - 1, y)] == WHITE:
                pointsToPaint.add((x - 1, y))
            if canvas[(x + 1, y)] == WHITE:
                pointsToPaint.add((x + 1, y))
            if canvas[(x, y - 1)] == WHITE:
                pointsToPaint.add((x, y - 1))
            if canvas[(x, y + 1)] == WHITE:
                pointsToPaint.add((x, y + 1))

    # Draw the canvas data structure:
    for y in range(height):
        for x in range(width):
            bext.bg(canvas[(x, y)])
            print(' ', end='')

        print()

    # Prompt user to create a new one:
    try:
        input('Press Enter for another work of art, or Ctrl-C to quit.')
    except KeyboardInterrupt:
        sys.exit() 

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

  • 用不同的调色板创建程序。
  • 使用Pillow模块制作蒙德里安艺术的图像文件。你可以从《Python 自动化指南》第 19 章了解这个模块,automatetheboringstuff.com/2e/chapter19

探索程序

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

  1. 如果把第 41 行的canvas[(x, y)] = WHITE改成canvas[(x, y)] = RED会出现什么错误?
  2. 如果把 176 行的print(' ', end='')改成print('A', end='')会怎么样?

四十八、蒙蒂霍尔问题

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

蒙蒂霍尔问题说明了一个令人惊讶的概率事实。这个问题大致基于老游戏节目《让我们做个交易》和它的主持人蒙蒂·霍尔。在蒙蒂大厅问题中,你可以选择三扇门中的一扇门。一扇门后有一个奖品:一辆新车。另外两扇门都通向一只没用的山羊。假设你选了 1 号门。在你选择的门打开之前,主人打开了另一扇门(2 号或 3 号),这导致了一只山羊。您可以选择打开您最初选择的门,或者切换到另一扇未打开的门。

看起来你是否换门并不重要,但是如果你换了门,你的机会就会增加!这个程序通过让你重复做实验来演示蒙蒂霍尔问题。

为了理解为什么你的机会增加了,考虑一个有一千个门而不是三个门的蒙蒂大厅问题的版本。你挑一扇门,然后主持人打开 998 扇门,里面都是山羊。仅有的两个未打开的门是您选择的门和另一个门。如果你一开始就选对了车门(1/1000 的概率),那么主人会让一个随机的山羊车门关着。如果你选了一个山羊车门(1000 分之 999 的概率),主人会特别选择车门保持关闭。选择打开哪扇门不是随机的;主人知道让车门关着。几乎可以肯定的是,你一开始就没有选车门,所以你应该换另一个车门。

另一种想法是,你有 1000 个盒子,一个盒子里装着奖品。你猜猜奖品在哪个盒子里,主持人把它放到你手里。你认为奖品在你的盒子里还是在其他 999 个盒子里?你不需要主持人打开 999 个不含奖品的盒子中的 998 个;选择的数量与 1000 扇门相同。你一开始猜对的几率是 1/1000,而猜错的几率(奖品在其他盒子里)几乎是 999/1000。

更多关于蒙蒂霍尔问题的信息可以在en.wikipedia.org/wiki/Monty_Hall_problem找到。

运行示例

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

The Monty Hall Problem, by Al Sweigart email@protected
`--snip--`
+------+  +------+  +------+
|      |  |      |  |      |
|   1  |  |   2  |  |   3  |
|      |  |      |  |      |
|      |  |      |  |      |
|      |  |      |  |      |
+------+  +------+  +------+
Pick a door 1, 2, or 3 (or "quit" to stop):
> 1

+------+  +------+  +------+
|      |  |      |  |  ((  |
|   1  |  |   2  |  |  oo  |
|      |  |      |  | /_/|_|
|      |  |      |  |    | |
|      |  |      |  |GOAT|||
+------+  +------+  +------+
Door 3 contains a goat!
Do you want to swap doors? Y/N
> y

+------+  +------+  +------+
|  ((  |  | CAR! |  |  ((  |
|  oo  |  |    __|  |  oo  |
| /_/|_|  |  _/  |  | /_/|_|
|    | |  | /_ __|  |    | |
|GOAT|||  |   O  |  |GOAT|||
+------+  +------+  +------+
Door 2 has the car!
You won!

Swapping:     1 wins, 0 losses, success rate 100.0%
Not swapping: 0 wins, 0 losses, success rate 0.0%

Press Enter to repeat the experiment...
`--snip--`

工作原理

ASCII 艺术画门的多行字符串存储在几个常量变量中,比如ALL_CLOSEDFIRST_GOATFIRST_CAR_OTHERS_GOAT。使用这些常量的代码,比如第 125 行的print(FIRST_GOAT),即使我们更新了图形也保持不变。通过将多行字符串一起放在源代码文件的顶部,我们将更容易比较它们,以确保图形是一致的。

"""The Monty Hall Problem, by Al Sweigart email@protected
A simulation of the Monty Hall game show problem.
More info at https://en.wikipedia.org/wiki/Monty_Hall_problem
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: large, game, math, simulation"""

import random, sys

ALL_CLOSED = """
+------+  +------+  +------+
|      |  |      |  |      |
|   1  |  |   2  |  |   3  |
|      |  |      |  |      |
|      |  |      |  |      |
|      |  |      |  |      |
+------+  +------+  +------+"""

FIRST_GOAT = """
+------+  +------+  +------+
|  ((  |  |      |  |      |
|  oo  |  |   2  |  |   3  |
| /_/|_|  |      |  |      |
|    | |  |      |  |      |
|GOAT|||  |      |  |      |
+------+  +------+  +------+"""

SECOND_GOAT = """
+------+  +------+  +------+
|      |  |  ((  |  |      |
|   1  |  |  oo  |  |   3  |
|      |  | /_/|_|  |      |
|      |  |    | |  |      |
|      |  |GOAT|||  |      |
+------+  +------+  +------+"""

THIRD_GOAT = """
+------+  +------+  +------+
|      |  |      |  |  ((  |
|   1  |  |   2  |  |  oo  |
|      |  |      |  | /_/|_|
|      |  |      |  |    | |
|      |  |      |  |GOAT|||
+------+  +------+  +------+"""

FIRST_CAR_OTHERS_GOAT = """
+------+  +------+  +------+
| CAR! |  |  ((  |  |  ((  |
|    __|  |  oo  |  |  oo  |
|  _/  |  | /_/|_|  | /_/|_|
| /_ __|  |    | |  |    | |
|   O  |  |GOAT|||  |GOAT|||
+------+  +------+  +------+"""

SECOND_CAR_OTHERS_GOAT = """
+------+  +------+  +------+
|  ((  |  | CAR! |  |  ((  |
|  oo  |  |    __|  |  oo  |
| /_/|_|  |  _/  |  | /_/|_|
|    | |  | /_ __|  |    | |
|GOAT|||  |   O  |  |GOAT|||
+------+  +------+  +------+"""

THIRD_CAR_OTHERS_GOAT = """
+------+  +------+  +------+
|  ((  |  |  ((  |  | CAR! |
|  oo  |  |  oo  |  |    __|
| /_/|_|  | /_/|_|  |  _/  |
|    | |  |    | |  | /_ __|
|GOAT|||  |GOAT|||  |   O  |
+------+  +------+  +------+"""

print('''The Monty Hall Problem, by Al Sweigart email@protected

In the Monty Hall game show, you can pick one of three doors. One door
has a new car for a prize. The other two doors have worthless goats:
{} 77\. Say you pick Door #1.
Before the door you choose is opened, another door with a goat is opened:
{} 80\. You can choose to either open the door you originally picked or swap
to the other unopened door.

It may seem like it doesn't matter if you swap or not, but your odds
do improve if you swap doors! This program demonstrates the Monty Hall
problem by letting you do repeated experiments.

You can read an explanation of why swapping is better at
https://en.wikipedia.org/wiki/Monty_Hall_problem
'''.format(ALL_CLOSED, THIRD_GOAT))

input('Press Enter to start...')


swapWins = 0
swapLosses = 0
stayWins = 0
stayLosses = 0
while True:  # Main program loop.
   # The computer picks which door has the car:
    doorThatHasCar = random.randint(1, 3)

    # Ask the player to pick a door:
    print(ALL_CLOSED)
    while True:  # Keep asking the player until they enter a valid door.
        print('Pick a door 1, 2, or 3 (or "quit" to stop):')
        response = input('> ').upper()
        if response == 'QUIT':
            # End the game.
            print('Thanks for playing!')
            sys.exit()

        if response == '1' or response == '2' or response == '3':
            break
    doorPick = int(response)

    # Figure out which goat door to show the player:
    while True:
        # Select a door that is a goat and not picked by the player:
        showGoatDoor = random.randint(1, 3)
        if showGoatDoor != doorPick and showGoatDoor != doorThatHasCar:
            break

    # Show this goat door to the player:
    if showGoatDoor == 1:
        print(FIRST_GOAT)
    elif showGoatDoor == 2:
        print(SECOND_GOAT)
    elif showGoatDoor == 3:
        print(THIRD_GOAT)

    print('Door {} contains a goat!'.format(showGoatDoor))

    # Ask the player if they want to swap:
    while True:  # Keep asking until the player enters Y or N.
        print('Do you want to swap doors? Y/N')
        swap = input('> ').upper()
        if swap == 'Y' or swap == 'N':
            break

    # Swap the player's door if they wanted to swap:
    if swap == 'Y':
        if doorPick == 1 and showGoatDoor == 2:
            doorPick = 3
        elif doorPick == 1 and showGoatDoor == 3:
            doorPick = 2
        elif doorPick == 2 and showGoatDoor == 1:
            doorPick = 3
        elif doorPick == 2 and showGoatDoor == 3:
            doorPick = 1
        elif doorPick == 3 and showGoatDoor == 1:
            doorPick = 2
        elif doorPick == 3 and showGoatDoor == 2:
            doorPick = 1

    # Open all the doors:
    if doorThatHasCar == 1:
        print(FIRST_CAR_OTHERS_GOAT)
    elif doorThatHasCar == 2:
        print(SECOND_CAR_OTHERS_GOAT)
    elif doorThatHasCar == 3:
        print(THIRD_CAR_OTHERS_GOAT)

    print('Door {} has the car!'.format(doorThatHasCar))

    # Record wins and losses for swapping and not swapping:
    if doorPick == doorThatHasCar:
        print('You won!')
        if swap == 'Y':
            swapWins += 1
        elif swap == 'N':
            stayWins += 1
    else:
        print('Sorry, you lost.')
        if swap == 'Y':
            swapLosses += 1
        elif swap == 'N':
            stayLosses += 1

    # Calculate success rate of swapping and not swapping:
    totalSwaps = swapWins + swapLosses
    if totalSwaps != 0:  # Prevent zero-divide error.
        swapSuccess = round(swapWins / totalSwaps * 100, 1)
    else:
        swapSuccess = 0.0

    totalStays = stayWins + stayLosses
    if (stayWins + stayLosses) != 0:  # Prevent zero-divide.
        staySuccess = round(stayWins / totalStays * 100, 1)
    else:
        staySuccess = 0.0

    print()
    print('Swapping:     ', end='')
    print('{} wins, {} losses, '.format(swapWins, swapLosses), end='')
    print('success rate {}%'.format(swapSuccess))
    print('Not swapping: ', end='')
    print('{} wins, {} losses, '.format(stayWins, stayLosses), end='')
    print('success rate {}%'.format(staySuccess))
    print()
    input('Press Enter repeat the experiment...') 

探索程序

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

  1. 如果把第 100 行的doorThatHasCar = random.randint(1, 3)改成doorThatHasCar = 1会怎么样?
  2. 如果把第 124 到 129 行换成print([FIRST_GOAT, SECOND_GOAT, THIRD_GOAT][showGoatDoor - 1])会怎么样?

四十九、乘法表

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

这个程序生成一个从0 × 012 × 12的乘法表。虽然简单,但它提供了嵌套循环的有用演示。

运行示例

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

Multiplication Table, by Al Sweigart email@protected
  |  0   1   2   3   4   5   6   7   8   9  10  11  12
--+---------------------------------------------------
 0|  0   0   0   0   0   0   0   0   0   0   0   0   0
 1|  0   1   2   3   4   5   6   7   8   9  10  11  12
 2|  0   2   4   6   8  10  12  14  16  18  20  22  24
 3|  0   3   6   9  12  15  18  21  24  27  30  33  36
 4|  0   4   8  12  16  20  24  28  32  36  40  44  48
 5|  0   5  10  15  20  25  30  35  40  45  50  55  60
 6|  0   6  12  18  24  30  36  42  48  54  60  66  72
 7|  0   7  14  21  28  35  42  49  56  63  70  77  84
 8|  0   8  16  24  32  40  48  56  64  72  80  88  96
 9|  0   9  18  27  36  45  54  63  72  81  90  99 108
10|  0  10  20  30  40  50  60  70  80  90 100 110 120
11|  0  11  22  33  44  55  66  77  88  99 110 121 132
12|  0  12  24  36  48  60  72  84  96 108 120 132 144

工作原理

第 9 行打印表格的第一行。请注意,它在数字之间设置了足够大的距离,以容纳最大长度为三位数的产品。由于这是一个12 × 12的乘法表,这个间距可以装下最大的积,144。如果您想创建一个更大的表格,您可能还需要增加列的间距。请记住,标准的终端窗口是 80 列宽,24 行高,所以如果不在窗口的右边换行,就无法创建更大的乘法表。

"""Multiplication Table, by Al Sweigart email@protected
Print a multiplication table.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: tiny, beginner, math"""

print('Multiplication Table, by Al Sweigart email@protected')

# Print the horizontal number labels:
print('  |  0   1   2   3   4   5   6   7   8   9  10  11  12')
print('--+---------------------------------------------------')

# Display each row of products:
for number1 in range(0, 13):

    # Print the vertical numbers labels:
    print(str(number1).rjust(2), end='')

    # Print a separating bar:
    print('|', end='')

    for number2 in range(0, 13):
        # Print the product followed by a space:
        print(str(number1 * number2).rjust(3), end=' ')

    print()  # Finish the row by printing a newline. 

探索程序

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

  1. 如果把第 13 行的range(0, 13)改成range(0, 80)会怎么样?
  2. 如果把第 13 行的range(0, 13)改成range(0, 100)会怎么样?

五十、九十九瓶

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

《九十九瓶》是一首来历不明的民歌,以其长度和反复性著称。歌词是这样的,“九十九瓶牛奶在墙上,九十九瓶牛奶。拿一个下来,传一传,墙上九十八瓶奶。”正如歌词所重复的,瓶子的数量从九十八降到九十七,再从九十七降到九十六,直到零:“墙上一瓶牛奶,一瓶牛奶。拿下来,传来传去,墙上已经没有牛奶瓶了!”

对我们来说幸运的是,计算机擅长执行重复性的任务,这个程序以编程的方式再现了所有的歌词。这个程序的一个扩展版本在项目 51 中,“90 分钟启动”

运行示例

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

Ninety-Nine Bottles, by Al Sweigart email@protected

(Press Ctrl-C to quit.)
99 bottles of milk on the wall,
99 bottles of milk,
Take one down, pass it around,
98 bottles of milk on the wall!

98 bottles of milk on the wall,
98 bottles of milk,
Take one down, pass it around,
97 bottles of milk on the wall!
`--snip--`

工作原理

这首歌中的重复很容易使用一个for循环(从第 20 行到第 30 行)来显示前 98 节。然而,最后一节有一些小的不同,需要单独的代码来显示(第 33 到 39 行)。这是因为最后一行'No more bottles of milk on the wall!'偏离了循环中重复的那一行,也是因为单词bottle是单数而不是复数。

"""Ninety-Nine Bottles of Milk on the Wall
By Al Sweigart email@protected
Print the full lyrics to one of the longest songs ever! Press
Ctrl-C to stop.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: tiny, beginner, scrolling"""

import sys, time

print('Ninety-Nine Bottles, by Al Sweigart email@protected')
print()
print('(Press Ctrl-C to quit.)')

time.sleep(2)

bottles = 99  # This is the starting number of bottles.
PAUSE = 2  # (!) Try changing this to 0 to see the full song at once.

try:
    while bottles > 1:  # Keep looping and display the lyrics.
        print(bottles, 'bottles of milk on the wall,')
        time.sleep(PAUSE)  # Pause for PAUSE number of seconds.
        print(bottles, 'bottles of milk,')
        time.sleep(PAUSE)
        print('Take one down, pass it around,')
        time.sleep(PAUSE)
        bottles = bottles - 1  # Decrease the number of bottles by one.
        print(bottles, 'bottles of milk on the wall!')
        time.sleep(PAUSE)
        print()  # Print a newline.

    # Display the last stanza:
    print('1 bottle of milk on the wall,')
    time.sleep(PAUSE)
    print('1 bottle of milk,')
    time.sleep(PAUSE)
    print('Take it down, pass it around,')
    time.sleep(PAUSE)
    print('No more bottles of milk on the wall!')
except KeyboardInterrupt:
    sys.exit()  # When Ctrl-C is pressed, end the program. 

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

  • 为重复的歌曲“圣诞节的十二天”创建一个程序
  • 为其他累积歌曲创建程序。你可以在en.wikipedia.org/wiki/Cumulative_song找到他们的名单。

探索程序

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

  1. 如果把第 27 行的bottles = bottles - 1改成bottles = bottles - 2会怎么样?
  2. 如果把第 20 行的while bottles > 1:改成while bottles < 1:会怎么样?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/10222.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ptuning v2 的 chatglm垂直领域训练记录

thunlp chatglm 6B是一款基于海量高质量中英文语料训练的面向文本对话场景的语言模型。 THUDM/ChatGLM-6B: ChatGLM-6B&#xff1a;开源双语对话语言模型 | An Open Bilingual Dialogue Language Model (github.com) 国内的一位大佬把chatglm ptuning 的训练改成了多层多卡并…

期刊论文图片代码复现【由图片还原代码】(OriginMatlab)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…

【Golang入门】简介与基本语法学习

下面是一篇关于Golang新手入门的博客&#xff0c;记录一下。&#xff08;如果有语言基础基本可以1小时入门&#xff09; 一、什么是Golang&#xff1f; Golang&#xff08;又称Go&#xff09;是一种由谷歌公司开发的编程语言。它是一种静态类型、编译型、并发型语言&#xff0…

【JLink仿真器】盗版检测、连接故障、检测不到芯片问题

【JLink仿真器】盗版检测、连接故障、检测不到芯片问题一、问题描述二、解决方法1、降低驱动&#xff08;解决非法问题以及连接故障&#xff09;2、SWD引脚被锁&#xff08;解决检测不到芯片&#xff09;三、说明一、问题描述 盗版检测&#xff1a;the connected probe appear…

【Linux】网络原理

本篇博客让我们一起来了解一下网络的基本原理 1.网络发展背景 关于网络发展的历史背景这种东西就不多bb了&#xff0c;网上很容易就能找到参考资料&#xff0c;我的专业性欠缺&#xff0c;文章参考意义也不大。这里只做简单说明。 网络发展经过了如下几个模式 独立模式&…

几何算法——4.交线(intersection curve)的表达与参数化、微分性质

几何算法——4.曲面求交的交线&#xff08;intersection curve&#xff09;的表达与参数化、微分性质1 关于曲面求交的交线表达2 交线的微分性质3 交线的参数化4 修正弦长参数化的微分性质1 关于曲面求交的交线表达 两个曲面求交&#xff0c;比较经典的方法是用跟踪法&#xf…

【CSS】绝对定位元素设置 水平 / 垂直 居中 ( 绝对定位元素居中设置 - 先偏移 50% 再回退子元素一半尺寸 | 绝对定位居中设置 )

文章目录一、问题提出二、绝对定位 居中设置1、设置固定尺寸2、先偏移50%再回退固定值三、绝对定位元素 水平 / 垂直 居中一、问题提出 绝对定位 不能通过 设置 margin: auto; 样式的方式 , 设置盒子模型水平居中 ; 相对定位 的 盒子模型 , 并没有脱离标准流限制 , 仍然可以使…

2023-数据质量管理方法总结

一、数据质量保障原则 如何评估数据质量的好坏&#xff0c;业界有不同的标准&#xff0c;阿里主要从4个方面进行评估&#xff1a;完整性、准确性、一致性、及时性&#xff1b; 1.完整性 数据完整性是数据最基础的保障&#xff1b; 完整性&#xff1a;指数据的记录和信息是否…

d2l 文本预处理textDataset

这一节极其重要&#xff0c;重要到本来是d2l的内容我也要归到pyhon封面&#xff0c;这里面class的操作很多&#xff0c;让我娓娓道来&#xff01; 目录 1.要实现的函数 2.读取数据集 3.词元化 4.Vocab类 4.1count_corpus(tokens) 4.2class中的各种self 4.2.1 _token_fr…

KIOPTRIX: LEVEL 4通关详解

环境配置 vulnhub上下载的文件没有vmx 去3的文件里偷一个 记事本打开把所有Kioptrix3_vmware改成Kioptrix4_vmware 然后网卡地址随便改一下 打开后会提示找不到虚拟机,手动选一下就行了 信息收集 漏洞发现 web一上去就是一个登录框 扫路径发现database.sql 但是密码是错的…

Amazon SageMaker简直就是机器学习平台的天花板

一、前言 最近参与了亚马逊云科技【云上探索实验】活动&#xff0c;通过Amazon SageMaker基于Stable Diffusion模型&#xff0c;非常简单快速搭建的第一个AIGC&#xff0c;一开始以为非常复杂&#xff0c;不懂动手操作&#xff0c;但实际上操作非常简单&#xff0c;没有想象中…

【嵌入式Linux】Jetson nano GPIO应用 | 驱动开发 | 官方gpiolib、设备树与chip_driver

GPIO子系统 0.暴露给应用层 应用 $ echo 79 > /sys/class/gpio/export //导出79号gpio 引脚&#xff0c;使得可在应用层访问 $ echo out > /sys/class/gpio/gpio79/direction //设置 为输出 $ echo 1 > /sys/class/gpio/gpio79/value //输出高电平 开灯 $ echo 0…

Spark对正常日志文件清洗并分析

目录 日志文件准备&#xff1a; 一.日志数据清洗&#xff1a; 第一步&#xff1a;数据清洗需求分析&#xff1a; 二.代码实现 2.1 代码和其详解 2.2创建jdbcUtils来连接Mysql数据库 2.3 运行后结果展示&#xff1a; 三、留存用户分析 3.1需求概览 3.2.代码实现 3…

T 级数据量迁移!知名云巨头如何从 Jira 切换至 ONES?

2021 年&#xff0c;Atlassian 旗下 Jira&Confluence 等系列产品 Server 版&#xff08;本地私有化部署版&#xff09;全面停售&#xff0c;并将在 2024 年停止维护&#xff0c;Server 版客户必须迁移至 Cloud&#xff08;云&#xff09;或 Data Center&#xff08;数据中心…

全网最详细,Jmeter性能测试-性能基础详解,控制器不同选择(四)

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 逻辑控制器 提前说…

一篇文章让你搞懂TypeScript中的??和?:和?.和!.是什么意思

TypeScript中的??和?:和?.和!.是什么意思&#xff1f;知识回调&#xff08;不懂就看这儿&#xff01;&#xff09;场景复现核心干货???:?.!.知识回调&#xff08;不懂就看这儿&#xff01;&#xff09; 知识专栏专栏链接TypeScript知识专栏https://blog.csdn.net/xsl_…

Scrapy爬虫框架(概念)

Scrapy 入门教程 | 菜鸟教程 (runoob.com) Scrapy是一个快速功能强大的网络爬虫框架 Scrapy的安装 通过 pip 安装 Scrapy 框架: pip install Scrapy 安装后小测&#xff1a; 执行 scrapy ‐h Scrapy不是一个函数功能库&#xff0c;而是一个爬虫框架。 Scrapy架构图(绿线是…

CentOS7 虚拟机 双网卡绑定

一、网卡绑定模式 模式类型特点mode0round-robin&#xff08;平衡轮询策略&#xff09;基于per packet方式&#xff0c;轮询往每条链路发送报文。提供负载均衡和容错的能力&#xff0c;当有链路出问题&#xff0c;会把流量切换到正常的链路上。交换机端需要配置聚合口。mode1a…

【论文笔记】CRN: Camera Radar Net for Accurate, Robust, Efficient 3D Perception

原文链接&#xff1a;https://arxiv.org/abs/2304.00670 1. 引言 本文提出两阶段融合方法CRN&#xff0c;能使用相机和雷达生成语义丰富且位置精确的BEV特征。具体来说&#xff0c;首先将图像透视特征转换到BEV下&#xff0c;该步骤依赖雷达&#xff0c;称为雷达辅助的视图变换…

C#基础复习

语句 目录 语句 switch&#xff1a; 跳转语句 标签语句 标签&#xff1a; 标签语句的作用域 goto语句 using 语句 资源的包装使用 using 语句示例&#xff1a; 多个资源和嵌套 语句是描述某个类型或让程序执行某个动作的源代码指令 块在语法上算作一个单条嵌入语句。任何语…