首页 > 编程语言 >Python 小型项目大全 36~40

Python 小型项目大全 36~40

时间:2023-04-10 11:47:26浏览次数:50  
标签:Python random 36 40 robots ant sand board print

三十六、沙漏

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

这个可视化程序有一个粗糙的物理引擎,模拟沙子通过沙漏的小孔落下。沙子堆积在沙漏的下半部分;然后把沙漏翻过来,重复这个过程。

运行示例

图 36-1 显示了运行hourglass.py时的输出。

f36001

:沙漏程序在落砂时的输出

工作原理

沙漏程序实现了一个基本的物理引擎。一个物理引擎是模拟物理物体在重力作用下下落,相互碰撞,按照物理定律运动的软件。你会发现在视频游戏、计算机动画和科学模拟中使用的物理引擎。在第 91 到 102 行,每一粒沙子检查它下面的空间是否是空的,如果是,就向下移动。否则,它检查它是否可以向左下方移动(第 104 到 112 行)或向右下方移动(第 114 到 122 行)。当然,运动学,经典物理学的一个分支,处理宏观物体的运动,远不止这些。然而,你不需要一个物理学学位来制作一个沙漏中沙子的原始模拟,它看起来是令人愉快的。

"""Hourglass, by Al Sweigart email@protected
An animation of an hourglass with falling sand. Press Ctrl-C to stop.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: large, artistic, bext, simulation"""

import random, sys, 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:
PAUSE_LENGTH = 0.2  # (!) Try changing this to 0.0 or 1.0.
# (!) Try changing this to any number between 0 and 100:
WIDE_FALL_CHANCE = 50

SCREEN_WIDTH = 79
SCREEN_HEIGHT = 25
X = 0  # The index of X values in an (x, y) tuple is 0.
Y = 1  # The index of Y values in an (x, y) tuple is 1.
SAND = chr(9617)
WALL = chr(9608)

# Set up the walls of the hour glass:
HOURGLASS = set()  # Has (x, y) tuples for where hourglass walls are.
# (!) Try commenting out some HOURGLASS.add() lines to erase walls:
for i in range(18, 37):
   HOURGLASS.add((i, 1))  # Add walls for the top cap of the hourglass.
   HOURGLASS.add((i, 23))  # Add walls for the bottom cap.
for i in range(1, 5):
   HOURGLASS.add((18, i))  # Add walls for the top left straight wall.
   HOURGLASS.add((36, i))  # Add walls for the top right straight wall.
   HOURGLASS.add((18, i + 19))  # Add walls for the bottom left.
   HOURGLASS.add((36, i + 19))  # Add walls for the bottom right.
for i in range(8):
   HOURGLASS.add((19 + i, 5 + i))  # Add the top left slanted wall.
   HOURGLASS.add((35 - i, 5 + i))  # Add the top right slanted wall.
   HOURGLASS.add((25 - i, 13 + i))  # Add the bottom left slanted wall.
   HOURGLASS.add((29 + i, 13 + i))  # Add the bottom right slanted wall.

# Set up the initial sand at the top of the hourglass:
INITIAL_SAND = set()
for y in range(8):
   for x in range(19 + y, 36 - y):
       INITIAL_SAND.add((x, y + 4))


def main():
   bext.fg('yellow')
   bext.clear()

   # Draw the quit message:
   bext.goto(0, 0)
   print('Ctrl-C to quit.', end='')

   # Display the walls of the hourglass:
   for wall in HOURGLASS:
       bext.goto(wall[X], wall[Y])
       print(WALL, end='')

   while True:  # Main program loop.
       allSand = list(INITIAL_SAND)

       # Draw the initial sand:
       for sand in allSand:
           bext.goto(sand[X], sand[Y])
           print(SAND, end='')

       runHourglassSimulation(allSand)


def runHourglassSimulation(allSand):
   """Keep running the sand falling simulation until the sand stops
   moving."""
   while True:  # Keep looping until sand has run out.
       random.shuffle(allSand)  # Random order of grain simulation.

       sandMovedOnThisStep = False
       for i, sand in enumerate(allSand):
           if sand[Y] == SCREEN_HEIGHT - 1:
               # Sand is on the very bottom, so it won't move:
               continue

           # If nothing is under this sand, move it down:
           noSandBelow = (sand[X], sand[Y] + 1) not in allSand
           noWallBelow = (sand[X], sand[Y] + 1) not in HOURGLASS
           canFallDown = noSandBelow and noWallBelow

           if canFallDown:
               # Draw the sand in its new position down one space:
               bext.goto(sand[X], sand[Y])
               print(' ', end='')  # Clear the old position.
               bext.goto(sand[X], sand[Y] + 1)
               print(SAND, end='')

                # Set the sand in its new position down one space:
                allSand[i] = (sand[X], sand[Y] + 1)
                sandMovedOnThisStep = True
            else:
                # Check if the sand can fall to the left:
                belowLeft = (sand[X] - 1, sand[Y] + 1)
                noSandBelowLeft = belowLeft not in allSand
                noWallBelowLeft = belowLeft not in HOURGLASS
                left = (sand[X] - 1, sand[Y])
                noWallLeft = left not in HOURGLASS
                notOnLeftEdge = sand[X] > 0
                canFallLeft = (noSandBelowLeft and noWallBelowLeft
                    and noWallLeft and notOnLeftEdge)

                # Check if the sand can fall to the right:
                belowRight = (sand[X] + 1, sand[Y] + 1)
                noSandBelowRight = belowRight not in allSand
                noWallBelowRight = belowRight not in HOURGLASS
                right = (sand[X] + 1, sand[Y])
                noWallRight = right not in HOURGLASS
                notOnRightEdge = sand[X] < SCREEN_WIDTH - 1
                canFallRight = (noSandBelowRight and noWallBelowRight
                    and noWallRight and notOnRightEdge)

                # Set the falling direction:
                fallingDirection = None
                if canFallLeft and not canFallRight:
                    fallingDirection = -1  # Set the sand to fall left.
                elif not canFallLeft and canFallRight:
                    fallingDirection = 1  # Set the sand to fall right.
                elif canFallLeft and canFallRight:
                    # Both are possible, so randomly set it:
                    fallingDirection = random.choice((-1, 1))

                # Check if the sand can "far" fall two spaces to
                # the left or right instead of just one space:
                if random.random() * 100 <= WIDE_FALL_CHANCE:
                    belowTwoLeft = (sand[X] - 2, sand[Y] + 1)
                    noSandBelowTwoLeft = belowTwoLeft not in allSand
                    noWallBelowTwoLeft = belowTwoLeft not in HOURGLASS
                    notOnSecondToLeftEdge = sand[X] > 1
                    canFallTwoLeft = (canFallLeft and noSandBelowTwoLeft
                        and noWallBelowTwoLeft and notOnSecondToLeftEdge)

                    belowTwoRight = (sand[X] + 2, sand[Y] + 1)
                    noSandBelowTwoRight = belowTwoRight not in allSand
                    noWallBelowTwoRight = belowTwoRight not in HOURGLASS
                    notOnSecondToRightEdge = sand[X] < SCREEN_WIDTH - 2
                    canFallTwoRight = (canFallRight
                        and noSandBelowTwoRight and noWallBelowTwoRight
                        and notOnSecondToRightEdge)

                    if canFallTwoLeft and not canFallTwoRight:
                        fallingDirection = -2
                    elif not canFallTwoLeft and canFallTwoRight:
                        fallingDirection = 2
                    elif canFallTwoLeft and canFallTwoRight:
                        fallingDirection = random.choice((-2, 2))

                if fallingDirection == None:
                    # This sand can't fall, so move on.
                    continue

                # Draw the sand in its new position:
                bext.goto(sand[X], sand[Y])
                print(' ', end='')  # Erase old sand.
                bext.goto(sand[X] + fallingDirection, sand[Y] + 1)
                print(SAND, end='')  # Draw new sand.

                # Move the grain of sand to its new position:
                allSand[i] = (sand[X] + fallingDirection, sand[Y] + 1)
                sandMovedOnThisStep = True

        sys.stdout.flush()  # (Required for bext-using programs.)
        time.sleep(PAUSE_LENGTH)  # Pause after this

        # If no sand has moved on this step, reset the hourglass:
        if not sandMovedOnThisStep:
            time.sleep(2)
            # Erase all of the sand:
            for sand in allSand:
                bext.goto(sand[X], sand[Y])
                print(' ', end='')
            break  # Break out of main simulation loop.


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

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

  • 创建除沙漏以外的墙壁形状。
  • 在屏幕上创建点,不断涌出新的沙粒。

探索程序

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

  1. 如果把第 31 行的range(18, 37)改成range(18, 30)会怎么样?
  2. 如果把第 39 行的range(8)改成range(0)会怎么样?
  3. 如果把第 82 行的sandMovedOnThisStep = False改成sandMovedOnThisStep = True会怎么样?
  4. 如果把 125 行的fallingDirection = None改成fallingDirection = 1会怎么样?
  5. 如果把 136 行的random.random() * 100 <= WIDE_FALL_CHANCE改成random.random() * 0 <= WIDE_FALL_CHANCE会怎么样?

三十七、饥饿机器人

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

你和饥饿的机器人被困在一个迷宫里!你不知道机器人为什么需要吃饭,但你也不想知道。机器人的程序设计很糟糕,即使被墙挡住,它们也会直接向你移动。你必须欺骗机器人互相碰撞(或死亡的机器人)而不被抓住。

你有一个个人传送装置,可以把你送到一个随机的新地方,但它的电池只够两次旅行。此外,你和机器人可以溜过角落!

运行示例

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

Hungry Robots, by Al Sweigart email@protected
`--snip--`
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
░   ░ R             R ░  ░             ░
░ ░    ░░░   R░                    ░░  ░
░     ░ ░    ░ ░  ░         ░  ░░░     ░
░    R░   ░    ░      ░░   ░░     ░    ░
░ ░░  ░     ░ ░░░    ░           ░     ░
░ ░░    ░   RX░░░  ░  ░  ░      ░      ░
░          ░ R     R        R ░      ░ ░
░    ░   ░            ░        ░   R ░ ░
░ ░ R       R     ░   R ░   R          ░
░   ░  ░     ░       ░  ░       ░   ░  ░
░  @            ░          ░    R░░░ ░ ░
░   ░  ░░      ░░                 ░    ░
░  ░   ░░  ░            ░     R       ░░
░░X          ░  ░        ░ R ░░RR  ░ R ░
░RR R       R ░    ░          ░       R░
░   ░░  RRR   R                        ░
░           ░░R     ░                  ░
░      R  ░ ░                     ░    ░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
(T)eleports remaining: 2
                    (Q) (W) ( )
                    (A) (S) (D)
Enter move or QUIT: (Z) (X) ( )
`--snip--`

工作原理

在这个游戏中代表位置的 x 和 y 笛卡尔坐标允许我们使用数学来确定机器人应该移动的方向。在编程中,x 坐标向右增加,y 坐标向下增加。这意味着如果机器人的 x 坐标大于玩家的坐标,它应该向左移动(即代码应该从其当前的 x 坐标中减去)以靠近玩家。如果机器人的 x 坐标更小,它应该向右移动(也就是说,代码应该添加到其当前的 x 坐标中)。这同样适用于基于相对 y 坐标的上下移动。

"""Hungry Robots, by Al Sweigart email@protected
Escape the hungry robots by making them crash into each other.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: large, game"""

import random, sys

# Set up the constants:
WIDTH = 40           # (!) Try changing this to 70 or 10.
HEIGHT = 20          # (!) Try changing this to 10.
NUM_ROBOTS = 10      # (!) Try changing this to 1 or 30.
NUM_TELEPORTS = 2    # (!) Try changing this to 0 or 9999.
NUM_DEAD_ROBOTS = 2  # (!) Try changing this to 0 or 20.
NUM_WALLS = 100      # (!) Try changing this to 0 or 300.

EMPTY_SPACE = ' '    # (!) Try changing this to '.'.
PLAYER = '@'         # (!) Try changing this to 'R'.
ROBOT = 'R'          # (!) Try changing this to '@'.
DEAD_ROBOT = 'X'     # (!) Try changing this to 'R'.

# (!) Try changing this to '#' or 'O' or ' ':
WALL = chr(9617)  # Character 9617 is '░'


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

You are trapped in a maze with hungry robots! You don't know why robots
need to eat, but you don't want to find out. The robots are badly
programmed and will move directly toward you, even if blocked by walls.
You must trick the robots into crashing into each other (or dead robots)
without being caught. You have a personal teleporter device, but it only
has enough battery for {} trips. Keep in mind, you and robots can slip
through the corners of two diagonal walls!
'''.format(NUM_TELEPORTS))

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

   # Set up a new game:
   board = getNewBoard()
   robots = addRobots(board)
   playerPosition = getRandomEmptySpace(board, robots)
   while True:  # Main game loop.
       displayBoard(board, robots, playerPosition)

       if len(robots) == 0:  # Check if the player has won.
           print('All the robots have crashed into each other and you')
           print('lived to tell the tale! Good job!')
           sys.exit()

       # Move the player and robots:
       playerPosition = askForPlayerMove(board, robots, playerPosition)
       robots = moveRobots(board, robots, playerPosition)

       for x, y in robots:  # Check if the player has lost.
           if (x, y) == playerPosition:
               displayBoard(board, robots, playerPosition)
               print('You have been caught by a robot!')
               sys.exit()


def getNewBoard():
   """Returns a dictionary that represents the board. The keys are
   (x, y) tuples of integer indexes for board positions, the values are
   WALL, EMPTY_SPACE, or DEAD_ROBOT. The dictionary also has the key
   'teleports' for the number of teleports the player has left.
   The living robots are stored separately from the board dictionary."""
   board = {'teleports': NUM_TELEPORTS}

   # Create an empty board:
   for x in range(WIDTH):
       for y in range(HEIGHT):
           board[(x, y)] = EMPTY_SPACE

   # Add walls on the edges of the board:
   for x in range(WIDTH):
       board[(x, 0)] = WALL  # Make top wall.
       board[(x, HEIGHT - 1)] = WALL  # Make bottom wall.
   for y in range(HEIGHT):
       board[(0, y)] = WALL  # Make left wall.
       board[(WIDTH - 1, y)] = WALL  # Make right wall.

   # Add the random walls:
   for i in range(NUM_WALLS):
       x, y = getRandomEmptySpace(board, [])
       board[(x, y)] = WALL

   # Add the starting dead robots:
   for i in range(NUM_DEAD_ROBOTS):
       x, y = getRandomEmptySpace(board, [])
       board[(x, y)] = DEAD_ROBOT
   return board


def getRandomEmptySpace(board, robots):
   """Return a (x, y) integer tuple of an empty space on the board."""
   while True:
       randomX = random.randint(1, WIDTH - 2)
       randomY = random.randint(1, HEIGHT - 2)
        if isEmpty(randomX, randomY, board, robots):
            break
    return (randomX, randomY)


def isEmpty(x, y, board, robots):
    """Return True if the (x, y) is empty on the board and there's also
    no robot there."""
    return board[(x, y)] == EMPTY_SPACE and (x, y) not in robots


def addRobots(board):
    """Add NUM_ROBOTS number of robots to empty spaces on the board and
    return a list of these (x, y) spaces where robots are now located."""
    robots = []
    for i in range(NUM_ROBOTS):
        x, y = getRandomEmptySpace(board, robots)
        robots.append((x, y))
    return robots


def displayBoard(board, robots, playerPosition):
    """Display the board, robots, and player on the screen."""
    # Loop over every space on the board:
    for y in range(HEIGHT):
        for x in range(WIDTH):
            # Draw the appropriate character:
            if board[(x, y)] == WALL:
                print(WALL, end='')
            elif board[(x, y)] == DEAD_ROBOT:
                print(DEAD_ROBOT, end='')
            elif (x, y) == playerPosition:
                print(PLAYER, end='')
            elif (x, y) in robots:
                print(ROBOT, end='')
            else:
                print(EMPTY_SPACE, end='')
        print()  # Print a newline.


def askForPlayerMove(board, robots, playerPosition):
    """Returns the (x, y) integer tuple of the place the player moves
    next, given their current location and the walls of the board."""
    playerX, playerY = playerPosition

    # Find which directions aren't blocked by a wall:
    q = 'Q' if isEmpty(playerX - 1, playerY - 1, board, robots) else ' '
    w = 'W' if isEmpty(playerX + 0, playerY - 1, board, robots) else ' '
    e = 'E' if isEmpty(playerX + 1, playerY - 1, board, robots) else ' '
    d = 'D' if isEmpty(playerX + 1, playerY + 0, board, robots) else ' '
    c = 'C' if isEmpty(playerX + 1, playerY + 1, board, robots) else ' '
    x = 'X' if isEmpty(playerX + 0, playerY + 1, board, robots) else ' '
    z = 'Z' if isEmpty(playerX - 1, playerY + 1, board, robots) else ' '
    a = 'A' if isEmpty(playerX - 1, playerY + 0, board, robots) else ' '
    allMoves = (q + w + e + d + c + x + a + z + 'S')

    while True:
        # Get player's move:
        print('(T)eleports remaining: {}'.format(board["teleports"]))
        print('                    ({}) ({}) ({})'.format(q, w, e))
        print('                    ({}) (S) ({})'.format(a, d))
        print('Enter move or QUIT: ({}) ({}) ({})'.format(z, x, c))

        move = input('> ').upper()
        if move == 'QUIT':
            print('Thanks for playing!')
            sys.exit()
        elif move == 'T' and board['teleports'] > 0:
            # Teleport the player to a random empty space:
            board['teleports'] -= 1
            return getRandomEmptySpace(board, robots)
        elif move != '' and move in allMoves:
            # Return the new player position based on their move:
            return {'Q': (playerX - 1, playerY - 1),
                    'W': (playerX + 0, playerY - 1),
                    'E': (playerX + 1, playerY - 1),
                    'D': (playerX + 1, playerY + 0),
                    'C': (playerX + 1, playerY + 1),
                    'X': (playerX + 0, playerY + 1),
                    'Z': (playerX - 1, playerY + 1),
                    'A': (playerX - 1, playerY + 0),
                    'S': (playerX, playerY)}[move]


def moveRobots(board, robotPositions, playerPosition):
    """Return a list of (x, y) tuples of new robot positions after they
    have tried to move toward the player."""
    playerx, playery = playerPosition
    nextRobotPositions = []

    while len(robotPositions) > 0:
        robotx, roboty = robotPositions[0]

        # Determine the direction the robot moves.
        if robotx < playerx:
            movex = 1  # Move right.
        elif robotx > playerx:
            movex = -1  # Move left.
        elif robotx == playerx:
            movex = 0  # Don't move horizontally.

        if roboty < playery:
            movey = 1  # Move up.
        elif roboty > playery:
            movey = -1  # Move down.
        elif roboty == playery:
            movey = 0  # Don't move vertically.

        # Check if the robot would run into a wall, and adjust course:
        if board[(robotx + movex, roboty + movey)] == WALL:
            # Robot would run into a wall, so come up with a new move:
            if board[(robotx + movex, roboty)] == EMPTY_SPACE:
                movey = 0  # Robot can't move horizontally.
            elif board[(robotx, roboty + movey)] == EMPTY_SPACE:
                movex = 0  # Robot can't move vertically.
            else:
                # Robot can't move.
                movex = 0
                movey = 0
        newRobotx = robotx + movex
        newRoboty = roboty + movey

        if (board[(robotx, roboty)] == DEAD_ROBOT
            or board[(newRobotx, newRoboty)] == DEAD_ROBOT):
            # Robot is at a crash site, remove it.
            del robotPositions[0]
            continue

        # Check if it moves into a robot, then destroy both robots:
        if (newRobotx, newRoboty) in nextRobotPositions:
            board[(newRobotx, newRoboty)] = DEAD_ROBOT
            nextRobotPositions.remove((newRobotx, newRoboty))
        else:
            nextRobotPositions.append((newRobotx, newRoboty))

        # Remove robots from robotPositions as they move.
        del robotPositions[0]
    return nextRobotPositions


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

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

  • 创造两种不同的机器人:只能沿对角线移动的机器人和只能沿基本方向移动的机器人。
  • 给玩家一定数量的陷阱,他们可以留下来阻止任何机器人踩到陷阱。
  • 给玩家有限数量的“瞬间墙”,他们可以建立自己的防御。

探索程序

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

  1. 如果把第 22 行的WALL = chr(9617)改成WALL = 'R'会怎么样?
  2. 如果把 237 行的return nextRobotPositions改成return robotPositions会怎么样?
  3. 如果删除或注释掉第 44 行的displayBoard(board, robots, playerPosition)会发生什么?
  4. 如果删除或注释掉第 53 行的robots = moveRobots(board, robots, playerPosition)会发生什么?

三十八、我控诉

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

你就是举世闻名的大侦探玛蒂尔德·加缪。猫佐菲不见了,你必须筛选线索。嫌疑人要么总是说谎,要么总是说真话。你会及时找到猫佐菲并指控有罪的一方吗?

在这个游戏中,你乘出租车到城市的不同地点。每个地方都有一个嫌疑犯和一件物品。可以向嫌疑人询问其他嫌疑人和物品的情况,将他们的回答与自己的探索笔记进行对比,确定他们是在说谎还是在说真话。有些人会知道谁绑架了佐菲(或者她在哪里,或者在绑架者的位置发现了什么物品),但是你必须确定你是否能相信他们。你有五分钟时间找到罪犯,但是如果你三次指控错误,你就输了。这款游戏的灵感来源于 Homestar Runner 的“鸡蛋在哪里?”游戏。

运行示例

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

J'ACCUSE! (a mystery game)
`--snip--`
Time left: 5 min, 0 sec
  You are in your TAXI. Where do you want to go?
(A)LBINO ALLIGATOR PIT
(B)OWLING ALLEY
(C)ITY HALL
(D)UCK POND
(H)IPSTER CAFE
(O)LD BARN
(U)NIVERSITY LIBRARY
(V)IDEO GAME MUSEUM
(Z)OO
> a

Time left: 4 min, 48 sec
  You are at the ALBINO ALLIGATOR PIT.
  ESPRESSA TOFFEEPOT with the ONE COWBOY BOOT is here.

(J) "J'ACCUSE!" (3 accusations left)
(Z) Ask if they know where ZOPHIE THE CAT is.
(T) Go back to the TAXI.
(1) Ask about ESPRESSA TOFFEEPOT
(2) Ask about ONE COWBOY BOOT
> z
  They give you this clue: "DUKE HAUTDOG"
Press Enter to continue...
`--snip--`

工作原理

要完全理解这个程序,您应该密切关注clues字典,它位于第 51 行到第 109 行。您可以取消对第 151 到 154 行的注释,以便在屏幕上显示它。这个字典有来自SUSPECTS列表的字符串作为键,有“线索字典”作为值。每个线索字典都包含来自SUSPECTSITEMS的字符串。当被问及另一个嫌疑人或物品时,最初的嫌疑人会用这些字符串回答。例如,如果clues['DUKE HAUTDOG']['CANDLESTICK']设定为'DUCK POND',那么当玩家向杜克·豪特多格询问烛台时,他们会说它在鸭塘。每次玩游戏时,嫌疑人、物品、地点和罪犯都会被洗牌。

这个程序的代码围绕着这个数据结构,所以理解它对于理解程序的其余部分是必要的。

"""J'ACCUSE!, by Al Sweigart email@protected
A mystery game of intrigue and a missing cat.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: extra-large, game, humor, puzzle"""

# Play the original Flash game at:
# https://homestarrunner.com/videlectrix/wheresanegg.html
# More info at: http://www.hrwiki.org/wiki/Where's_an_Egg%3F

import time, random, sys

# Set up the constants:
SUSPECTS = ['DUKE HAUTDOG', 'MAXIMUM POWERS', 'BILL MONOPOLIS', 'SENATOR SCHMEAR', 'MRS. FEATHERTOSS', 'DR. JEAN SPLICER', 'RAFFLES THE CLOWN', 'ESPRESSA TOFFEEPOT', 'CECIL EDGAR VANDERTON']
ITEMS = ['FLASHLIGHT', 'CANDLESTICK', 'RAINBOW FLAG', 'HAMSTER WHEEL', 'ANIME VHS TAPE', 'JAR OF PICKLES', 'ONE COWBOY BOOT', 'CLEAN UNDERPANTS', '5 DOLLAR GIFT CARD']
PLACES = ['ZOO', 'OLD BARN', 'DUCK POND', 'CITY HALL', 'HIPSTER CAFE', 'BOWLING ALLEY', 'VIDEO GAME MUSEUM', 'UNIVERSITY LIBRARY', 'ALBINO ALLIGATOR PIT']
TIME_TO_SOLVE = 300  # 300 seconds (5 minutes) to solve the game.

# First letters and longest length of places are needed for menu display:
PLACE_FIRST_LETTERS = {}
LONGEST_PLACE_NAME_LENGTH = 0
for place in PLACES:
   PLACE_FIRST_LETTERS[place[0]] = place
   if len(place) > LONGEST_PLACE_NAME_LENGTH:
       LONGEST_PLACE_NAME_LENGTH = len(place)

# Basic sanity checks of the constants:
assert len(SUSPECTS) == 9
assert len(ITEMS) == 9
assert len(PLACES) == 9
# First letters must be unique:
assert len(PLACE_FIRST_LETTERS.keys()) == len(PLACES)


knownSuspectsAndItems = []
# visitedPlaces: Keys=places, values=strings of the suspect & item there.
visitedPlaces = {}
currentLocation = 'TAXI'  # Start the game at the taxi.
accusedSuspects = []  # Accused suspects won't offer clues.
liars = random.sample(SUSPECTS, random.randint(3, 4))
accusationsLeft = 3  # You can accuse up to 3 people.
culprit = random.choice(SUSPECTS)

# Common indexes link these; e.g. SUSPECTS[0] and ITEMS[0] are at PLACES[0].
random.shuffle(SUSPECTS)
random.shuffle(ITEMS)
random.shuffle(PLACES)

# Create data structures for clues the truth-tellers give about each
# item and suspect.
# clues: Keys=suspects being asked for a clue, value="clue dictionary".
clues = {}
for i, interviewee in enumerate(SUSPECTS):
   if interviewee in liars:
       continue  # Skip the liars for now.

   # This "clue dictionary" has keys=items & suspects,
   # value=the clue given.
   clues[interviewee] = {}
   clues[interviewee]['debug_liar'] = False  # Useful for debugging.
   for item in ITEMS:  # Select clue about each item.
       if random.randint(0, 1) == 0:  # Tells where the item is:
           clues[interviewee][item] = PLACES[ITEMS.index(item)]
       else:  # Tells who has the item:
           clues[interviewee][item] = SUSPECTS[ITEMS.index(item)]
   for suspect in SUSPECTS:  # Select clue about each suspect.
       if random.randint(0, 1) == 0:  # Tells where the suspect is:
           clues[interviewee][suspect] = PLACES[SUSPECTS.index(suspect)]
       else:  # Tells what item the suspect has:
           clues[interviewee][suspect] = ITEMS[SUSPECTS.index(suspect)]

# Create data structures for clues the liars give about each item
# and suspect:
for i, interviewee in enumerate(SUSPECTS):
   if interviewee not in liars:
       continue  # We've already handled the truth-tellers.

   # This "clue dictionary" has keys=items & suspects,
   # value=the clue given:
   clues[interviewee] = {}
   clues[interviewee]['debug_liar'] = True  # Useful for debugging.

   # This interviewee is a liar and gives wrong clues:
   for item in ITEMS:
       if random.randint(0, 1) == 0:
           while True:  # Select a random (wrong) place clue.
               # Lies about where the item is.
               clues[interviewee][item] = random.choice(PLACES)
               if clues[interviewee][item] != PLACES[ITEMS.index(item)]:
                   # Break out of the loop when wrong clue is selected.
                   break
       else:
           while True:  # Select a random (wrong) suspect clue.
               clues[interviewee][item] = random.choice(SUSPECTS)
               if clues[interviewee][item] != SUSPECTS[ITEMS.index(item)]:
                   # Break out of the loop when wrong clue is selected.
                   break
   for suspect in SUSPECTS:
       if random.randint(0, 1) == 0:
           while True:  # Select a random (wrong) place clue.
                clues[interviewee][suspect] = random.choice(PLACES)
                if clues[interviewee][suspect] != PLACES[ITEMS.index(item)]:
                    # Break out of the loop when wrong clue is selected.
                    break
        else:
            while True:  # Select a random (wrong) item clue.
                clues[interviewee][suspect] = random.choice(ITEMS)
                if clues[interviewee][suspect] != ITEMS[SUSPECTS.index(suspect)]:
                    # Break out of the loop when wrong clue is selected.
                    break

# Create the data structures for clues given when asked about Zophie:
zophieClues = {}
for interviewee in random.sample(SUSPECTS, random.randint(3, 4)):
    kindOfClue = random.randint(1, 3)
    if kindOfClue == 1:
        if interviewee not in liars:
            # They tell you who has Zophie.
            zophieClues[interviewee] = culprit
        elif interviewee in liars:
            while True:
                # Select a (wrong) suspect clue.
                zophieClues[interviewee] = random.choice(SUSPECTS)
                if zophieClues[interviewee] != culprit:
                    # Break out of the loop when wrong clue is selected.
                    break

    elif kindOfClue == 2:
        if interviewee not in liars:
            # They tell you where Zophie is.
            zophieClues[interviewee] = PLACES[SUSPECTS.index(culprit)]
        elif interviewee in liars:
            while True:
                # Select a (wrong) place clue.
                zophieClues[interviewee] = random.choice(PLACES)
                if zophieClues[interviewee] != PLACES[SUSPECTS.index(culprit)]:
                    # Break out of the loop when wrong clue is selected.
                    break
    elif kindOfClue == 3:
        if interviewee not in liars:
            # They tell you what item Zophie is near.
            zophieClues[interviewee] = ITEMS[SUSPECTS.index(culprit)]
        elif interviewee in liars:
            while True:
                # Select a (wrong) item clue.
                zophieClues[interviewee] = random.choice(ITEMS)
                if zophieClues[interviewee] != ITEMS[SUSPECTS.index(culprit)]:
                    # Break out of the loop when wrong clue is selected.
                    break

# EXPERIMENT: Uncomment this code to view the clue data structures:
#import pprint
#pprint.pprint(clues)
#pprint.pprint(zophieClues)
#print('culprit =', culprit)

# START OF THE GAME
print("""J'ACCUSE! (a mystery game)")
By Al Sweigart email@protected
Inspired by Homestar Runner\'s "Where\'s an Egg?" game

You are the world-famous detective, Mathilde Camus.
ZOPHIE THE CAT has gone missing, and you must sift through the clues.
Suspects either always tell lies, or always tell the truth. Ask them
about other people, places, and items to see if the details they give are
truthful and consistent with your observations. Then you will know if
their clue about ZOPHIE THE CAT is true or not. Will you find ZOPHIE THE
CAT in time and accuse the guilty party?
""")
input('Press Enter to begin...')


startTime = time.time()
endTime = startTime + TIME_TO_SOLVE

while True:  # Main game loop.
    if time.time() > endTime or accusationsLeft == 0:
        # Handle "game over" condition:
        if time.time() > endTime:
            print('You have run out of time!')
        elif accusationsLeft == 0:
            print('You have accused too many innocent people!')
        culpritIndex = SUSPECTS.index(culprit)
        print('It was {} at the {} with the {} who catnapped her!'.format(culprit, PLACES[culpritIndex], ITEMS[culpritIndex]))
        print('Better luck next time, Detective.')
        sys.exit()

    print()
    minutesLeft = int(endTime - time.time()) // 60
    secondsLeft = int(endTime - time.time()) % 60
    print('Time left: {} min, {} sec'.format(minutesLeft, secondsLeft))

    if currentLocation == 'TAXI':
        print('  You are in your TAXI. Where do you want to go?')
        for place in sorted(PLACES):
            placeInfo = ''
            if place in visitedPlaces:
                placeInfo = visitedPlaces[place]
            nameLabel = '(' + place[0] + ')' + place[1:]
            spacing = " " * (LONGEST_PLACE_NAME_LENGTH - len(place))
            print('{}  {}{}'.format(nameLabel, spacing, placeInfo))
        print('(Q)UIT GAME')
        while True:  # Keep asking until a valid response is given.
            response = input('> ').upper()
            if response == '':
                continue  # Ask again.
            if response == 'Q':
                print('Thanks for playing!')
                sys.exit()
            if response in PLACE_FIRST_LETTERS.keys():
                break
        currentLocation = PLACE_FIRST_LETTERS[response]
        continue  # Go back to the start of the main game loop.

    # At a place; player can ask for clues.
    print('  You are at the {}.'.format(currentLocation))
    currentLocationIndex = PLACES.index(currentLocation)
    thePersonHere = SUSPECTS[currentLocationIndex]
    theItemHere = ITEMS[currentLocationIndex]
    print(' {} with the {} is here.'.format(thePersonHere, theItemHere))

    # Add the suspect and item at this place to our list of known
    # suspects and items:
    if thePersonHere not in knownSuspectsAndItems:
        knownSuspectsAndItems.append(thePersonHere)
    if ITEMS[currentLocationIndex] not in knownSuspectsAndItems:
        knownSuspectsAndItems.append(ITEMS[currentLocationIndex])
    if currentLocation not in visitedPlaces.keys():
        visitedPlaces[currentLocation] = '({}, {})'.format(thePersonHere.lower(), theItemHere.lower())

    # If the player has accused this person wrongly before, they
    # won't give clues:
    if thePersonHere in accusedSuspects:
        print('They are offended that you accused them,')
        print('and will not help with your investigation.')
        print('You go back to your TAXI.')
        print()
        input('Press Enter to continue...')
        currentLocation = 'TAXI'
        continue  # Go back to the start of the main game loop.

    # Display menu of known suspects & items to ask about:
    print()
    print('(J) "J\'ACCUSE!" ({} accusations left)'.format(accusationsLeft))
    print('(Z) Ask if they know where ZOPHIE THE CAT is.')
    print('(T) Go back to the TAXI.')
    for i, suspectOrItem in enumerate(knownSuspectsAndItems):
        print('({}) Ask about {}'.format(i + 1, suspectOrItem))

    while True:  # Keep asking until a valid response is given.
        response = input('> ').upper()
        if response in 'JZT' or (response.isdecimal() and 0 < int(response) <= len(knownSuspectsAndItems)):
            break

    if response == 'J':  # Player accuses this suspect.
        accusationsLeft -= 1  # Use up an accusation.
        if thePersonHere == culprit:
            # You've accused the correct suspect.
            print('You\'ve cracked the case, Detective!')
            print('It was {} who had catnapped ZOPHIE THE CAT.'.format(culprit))
            minutesTaken = int(time.time() - startTime) // 60
            secondsTaken = int(time.time() - startTime) % 60
            print('Good job! You solved it in {} min, {} sec.'.format(minutesTaken, secondsTaken))
            sys.exit()
        else:
            # You've accused the wrong suspect.
            accusedSuspects.append(thePersonHere)
            print('You have accused the wrong person, Detective!')
            print('They will not help you with anymore clues.')
            print('You go back to your TAXI.')
            currentLocation = 'TAXI'

    elif response == 'Z':  # Player asks about Zophie.
        if thePersonHere not in zophieClues:
            print('"I don\'t know anything about ZOPHIE THE CAT."')
        elif thePersonHere in zophieClues:
            print('  They give you this clue: "{}"'.format(zophieClues[thePersonHere]))
            # Add non-place clues to the list of known things:
            if zophieClues[thePersonHere] not in knownSuspectsAndItems and zophieClues[thePersonHere] not in PLACES:
                knownSuspectsAndItems.append(zophieClues[thePersonHere])

    elif response == 'T':  # Player goes back to the taxi.
        currentLocation = 'TAXI'
        continue  # Go back to the start of the main game loop.

    else:  # Player asks about a suspect or item.
        thingBeingAskedAbout = knownSuspectsAndItems[int(response) - 1]
        if thingBeingAskedAbout in (thePersonHere, theItemHere):
            print('  They give you this clue: "No comment."')
        else:
            print('  They give you this clue: "{}"'.format(clues[thePersonHere][thingBeingAskedAbout]))
            # Add non-place clues to the list of known things:
            if clues[thePersonHere][thingBeingAskedAbout] not in knownSuspectsAndItems and clues[thePersonHere][thingBeingAskedAbout] not in PLACES:
                knownSuspectsAndItems.append(clues[thePersonHere][thingBeingAskedAbout])

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

探索程序

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

  1. 如果把第 16 行的TIME_TO_SOLVE = 300改成TIME_TO_SOLVE = 0会怎么样?
  2. 如果把 176 行的time.time() > endTime or accusationsLeft == 0改成time.time() > endTime and accusationsLeft == 0会怎么样?
  3. 如果把 198 行的place[1:]改成place会怎么样?
  4. 如果把 173 行的startTime + TIME_TO_SOLVE改成startTime * TIME_TO_SOLVE会怎么样?

三十九、兰顿的蚂蚁

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

兰顿的蚂蚁是二维网格上的元胞自动机模拟,类似于项目 13“康威的生命游戏”。在模拟中,一只“蚂蚁”从两种颜色之一的正方形开始。如果空间是第一种颜色,蚂蚁将它切换到第二种颜色,向右旋转 90 度,并向前移动一个空间。如果空间是第二种颜色,蚂蚁将它切换到第一种颜色,向左旋转 90 度,并向前移动一个空间。尽管规则非常简单,但模拟显示了复杂的突发行为。模拟可以在同一个空间中展示多只蚂蚁,当它们彼此相遇时,会产生有趣的互动。兰顿的蚂蚁是计算机科学家克里斯·兰顿在 1986 年发明的。更多关于兰顿蚂蚁的信息可以在en.wikipedia.org/wiki/Langton%27s_ant找到。

运行示例

图 39-1 显示了运行langtonsant.py时的输出。

f39001

:兰顿蚂蚁细胞自动机的催眠输出

工作原理

这个程序使用了两种“方向”的含义一方面,代表每只蚂蚁的字典存储了基本方向:北、南、东、西。然而,向左或向右(或逆时针和顺时针,因为我们是从上面看蚂蚁)是一个旋转方向。蚂蚁应该根据它们所站的瓷砖向左转或向右转,所以第 78 到 100 行根据蚂蚁当前的基本方向和它们转向的方向设置了一个新的基本方向。

"""Langton's Ant, by Al Sweigart email@protected
A cellular automata animation. Press Ctrl-C to stop.
More info: https://en.wikipedia.org/wiki/Langton%27s_ant
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: large, artistic, bext, simulation"""

import copy, random, sys, 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
HEIGHT -= 1  # Adjustment for the quit message at the bottom.

NUMBER_OF_ANTS = 10  # (!) Try changing this to 1 or 50.
PAUSE_AMOUNT = 0.1  # (!) Try changing this to 1.0 or 0.0.

# (!) Try changing these to make the ants look different:
ANT_UP = '^'
ANT_DOWN = 'v'
ANT_LEFT = '<'
ANT_RIGHT = '>'

# (!) Try changing these colors to one of 'black', 'red', 'green',
# 'yellow', 'blue', 'purple', 'cyan', or 'white'. (These are the only
# colors that the bext module supports.)
ANT_COLOR = 'red'
BLACK_TILE = 'black'
WHITE_TILE = 'white'

NORTH = 'north'
SOUTH = 'south'
EAST = 'east'
WEST = 'west'


def main():
   bext.fg(ANT_COLOR)  # The ants' color is the foreground color.
   bext.bg(WHITE_TILE)  # Set the background to white to start.
   bext.clear()

   # Create a new board data structure:
   board = {'width': WIDTH, 'height': HEIGHT}

   # Create ant data structures:
   ants = []
   for i in range(NUMBER_OF_ANTS):
       ant = {
           'x': random.randint(0, WIDTH - 1),
           'y': random.randint(0, HEIGHT - 1),
           'direction': random.choice([NORTH, SOUTH, EAST, WEST]),
       }
       ants.append(ant)

   # Keep track of which tiles have changed and need to be redrawn on
   # the screen:
   changedTiles = []

   while True:  # Main program loop.
       displayBoard(board, ants, changedTiles)
       changedTiles = []

       # nextBoard is what the board will look like on the next step in
       # the simulation. Start with a copy of the current step's board:
       nextBoard = copy.copy(board)

       # Run a single simulation step for each ant:
       for ant in ants:
           if board.get((ant['x'], ant['y']), False) == True:
               nextBoard[(ant['x'], ant['y'])] = False
               # Turn clockwise:
               if ant['direction'] == NORTH:
                   ant['direction'] = EAST
               elif ant['direction'] == EAST:
                   ant['direction'] = SOUTH
               elif ant['direction'] == SOUTH:
                   ant['direction'] = WEST
               elif ant['direction'] == WEST:
                   ant['direction'] = NORTH
           else:
               nextBoard[(ant['x'], ant['y'])] = True
               # Turn counter clockwise:
               if ant['direction'] == NORTH:
                   ant['direction'] = WEST
               elif ant['direction'] == WEST:
                   ant['direction'] = SOUTH
               elif ant['direction'] == SOUTH:
                   ant['direction'] = EAST
               elif ant['direction'] == EAST:
                   ant['direction'] = NORTH
            changedTiles.append((ant['x'], ant['y']))

            # Move the ant forward in whatever direction it's facing:
            if ant['direction'] == NORTH:
                ant['y'] -= 1
            if ant['direction'] == SOUTH:
                ant['y'] += 1
            if ant['direction'] == WEST:
                ant['x'] -= 1
            if ant['direction'] == EAST:
                ant['x'] += 1

            # If the ant goes past the edge of the screen,
            # it should wrap around to other side.
            ant['x'] = ant['x'] % WIDTH
            ant['y'] = ant['y'] % HEIGHT

            changedTiles.append((ant['x'], ant['y']))

        board = nextBoard


def displayBoard(board, ants, changedTiles):
    """Displays the board and ants on the screen. The changedTiles
    argument is a list of (x, y) tuples for tiles on the screen that
    have changed and need to be redrawn."""

    # Draw the board data structure:
    for x, y in changedTiles:
        bext.goto(x, y)
        if board.get((x, y), False):
            bext.bg(BLACK_TILE)
        else:
            bext.bg(WHITE_TILE)

        antIsHere = False
        for ant in ants:
            if (x, y) == (ant['x'], ant['y']):
                antIsHere = True
                if ant['direction'] == NORTH:
                    print(ANT_UP, end='')
                elif ant['direction'] == SOUTH:
                    print(ANT_DOWN, end='')
                elif ant['direction'] == EAST:
                    print(ANT_LEFT, end='')
                elif ant['direction'] == WEST:
                    print(ANT_RIGHT, end='')
                break
        if not antIsHere:
            print(' ', end='')

    # Display the quit message at the bottom of the screen:
    bext.goto(0, HEIGHT)
    bext.bg(WHITE_TILE)
    print('Press Ctrl-C to quit.', end='')

    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("Langton's Ant, by Al Sweigart email@protected")
        sys.exit()  # When Ctrl-C is pressed, end the program. 

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

  • 让玩家从文本文件中加载并保存棋盘的状态。
  • 使用新的移动规则创建额外的平铺状态,看看会出现什么行为。
  • 为兰顿的蚂蚁实现维基百科文章中建议的一些想法。

探索程序

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

  1. 如果把 149 行的print(' ', end='')改成print('.', end='')会怎么样?
  2. 如果把 106 行的ant['y'] += 1改成ant['y'] -= 1会怎么样?
  3. 如果把第 79 行的nextBoard[(ant['x'], ant['y'])] = False改成nextBoard[(ant['x'], ant['y'])] = True会怎么样?
  4. 如果把第 21 行的WIDTH -= 1改成WIDTH -= 40会怎么样?
  5. 如果把 119 行的board = nextBoard改成board = board会怎么样?

四十、黑客语

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

没有比用数字替换文本中的字母更好的方法来展示您疯狂的黑客技能了:m4d h4x0r 5k1llz!!!这个单词程序自动将普通英语转换成黑客语,这是最酷的在线交谈方式。或者至少是在 1993 年。

这需要一段时间来适应,但经过一些练习,你最终会流利地阅读黑客语。比如1t email@protected]<3s 4 w|-|1le +o g37 |_|s3|) 70, b|_|+ y0u (an 3\/3nt|_|/-\lly r3a|) l33t$peak phl|_|3n+ly。黑客语可能一开始很难读懂,但程序本身很简单,对初学者来说很好。更多关于黑客语的信息可以在en.wikipedia.org/wiki/Leet找到。

运行示例

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

L3375P34]< (leetspeek)
By Al Sweigart email@protected

Enter your leet message:
> I am a leet hacker. Fear my mad skills. The 90s were over two decades ago.

! @m a l33t email@protected(]<er. email@protected my m4|) $k|ll$. +h3 90s w3r3 0ver tw0 d3(ad3$ 4g0.
(Copied leetspeak to clipboard.)

工作原理

第 36 行的charMapping变量中的字典将普通英语字符映射到黑客语字符。然而,由于可能有多个可能的黑客语字符(例如字母't''7''+'),charMapping字典中的每个值都是一个字符串列表。当创建新的黑客语字符串时,程序有 30%的机会简单地使用原始英文消息中的字符,有 70%的机会使用黑客语字符之一。这意味着同一个英语信息有多种可能的翻译。

"""Leetspeak, by Al Sweigart email@protected
Translates English messages into l33t5p34]<.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: tiny, beginner, word"""

import random

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


def main():
    print('''L3375P34]< (leetspeek)
By Al Sweigart email@protected

Enter your leet message:''')
    english = input('> ')
    print()
    leetspeak = englishToLeetspeak(english)
    print(leetspeak)

    try:
        # Trying to use pyperclip will raise a NameError exception if
        # it wasn't imported:
        pyperclip.copy(leetspeak)
        print('(Copied leetspeak to clipboard.)')
    except NameError:
        pass  # Do nothing if pyperclip wasn't installed.


def englishToLeetspeak(message):
    """Convert the English string in message and return leetspeak."""
    # Make sure all the keys in `charMapping` are lowercase.
    charMapping = {
    'a': ['4', '@', '/-\\'], 'c': ['('], 'd': ['|)'], 'e': ['3'],
    'f': ['ph'], 'h': [']-[', '|-|'], 'i': ['1', '!', '|'], 'k': [']<'],
    'o': ['0'], 's': ['$', '5'], 't': ['7', '+'], 'u': ['|_|'],
    'v': ['\\/']}
    leetspeak = ''
    for char in message:  # Check each character:
        # There is a 70% chance we change the character to leetspeak.
        if char.lower() in charMapping and random.random() <= 0.70:
            possibleLeetReplacements = charMapping[char.lower()]
            leetReplacement = random.choice(possibleLeetReplacements)
            leetspeak = leetspeak + leetReplacement
        else:
            # Don't translate this character:
            leetspeak = leetspeak + char
    return leetspeak


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

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

  • 修改charMapping字典,使其支持新的黑客语字符。
  • 添加一个功能,可以将黑客语转换回简单的英语。

探索程序

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

  1. 如果把 51 行的return leetspeak改成return message会怎么样?
  2. 如果把第 44 行的char.lower()改成char会怎么样?
  3. 如果把第 44 行的char.lower()改成char.upper()会怎么样?
  4. 如果把第 47 行的leetspeak = leetspeak + leetReplacement改成leetspeak = leetReplacement会怎么样?

标签:Python,random,36,40,robots,ant,sand,board,print
From: https://www.cnblogs.com/apachecn/p/17302412.html

相关文章

  • Python 小型项目大全 41~45
    四十一、幸运星原文:http://inventwithpython.com/bigbookpython/project41.html在这个碰运气游戏中,你掷骰子来收集星星。你掷得越多,你能得到的星星就越多,但是如果你得到三个头骨,你就失去了一切!这款快速多人游戏可以支持任意多的玩家,是聚会的理想选择。在你的回合中,你从骰盅......
  • 关于Python爬虫的一些总结
    作为一名资深的爬虫工程师来说,把别人公开的一些合法数据通过爬虫手段实现汇总收集是一件很有成就的事情,其实这只是一种技术。初始爬虫问题:什么是爬虫?网络爬虫是一种按照一定的规则,自动地抓取网络信息的程序或者脚本。爬虫有什么用?①网络数据采集②大数据分析③网页分析......
  • Python 小型项目大全 11~15
    十一、标题党生成器原文:http://inventwithpython.com/bigbookpython/project11.html我们的网站需要欺骗人们去看广告!但是想出有创意的原创内容太难了。幸运的是,有了标题党生成器,我们可以让一台计算机产生数百万个令人发指的虚假标题。都是低质量的,但读者似乎并不介意。这个程......
  • Python 小型项目大全 16~20
    #16钻石原文:http://inventwithpython.com/bigbookpython/project16.html这个程序的特点是一个小算法,用于绘制各种尺寸的ASCII艺术画钻石。它包含绘制轮廓或你指定大小的填充式菱形的功能。这些功能对于初学者来说是很好的练习;试着理解钻石图背后的图案,因为它们的尺寸越来......
  • Python 小型项目大全 21~25
    二十一、DNA可视化原文:http://inventwithpython.com/bigbookpython/project21.html脱氧核糖核酸是一种微小的分子,存在于我们身体的每个细胞中,包含着我们身体如何生长的蓝图。它看起来像一对核苷酸分子的双螺旋结构:鸟嘌呤、胞嘧啶、腺嘌呤和胸腺嘧啶。这些用字母G、C、A和......
  • MIT 6.5840 2023 Spring(6.824)LAB1:MapReduce
    MIT6.58402023Spring(6.824)LAB1:MapReduce前言本次lab主要是完成一个基于RPC远程调用的单机单文件系统的简单MapReduce框架,并完成单词计数任务。基于golang实现,单Master,多Worker。实现worker的奔溃恢复(FaultTorrance),通过超时重新执行实现。主要的任务有,RPC调用参数及返回参数......
  • Python 小型项目大全 26~30
    二十六、斐波那契原文:http://inventwithpython.com/bigbookpython/project26.html斐波那契数列是一个著名的数学模式,被认为是13世纪意大利数学家斐波那契的杰作(尽管其他人发现它的时间更早)。序列从0和1开始,下一个数字总是前两个数字的和。这个序列永远继续下去:0,1,1......
  • Python 小型项目大全 6~10
    六、凯撒密码原文:http://inventwithpython.com/bigbookpython/project6.html凯撒密码是朱利叶斯·凯撒使用的一种古老的加密算法。它通过将字母在字母表中移动一定的位置来加密字母。我们称移位的长度为密钥。比如,如果密钥是3,那么A变成D,B变成E,C变成F,以此类推。要解密信息,你......
  • Python中的args和kwargs
    在Python的使用中,我们经常会遇到这样的函数定义:defmy_func(x,y,*args,**kwargs):forarginargs:print(arg)forkey,valueinkwargs.items():print(f"{key}:{value}")你是否好奇,这里的args和kwargs分别是什么含义呢?args顾名思义,是argumen......
  • 用 Go 剑指 Offer 40. 最小的k个数 (Top K 问题)
    输入整数数组arr,找出其中最小的k个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。 示例1:输入:arr=[3,2,1],k=2输出:[1,2]或者[2,1]示例2:输入:arr=[0,1,2,1],k=1输出:[0] 限制:0<=k<=arr.length<=100000<=arr[i] <=100......