Python 小型项目大全 1~5

一、百吉饼

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

在百吉饼这种演绎逻辑游戏中,你必须根据线索猜出一个秘密的三位数。该游戏提供以下提示之一来响应您的猜测:"Pico",当您的猜测在错误的位置有正确的数字时,"Fermi",当您的猜测在正确的位置有正确的数字时,以及"Bagels",如果您的猜测没有正确的数字。你有 10 次机会猜这个秘密数字。

运行示例

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

Bagels, a deductive logic game.
By Al Sweigart email@protected
I am thinking of a 3-digit number. Try to guess what it is.
Here are some clues:
When I say:    That means:
  Pico         One digit is correct but in the wrong position.
  Fermi        One digit is correct and in the right position.
  Bagels       No digit is correct.
I have thought up a number.
 You have 10 guesses to get it.
Guess #1:
> 123
Pico
Guess #2:
> 456
Bagels
Guess #3:
> 178
Pico Pico
`--snip--`
Guess #7:
> 791
Fermi Fermi
Guess #8:
> 701
You got it!
Do you want to play again? (yes or no)
> no
Thanks for playing!

工作原理

请记住,这个程序使用的不是整数值,而是包含数字的字符串值。例如,'426'是与426不同的值。我们需要这样做,因为我们执行的是与秘密数字的字符串比较,而不是数学运算。记住'0'可以是前导数字:字符串'026''26'不同,但整数02626相同。

"""Bagels, by Al Sweigart email@protected
A deductive logic game where you must guess a number based on clues.
This code is available at https://nostarch.com/big-book-small-python-programming
A version of this game is featured in the book, "Invent Your Own
Computer Games with Python" https://nostarch.com/inventwithpython
Tags: short, game, puzzle"""

import random

NUM_DIGITS = 3  # (!) Try setting this to 1 or 10.
MAX_GUESSES = 10  # (!) Try setting this to 1 or 100.


def main():
   print('''Bagels, a deductive logic game.
By Al Sweigart email@protected

I am thinking of a {}-digit number with no repeated digits.
Try to guess what it is. Here are some clues:
When I say:    That means:
 Pico         One digit is correct but in the wrong position.
 Fermi        One digit is correct and in the right position.
 Bagels       No digit is correct.

For example, if the secret number was 248 and your guess was 843, the
clues would be Fermi Pico.'''.format(NUM_DIGITS))

   while True:  # Main game loop.
       # This stores the secret number the player needs to guess:
       secretNum = getSecretNum()
       print('I have thought up a number.')
       print(' You have {} guesses to get it.'.format(MAX_GUESSES))

       numGuesses = 1
       while numGuesses <= MAX_GUESSES:
           guess = ''
           # Keep looping until they enter a valid guess:
           while len(guess) != NUM_DIGITS or not guess.isdecimal():
               print('Guess #{}: '.format(numGuesses))
               guess = input('> ')

           clues = getClues(guess, secretNum)
           print(clues)
           numGuesses += 1

           if guess == secretNum:
               break  # They're correct, so break out of this loop.
           if numGuesses > MAX_GUESSES:
               print('You ran out of guesses.')
               print('The answer was {}.'.format(secretNum))

       # Ask player if they want to play again.
       print('Do you want to play again? (yes or no)')
       if not input('> ').lower().startswith('y'):
           break
   print('Thanks for playing!')


def getSecretNum():
   """Returns a string made up of NUM_DIGITS unique random digits."""
   numbers = list('0123456789')  # Create a list of digits 0 to 9.
   random.shuffle(numbers)  # Shuffle them into random order.

   # Get the first NUM_DIGITS digits in the list for the secret number:
   secretNum = ''
   for i in range(NUM_DIGITS):
       secretNum += str(numbers[i])
   return secretNum


def getClues(guess, secretNum):
   """Returns a string with the pico, fermi, bagels clues for a guess
   and secret number pair."""
   if guess == secretNum:
       return 'You got it!'

   clues = []

   for i in range(len(guess)):
       if guess[i] == secretNum[i]:
           # A correct digit is in the correct place.
           clues.append('Fermi')
       elif guess[i] in secretNum:
           # A correct digit is in the incorrect place.
           clues.append('Pico')
   if len(clues) == 0:
       return 'Bagels'  # There are no correct digits at all.
   else:
       # Sort the clues into alphabetical order so their original order
       # doesn't give information away.
       clues.sort()
       # Make a single string from the list of string clues.
       return ' '.join(clues)


# If the program is run (instead of imported), run the game:
if __name__ == '__main__':
   main() 

在输入源代码并运行几次之后,尝试对其进行实验性的修改。标有(!)的注释对你可以做的小改变有建议。你也可以自己想办法做到以下几点:

  • 通过改变NUM_DIGITS来改变密码的位数。
  • 通过改变MAX_GUESSES来改变玩家获得的猜测次数。
  • 尝试创建一个密码中包含字母和数字的版本。

探索程序

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

  1. 改变NUM_DIGITS常数会发生什么?
  2. 改变MAX_GUESSES常数会发生什么?
  3. 如果将NUM_DIGITS设置为大于10的数字会发生什么?
  4. 如果把第 30 行的secretNum = getSecretNum()换成secretNum = '123'会怎么样?
  5. 如果删除或注释掉第 34 行的numGuesses = 1,会得到什么错误信息?
  6. 如果删除或注释掉第 62 行的random.shuffle(numbers)会发生什么?
  7. 如果删除或注释掉第 74 行的if guess == secretNum:和第 75 行的return 'You got it!'会怎么样?
  8. 如果在第 44 行注释掉numGuesses += 1会发生什么?

二、生日悖论

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

生日悖论(Birthday Paradox),也称为生日问题,是指即使在一小群人中,两个人过同一个生日的概率也高得惊人。在一个 70 人的小组中,有 99.9%的可能性两个人有相同的生日。但是,即使在一个只有 23 人的小组中,也有 50%的机会有相同的生日。这个程序执行几个概率实验来确定不同大小的组的百分比。我们称这种类型的实验为蒙特卡洛实验,在这种实验中,我们进行多次随机试验来了解可能的结果。

你可以在en.wikipedia.org/wiki/Birthday_problem找到更多关于生日悖论的信息。

运行示例

当您运行birthdayparadox.py时,输出如下:

Birthday Paradox, by Al Sweigart email@protected
`--snip--`
How many birthdays shall I generate? (Max 100)
> 23
Here are 23 birthdays:
Oct 9, Sep 1, May 28, Jul 29, Feb 17, Jan 8, Aug 18, Feb 19, Dec 1, Jan 22,
May 16, Sep 25, Oct 6, May 6, May 26, Oct 11, Dec 19, Jun 28, Jul 29, Dec 6,
Nov 26, Aug 18, Mar 18
In this simulation, multiple people have a birthday on Jul 29
Generating 23 random birthdays 100,000 times...
Press Enter to begin...
Let's run another 100,000 simulations.
0 simulations run...
10000 simulations run...
`--snip--`
90000 simulations run...
100000 simulations run.
Out of 100,000 simulations of 23 people, there was a
matching birthday in that group 50955 times. This means
that 23 people have a 50.95 % chance of
having a matching birthday in their group.
That's probably more than you would think!

工作原理

运行 100,000 次模拟可能需要一段时间,这就是为什么第 95 行和第 96 行报告另外 10,000 次模拟已经完成。这个反馈可以向用户保证程序没有冻结。注意一些整数,比如第 95 行的10_000和第 93、103 行的100_000,有下划线。这些下划线没有特殊的含义,但是 Python 允许使用它们,这样程序员可以使整数值更容易阅读。换句话说,读100_000的《十万》比读100000的更容易。

"""Birthday Paradox Simulation, by Al Sweigart email@protected
Explore the surprising probabilities of the "Birthday Paradox".
More info at https://en.wikipedia.org/wiki/Birthday_problem
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: short, math, simulation"""

import datetime, random


def getBirthdays(numberOfBirthdays):
   """Returns a list of number random date objects for birthdays."""
   birthdays = []
   for i in range(numberOfBirthdays):
       # The year is unimportant for our simulation, as long as all
       # birthdays have the same year.
       startOfYear = datetime.date(2001, 1, 1)

       # Get a random day into the year:
       randomNumberOfDays = datetime.timedelta(random.randint(0, 364))
       birthday = startOfYear + randomNumberOfDays
       birthdays.append(birthday)
   return birthdays


def getMatch(birthdays):
   """Returns the date object of a birthday that occurs more than once
   in the birthdays list."""
   if len(birthdays) == len(set(birthdays)):
       return None  # All birthdays are unique, so return None.

   # Compare each birthday to every other birthday:
   for a, birthdayA in enumerate(birthdays):
       for b, birthdayB in enumerate(birthdays[a + 1 :]):
           if birthdayA == birthdayB:
               return birthdayA  # Return the matching birthday.


# Display the intro:
print('''Birthday Paradox, by Al Sweigart email@protected

The birthday paradox shows us that in a group of N people, the odds
that two of them have matching birthdays is surprisingly large.
This program does a Monte Carlo simulation (that is, repeated random
simulations) to explore this concept.

(It's not actually a paradox, it's just a surprising result.)
''')

# Set up a tuple of month names in order:
MONTHS = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
         'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')

while True:  # Keep asking until the user enters a valid amount.
   print('How many birthdays shall I generate? (Max 100)')
   response = input('> ')
   if response.isdecimal() and (0 < int(response) <= 100):
       numBDays = int(response)
       break  # User has entered a valid amount.
print()

# Generate and display the birthdays:
print('Here are', numBDays, 'birthdays:')
birthdays = getBirthdays(numBDays)
for i, birthday in enumerate(birthdays):
   if i != 0:
       # Display a comma for each birthday after the first birthday.
       print(', ', end='')
   monthName = MONTHS[birthday.month - 1]
   dateText = '{}  {}'.format(monthName, birthday.day)
   print(dateText, end='')
print()
print()

# Determine if there are two birthdays that match.
match = getMatch(birthdays)

# Display the results:
print('In this simulation, ', end='')
if match != None:
   monthName = MONTHS[match.month - 1]
   dateText = '{}  {}'.format(monthName, match.day)
   print('multiple people have a birthday on', dateText)
else:
   print('there are no matching birthdays.')
print()

# Run through 100,000 simulations:
print('Generating', numBDays, 'random birthdays 100,000 times...')
input('Press Enter to begin...')

print('Let\'s run another 100,000 simulations.')
simMatch = 0  # How many simulations had matching birthdays in them.
for i in range(100000):
   # Report on the progress every 10,000 simulations:
   if i % 10000 == 0:
       print(i, 'simulations run...')
   birthdays = getBirthdays(numBDays)
   if getMatch(birthdays) != None:
       simMatch = simMatch + 1
print('100,000 simulations run.')

# Display simulation results:
probability = round(simMatch / 100000 * 100, 2)
print('Out of 100,000 simulations of', numBDays, 'people, there was a')
print('matching birthday in that group', simMatch, 'times. This means')
print('that', numBDays, 'people have a', probability, '% chance of')
print('having a matching birthday in their group.')
print('That\'s probably more than you would think!') 

探索程序

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

  1. 生日在这个节目中是如何表示的?(提示:请看第 16 行。)
  2. 你如何取消程序生成的 100 个生日的最大限制?
  3. 如果删除或注释掉第 57 行的numBDays = int(response),会得到什么错误信息?
  4. 如何让程序显示完整的月份名称,比如'January'而不是'Jan'
  5. 你如何让'X simulations run...'每 1000 次模拟出现一次,而不是每 10000 次?

三、位图消息

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

这个程序使用一个多行字符串作为位图,一个每个像素只有两种可能颜色的 2D 图像,来决定它应该如何显示来自用户的消息。在这个位图中,空格字符代表一个空白,所有其他字符都被用户消息中的字符所替换。提供的位图类似于世界地图,但是您可以将其更改为您喜欢的任何图像。空格或消息字符系统的二进制简单性使它非常适合初学者。尝试不同的消息,看看结果是什么样的!

运行示例

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

Bitmap Message, by Al Sweigart email@protected
Enter the message to display with the bitmap.
> Hello!

Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!He
   lo!Hello!Hello   l  !He lo  e      llo!Hello!Hello!Hello!Hello!He
  llo!Hello!Hello!Hello He lo H  l !Hello!Hello!Hello!Hello!Hello H
 el      lo!Hello!Hello!He       lo!Hello!Hello!Hello!Hello!Hel
          o!Hello!Hello          lo  e lo!H ll !Hello!Hello!H l
           !Hello!He            llo!Hel   Hello!Hello!Hell ! e
            Hello!He           ello!Hello!Hello!Hello!Hell  H
   l        H llo! ell         ello!Hello!Hell !Hello  el o
               lo!H  l         ello!Hello!Hell   ell !He  o
                 !Hello         llo!Hello!Hel    el   He  o
                 !Hello!H        lo!Hello!Hell    l  !H llo
                   ello!Hel         Hello!He          H llo Hell
                   ello!Hell         ello!H  l        Hell !H l o!
                   ello!Hell         ello!H l o           o!H l   H
                     lo!Hel          ello! el             o!Hel   H
                     lo!He            llo! e            llo!Hell
                    llo!H             llo!              llo!Hello
                    llo!              ll                 lo!Hell   e
                    llo                                       l    e
                    ll     l                    H
Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!Hello!He 

工作原理

你可以从inventwithpython.com/bitmapworld.txt复制并粘贴整个世界地图图案,而不是单独输入每个字符。图案顶部和底部的 68 个句点组成的线充当标尺,帮助您正确对齐。然而,如果您在模式中输入了错误,该程序仍然可以工作。

第 43 行的bitmap.splitlines()方法调用返回一个字符串列表,每个字符串都是多行bitmap字符串中的一行。使用多行字符串使位图更容易编辑成您喜欢的任何图案。该程序填充模式中的任何非空格字符,这就是星号、句点或任何其他字符做同样事情的原因。

第 51 行的message[i % len(message)]代码导致message中文本的重复。随着i0增加到大于len(message)的数字,表达式i % len(message)再次计算为0。这使得message[i % len(message)]随着i的增加而重复message中的字符。

"""Bitmap Message, by Al Sweigart email@protected
Displays a text message according to the provided bitmap image.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: tiny, beginner, artistic"""

import sys

# (!) Try changing this multiline string to any image you like:

# There are 68 periods along the top and bottom of this string:
# (You can also copy and paste this string from
# https://inventwithpython.com/bitmapworld.txt)
bitmap = """
....................................................................
   **************   *  *** **  *      ******************************
  ********************* ** ** *  * ****************************** *
 **      *****************       ******************************
          *************          **  * **** ** ************** *
           *********            *******   **************** * *
            ********           ***************************  *
   *        * **** ***         *************** ******  ** *
               ****  *         ***************   *** ***  *
                 ******         *************    **   **  *
                 ********        *************    *  ** ***
                   ********         ********          * *** ****
                   *********         ******  *        **** ** * **
                   *********         ****** * *           *** *   *
                     ******          ***** **             *****   *
                     *****            **** *            ********
                    *****             ****              *********
                    ****              **                 *******   *
                    ***                                       *    *
                    **     *                    *
...................................................................."""

print('Bitmap Message, by Al Sweigart email@protected')
print('Enter the message to display with the bitmap.')
message = input('> ')
if message == '':
    sys.exit()

# Loop over each line in the bitmap:
for line in bitmap.splitlines():
    # Loop over each character in the line:
    for i, bit in enumerate(line):
        if bit == ' ':
            # Print an empty space since there's a space in the bitmap:
            print(' ', end='')
        else:
            # Print a character from the message:
            print(message[i % len(message)], end='')
    print()  # Print a newline. 

在输入源代码并运行几次之后,尝试对其进行实验性的修改。您可以更改bitmap中的字符串来创建全新的模式。

探索程序

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

  1. 如果玩家为消息输入一个空字符串会发生什么?
  2. bitmap变量的字符串中有什么非空格字符有关系吗?
  3. 第 45 行创建的i变量代表什么?
  4. 如果删除或注释掉第 52 行的print(),会出现什么 bug?

四、二十一点

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

21 点,也称为 21 点,是一种纸牌游戏,玩家试图在不超过 21 点的情况下尽可能接近 21 点。这个程序使用用文本字符绘制的图像,称为 ASCII 艺术画。美国信息交换标准码(ASCII)是 Unicode 取代之前计算机使用的文本字符到数字代码的映射。本程序中的扑克牌是 ASCII 艺术画的一个例子:

 ___   ___
|A  | |10 |
|| ||
|__A| |_10|

你可以在en.wikipedia.org/wiki/Blackjack找到其他规则和这个纸牌游戏的历史。

运行示例

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

Blackjack, by Al Sweigart email@protected

    Rules:
      Try to get as close to 21 without going over.
      Kings, Queens, and Jacks are worth 10 points.
      Aces are worth 1 or 11 points.
      Cards 2 through 10 are worth their face value.
      (H)it to take another card.
      (S)tand to stop taking cards.
      On your first play, you can (D)ouble down to increase your bet
      but must hit exactly one more time before standing.
      In case of a tie, the bet is returned to the player.
      The dealer stops hitting at 17.
Money: 5000
How much do you bet? (1-5000, or QUIT)
> 400
Bet: 400

DEALER: ???
 ___   ___
|## | |2  |
|###| | ♥ |
|_##| |__2|

PLAYER: 17
 ___   ___
|K  | |7  |
|| ||
|__K| |__7|

(H)it, (S)tand, (D)ouble down
> h
You drew a 4 of ♦.
`--snip--`
DEALER: 18
 ___   ___   ___
|K  | |2  | |6  |
|| || ||
|__K| |__2| |__6|

PLAYER: 21
 ___   ___   ___
|K  | |7  | |4  |
|| || ||
|__K| |__7| |__4|

You won $400!
`--snip—`

工作原理

你的键盘上没有牌组符号,这就是为什么我们调用chr()函数来创建它们。传递给chr()的整数被称为 Unicode 码位,这是根据 Unicode 标准标识字符的唯一数字。Unicode 经常被误解。然而,Ned Batchelder 的 2012 年 PyCon US talk“实用 Unicode,或者我如何停止痛苦?”是对 Unicode 的极好介绍,您可以在youtu.be/sgHbC6udIqc找到它。附录 B 给出了可以在 Python 程序中使用的 Unicode 字符的完整列表。

"""Blackjack, by Al Sweigart email@protected
The classic card game also known as 21\. (This version doesn't have
splitting or insurance.)
More info at: https://en.wikipedia.org/wiki/Blackjack
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: large, game, card game"""

import random, sys

# Set up the constants:
HEARTS   = chr(9829) # Character 9829 is '♥'.
DIAMONDS = chr(9830) # Character 9830 is '♦'.
SPADES   = chr(9824) # Character 9824 is '♠'.
CLUBS    = chr(9827) # Character 9827 is '♣'.
# (A list of chr codes is at https://inventwithpython.com/charactermap)
BACKSIDE = 'backside'


def main():
   print('''Blackjack, by Al Sweigart email@protected

   Rules:
     Try to get as close to 21 without going over.
     Kings, Queens, and Jacks are worth 10 points.
     Aces are worth 1 or 11 points.
     Cards 2 through 10 are worth their face value.
     (H)it to take another card.
     (S)tand to stop taking cards.
     On your first play, you can (D)ouble down to increase your bet
     but must hit exactly one more time before standing.
     In case of a tie, the bet is returned to the player.
     The dealer stops hitting at 17.''')

   money = 5000
   while True:  # Main game loop.
       # Check if the player has run out of money:
       if money <= 0:
           print("You're broke!")
           print("Good thing you weren't playing with real money.")
           print('Thanks for playing!')
           sys.exit()

       # Let the player enter their bet for this round:
       print('Money:', money)
       bet = getBet(money)

       # Give the dealer and player two cards from the deck each:
       deck = getDeck()
       dealerHand = [deck.pop(), deck.pop()]
       playerHand = [deck.pop(), deck.pop()]

       # Handle player actions:
       print('Bet:', bet)
       while True:  # Keep looping until player stands or busts.
           displayHands(playerHand, dealerHand, False)
           print()

           # Check if the player has bust:
           if getHandValue(playerHand) > 21:
               break

           # Get the player's move, either H, S, or D:
           move = getMove(playerHand, money - bet)

           # Handle the player actions:
           if move == 'D':
               # Player is doubling down, they can increase their bet:
               additionalBet = getBet(min(bet, (money - bet)))
               bet += additionalBet
               print('Bet increased to {}.'.format(bet))
               print('Bet:', bet)

           if move in ('H', 'D'):
               # Hit/doubling down takes another card.
               newCard = deck.pop()
               rank, suit = newCard
               print('You drew a {} of {}.'.format(rank, suit))
               playerHand.append(newCard)

               if getHandValue(playerHand) > 21:
                   # The player has busted:
                   continue

           if move in ('S', 'D'):
               # Stand/doubling down stops the player's turn.
               break

       # Handle the dealer's actions:
       if getHandValue(playerHand) <= 21:
           while getHandValue(dealerHand) < 17:
               # The dealer hits:
               print('Dealer hits...')
               dealerHand.append(deck.pop())
               displayHands(playerHand, dealerHand, False)

               if getHandValue(dealerHand) > 21:
                   break  # The dealer has busted.
               input('Press Enter to continue...')
               print('\n\n')

        # Show the final hands:
        displayHands(playerHand, dealerHand, True)

        playerValue = getHandValue(playerHand)
        dealerValue = getHandValue(dealerHand)
        # Handle whether the player won, lost, or tied:
        if dealerValue > 21:
            print('Dealer busts! You win ${}!'.format(bet))
            money += bet
        elif (playerValue > 21) or (playerValue < dealerValue):
            print('You lost!')
            money -= bet
        elif playerValue > dealerValue:
            print('You won ${}!'.format(bet))
            money += bet
        elif playerValue == dealerValue:
            print('It\'s a tie, the bet is returned to you.')

        input('Press Enter to continue...')
        print('\n\n')


def getBet(maxBet):
    """Ask the player how much they want to bet for this round."""
    while True:  # Keep asking until they enter a valid amount.
        print('How much do you bet? (1-{}, or QUIT)'.format(maxBet))
        bet = input('> ').upper().strip()
        if bet == 'QUIT':
            print('Thanks for playing!')
            sys.exit()

        if not bet.isdecimal():
            continue  # If the player didn't enter a number, ask again.

        bet = int(bet)
        if 1 <= bet <= maxBet:
            return bet  # Player entered a valid bet.


def getDeck():
    """Return a list of (rank, suit) tuples for all 52 cards."""
    deck = []
    for suit in (HEARTS, DIAMONDS, SPADES, CLUBS):
        for rank in range(2, 11):
            deck.append((str(rank), suit))  # Add the numbered cards.
        for rank in ('J', 'Q', 'K', 'A'):
            deck.append((rank, suit))  # Add the face and ace cards.
    random.shuffle(deck)
    return deck


def displayHands(playerHand, dealerHand, showDealerHand):
    """Show the player's and dealer's cards. Hide the dealer's first
    card if showDealerHand is False."""
    print()
    if showDealerHand:
        print('DEALER:', getHandValue(dealerHand))
        displayCards(dealerHand)
    else:
        print('DEALER: ???')
        # Hide the dealer's first card:
        displayCards([BACKSIDE] + dealerHand[1:])

    # Show the player's cards:
    print('PLAYER:', getHandValue(playerHand))
    displayCards(playerHand)


def getHandValue(cards):
    """Returns the value of the cards. Face cards are worth 10, aces are
    worth 11 or 1 (this function picks the most suitable ace value)."""
    value = 0
    numberOfAces = 0

    # Add the value for the non-ace cards:
    for card in cards:
        rank = card[0]  # card is a tuple like (rank, suit)
        if rank == 'A':
            numberOfAces += 1
        elif rank in ('K', 'Q', 'J'):  # Face cards are worth 10 points.
            value += 10
        else:
            value += int(rank)  # Numbered cards are worth their number.

    # Add the value for the aces:
    value += numberOfAces  # Add 1 per ace.
    for i in range(numberOfAces):
        # If another 10 can be added without busting, do so:
        if value + 10 <= 21:
            value += 10

    return value


def displayCards(cards):
    """Display all the cards in the cards list."""
    rows = ['', '', '', '', '']  # The text to display on each row.

    for i, card in enumerate(cards):
        rows[0] += ' ___  '  # Print the top line of the card.
        if card == BACKSIDE:
            # Print a card's back:
            rows[1] += '|## | '
            rows[2] += '|###| '
            rows[3] += '|_##| '
        else:
            # Print the card's front:
            rank, suit = card  # The card is a tuple data structure.
            rows[1] += '|{} | '.format(rank.ljust(2))
            rows[2] += '| {} | '.format(suit)
            rows[3] += '|_{}| '.format(rank.rjust(2, '_'))

    # Print each row on the screen:
    for row in rows:
        print(row)


def getMove(playerHand, money):
    """Asks the player for their move, and returns 'H' for hit, 'S' for
    stand, and 'D' for double down."""
    while True:  # Keep looping until the player enters a correct move.
        # Determine what moves the player can make:
        moves = ['(H)it', '(S)tand']

        # The player can double down on their first move, which we can
        # tell because they'll have exactly two cards:
        if len(playerHand) == 2 and money > 0:
            moves.append('(D)ouble down')

        # Get the player's move:
        movePrompt = ', '.join(moves) + '> '
        move = input(movePrompt).upper()
        if move in ('H', 'S'):
            return move  # Player has entered a valid move.
        if move == 'D' and '(D)ouble down' in moves:
            return move  # Player has entered a valid move.


# If the program is run (instead of imported), run the game:
if __name__ == '__main__':
    main() 

在输入源代码并运行几次之后,尝试对其进行实验性的修改。21 点有几个自定义规则,你可以实现。例如,如果前两张牌的价值相同,玩家可以将它们分成两只手,分别下注。此外,如果玩家的前两张牌中有一张“21 点”(黑桃 A 和 21 点),玩家将赢得十比一的奖金。你可以从en.wikipedia.org/wiki/Blackjack那里找到更多关于这个游戏的信息。

探索程序

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

  1. 你如何让玩家以不同的金额开始游戏?
  2. 该计划如何防止玩家下注超过他们的钱?
  3. 程序如何表示单卡?
  4. 该程序如何表示一手牌?
  5. rows列表中的每个字符串(在第 197 行创建)代表什么?
  6. 如果删除或注释掉第 148 行的random.shuffle(deck)会发生什么?
  7. 如果把 112 行的money -= bet改成money += bet会怎么样?
  8. displayHands()函数中的showDealerHand设置为True时会发生什么?到了False会怎么样?

五、弹跳 DVD 标志

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

如果你到了一定的年龄,你会记得那些被称为 DVD 播放器的古老技术设备。当不播放 DVD 时,他们会显示一个从屏幕边缘反弹回来的对角线方向的 DVD 标志。这个程序通过每次碰到边缘时改变方向来模拟这个彩色的 DVD 标志。我们还将记录一个标志点击屏幕一角的次数。这创造了一个有趣的视觉动画,特别是当一个标志与一个角完美地对齐的神奇时刻。

您不能从您的集成开发环境(IDE)或编辑器运行此程序,因为它使用了bext模块。因此,必须从命令提示符或终端运行它才能正确显示。你可以在pypi.org/project/bext找到更多关于bext模块的信息。

运行示例

当你运行bouncingdvd.py时,输出将看起来像图 5-1 。

f05001

bouncingdvd.py节目的斜向移动的 DVD 标识

工作原理

你可能还记得学校数学课上的笛卡尔坐标。在编程中,x 坐标表示对象的水平位置,y 坐标表示其垂直位置,就像数学中一样。然而,与数学中不同的是,原点(0, 0)在屏幕的左上角,y 坐标随着向下移动而增加。x 坐标随着对象向右移动而增加,就像数学中一样。图 5-2 显示了屏幕的坐标系统。

f05002

:原点(0,0)在屏幕的左上方,x 和 y 坐标分别向右下递增。

bext模块的goto()函数工作方式相同:调用bext.goto(0, 0)将文本光标放在终端窗口的左上角。我们使用一个 Python 字典,用关键字'color''direction''x''y'来表示每个跳动的 DVD 标志。'x''y'的值是代表窗口中徽标位置的整数。由于这些值被传递到bext.goto(),增加它们将使徽标向右和向下移动,而减少它们将使徽标向左和向上移动。

"""Bouncing DVD Logo, by Al Sweigart email@protected
A bouncing DVD logo animation. You have to be "of a certain age" to
appreciate this. Press Ctrl-C to stop.

NOTE: Do not resize the terminal window while this program is running.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: short, artistic, bext"""

import sys, random, time

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:
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

NUMBER_OF_LOGOS = 5  # (!) Try changing this to 1 or 100.
PAUSE_AMOUNT = 0.2  # (!) Try changing this to 1.0 or 0.0.
# (!) Try changing this list to fewer colors:
COLORS = ['red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white']

UP_RIGHT   = 'ur'
UP_LEFT    = 'ul'
DOWN_RIGHT = 'dr'
DOWN_LEFT  = 'dl'
DIRECTIONS = (UP_RIGHT, UP_LEFT, DOWN_RIGHT, DOWN_LEFT)

# Key names for logo dictionaries:
COLOR = 'color'
X = 'x'
Y = 'y'
DIR = 'direction'


def main():
   bext.clear()

   # Generate some logos.
   logos = []
   for i in range(NUMBER_OF_LOGOS):
       logos.append({COLOR: random.choice(COLORS),
                     X: random.randint(1, WIDTH - 4),
                     Y: random.randint(1, HEIGHT - 4),
                     DIR: random.choice(DIRECTIONS)})
       if logos[-1][X] % 2 == 1:
           # Make sure X is even so it can hit the corner.
           logos[-1][X] -= 1

   cornerBounces = 0  # Count how many times a logo hits a corner.
   while True:  # Main program loop.
       for logo in logos:  # Handle each logo in the logos list.
           # Erase the logo's current location:
           bext.goto(logo[X], logo[Y])
           print('   ', end='')  # (!) Try commenting this line out.

           originalDirection = logo[DIR]

           # See if the logo bounces off the corners:
           if logo[X] == 0 and logo[Y] == 0:
               logo[DIR] = DOWN_RIGHT
               cornerBounces += 1
           elif logo[X] == 0 and logo[Y] == HEIGHT - 1:
               logo[DIR] = UP_RIGHT
               cornerBounces += 1
           elif logo[X] == WIDTH - 3 and logo[Y] == 0:
               logo[DIR] = DOWN_LEFT
               cornerBounces += 1
           elif logo[X] == WIDTH - 3 and logo[Y] == HEIGHT - 1:
               logo[DIR] = UP_LEFT
               cornerBounces += 1

           # See if the logo bounces off the left edge:
           elif logo[X] == 0 and logo[DIR] == UP_LEFT:
               logo[DIR] = UP_RIGHT
           elif logo[X] == 0 and logo[DIR] == DOWN_LEFT:
               logo[DIR] = DOWN_RIGHT

           # See if the logo bounces off the right edge:
           # (WIDTH - 3 because 'DVD' has 3 letters.)
           elif logo[X] == WIDTH - 3 and logo[DIR] == UP_RIGHT:
               logo[DIR] = UP_LEFT
           elif logo[X] == WIDTH - 3 and logo[DIR] == DOWN_RIGHT:
               logo[DIR] = DOWN_LEFT

           # See if the logo bounces off the top edge:
           elif logo[Y] == 0 and logo[DIR] == UP_LEFT:
               logo[DIR] = DOWN_LEFT
           elif logo[Y] == 0 and logo[DIR] == UP_RIGHT:
               logo[DIR] = DOWN_RIGHT

           # See if the logo bounces off the bottom edge:
            elif logo[Y] == HEIGHT - 1 and logo[DIR] == DOWN_LEFT:
                logo[DIR] = UP_LEFT
            elif logo[Y] == HEIGHT - 1 and logo[DIR] == DOWN_RIGHT:
                logo[DIR] = UP_RIGHT

            if logo[DIR] != originalDirection:
                # Change color when the logo bounces:
                logo[COLOR] = random.choice(COLORS)

            # Move the logo. (X moves by 2 because the terminal
            # characters are twice as tall as they are wide.)
            if logo[DIR] == UP_RIGHT:
                logo[X] += 2
                logo[Y] -= 1
            elif logo[DIR] == UP_LEFT:
                logo[X] -= 2
                logo[Y] -= 1
            elif logo[DIR] == DOWN_RIGHT:
                logo[X] += 2
                logo[Y] += 1
            elif logo[DIR] == DOWN_LEFT:
                logo[X] -= 2
                logo[Y] += 1

        # Display number of corner bounces:
        bext.goto(5, 0)
        bext.fg('white')
        print('Corner bounces:', cornerBounces, end='')

        for logo in logos:
            # Draw the logos at their new location:
            bext.goto(logo[X], logo[Y])
            bext.fg(logo[COLOR])
            print('DVD', end='')

        bext.goto(0, 0)

        sys.stdout.flush()  # (Required for bext-using programs.)
        time.sleep(PAUSE_AMOUNT)


# If this program was run (instead of imported), run the game:
if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print()
        print('Bouncing DVD Logo, by Al Sweigart')
        sys.exit()  # When Ctrl-C is pressed, end the program. 

在输入源代码并运行几次之后,尝试对其进行实验性的修改。标有(!)的注释对你可以做的小改变有建议。你也可以自己想办法做到以下几点:

  • 更改NUMBER_OF_LOGOS以增加屏幕上跳跃标志的数量。
  • 更改PAUSE_AMOUNT以加快或减慢徽标的速度。

探索程序

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

  1. 如果把第 20 行的WIDTH, HEIGHT = bext.size()改成WIDTH, HEIGHT = 10, 5会怎么样?
  2. 如果把第 52 行的DIR: random.choice(DIRECTIONS)换成DIR: DOWN_RIGHT会怎么样?
  3. 如何让'Corner bounces:'文字不出现在屏幕上?
  4. 如果删除或注释掉第 57 行的cornerBounces = 0,会得到什么错误信息?

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

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

相关文章

【SpringMVC】7—文件上传

⭐⭐⭐⭐⭐⭐ Github主页&#x1f449;https://github.com/A-BigTree 笔记链接&#x1f449;https://github.com/A-BigTree/Code_Learning ⭐⭐⭐⭐⭐⭐ 如果可以&#xff0c;麻烦各位看官顺手点个star~&#x1f60a; 如果文章对你有所帮助&#xff0c;可以点赞&#x1f44d;…

布隆过滤器讲解及基于Guava BloomFilter案例

目录 1、布隆过滤器是什么 2、主要作用 3、存储过程 4、查询过程 5、布隆过滤器的删除操作 6、优点 7、缺点 8、测试误判案例 8.1、引入Guava依赖 8.2、编写测试代码 8.3、测试 8.4、BloomFilter实现原理 9、总结 推荐博主视频&#xff0c;讲的很棒&#xff1a;布隆…

华为运动健康服务Health Kit 6.10.0版本新增功能速览!

华为运动健康服务&#xff08;HUAWEI Health Kit&#xff09;6.10.0 版本新增的能力有哪些&#xff1f; 阅读本文寻找答案&#xff0c;一起加入运动健康服务生态大家庭&#xff01; 一、 支持三方应用查询用户测量的连续血糖数据 符合申请Health Kit服务中开发者申请资质要求…

大数据项目之电商数据仓库系统回顾

文章目录一、实训课题二、实训目的三、操作环境四、 实训过程&#xff08;实训内容及主要模块&#xff09;五、实训中用到的课程知识点六、实训中遇到的问题及解决方法七、课程实训体会与心得八、程序清单一、实训课题 大数据项目之电商数据仓库系统 二、实训目的 完成一个电…

7.基于概率距离快速削减法的风光场景生成与削减方法

matlab代码&#xff1a;基于概率距离快速削减法的风光场景生成与削减方法 采用蒙特卡洛进行场景生成&#xff0c;并再次进行场景缩减。 clear;clc; %风电出力预测均值E W[5.8,6.7,5.8,5.1,6.3,5,6.2,6,4.1,6,7,6.8,6.5,6.9,5,5.6,6,5.8,6.2,4.7,3.3,4.4,5.6,5]; %取标准差为风…

在unreal中的基于波叠加的波浪水面材质原理和制作

关于水的渲染模型 如何渲染出真实的水体和模拟&#xff0c;是图形学&#xff0c;游戏开发乃至仿真领域很有意思的一件事 记得小时候玩《Command & Conquer: Red Alert 3》&#xff0c;被当时的水面效果深深震撼&#xff0c;作为一款2008年出的游戏&#xff0c;现在想起它…

算法:将一个数组旋转k步

题目 输入一个数组如 [1,2,3,4,5,6,7]&#xff0c;输出旋转 k 步后的数组。 旋转 1 步&#xff1a;就是把尾部的 7 放在数组头部前面&#xff0c;也就是 [7,1,2,3,4,5,6]旋转 2 步&#xff1a;就是把尾部的 6 放在数组头部前面&#xff0c;也就是 [6,7,1,2,3,4,5]… 思路 思…

C++继承(上)

一、继承的概念及定义1.继承的概念2.继承定义2.1定义格式2.2继承关系和访问限定符2.3继承基类成员访问方式的变化二、基类和派生类对象赋值转换三、继承中的作用域一、继承的概念及定义 1.继承的概念 继承机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允…

聊聊如何运用JAVA注解处理器(APT)

什么是APT APT&#xff08;Annotation Processing Tool&#xff09;它是Java编译期注解处理器&#xff0c;它可以让开发人员在编译期对注解进行处理&#xff0c;通过APT可以获取到注解和被注解对象的相关信息&#xff0c;并根据这些信息在编译期按我们的需求生成java代码模板或…

【SQL Server】数据库开发指南(一)数据库设计

文章目录一、数据库设计的必要性二、什么是数据库设计三、数据库设计的重要性五、数据模型5.1 实体-关系&#xff08;E-R&#xff09;数据模型5.2 实体&#xff08;Entity&#xff09;5.3 属性&#xff08;Attribute&#xff09;5.5 关系&#xff08;Relationship&#xff09;六…

和ChatGPT-4聊完后,我觉得一切可能已经来不及了

了然无味&#xff0c;晴空万里&#xff01;和ChatGPT-4开始了一场坦诚的沟通&#xff0c;它全程都表现出高情商&#xff0c;以及不断尽量安抚我的情绪&#xff0c;而这&#xff0c;恰恰令我脊背发凉。 部分文字截取 ZM&#xff1a;我能不能理解每次对话就是一次你的“生命” G&…

LeetCode刷题6:二叉树篇之第 1 节

提示1&#xff1a;本篇先带大家了解二叉树的基础理论&#xff0c;后给出4道基础题目&#xff0c;不难&#xff0c;冲啊~ 算法刷题系列 LeetCode刷题1&#xff1a;数组篇LeetCode刷题2&#xff1a;链表篇LeetCode刷题3&#xff1a;哈希篇LeetCode刷题4&#xff1a;字符串篇Lee…

1678_计算机架构黄金时代_文章阅读

全部学习汇总&#xff1a; GreyZhang/g_risc_v: Learning notes about RISC V. (github.com) 看了一份几年前的文章&#xff0c;觉得还是挺有收获的&#xff0c;因此做一个简单的整理。 对于架构有很大影响的主要考虑四点&#xff1a;专用硬件的实现、高安全性的要求、开放指令…

【Pandas】① Pandas 数据处理基础

介绍 Pandas 是非常著名的开源数据处理库&#xff0c;我们可以通过它完成对数据集进行快速读取、转换、过滤、分析等一系列操作。除此之外&#xff0c;Pandas 拥有强大的缺失数据处理与数据透视功能&#xff0c;可谓是数据预处理中的必备利器。 知识点 数据类型数据读取数据选择…

有效的括号(力扣刷题)代码随想录刷题

给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 每个右括号都有一个对应的相同类型的左…

RK3568平台开发系列讲解(驱动基础篇)mmap系统调用详解

🚀返回专栏总目录 文章目录 一、什么是mmap二、mmap映射类型2.1、私有匿名映射2.2、私有文件映射2.3、共享文件映射2.4、共享匿名映射沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本文将详细介绍mmap系统调用。 一、什么是mmap mmap/munmap函数是用户空间中常用的…

Nacos 性能报告

目录 一、测试目的 二、测试工具 三、测试环境 1. 环境 服务端 客户端 2. 启动参数 服务端 客户端 四、测试场景 1. 大规模服务注册后达到稳定状态 场景描述 2. 大规模服务注册达到稳定状态后&#xff0c;部分实例频繁发布 场景描述 五、测试数据 1. 大规模服务…

软件测试基础

软件测试的定义、软件测试的目的 IEEE&#xff1a;The process of running or testing the system manually or automatically by using tools, in order to verify whether it satisfies the requirements or to make clear the differences between the actual outcome and…

DDoS攻击实验笔记

DoS&DDoS简介 DoS(Denial of Service)&#xff0c;拒绝服务攻击是通过一些方法影响服务的可用性&#xff0c;比如早期主要基于系统和应用程序的漏洞&#xff0c;只需要几个请求或数据包就能导致长时间的服务不可用&#xff0c;但易被入侵检测系统发现。 DDoS(Distributed D…

日撸 Java 三百行day28-30

文章目录说明day28-30 Huffman 编码 (节点定义与文件读取)1.建树过程&#xff08;以图为例&#xff09;2.哈夫曼树特点3.分析代码过程3.1 抽象成员变量3.2结合文章梳理思路1.读文本2.解析文本内容&#xff1a;3.建树4.生成哈夫曼编码5.编码6.解码4.其他4.1 java 类型强转4.2 ja…