原文:http://inventwithpython.com/bigbookpython/project31.html
猜数字是初学者练习基本编程技术的经典游戏。在这个游戏中,电脑会想到一个介于 1 到 100 之间的随机数。玩家有 10 次机会猜出数字。每次猜中后,电脑会告诉玩家它是太高还是太低。
当您运行guess.py
时,输出将如下所示:
Guess the Number, by Al Sweigart email@protected
I am thinking of a number between 1 and 100.
You have 10 guesses left. Take a guess.
> 50
Your guess is too high.
You have 9 guesses left. Take a guess.
> 25
Your guess is too low.
`--snip--`
You have 5 guesses left. Take a guess.
> 42
Yay! You guessed my number!
猜数字使用了几个基本的编程概念:循环、if-else
语句、函数、方法调用和随机数。Python 的random
模块生成伪随机数——看似随机但技术上可预测的数字。对于计算机来说,伪随机数比真正的随机数更容易生成,对于视频游戏和一些科学模拟等应用来说,伪随机数被认为是“足够随机”的。
Python 的random
模块从一个种子值产生伪随机数,从同一个种子产生的每个伪随机数流都将是相同的。例如,在交互式 shell 中输入以下内容:
>>> import random
>>> random.seed(42)
>>> random.randint(1, 10); random.randint(1, 10); random.randint(1, 10)
2
1
5
如果您重新启动交互式 shell 并再次运行这段代码,它会产生相同的伪随机数:2
、1
、5
。视频游戏《我的世界》(也叫《挖矿争霸》)从起始种子值生成其伪随机虚拟世界,这就是为什么不同的玩家可以通过使用相同的种子来重新创建相同的世界。
"""Guess the Number, by Al Sweigart email@protected
Try to guess the secret number based on hints.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: tiny, beginner, game"""
import random
def askForGuess():
while True:
guess = input('> ') # Enter the guess.
if guess.isdecimal():
return int(guess) # Convert string guess to an integer.
print('Please enter a number between 1 and 100.')
print('Guess the Number, by Al Sweigart email@protected')
print()
secretNumber = random.randint(1, 100) # Select a random number.
print('I am thinking of a number between 1 and 100.')
for i in range(10): # Give the player 10 guesses.
print('You have {} guesses left. Take a guess.'.format(10 - i))
guess = askForGuess()
if guess == secretNumber:
break # Break out of the for loop if the guess is correct.
# Offer a hint:
if guess < secretNumber:
print('Your guess is too low.')
if guess > secretNumber:
print('Your guess is too high.')
# Reveal the results:
if guess == secretNumber:
print('Yay! You guessed my number!')
else:
print('Game over. The number I was thinking of was', secretNumber)
在输入源代码并运行几次之后,尝试对其进行实验性的修改。你也可以自己想办法做到以下几点:
试着找出下列问题的答案。尝试对代码进行一些修改,然后重新运行程序,看看这些修改有什么影响。
input('> ')
改成input(secretNumber)
会怎么样?return int(guess)
改为return guess
,会得到什么错误信息?random.randint(1, 100)
改成random.randint(1, 1)
会怎么样?format(10 - i)
改成format(i)
会怎么样?guess == secretNumber
改为guess = secretNumber
,会得到什么错误信息?原文:http://inventwithpython.com/bigbookpython/project32.html
在这个简短的节目中,你可以学到让一个容易受骗的人忙碌几个小时的秘密和微妙的艺术。我不会破坏这里的妙语。复制代码并自己运行。这个项目对初学者来说很棒,不管你是聪明的还是。。。不太聪明。
当您运行gullible.py
时,输出将如下所示:
Gullible, by Al Sweigart email@protected
Do you want to know how to keep a gullible person busy for hours? Y/N
> y
Do you want to know how to keep a gullible person busy for hours? Y/N
> y
Do you want to know how to keep a gullible person busy for hours? Y/N
> yes
Do you want to know how to keep a gullible person busy for hours? Y/N
> YES
Do you want to know how to keep a gullible person busy for hours? Y/N
> TELL ME HOW TO KEEP A GULLIBLE PERSON BUSY FOR HOURS
"TELL ME HOW TO KEEP A GULLIBLE PERSON BUSY FOR HOURS" is not a valid yes/no response.
Do you want to know how to keep a gullible person busy for hours? Y/N
> y
Do you want to know how to keep a gullible person busy for hours? Y/N
> y
Do you want to know how to keep a gullible person busy for hours? Y/N
> n
Thank you. Have a nice day!
为了更加用户友好,你的程序应该尝试解释用户可能的输入。例如,这个程序问用户一个是/否的问题,但是对于玩家来说,简单地输入y
或n
而不是输入完整的单词会更简单。如果玩家的CapsLock
键被激活,程序也可以理解玩家的意图,因为它会在玩家输入的字符串上调用lower()
字符串方法。这样,'y'
、'yes'
、'Y'
、'Yes'
、'YES'
都被程序解释的一样。玩家的负面反应也是如此。
"""Gullible, by Al Sweigart email@protected
How to keep a gullible person busy for hours. (This is a joke program.)
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: tiny, beginner, humor"""
print('Gullible, by Al Sweigart email@protected')
while True: # Main program loop.
print('Do you want to know how to keep a gullible person busy for hours? Y/N')
response = input('> ') # Get the user's response.
if response.lower() == 'no' or response.lower() == 'n':
break # If "no", break out of this loop.
if response.lower() == 'yes' or response.lower() == 'y':
continue # If "yes", continue to the start of this loop.
print('"{}" is not a valid yes/no response.'.format(response))
print('Thank you. Have a nice day!')
试着找出下列问题的答案。尝试对代码进行一些修改,然后重新运行程序,看看这些修改有什么影响。
response.lower() == 'no'
改成response.lower() != 'no'
会怎么样?while True:
改成while False:
会怎么样?原文:http://inventwithpython.com/bigbookpython/project33.html
在这个游戏中,玩家必须通过猜测一个七个字母的单词作为秘密密码来入侵电脑。电脑的记忆库显示可能的单词,并提示玩家每次猜测的接近程度。例如,如果密码是MONITOR
,但玩家猜了CONTAIN
,他们会得到提示,七个字母中有两个是正确的,因为MONITOR
和CONTAIN
的第二个和第三个字母都是字母O
和N
。这个游戏类似于项目 1,“百吉饼”,以及辐射系列视频游戏中的黑客迷你游戏。
当您运行hacking.py
时,输出将如下所示:
Hacking Minigame, by Al Sweigart email@protected
Find the password in the computer's memory:
0x1150 $],>@|~~RESOLVE^ 0x1250 {>+)<!?CHICKEN,%
0x1160 }@%_-:;/$^(|<|!( 0x1260 .][})?#@#ADDRESS
0x1170 _;)][#?<&~$~+&}} 0x1270 ,#=)>{-;/DESPITE
0x1180 %[!]{email@protected?~, 0x1280 }/.}!-DISPLAY%%/
0x1190 _[^%[@}^<_+{email@protected$~ 0x1290 =>>,:*%email@protected+{%#.
0x11a0 )?~/)+PENALTY?-= 0x12a0 >[,?*#email@protected$/
`--snip--`
Enter password: (4 tries remaining)
> resolve
Access Denied (2/7 correct)
Enter password: (3 tries remaining)
> improve
A C C E S S G R A N T E D
这个游戏有一个黑客主题,但不涉及任何实际的电脑黑客行为。如果我们只是在屏幕上列出可能的单词,游戏就会完全一样。然而,模仿计算机记忆库的装饰性添加传达了一种令人兴奋的计算机黑客的感觉。对细节和用户体验的关注将一个平淡、无聊的游戏变成了一个令人兴奋的游戏。
"""Hacking Minigame, by Al Sweigart email@protected
The hacking mini-game from "Fallout 3". Find out which seven-letter
word is the password by using clues each guess gives you.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: large, artistic, game, puzzle"""
# NOTE: This program requires the sevenletterwords.txt file. You can
# download it from https://inventwithpython.com/sevenletterwords.txt
import random, sys
# Set up the constants:
# The garbage filler characters for the "computer memory" display.
GARBAGE_CHARS = 'email@protected#$%^&*()_+-={}[]|;:,.<>?/'
# Load the WORDS list from a text file that has 7-letter words.
with open('sevenletterwords.txt') as wordListFile:
WORDS = wordListFile.readlines()
for i in range(len(WORDS)):
# Convert each word to uppercase and remove the trailing newline:
WORDS[i] = WORDS[i].strip().upper()
def main():
"""Run a single game of Hacking."""
print('''Hacking Minigame, by Al Sweigart email@protected
Find the password in the computer's memory. You are given clues after
each guess. For example, if the secret password is MONITOR but the
player guessed CONTAIN, they are given the hint that 2 out of 7 letters
were correct, because both MONITOR and CONTAIN have the letter O and N
as their 2nd and 3rd letter. You get four guesses.\n''')
input('Press Enter to begin...')
gameWords = getWords()
# The "computer memory" is just cosmetic, but it looks cool:
computerMemory = getComputerMemoryString(gameWords)
secretPassword = random.choice(gameWords)
print(computerMemory)
# Start at 4 tries remaining, going down:
for triesRemaining in range(4, 0, -1):
playerMove = askForPlayerGuess(gameWords, triesRemaining)
if playerMove == secretPassword:
print('A C C E S S G R A N T E D')
return
else:
numMatches = numMatchingLetters(secretPassword, playerMove)
print('Access Denied ({}/7 correct)'.format(numMatches))
print('Out of tries. Secret password was {}.'.format(secretPassword))
def getWords():
"""Return a list of 12 words that could possibly be the password.
The secret password will be the first word in the list.
To make the game fair, we try to ensure that there are words with
a range of matching numbers of letters as the secret word."""
secretPassword = random.choice(WORDS)
words = [secretPassword]
# Find two more words; these have zero matching letters.
# We use "< 3" because the secret password is already in words.
while len(words) < 3:
randomWord = getOneWordExcept(words)
if numMatchingLetters(secretPassword, randomWord) == 0:
words.append(randomWord)
# Find two words that have 3 matching letters (but give up at 500
# tries if not enough can be found).
for i in range(500):
if len(words) == 5:
break # Found 5 words, so break out of the loop.
randomWord = getOneWordExcept(words)
if numMatchingLetters(secretPassword, randomWord) == 3:
words.append(randomWord)
# Find at least seven words that have at least one matching letter
# (but give up at 500 tries if not enough can be found).
for i in range(500):
if len(words) == 12:
break # Found 7 or more words, so break out of the loop.
randomWord = getOneWordExcept(words)
if numMatchingLetters(secretPassword, randomWord) != 0:
words.append(randomWord)
# Add any random words needed to get 12 words total.
while len(words) < 12:
randomWord = getOneWordExcept(words)
words.append(randomWord)
assert len(words) == 12
return words
def getOneWordExcept(blocklist=None):
"""Returns a random word from WORDS that isn't in blocklist."""
if blocklist == None:
blocklist = []
while True:
randomWord = random.choice(WORDS)
if randomWord not in blocklist:
return randomWord
def numMatchingLetters(word1, word2):
"""Returns the number of matching letters in these two words."""
matches = 0
for i in range(len(word1)):
if word1[i] == word2[i]:
matches += 1
return matches
def getComputerMemoryString(words):
"""Return a string representing the "computer memory"."""
# Pick one line per word to contain a word. There are 16 lines, but
# they are split into two halves.
linesWithWords = random.sample(range(16 * 2), len(words))
# The starting memory address (this is also cosmetic).
memoryAddress = 16 * random.randint(0, 4000)
# Create the "computer memory" string.
computerMemory = [] # Will contain 16 strings, one for each line.
nextWord = 0 # The index in words of the word to put into a line.
for lineNum in range(16): # The "computer memory" has 16 lines.
# Create a half line of garbage characters:
leftHalf = ''
rightHalf = ''
for j in range(16): # Each half line has 16 characters.
leftHalf += random.choice(GARBAGE_CHARS)
rightHalf += random.choice(GARBAGE_CHARS)
# Fill in the password from words:
if lineNum in linesWithWords:
# Find a random place in the half line to insert the word:
insertionIndex = random.randint(0, 9)
# Insert the word:
leftHalf = (leftHalf[:insertionIndex] + words[nextWord]
+ leftHalf[insertionIndex + 7:])
nextWord += 1 # Update the word to put in the half line.
if lineNum + 16 in linesWithWords:
# Find a random place in the half line to insert the word:
insertionIndex = random.randint(0, 9)
# Insert the word:
rightHalf = (rightHalf[:insertionIndex] + words[nextWord]
+ rightHalf[insertionIndex + 7:])
nextWord += 1 # Update the word to put in the half line.
computerMemory.append('0x' + hex(memoryAddress)[2:].zfill(4)
+ ' ' + leftHalf + ' '
+ '0x' + hex(memoryAddress + (16*16))[2:].zfill(4)
+ ' ' + rightHalf)
memoryAddress += 16 # Jump from, say, 0xe680 to 0xe690.
# Each string in the computerMemory list is joined into one large
# string to return:
return '\n'.join(computerMemory)
def askForPlayerGuess(words, tries):
"""Let the player enter a password guess."""
while True:
print('Enter password: ({} tries remaining)'.format(tries))
guess = input('> ').upper()
if guess in words:
return guess
print('That is not one of the possible passwords listed above.')
print('Try entering "{}" or "{}".'.format(words[0], words[1]))
# 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.
在输入源代码并运行几次之后,尝试对其进行实验性的修改。你也可以自己想办法做到以下几点:
sevenletterwords.txt
,也许是一个由六个或八个字母组成的文件。试着找出下列问题的答案。尝试对代码进行一些修改,然后重新运行程序,看看这些修改有什么影响。
for j in range(16):
改成for j in range(0):
会怎么样?GARBAGE_CHARS = 'email@protected#$%^&*()_+-={}[]|;:,.<>?/'
改成GARBAGE_CHARS = '.'
会怎么样?gameWords = getWords()
改成gameWords = ['MALKOVICH'] * 20
会怎么样?return words
改为return
,会得到什么错误信息?randomWord = random.choice(WORDS)
改成secretPassword = 'PASSWORD'
会怎么样?原文:http://inventwithpython.com/bigbookpython/project34.html
这个经典的文字游戏让玩家猜一个秘密单词的字母。对于每一个不正确的字母,刽子手的另一部分被画出来。在刽子手完成之前,试着猜出完整的单词。这个版本的密语都是兔子鸽子之类的动物,但是你可以用自己的一套话来代替这些。
HANGMAN_PICS
变量包含刽子手绞索每一步的 ASCII 艺术画字符串:
+--+ +--+ +--+ +--+ +--+ +--+ +--+
| | | | | | | | | | | | | |
| O | O | O | O | O | O |
| | | | /| | /|\ | /|\ | /|\ |
| | | | | / | / \ |
| | | | | | |
===== ===== ===== ===== ===== ===== =====
对于游戏中的法式转折,您可以用以下描述断头台的字符串替换HANGMAN_PICS
变量中的字符串:
| | | |===| |===| |===| |===| |===|
| | | | | | | | | || /| || /|
| | | | | | | | | ||/ | ||/ |
| | | | | | | | | | | | |
| | | | | | | | | | | | |
| | | | | | | |/-\| |/-\| |/-\|
| | | | | |\ /| |\ /| |\ /| |\O/|
|=== |===| |===| |===| |===| |===| |===|
当您运行hangman.py
时,输出将如下所示:
Hangman, by Al Sweigart email@protected
+--+
| |
|
|
|
|
=====
The category is: Animals
Missed letters: No missed letters yet.
_ _ _ _ _
Guess a letter.
> e
`--snip--`
+--+
| |
O |
/| |
|
|
=====
The category is: Animals
Missed letters: A I S
O T T E _
Guess a letter.
> r
Yes! The secret word is: OTTER
You have won!
刽子手和断头台共享相同的游戏机制,但有不同的表现形式。这使得用 ASCII 艺术画的断头台图形替换 ASCII 艺术画的绞索图形变得容易,而不必改变程序遵循的主要逻辑。程序的表示和逻辑部分的分离使得用新的特性或不同的设计进行更新变得更加容易。在专业软件开发中,这种策略是软件设计模式或软件架构的一个例子,它关注于如何构建你的程序,以便于理解和修改。这主要在大型软件应用中有用,但是您也可以将这些原则应用到较小的项目中。
"""Hangman, by Al Sweigart email@protected
Guess the letters to a secret word before the hangman is drawn.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: large, game, word, puzzle"""
# A version of this game is featured in the book "Invent Your Own
# Computer Games with Python" https://nostarch.com/inventwithpython
import random, sys
# Set up the constants:
# (!) Try adding or changing the strings in HANGMAN_PICS to make a
# guillotine instead of a gallows.
HANGMAN_PICS = [r"""
+--+
| |
|
|
|
|
=====""",
r"""
+--+
| |
O |
|
|
|
=====""",
r"""
+--+
| |
O |
| |
|
|
=====""",
r"""
+--+
| |
O |
/| |
|
|
=====""",
r"""
+--+
| |
O |
/|\ |
|
|
=====""",
r"""
+--+
| |
O |
/|\ |
/ |
|
=====""",
r"""
+--+
| |
O |
/|\ |
/ \ |
|
====="""]
# (!) Try replacing CATEGORY and WORDS with new strings.
CATEGORY = 'Animals'
WORDS = 'ANT BABOON BADGER BAT BEAR BEAVER CAMEL CAT CLAM COBRA COUGAR COYOTE CROW DEER DOG DONKEY DUCK EAGLE FERRET FOX FROG GOAT GOOSE HAWK LION LIZARD LLAMA MOLE MONKEY MOOSE MOUSE MULE NEWT OTTER OWL PANDA PARROT PIGEON PYTHON RABBIT RAM RAT RAVEN RHINO SALMON SEAL SHARK SHEEP SKUNK SLOTH SNAKE SPIDER STORK SWAN TIGER TOAD TROUT TURKEY TURTLE WEASEL WHALE WOLF WOMBAT ZEBRA'.split()
def main():
print('Hangman, by Al Sweigart email@protected')
# Setup variables for a new game:
missedLetters = [] # List of incorrect letter guesses.
correctLetters = [] # List of correct letter guesses.
secretWord = random.choice(WORDS) # The word the player must guess.
while True: # Main game loop.
drawHangman(missedLetters, correctLetters, secretWord)
# Let the player enter their letter guess:
guess = getPlayerGuess(missedLetters + correctLetters)
if guess in secretWord:
# Add the correct guess to correctLetters:
correctLetters.append(guess)
# Check if the player has won:
foundAllLetters = True # Start off assuming they've won.
for secretWordLetter in secretWord:
if secretWordLetter not in correctLetters:
# There's a letter in the secret word that isn't
# yet in correctLetters, so the player hasn't won:
foundAllLetters = False
break
if foundAllLetters:
print('Yes! The secret word is:', secretWord)
print('You have won!')
break # Break out of the main game loop.
else:
# The player has guessed incorrectly:
missedLetters.append(guess)
# Check if player has guessed too many times and lost. (The
# "- 1" is because we don't count the empty gallows in
# HANGMAN_PICS.)
if len(missedLetters) == len(HANGMAN_PICS) - 1:
drawHangman(missedLetters, correctLetters, secretWord)
print('You have run out of guesses!')
print('The word was "{}"'.format(secretWord))
break
def drawHangman(missedLetters, correctLetters, secretWord):
"""Draw the current state of the hangman, along with the missed and
correctly-guessed letters of the secret word."""
print(HANGMAN_PICS[len(missedLetters)])
print('The category is:', CATEGORY)
print()
# Show the incorrectly guessed letters:
print('Missed letters: ', end='')
for letter in missedLetters:
print(letter, end=' ')
if len(missedLetters) == 0:
print('No missed letters yet.')
print()
# Display the blanks for the secret word (one blank per letter):
blanks = ['_'] * len(secretWord)
# Replace blanks with correctly guessed letters:
for i in range(len(secretWord)):
if secretWord[i] in correctLetters:
blanks[i] = secretWord[i]
# Show the secret word with spaces in between each letter:
print(' '.join(blanks))
def getPlayerGuess(alreadyGuessed):
"""Returns the letter the player entered. This function makes sure
the player entered a single letter they haven't guessed before."""
while True: # Keep asking until the player enters a valid letter.
print('Guess a letter.')
guess = input('> ').upper()
if len(guess) != 1:
print('Please enter a single letter.')
elif guess in alreadyGuessed:
print('You have already guessed that letter. Choose again.')
elif not guess.isalpha():
print('Please enter a LETTER.')
else:
return guess
# 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.
在输入源代码并运行几次之后,尝试对其进行实验性的修改。标有(!)
的注释对你可以做的小改变有建议。你也可以自己想办法做到以下几点:
试着找出下列问题的答案。尝试对代码进行一些修改,然后重新运行程序,看看这些修改有什么影响。
missedLetters.append(guess)
会发生什么?drawHangman(missedLetters, correctLetters, secretWord)
改成drawHangman(correctLetters, missedLetters, secretWord)
会怎么样?['_']
改成['*']
会怎么样?print(' '.join(blanks))
改成print(secretWord)
会怎么样?原文:http://inventwithpython.com/bigbookpython/project35.html
这个简短的程序产生一个类似于铁丝网的六角形网格的镶嵌图像。这说明你不需要很多代码就能做出有趣的东西。这个项目的一个稍微复杂一点的变体是项目 65,“闪光地毯”
注意,这个程序使用原始字符串,它在开始的引号前面加上小写的r
,这样字符串中的反斜杠就不会被解释为转义字符。
图 35-1 显示了运行hexgrid.py
时的输出。
:显示六边形网格镶嵌图像的输出
编程背后的力量在于它能让计算机快速无误地执行重复的指令。这就是十几行代码如何在屏幕上创建数百、数千或数百万个六边形。
在命令提示符或终端窗口中,您可以将程序的输出从屏幕重定向到文本文件。在 Windows 上,运行py hexgrid.py > hextiles.txt
创建一个包含六边形的文本文件。在 Linux 和 macOS 上,运行python3 hexgrid.py > hextiles.txt
。没有屏幕大小的限制,您可以增加X_REPEAT
和Y_REPEAT
常量并将内容保存到文件中。从那里,很容易将文件打印在纸上,用电子邮件发送,或发布到社交媒体上。这适用于你创作的任何计算机生成的作品。
"""Hex Grid, by Al Sweigart email@protected
Displays a simple tessellation of a hexagon grid.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: tiny, beginner, artistic"""
# Set up the constants:
# (!) Try changing these values to other numbers:
X_REPEAT = 19 # How many times to tessellate horizontally.
Y_REPEAT = 12 # How many times to tessellate vertically.
for y in range(Y_REPEAT):
# Display the top half of the hexagon:
for x in range(X_REPEAT):
print(r'/ \_', end='')
print()
# Display the bottom half of the hexagon:
for x in range(X_REPEAT):
print(r'\_/ ', end='')
print()
在输入源代码并运行几次之后,尝试对其进行实验性的修改。标有(!)
的注释对你可以做的小改变有建议。你也可以自己想办法做到以下几点:
为了练习,请尝试使用更大的六边形网格重新创建此程序,如下图所示:
/ \ / \ / \ / \ / \ / \ / \
/ \___/ \___/ \___/ \___/ \___/ \___/ \
\ / \ / \ / \ / \ / \ / \ /
\___/ \___/ \___/ \___/ \___/ \___/ \___/
/ \ / \ / \ / \ / \ / \ / \
/ \___/ \___/ \___/ \___/ \___/ \___/ \
/ \ / \ / \ / \
/ \ / \ / \ / \
/ \_____/ \_____/ \_____/ \_____
\ / \ / \ / \ /
\ / \ / \ / \ /
\_____/ \_____/ \_____/ \_____/
/ \ / \ / \ / \
/ \ / \ / \ / \
/ \_____/ \_____/ \_____/ \_____
这是一个基础程序,所以没有太多的选项来定制它。取而代之的是,考虑你如何能类似地编程其他形状的模式。