Python 小型项目大全 61~65

news2024/10/7 16:27:19

六十一、ROT13 密码

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

ROT13 密码是最简单的加密算法之一,代表“旋转 13 个空格”密码将字母AZ表示为数字 0 到 25,加密后的字母距离明文字母 13 个空格: A变成NB变成O,以此类推。加密过程和解密过程是一样的,这使得编程变得很简单。然而,加密也很容易被破解。正因为如此,你会经常发现 ROT13 被用来隐藏非敏感信息,如剧透或琐事答案,所以它不会被无意中读取。更多关于 ROT13 密码的信息可以在en.wikipedia.org/wiki/ROT13找到。如果你想更一般地了解密码和密码破解,你可以阅读我的书《Python 密码破解指南》(NoStarch 出版社,2018)。

运行示例

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

ROT13 Cipher, by Al Sweigart email@protected

Enter a message to encrypt/decrypt (or QUIT):
> Meet me by the rose bushes tonight.
The translated message is:
Zrrg zr ol gur ebfr ohfurf gbavtug.

(Copied to clipboard.)
Enter a message to encrypt/decrypt (or QUIT):
`--snip--`

工作原理

ROT13 与项目 6“凯撒密码”共享大量代码,尽管它要简单得多,因为它总是使用密钥 13。因为相同的代码执行加密和解密(第 27 到 39 行),所以没有必要询问玩家他们想要使用哪种模式。

一个不同之处是,这个程序保持原始消息的大小写,而不是自动将消息转换为大写。例如,HELLO加密为URYYB,而Hello加密为Uryyb

"""ROT13 Cipher, by Al Sweigart email@protected
The simplest shift cipher for encrypting and decrypting text.
More info at https://en.wikipedia.org/wiki/ROT13
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: tiny, cryptography"""

try:
   import pyperclip  # pyperclip copies text to the clipboard.
except ImportError:
    pass  # If pyperclip is not installed, do nothing. It's no big deal.

# Set up the constants:
UPPER_LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
LOWER_LETTERS = 'abcdefghijklmnopqrstuvwxyz'

print('ROT13 Cipher, by Al Sweigart email@protected')
print()

while True:  # Main program loop.
    print('Enter a message to encrypt/decrypt (or QUIT):')
    message = input('> ')

    if message.upper() == 'QUIT':
        break  # Break out of the main program loop.

    # Rotate the letters in message by 13 characters.
    translated = ''
    for character in message:
        if character.isupper():
            # Concatenate uppercase translated character.
            transCharIndex = (UPPER_LETTERS.find(character) + 13) % 26
            translated += UPPER_LETTERS[transCharIndex]
        elif character.islower():
            # Concatenate lowercase translated character.
            transCharIndex = (LOWER_LETTERS.find(character) + 13) % 26
            translated += LOWER_LETTERS[transCharIndex]
        else:
            # Concatenate the character untranslated.
            translated += character

    # Display the translation:
    print('The translated message is:')
    print(translated)
    print()

    try:
        # Copy the translation to the clipboard:
        pyperclip.copy(translated)
        print('(Copied to clipboard.)')
    except:
        pass 

探索程序

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

  1. 如果把第 29 行的character.isupper()改成character.islower()会怎么样?
  2. 如果把第 43 行的print(translated)改成print(message)会怎么样?

六十二、旋转立方体

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

这个项目的特点是使用三角函数的 3D 立方体旋转动画。您可以在自己的动画程序中修改 3D 点旋转数学和line()函数。

虽然我们将用来绘制立方体的块文本字符看起来不像细而直的线,但这种绘制被称为线框模型,因为它只渲染物体表面的边缘。图 62-1 显示了立方体和 icosphere 的线框模型,icosphere 是一个由三角形组成的粗糙球体。

f62001

立方体(左)和 icosphere(右)的线框模型

运行示例

图 62-2 显示了运行rotatingcube.py时的输出。

f62002

:程序绘制到屏幕上的线框立方体

工作原理

这个算法有两个主要部分:函数line()和函数rotatePoint()。立方体有八个点,每个角一个。程序将这些角存储为CUBE_CORNERS列表中的(x, y, z)元组。这些点也定义了立方体边缘线的连接。当所有的点都向同一个方向旋转相同的量时,它们会产生立方体旋转的错觉。

"""Rotating Cube, by Al Sweigart email@protected
A rotating cube animation. Press Ctrl-C to stop.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: large, artistic, math"""

# This program MUST be run in a Terminal/Command Prompt window.

import math, time, sys, os

# Set up the constants:
PAUSE_AMOUNT = 0.1  # Pause length of one-tenth of a second.
WIDTH, HEIGHT = 80, 24
SCALEX = (WIDTH - 4) // 8
SCALEY = (HEIGHT - 4) // 8
# Text cells are twice as tall as they are wide, so set scaley:
SCALEY *= 2
TRANSLATEX = (WIDTH - 4) // 2
TRANSLATEY = (HEIGHT - 4) // 2

# (!) Try changing this to '#' or '*' or some other character:
LINE_CHAR = chr(9608)  # Character 9608 is a solid block.

# (!) Try setting two of these values to zero to rotate the cube only
# along a single axis:
X_ROTATE_SPEED = 0.03
Y_ROTATE_SPEED = 0.08
Z_ROTATE_SPEED = 0.13

# This program stores XYZ coordinates in lists, with the X coordinate
# at index 0, Y at 1, and Z at 2\. These constants make our code more
# readable when accessing the coordinates in these lists.
X = 0
Y = 1
Z = 2


def line(x1, y1, x2, y2):
   """Returns a list of points in a line between the given points.

   Uses the Bresenham line algorithm. More info at:
   https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm"""
   points = []  # Contains the points of the line.
   # "Steep" means the slope of the line is greater than 45 degrees or
   # less than -45 degrees:

   # Check for the special case where the start and end points are
   # certain neighbors, which this function doesn't handle correctly,
   # and return a hard coded list instead:
   if (x1 == x2 and y1 == y2 + 1) or (y1 == y2 and x1 == x2 + 1):
       return [(x1, y1), (x2, y2)]

   isSteep = abs(y2 - y1) > abs(x2 - x1)
   if isSteep:
       # This algorithm only handles non-steep lines, so let's change
       # the slope to non-steep and change it back later.
       x1, y1 = y1, x1  # Swap x1 and y1
       x2, y2 = y2, x2  # Swap x2 and y2
   isReversed = x1 > x2  # True if the line goes right-to-left.

   if isReversed:  # Get the points on the line going right-to-left.
       x1, x2 = x2, x1  # Swap x1 and x2
       y1, y2 = y2, y1  # Swap y1 and y2

       deltax = x2 - x1
       deltay = abs(y2 - y1)
       extray = int(deltax / 2)
       currenty = y2
       if y1 < y2:
           ydirection = 1
       else:
           ydirection = -1
       # Calculate the y for every x in this line:
       for currentx in range(x2, x1 - 1, -1):
           if isSteep:
               points.append((currenty, currentx))
           else:
               points.append((currentx, currenty))
           extray -= deltay
           if extray <= 0:  # Only change y once extray <= 0.
               currenty -= ydirection
               extray += deltax
   else:  # Get the points on the line going left to right.
       deltax = x2 - x1
       deltay = abs(y2 - y1)
       extray = int(deltax / 2)
       currenty = y1
       if y1 < y2:
           ydirection = 1
       else:
           ydirection = -1
       # Calculate the y for every x in this line:
       for currentx in range(x1, x2 + 1):
           if isSteep:
               points.append((currenty, currentx))
           else:
               points.append((currentx, currenty))
           extray -= deltay
           if extray < 0:  # Only change y once extray < 0.
               currenty += ydirection
                extray += deltax
    return points


def rotatePoint(x, y, z, ax, ay, az):
    """Returns an (x, y, z) tuple of the x, y, z arguments rotated.

    The rotation happens around the 0, 0, 0 origin by angles
    ax, ay, az (in radians).
        Directions of each axis:
         -y
          |
          +-- +x
         /
        +z
    """

    # Rotate around x axis:
    rotatedX = x
    rotatedY = (y * math.cos(ax)) - (z * math.sin(ax))
    rotatedZ = (y * math.sin(ax)) + (z * math.cos(ax))
    x, y, z = rotatedX, rotatedY, rotatedZ

    # Rotate around y axis:
    rotatedX = (z * math.sin(ay)) + (x * math.cos(ay))
    rotatedY = y
    rotatedZ = (z * math.cos(ay)) - (x * math.sin(ay))
    x, y, z = rotatedX, rotatedY, rotatedZ

    # Rotate around z axis:
    rotatedX = (x * math.cos(az)) - (y * math.sin(az))
    rotatedY = (x * math.sin(az)) + (y * math.cos(az))
    rotatedZ = z

    return (rotatedX, rotatedY, rotatedZ)


def adjustPoint(point):
    """Adjusts the 3D XYZ point to a 2D XY point fit for displaying on
    the screen. This resizes this 2D point by a scale of SCALEX and
    SCALEY, then moves the point by TRANSLATEX and TRANSLATEY."""
    return (int(point[X] * SCALEX + TRANSLATEX),
            int(point[Y] * SCALEY + TRANSLATEY))


"""CUBE_CORNERS stores the XYZ coordinates of the corners of a cube.
The indexes for each corner in CUBE_CORNERS are marked in this diagram:
      0---1
     /|  /|
    2---3 |
    | 4-|-5
    |/  |/
    6---7"""
CUBE_CORNERS = [[-1, -1, -1], # Point 0
                [ 1, -1, -1], # Point 1
                [-1, -1,  1], # Point 2
                [ 1, -1,  1], # Point 3
                [-1,  1, -1], # Point 4
                [ 1,  1, -1], # Point 5
                [-1,  1,  1], # Point 6
                [ 1,  1,  1]] # Point 7
# rotatedCorners stores the XYZ coordinates from CUBE_CORNERS after
# they've been rotated by rx, ry, and rz amounts:
rotatedCorners = [None, None, None, None, None, None, None, None]
# Rotation amounts for each axis:
xRotation = 0.0
yRotation = 0.0
zRotation = 0.0

try:
    while True:  # Main program loop.
        # Rotate the cube along different axes by different amounts:
        xRotation += X_ROTATE_SPEED
        yRotation += Y_ROTATE_SPEED
        zRotation += Z_ROTATE_SPEED
        for i in range(len(CUBE_CORNERS)):
            x = CUBE_CORNERS[i][X]
            y = CUBE_CORNERS[i][Y]
            z = CUBE_CORNERS[i][Z]
            rotatedCorners[i] = rotatePoint(x, y, z, xRotation,
                yRotation, zRotation)

        # Get the points of the cube lines:
        cubePoints = []
        for fromCornerIndex, toCornerIndex in ((0, 1), (1, 3), (3, 2), (2, 0), (0, 4), (1, 5), (2, 6), (3, 7), (4, 5), (5, 7), (7, 6), (6, 4)):
            fromX, fromY = adjustPoint(rotatedCorners[fromCornerIndex])
            toX, toY = adjustPoint(rotatedCorners[toCornerIndex])
            pointsOnLine = line(fromX, fromY, toX, toY)
            cubePoints.extend(pointsOnLine)

        # Get rid of duplicate points:
        cubePoints = tuple(frozenset(cubePoints))

        # Display the cube on the screen:
        for y in range(HEIGHT):
            for x in range(WIDTH):
                if (x, y) in cubePoints:
                    # Display full block:
                    print(LINE_CHAR, end='', flush=False)
                else:
                    # Display empty space:
                    print(' ', end='', flush=False)
            print(flush=False)
        print('Press Ctrl-C to quit.', end='', flush=True)

        time.sleep(PAUSE_AMOUNT)  # Pause for a bit.

        # Clear the screen:
        if sys.platform == 'win32':
            os.system('cls')  # Windows uses the cls command.
        else:
            os.system('clear')  # macOS and Linux use the clear command.

except KeyboardInterrupt:
    print('Rotating Cube, by Al Sweigart email@protected')
    sys.exit()  # When Ctrl-C is pressed, end the program. 

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

  • 修改CUBE_CORNERS和第 184 行的元组,创建不同的线框模型,如金字塔和扁平六边形。
  • CUBE_CORNERS的坐标增加1.5,使立方体围绕屏幕中心旋转,而不是围绕自己的中心旋转。

探索程序

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

  1. 如果删除或注释掉第 208 到 211 行会发生什么?
  2. 如果把 184 行的元组改成<((0, 1), (1, 3), (3, 2), (2, 0), (0,4), (4, 5), (5, 1))>会怎么样?

六十三、乌尔皇家游戏

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

乌尔的皇家游戏是一个来自美索不达米亚的有 5000 年历史的游戏。考古学家在 1922 年至 1934 年间的挖掘过程中,在现代伊拉克南部的乌尔皇家墓地重新发现了这款游戏。这些规则是根据游戏棋盘(如图 63-1 所示)和一块巴比伦泥板重建的,它们类似于 Parcheesi。你需要运气和技巧才能赢。

f63001

图 63-1 :在乌尔皇家墓地发现的五块游戏板之一

两名玩家每人从家中的七个代币开始,第一个将所有七个代币移动到目标位置的玩家获胜。玩家轮流掷出四个骰子。这些骰子是称为四面体的四角金字塔形状。每个骰子都有两个标记点,这使得骰子有标记或无标记的机会均等。我们的游戏用硬币代替骰子,硬币的头部作为标记点。玩家可以为出现的每一个标记点移动一格代币。这意味着他们可以在 0 到 4 个空格之间移动一个代币,尽管他们最有可能掷出两个空格。

代币沿着图 63-2 中所示的路径行进。一个空间上一次只能存在一个代币。如果一个代币在共享中间路径上落在对手的代币上,对手的代币会被送回家。如果一个代币落在中间的花方格上,它就不会被落在上面。如果一个代币落在其他四个花牌中的任何一个上,玩家可以再掷一次。我们的游戏将用字母XO来代表代币。

f63002

图 63-2 :每个玩家的代币从他们的家到他们的目标的路径

www.youtube.com/watch?v=WZskjLq040I可以找到优图伯·汤姆·斯科特和大英博物馆馆长欧文·芬克尔讨论乌尔王族游戏的视频。

运行示例

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

The Royal Game of Ur, by Al Sweigart
`--snip--`
                   XXXXXXX           .......
                   Home              Goal
                     v                 ^
+-----+-----+-----+--v--+           +--^--+-----+
|*****|     |     |     |           |*****|     |
|*   *<     <     <     |           |*   *<     |
|****h|    g|    f|    e|           |****t|    s|
+--v--+-----+-----+-----+-----+-----+-----+--^--+
|     |     |     |*****|     |     |     |     |
|     >     >     >*   *>     >     >     >     |
|    i|    j|    k|****l|    m|    n|    o|    p|
+--^--+-----+-----+-----+-----+-----+-----+--v--+
|*****|     |     |     |           |*****|     |
|*   *<     <     <     |           |*   *<     |
|****d|    c|    b|    a|           |****r|    q|
+-----+-----+-----+--^--+           +--v--+-----+
                     ^                 v
                   Home              Goal
                   OOOOOOO           .......

It is O's turn. Press Enter to flip...
Flips: H-H-H-H  Select token to move 4 spaces: home quit
> home
O landed on a flower space and gets to go again.
Press Enter to continue...
`--snip--`

工作原理

就像项目 43“曼卡拉”一样,ASCII 艺术画游戏棋盘上的空格用字母at标注。掷骰子后,玩家可以选择一个包含其代币的空间来移动代币,或者他们可以选择home开始将代币从家中移到棋盘上。该程序将棋盘表示为一个字典,其中键为'a''t',值为'X''O'用于标记(或' '用于空格)。

此外,这个字典有关键字'x_home''o_home''x_goal''o_goal',这些关键字的值是七个字符的字符串,表示家庭和目标有多满。这些字符串中的'X''O'字符代表主场或球门的代币,'.'代表空位置。displayBoard()函数在屏幕上显示这七个字符串。

"""The Royal Game of Ur, by Al Sweigart email@protected
A 5,000 year old board game from Mesopotamia. Two players knock each
other back as they race for the goal.
More info https://en.wikipedia.org/wiki/Royal_Game_of_Ur
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: large, board game, game, two-player
"""

import random, sys

X_PLAYER = 'X'
O_PLAYER = 'O'
EMPTY = ' '

# Set up constants for the space labels:
X_HOME = 'x_home'
O_HOME = 'o_home'
X_GOAL = 'x_goal'
O_GOAL = 'o_goal'

# The spaces in left to right, top to bottom order:
ALL_SPACES = 'hgfetsijklmnopdcbarq'
X_TRACK = 'HefghijklmnopstG'  # (H stands for Home, G stands for Goal.)
O_TRACK = 'HabcdijklmnopqrG'

FLOWER_SPACES = ('h', 't', 'l', 'd', 'r')

BOARD_TEMPLATE = """
{}  {} 30\.                   Home              Goal
                    v                 ^
+-----+-----+-----+--v--+           +--^--+-----+
|*****|     |     |     |           |*****|     |
|* {} *< {} < {} < {} |           |* {} *< {} |
|****h|    g|    f|    e|           |****t|    s|
+--v--+-----+-----+-----+-----+-----+-----+--^--+
|     |     |     |*****|     |     |     |     |
| {} > {} > {} >* {} *> {} > {} > {} > {} |
|    i|    j|    k|****l|    m|    n|    o|    p|
+--^--+-----+-----+-----+-----+-----+-----+--v--+
|*****|     |     |     |           |*****|     |
|* {} *< {} < {} < {} |           |* {} *< {} |
|****d|    c|    b|    a|           |****r|    q|
+-----+-----+-----+--^--+           +--v--+-----+
                    ^                 v
                  Home              Goal
{}  {} 48\. """


def main():
   print('''The Royal Game of Ur, by Al Sweigart

This is a 5,000 year old game. Two players must move their tokens
from their home to their goal. On your turn you flip four coins and can
move one token a number of spaces equal to the heads you got.

Ur is a racing game; the first player to move all seven of their tokens
to their goal wins. To do this, tokens must travel from their home to
their goal:

           X Home      X Goal
             v           ^
+---+---+---+-v-+       +-^-+---+
|v<<<<<<<<<<<<< |       | ^<|<< |
|v  |   |   |   |       |   | ^ |
+v--+---+---+---+---+---+---+-^-+
|>>>>>>>>>>>>>>>>>>>>>>>>>>>>>^ |
|>>>>>>>>>>>>>>>>>>>>>>>>>>>>>v |
+^--+---+---+---+---+---+---+-v-+
|^  |   |   |   |       |   | v |
|^<<<<<<<<<<<<< |       | v<<<< |
+---+---+---+-^-+       +-v-+---+
             ^           v
           O Home      O Goal

If you land on an opponent's token in the middle track, it gets sent
back home. The **flower** spaces let you take another turn. Tokens in
the middle flower space are safe and cannot be landed on.''')
   input('Press Enter to begin...')

   gameBoard = getNewBoard()
   turn = O_PLAYER
   while True:  # Main game loop.
       # Set up some variables for this turn:
       if turn == X_PLAYER:
           opponent = O_PLAYER
           home = X_HOME
           track = X_TRACK
           goal = X_GOAL
           opponentHome = O_HOME
       elif turn == O_PLAYER:
           opponent = X_PLAYER
           home = O_HOME
           track = O_TRACK
           goal = O_GOAL
           opponentHome = X_HOME

       displayBoard(gameBoard)

        input('It is ' + turn + '\'s turn. Press Enter to flip...')

        flipTally = 0
        print('Flips: ', end='')
        for i in range(4):  # Flip 4 coins.
            result = random.randint(0, 1)
            if result == 0:
                print('T', end='')  # Tails.
            else:
                print('H', end='')  # Heads.
            if i != 3:
                print('-', end='')  # Print separator.
            flipTally += result
        print('  ', end='')

        if flipTally == 0:
            input('You lose a turn. Press Enter to continue...')
            turn = opponent  # Swap turns to the other player.
            continue

        # Ask the player for their move:
        validMoves = getValidMoves(gameBoard, turn, flipTally)

        if validMoves == []:
            print('There are no possible moves, so you lose a turn.')
            input('Press Enter to continue...')
            turn = opponent  # Swap turns to the other player.
            continue

        while True:
            print('Select move', flipTally, 'spaces: ', end='')
            print(' '.join(validMoves) + ' quit')
            move = input('> ').lower()

            if move == 'quit':
                print('Thanks for playing!')
                sys.exit()
            if move in validMoves:
                break  # Exit the loop when a valid move is selected.

            print('That is not a valid move.')

        # Perform the selected move on the board:
        if move == 'home':
            # Subtract tokens at home if moving from home:
            gameBoard[home] -= 1
            nextTrackSpaceIndex = flipTally
        else:
            gameBoard[move] = EMPTY  # Set the "from" space to empty.
            nextTrackSpaceIndex = track.index(move) + flipTally

        movingOntoGoal = nextTrackSpaceIndex == len(track) - 1
        if movingOntoGoal:
            gameBoard[goal] += 1
            # Check if the player has won:
            if gameBoard[goal] == 7:
                displayBoard(gameBoard)
                print(turn, 'has won the game!')
                print('Thanks for playing!')
                sys.exit()
        else:
            nextBoardSpace = track[nextTrackSpaceIndex]
            # Check if the opponent has a tile there:
            if gameBoard[nextBoardSpace] == opponent:
                gameBoard[opponentHome] += 1

            # Set the "to" space to the player's token:
            gameBoard[nextBoardSpace] = turn

        # Check if the player landed on a flower space and can go again:
        if nextBoardSpace in FLOWER_SPACES:
            print(turn, 'landed on a flower space and goes again.')
            input('Press Enter to continue...')
        else:
            turn = opponent  # Swap turns to the other player.

def getNewBoard():
    """
    Returns a dictionary that represents the state of the board. The
    keys are strings of the space labels, the values are X_PLAYER,
    O_PLAYER, or EMPTY. There are also counters for how many tokens are
    at the home and goal of both players.
    """
    board = {X_HOME: 7, X_GOAL: 0, O_HOME: 7, O_GOAL: 0}
    # Set each space as empty to start:
    for spaceLabel in ALL_SPACES:
        board[spaceLabel] = EMPTY
    return board


def displayBoard(board):
    """Display the board on the screen."""
    # "Clear" the screen by printing many newlines, so the old
    # board isn't visible anymore.
    print('\n' * 60)

    xHomeTokens = ('X' * board[X_HOME]).ljust(7, '.')
    xGoalTokens = ('X' * board[X_GOAL]).ljust(7, '.')
    oHomeTokens = ('O' * board[O_HOME]).ljust(7, '.')
    oGoalTokens = ('O' * board[O_GOAL]).ljust(7, '.')

    # Add the strings that should populate BOARD_TEMPLATE in order,
    # going from left to right, top to bottom.
    spaces = []
    spaces.append(xHomeTokens)
    spaces.append(xGoalTokens)
    for spaceLabel in ALL_SPACES:
        spaces.append(board[spaceLabel])
    spaces.append(oHomeTokens)
    spaces.append(oGoalTokens)

    print(BOARD_TEMPLATE.format(*spaces))


def getValidMoves(board, player, flipTally):
    validMoves = []  # Contains the spaces with tokens that can move.
    if player == X_PLAYER:
        opponent = O_PLAYER
        track = X_TRACK
        home = X_HOME
    elif player == O_PLAYER:
        opponent = X_PLAYER
        track = O_TRACK
        home = O_HOME

    # Check if the player can move a token from home:
    if board[home] > 0 and board[track[flipTally]] == EMPTY:
        validMoves.append('home')

    # Check which spaces have a token the player can move:
    for trackSpaceIndex, space in enumerate(track):
        if space == 'H' or space == 'G' or board[space] != player:
            continue
        nextTrackSpaceIndex = trackSpaceIndex + flipTally
        if nextTrackSpaceIndex >= len(track):
            # You must flip an exact number of moves onto the goal,
            # otherwise you can't move on the goal.
            continue
        else:
            nextBoardSpaceKey = track[nextTrackSpaceIndex]
            if nextBoardSpaceKey == 'G':
                # This token can move off the board:
                validMoves.append(space)
                continue
        if board[nextBoardSpaceKey] in (EMPTY, opponent):
            # If the next space is the protected middle space, you
            # can only move there if it is empty:
            if nextBoardSpaceKey == 'l' and board['l'] == opponent:
                continue  # Skip this move, the space is protected.
            validMoves.append(space)

    return validMoves


if __name__ == '__main__':
    main() 

探索程序

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

  1. 如果把 152 行的nextTrackSpaceIndex == len(track) - 1改成nextTrackSpaceIndex == 1会怎么样?
  2. 如果把 106 行的result = random.randint(0, 1)改成result = 1会怎么样?
  3. 如果把 184 行的board = {X_HOME: 7, X_GOAL: 0, O_HOME: 7, O_GOAL: 0}改成board = {}会导致什么错误?

六十四、七段显示模块

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

七段显示器是一种 LCD 组件,用于在袖珍计算器、微波炉和其他小型电子设备中显示数字。通过 LCD 中七个线段的不同组合,七段显示器可以表示数字 0 到 9。它们看起来像这样:

   __         __    __          __    __   __    __    __
  |  |    |   __|   __|  |__|  |__   |__     |  |__|  |__|
  |__|    |  |__    __|     |   __|  |__|    |  |__|   __|

这个程序的好处是其他程序可以把它作为一个模块导入。项目 14,“倒计时”和项目 19,“数字钟”,导入sevseg.py文件,这样他们就可以使用它的getSevSegStr()函数。你可以在en.wikipedia.org/wiki/Seven-segment_display找到更多关于七段显示器和其他变化的信息。

运行示例

尽管它是一个模块,当你直接运行程序时,sevseg.py输出一个它产生的数字的示例演示。输出将如下所示:

This module is meant to be imported rather than run.
For example, this code:
    import sevseg
    myNumber = sevseg.getSevSegStr(42, 3)
    print(myNumber)

Will print 42, zero-padded to three digits:
 __        __
|  | |__|  __|
|__|    | |__

工作原理

getSevSegStr()函数首先创建一个包含三个字符串的列表。这些字符串表示数字的顶行、中间行和底行。第 27 行到第 75 行有一长串针对每个数字(以及小数点和减号)的if - elif语句,这些语句将每个数字的行连接到这些字符串。这三个字符串在第 84 行用换行符连接在一起,因此函数返回一个适合传递给print()的多行字符串。

"""Sevseg, by Al Sweigart email@protected
A seven-segment number display module, used by the Countdown and Digital
Clock programs.
More info at https://en.wikipedia.org/wiki/Seven-segment_display
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: short, module"""

"""A labeled seven-segment display, with each segment labeled A to G:
__A__
|     |    Each digit in a seven-segment display:
F     B     __       __   __        __   __  __   __   __
|__G__|    |  |   |  __|  __| |__| |__  |__    | |__| |__|
|     |    |__|   | |__   __|    |  __| |__|   | |__|  __|
E     C
|__D__|"""


def getSevSegStr(number, minWidth=0):
   """Return a seven-segment display string of number. The returned
   string will be padded with zeros if it is smaller than minWidth."""

   # Convert number to string in case it's an int or float:
   number = str(number).zfill(minWidth)

   rows = ['', '', '']
   for i, numeral in enumerate(number):
       if numeral == '.':  # Render the decimal point.
           rows[0] += ' '
           rows[1] += ' '
           rows[2] += '.'
           continue  # Skip the space in between digits.
       elif numeral == '-':  # Render the negative sign:
           rows[0] += '    '
           rows[1] += ' __ '
           rows[2] += '    '
       elif numeral == '0':  # Render the 0.
           rows[0] += ' __ '
           rows[1] += '|  |'
           rows[2] += '|__|'
       elif numeral == '1':  # Render the 1.
           rows[0] += '    '
           rows[1] += '   |'
           rows[2] += '   |'
       elif numeral == '2':  # Render the 2.
           rows[0] += ' __ '
           rows[1] += ' __|'
           rows[2] += '|__ '
       elif numeral == '3':  # Render the 3.
           rows[0] += ' __ '
           rows[1] += ' __|'
           rows[2] += ' __|'
       elif numeral == '4':  # Render the 4.
           rows[0] += '    '
           rows[1] += '|__|'
           rows[2] += '   |'
       elif numeral == '5':  # Render the 5.
           rows[0] += ' __ '
           rows[1] += '|__ '
           rows[2] += ' __|'
       elif numeral == '6':  # Render the 6.
           rows[0] += ' __ '
           rows[1] += '|__ '
           rows[2] += '|__|'
       elif numeral == '7':  # Render the 7.
           rows[0] += ' __ '
           rows[1] += '   |'
           rows[2] += '   |'
       elif numeral == '8':  # Render the 8.
           rows[0] += ' __ '
           rows[1] += '|__|'
           rows[2] += '|__|'
       elif numeral == '9':  # Render the 9.
           rows[0] += ' __ '
           rows[1] += '|__|'
           rows[2] += ' __|'

       # Add a space (for the space in between numerals) if this
       # isn't the last numeral and the decimal point isn't next:
       if i != len(number) - 1 and number[i + 1] != '.':
           rows[0] += ' '
           rows[1] += ' '
           rows[2] += ' '

   return '\n'.join(rows)


# If this program isn't being imported, display the numbers 00 to 99.
if __name__ == '__main__':
   print('This module is meant to be imported rather than run.')
   print('For example, this code:')
   print('    import sevseg')
   print('    myNumber = sevseg.getSevSegStr(42, 3)')
   print('    print(myNumber)')
   print()
   print('...will print 42, zero-padded to three digits:')
   print(' __        __ ')
   print('|  | |__|  __|')
   print('|__|    | |__ ') 

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

  • 为数字创建新的字体,比如使用五行和chr(9608)返回的块字符串。
  • 查看维基百科关于七段显示的文章,了解如何显示字母,然后将它们添加到sevseg.py
  • en.wikipedia.org/wiki/Sixteen-segment_display学习十六段显示,并创建一个十六段显示模块来生成该样式的数字。

探索程序

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

  1. 如果将第 80、81 和 82 行的单空格字符串改为空字符串会发生什么?
  2. 如果将第 18 行的默认参数minWidth=0改为minWidth=8,会发生什么?

六十五、闪光地毯

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

斯坦利·库布里克执导的 1980 年心理恐怖片《闪光》发生在闹鬼的远眺酒店。酒店地毯的六边形设计成为这部著名电影的标志性部分。地毯的特点是交替和连锁的六边形,其催眠效果非常适合这样一部令人紧张的电影。这个项目中的短程序,类似于项目 35,“六边形网格”,在屏幕上打印这个重复的图案。

注意,这个程序使用原始字符串,它在开始的引号前面加上小写的r,这样字符串中的反斜杠就不会被解释为转义字符。

运行示例

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

_ \ \ \_/ ___ \ \ \_/ ___ \ \ \_/ ___ \ \ \_/ ___ \ \ \_/ ___ \ \ \_/ __
 \ \ \___/ _ \ \ \___/ _ \ \ \___/ _ \ \ \___/ _ \ \ \___/ _ \ \ \___/ _
\ \ \_____/ \ \ \_____/ \ \ \_____/ \ \ \_____/ \ \ \_____/ \ \ \_____/
/ / / ___ \_/ / / ___ \_/ / / ___ \_/ / / ___ \_/ / / ___ \_/ / / ___ \_
_/ / / _ \___/ / / _ \___/ / / _ \___/ / / _ \___/ / / _ \___/ / / _ \__
__/ / / \_____/ / / \_____/ / / \_____/ / / \_____/ / / \_____/ / / \___
_ \ \ \_/ ___ \ \ \_/ ___ \ \ \_/ ___ \ \ \_/ ___ \ \ \_/ ___ \ \ \_/ __
 \ \ \___/ _ \ \ \___/ _ \ \ \___/ _ \ \ \___/ _ \ \ \___/ _ \ \ \___/ _
\ \ \_____/ \ \ \_____/ \ \ \_____/ \ \ \_____/ \ \ \_____/ \ \ \_____/
/ / / ___ \_/ / / ___ \_/ / / ___ \_/ / / ___ \_/ / / ___ \_/ / / ___ \_
_/ / / _ \___/ / / _ \___/ / / _ \___/ / / _ \___/ / / _ \___/ / / _ \__
__/ / / \_____/ / / \_____/ / / \_____/ / / \_____/ / / \_____/ / / \___
_ \ \ \_/ ___ \ \ \_/ ___ \ \ \_/ ___ \ \ \_/ ___ \ \ \_/ ___ \ \ \_/ __
 \ \ \___/ _ \ \ \___/ _ \ \ \___/ _ \ \ \___/ _ \ \ \___/ _ \ \ \___/ _
\ \ \_____/ \ \ \_____/ \ \ \_____/ \ \ \_____/ \ \ \_____/ \ \ \_____/
/ / / ___ \_/ / / ___ \_/ / / ___ \_/ / / ___ \_/ / / ___ \_/ / / ___ \_
_/ / / _ \___/ / / _ \___/ / / _ \___/ / / _ \___/ / / _ \___/ / / _ \__
__/ / / \_____/ / / \_____/ / / \_____/ / / \_____/ / / \_____/ / / \___

工作原理

创建这样的程序(或类似的第三十五个项目)并不是从编码开始,而是在文本编辑器中绘制镶嵌形状。一旦你写出了图案,你就可以把它切割成需要平铺的最小单元:

_ \ \ \_/ __
 \ \ \___/ _
\ \ \_____/
/ / / ___ \_
_/ / / _ \__
__/ / / \___

将这段文本复制并粘贴到源代码中后,您可以围绕它编写程序的其余部分。软件不仅仅是坐下来从头到尾写代码。每个专业软件开发人员都要经历几次反复的修补、实验和调试。最终的结果可能只有九行代码,但是一个小程序并不一定意味着花了很少的精力来完成它。

"""Shining Carpet, by Al Sweigart email@protected
Displays a tessellation of the carpet pattern from The Shining.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: tiny, beginner, artistic"""

# Set up the constants:
X_REPEAT = 6  # How many times to tessellate horizontally.
Y_REPEAT = 4  # How many times to tessellate vertically.

for i in range(Y_REPEAT):
    print(r'_ \ \ \_/ __' * X_REPEAT)
    print(r' \ \ \___/ _' * X_REPEAT)
    print(r'\ \ \_____/ ' * X_REPEAT)
    print(r'/ / / ___ \_' * X_REPEAT)
    print(r'_/ / / _ \__' * X_REPEAT)
    print(r'__/ / / \___' * X_REPEAT) 

探索程序

在实践中,尝试创建如下模式:

___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|
_|___|___|___|___|___|___|___|___|___|___|___|___|___|___|__
___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|
_|___|___|___|___|___|___|___|___|___|___|___|___|___|___|__
___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|
_|___|___|___|___|___|___|___|___|___|___|___|___|___|___|__

((  )((  )((  )((  )((  )((  )((  )((  )((  )((  )((  )((  )
 ))(  ))(  ))(  ))(  ))(  ))(  ))(  ))(  ))(  ))(  ))(  ))(
((  )((  )((  )((  )((  )((  )((  )((  )((  )((  )((  )((  )
 ))(  ))(  ))(  ))(  ))(  ))(  ))(  ))(  ))(  ))(  ))(  ))(
((  )((  )((  )((  )((  )((  )((  )((  )((  )((  )((  )((  )
 ))(  ))(  ))(  ))(  ))(  ))(  ))(  ))(  ))(  ))(  ))(  ))(

 / __ \ \__/ / __ \ \__/ / __ \ \__/ / __ \ \__/ / __ \ \__/
/ /  \ \____/ /  \ \____/ /  \ \____/ /  \ \____/ /  \ \____
\ \__/ / __ \ \__/ / __ \ \__/ / __ \ \__/ / __ \ \__/ / __
 \____/ /  \ \____/ /  \ \____/ /  \ \____/ /  \ \____/ /  \
 / __ \ \__/ / __ \ \__/ / __ \ \__/ / __ \ \__/ / __ \ \__/
/ /  \ \____/ /  \ \____/ /  \ \____/ /  \ \____/ /  \ \____
\ \__/ / __ \ \__/ / __ \ \__/ / __ \ \__/ / __ \ \__/ / __
 \____/ /  \ \____/ /  \ \____/ /  \ \____/ /  \ \____/ /  \

  \__   \__   \__   \__   \__   \__   \__   \__   \__   \__
__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \
  \     \     \     \     \     \     \     \     \     \
__/   __/   __/   __/   __/   __/   __/   __/   __/   __/
  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/
__/     /     /     /     /     /     /     /     /     /
  \__   \__   \__   \__   \__   \__   \__   \__   \__   \__
__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \__/  \

/ ___ \ ^ / ___ \ ^ / ___ \ ^ / ___ \ ^ / ___ \ ^ / ___ \ ^
 /   \ VVV /   \ VVV /   \ VVV /   \ VVV /   \ VVV /   \ VVV
|() ()|   |() ()|   |() ()|   |() ()|   |() ()|   |() ()|
 \ ^ / ___ \ ^ / ___ \ ^ / ___ \ ^ / ___ \ ^ / ___ \ ^ / ___
\ VVV /   \ VVV /   \ VVV /   \ VVV /   \ VVV /   \ VVV /
)|   |() ()|   |() ()|   |() ()|   |() ()|   |() ()|   |() (

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MyBatis 03 -MyBatis动态SQL与分页插件

动态SQL与分页插件 动态SQL与分页插件动态SQL与分页插件1 动态SQL1.1 < sql >1.2 < if >1.3 < where >1.4 < set >1.5 < choose >1.6 < trim >1.7 < foreach >2 mybatis缓存2.1 一级缓存2.2 二级缓存3 分页插件3.1 概念3.2 访问与下…

没有什么壁纸比这里的更绝美精致了吧,我一天换一张

嗨&#xff0c;这里是清安&#xff0c;本章来学习学习获取精美壁纸。视频教程&#xff1a;https://b23.tv/iR7bOFF源码&#xff1a;https://gitee.com/qinganan_admin/reptile-case/tree/master/%E5%A3%81%E7%BA%B8本视频还会有第二期&#xff0c;代码也会有第二份&#xff0c;…

类ChatGPT项目的部署与微调(上):从LLaMA到Alpaca、Vicuna、BELLE

前言 近期&#xff0c;除了研究ChatGPT背后的各种技术细节 不断看论文(至少100篇&#xff0c;100篇目录见此&#xff1a;ChatGPT相关技术必读论文100篇)&#xff0c;还开始研究一系列开源模型(包括各自对应的模型架构、训练方法、训练数据、本地私有化部署、硬件配置要求、微…

Python | 蓝桥杯进阶第三卷——动态规划

欢迎交流学习~~ 专栏&#xff1a; 蓝桥杯Python组刷题日寄 蓝桥杯进阶系列&#xff1a; &#x1f3c6; Python | 蓝桥杯进阶第一卷——字符串 &#x1f50e; Python | 蓝桥杯进阶第二卷——贪心 &#x1f49d; Python | 蓝桥杯进阶第三卷——动态规划 ✈️ Python | 蓝桥杯进阶…

精通Python(基础篇)——流程控制语句

流程控制语句 文章目录流程控制语句1️⃣简介2️⃣条件判断⚜️关系运算符⚜️逻辑运算符⚜️if语句⚜️if...else 语句⚜️if...elif...else语句⚜️match...case3️⃣循环结构⚜️while⚜️while...else语句⚜️for⚜️for...else语句4️⃣退出循环⚜️continue⚜️break1️⃣…

(排序6)快速排序(小区间优化,非递归实现)

TIPS 快速排序本质上是一个分治递归的一个排序。快速排序的时间复杂度是NlogN&#xff0c;这是在理想的情况之下&#xff0c;但是它最坏可以到达N^2。决定快速排序的效率是在单趟排序之后这个key最终落在的位置&#xff0c;越落在中间就越接近二分&#xff0c;越接近2分就越接…

Android创建项目

目录 创建Android项目 配置项目结构 创建安卓模拟器 模拟器运行 HelloWorld 应用 真机运行 HelloWorld 应用 创建Android项目 打开 Android studio 工具&#xff0c;选择Project&#xff0c;选择 New Project 由于现在是教程博客&#xff0c;所以我们随便选择 一个 空 Ac…

JS内置对象2

数组对象&#xff1a; &#xff08;1&#xff09;检测是否为数组&#xff1a; …

【数据结构】第十站:堆与堆排序

目录 一、二叉树的顺序结构 二、堆的概念及结构 三、堆的实现 1.堆的创建 2.堆的各接口实现 四、堆排序 1.堆排序的基本思想 2.堆排序的实现 3.堆排序时间复杂度 四、TOP-K问题 五、堆的完整代码 一、二叉树的顺序结构 二叉树有顺序结构和链式结构&#xff0c;分别使…

Android之adb安装busybox使用wget、telnet等服务

一、adb里面安装busybox BusyBox 是一个集成了三百多个最常用Linux命令和工具的软件。BusyBox 包含了一些简单的工具&#xff0c;例如ls、cat和echo等等&#xff0c;还包含了一些更大、更复杂的工具&#xff0c;例grep、find、mount以及telnet。 1、下载busybox busybox—bi…

有哪些通过PMP认证考试的心得值得分享?

回顾这100多天来艰辛的备考经历&#xff0c;感慨颇多 一&#xff0c;对于pmp的认知 百度百科&#xff1a;PMP&#xff08;Project Management Professional&#xff09;指项目管理专业人士&#xff08;人事&#xff09;资格认证。美国项目管理协会&#xff08;PMI&#xff09;举…

使用 Floyd Warshall 检测负循环

我们得到了一个有向图。我们需要计算图形是否有负循环。负循环是循环的总和为负的循环。 在图形的各种应用中都可以找到负权重。例如,如果我们沿着这条路走,我们可能会得到一些好处,而不是为一条路付出代价。 例子:

PVE相关的各种一键脚本(一键安装PVE)(一键开设KVM虚拟化的NAT服务器-自带内外网端口转发)

PVE 原始仓库&#xff1a;https://github.com/spiritLHLS/pve 前言 建议debian在使用前尽量使用最新的系统 非debian11可使用 debian一键升级 来升级系统 当然不使用最新的debian系统也没问题&#xff0c;只不过得不到官方支持 请确保使用前机器可以重装系统&#xff0c;…

RK3568平台开发系列讲解(驱动基础篇)自动创建设备节点

🚀返回专栏总目录 文章目录 一、自动创建设备节点1.1、创建和删除类函数1.2、创建设备函数二、创建类函数三、创建设备函数沉淀、分享、成长,让自己和他人都能有所收获!😄 📢自动创建设备节点分为两个步骤: 步骤一:使用 class_create 函数创建一个类。步骤二:使用 d…

C++算法初级7——二分查找

C算法初级7——二分查找 文章目录C算法初级7——二分查找在升序的数组上进行二分查找总结应用范围应用二分查找的原理&#xff1a;每次排除掉一半答案&#xff0c;使可能的答案区间快速缩小。 二分查找的时间复杂度&#xff1a;O(log n)&#xff0c;因为每次询问会使可行区间的…

【MyBatis Plus】001 -- MyBatis-Plus快速入门(介绍、QuickStart)

目录 1、了解MyBatis-Plus 1.1 MyBatis-Plus介绍 1.2 代码及文档 1.3 特性 1.4 架构 1.5 作者 2、快速开始 2.1 创建数据库以及表 2.2 创建工程 2.3 MyBatis MP 2.3.1 创建子module 2.3.2 MyBatis实现查询User&#xff08;无Service方法&#xff0c;直接通过Mapper实现查询&am…

海外虚拟主机空间:如何使用CDN加速提升用户体验?

随着互联网的迅速发展和全球化的趋势&#xff0c;越来越多的企业和个人选择海外虚拟主机空间。然而&#xff0c;由于服务器的地理位置和网络延迟等原因&#xff0c;这些网站在国内访问时可能会遇到较慢的加载速度和不稳定的用户体验。为了解决这一问题&#xff0c;使用CDN加速是…

Web漏洞-文件包含漏洞超详细全解(附实例)

目录 一、导图 二、文件包含漏洞 1.脚本代码 2.原理演示 3.漏洞成因 4.检测方法 5.类型分类 三、本地文件包含漏洞的利用 <无限制本地文件包含> <有限制本地文件包含> 四、远程文件包含漏洞的利用 <无限制远程文件包含> <有限制远程文件包含…

开心档之C++ 多线程

C 多线程 目录 C 多线程 创建线程 终止线程 实例 实例 实例 向线程传递参数 实例 连接和分离线程 实例 std::thread 实例 多线程是多任务处理的一种特殊形式&#xff0c;多任务处理允许让电脑同时运行两个或两个以上的程序。一般情况下&#xff0c;两种类型的多任务…

NumPy 初学者指南中文第三版:11~14

原文&#xff1a;NumPy: Beginner’s Guide - Third Edition 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 十一、玩转 Pygame 本章适用于希望使用 NumPy 和 Pygame 快速轻松创建游戏的开发人员。 基本的游戏开发经验会有所帮助&#xff0c;但这不是必需的。 您将学…