Python 小型项目大全 66~70
六十六、简单替换密码
原文:http://inventwithpython.com/bigbookpython/project66.html

简单替换密码用一个字母代替另一个字母。由于字母A有 26 种可能的替换,B有 25 种可能的替换,C有 24 种可能的替换,等等,所以可能的键的总数是26 × 25 × 24 × 23 × ... × 1,即 403291461126605635584000000 个密钥!对于一台超级计算机来说,这对于暴力破解来说太多了,所以项目 7“凯撒破解”中使用的密码破解方法不能用于对抗简单的密码。不幸的是,狡猾的攻击者可以利用已知的弱点来破解代码。如果你想了解更多关于密码和密码破解的知识,你可以阅读我的书《Python 密码破解指南》(NoStarch 出版社,2018)。
运行示例
当您运行simplesubcipher.py时,输出将如下所示:
Simple Substitution Cipher, by Al Sweigart
A simple substitution cipher has a one-to-one translation for each
symbol in the plaintext and each symbol in the ciphertext.
Do you want to (e)ncrypt or (d)ecrypt?
> e
Please specify the key to use.
Or enter RANDOM to have one generated for you.
> random
The key is WNOMTRCEHDXBFVSLKAGZIPYJQU. KEEP THIS SECRET!
Enter the message to encrypt.
> Meet me by the rose bushes tonight.
The encrypted message is:
Fttz ft nq zet asgt nigetg zsvhcez.
Full encrypted text copied to clipboard.Simple Substitution Cipher, by Al Sweigart
A simple substitution cipher has a one-to-one translation for each
symbol in the plaintext and each symbol in the ciphertext.
Do you want to (e)ncrypt or (d)ecrypt?
> d
Please specify the key to use.
> WNOMTRCEHDXBFVSLKAGZIPYJQU
Enter the message to decrypt.
> Fttz ft nq zet asgt nigetg zsvhcez.
The decrypted message is:
Meet me by the rose bushes tonight.
Full decrypted text copied to clipboard.
工作原理
密钥的 26 个字母中的每一个的位置对应于字母表中相同位置的字母:

:字母表中的字母如何用一个以WNOM开头的密钥加密。若要解密,请将底部的字母替换为上面相应的字母。
用这个密钥,字母A加密到W (而W解密到A,字母B加密到N,以此类推。LETTERS和key变量被分配给charsA和charsB(或者在解密时反过来)。用charsB中的相应字符替换charsA中的任何消息字符,以产生最终翻译的消息。
"""Simple Substitution Cipher, by Al Sweigart email@protected
A simple substitution cipher has a one-to-one translation for each
symbol in the plaintext and each symbol in the ciphertext.
More info at: https://en.wikipedia.org/wiki/Substitution_cipher
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: short, cryptography, math"""import randomtry:import pyperclip # pyperclip copies text to the clipboard.
except ImportError:pass # If pyperclip is not installed, do nothing. It's no big deal.# Every possible symbol that can be encrypted/decrypted:
LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'def main():print('''Simple Substitution Cipher, by Al Sweigart
A simple substitution cipher has a one-to-one translation for each
symbol in the plaintext and each symbol in the ciphertext.''')# Let the user specify if they are encrypting or decrypting:while True: # Keep asking until the user enters e or d.print('Do you want to (e)ncrypt or (d)ecrypt?')response = input('> ').lower()if response.startswith('e'):myMode = 'encrypt'breakelif response.startswith('d'):myMode = 'decrypt'breakprint('Please enter the letter e or d.')# Let the user specify the key to use:while True: # Keep asking until the user enters a valid key.print('Please specify the key to use.')if myMode == 'encrypt':print('Or enter RANDOM to have one generated for you.')response = input('> ').upper()if response == 'RANDOM':myKey = generateRandomKey()print('The key is {}. KEEP THIS SECRET!'.format(myKey))breakelse:if checkKey(response):myKey = responsebreak# Let the user specify the message to encrypt/decrypt:print('Enter the message to {}.'.format(myMode))myMessage = input('> ')# Perform the encryption/decryption:if myMode == 'encrypt':translated = encryptMessage(myMessage, myKey)elif myMode == 'decrypt':translated = decryptMessage(myMessage, myKey)# Display the results:print('The %sed message is:' % (myMode))print(translated)try:pyperclip.copy(translated)print('Full %sed text copied to clipboard.' % (myMode))except:pass # Do nothing if pyperclip wasn't installed.def checkKey(key):"""Return True if key is valid. Otherwise return False."""keyList = list(key)lettersList = list(LETTERS)keyList.sort()lettersList.sort()if keyList != lettersList:print('There is an error in the key or symbol set.')return Falsereturn Truedef encryptMessage(message, key):"""Encrypt the message using the key."""return translateMessage(message, key, 'encrypt')def decryptMessage(message, key):"""Decrypt the message using the key."""return translateMessage(message, key, 'decrypt')def translateMessage(message, key, mode):"""Encrypt or decrypt the message using the key."""translated = ''charsA = LETTERScharsB = keyif mode == 'decrypt':# For decrypting, we can use the same code as encrypting. We# just need to swap where the key and LETTERS strings are used.charsA, charsB = charsB, charsA# Loop through each symbol in the message:for symbol in message:if symbol.upper() in charsA:# Encrypt/decrypt the symbol:symIndex = charsA.find(symbol.upper())if symbol.isupper():translated += charsB[symIndex].upper()else:translated += charsB[symIndex].lower()else:# The symbol is not in LETTERS, just add it unchanged.translated += symbolreturn translateddef generateRandomKey():"""Generate and return a random encryption key."""key = list(LETTERS) # Get a list from the LETTERS string.random.shuffle(key) # Randomly shuffle the list.return ''.join(key) # Get a string from the list.# If this program was run (instead of imported), run the program:
if __name__ == '__main__':main()
探索程序
试着找出下列问题的答案。尝试对代码进行一些修改,然后重新运行程序,看看这些修改有什么影响。
- 如果删除或注释掉第 122 行的
random.shuffle(key)并输入密钥RANDOM会发生什么? - 如果将第 16 行的
LETTERS字符串扩展成'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'会发生什么?
六十七、正弦消息
原文:http://inventwithpython.com/bigbookpython/project67.html

当文本向上滚动时,这个程序以波浪形显示用户选择的消息。它用实现三角正弦波函数的math.sin()来实现这个效果。但是即使你不懂数学,这个程序也很短,很容易复制。
运行示例
当您运行sinemessage.py时,输出将如下所示:
Sine Message, by Al Sweigart email@protected
(Press Ctrl-C to quit.)What message do you want to display? (Max 39 chars.)
> I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!
I <3 Programming!
I <3 Programming!I <3 Programming!I <3 Programming!I <3 Programming!
`--snip--`
工作原理
Python 的math模块中的math.sin()函数接受一个参数,我们称之为x,并返回另一个数字,称为x的正弦值。一些数学应用使用正弦函数;在我们的程序中,它的目的仅仅是创建一个整洁的波浪效果。我们将名为step的变量传递给math.sin()。该变量从0开始,在主程序循环的每次迭代中增加0.25。
我们将使用math.sin()的返回值来计算我们应该在用户消息的两边打印多少空格的填充。由于math.sin()返回一个在-1.0和1.0之间的浮点数,但是我们想要的最小填充量是零,而不是负值,所以第 31 行在math.sin()的返回值上加上1,使得有效范围从0.0到2.0。我们当然需要不止 0 到 2 个空格,所以第 31 行将这个数字乘以一个名为multiplier的变量来增加填充量。这个乘积就是在打印用户消息之前要添加到左侧的空格数。
结果就是你运行程序时看到的挥动的信息动画。
"""Sine Message, by Al Sweigart email@protected
Create a sine-wavy message.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: tiny, artistic"""import math, shutil, sys, time# Get the size of the terminal window:
WIDTH, HEIGHT = shutil.get_terminal_size()
# We can't print to the last column on Windows without it adding a
# newline automatically, so reduce the width by one:
WIDTH -= 1print('Sine Message, by Al Sweigart email@protected')
print('(Press Ctrl-C to quit.)')
print()
print('What message do you want to display? (Max', WIDTH // 2, 'chars.)')
while True:message = input('> ')if 1 <= len(message) <= (WIDTH // 2):breakprint('Message must be 1 to', WIDTH // 2, 'characters long.')step = 0.0 # The "step" determines how far into the sine wave we are.
# Sine goes from -1.0 to 1.0, so we need to change it by a multiplier:
multiplier = (WIDTH - len(message)) / 2
try:while True: # Main program loop.sinOfStep = math.sin(step)padding = ' ' * int((sinOfStep + 1) * multiplier)print(padding + message)time.sleep(0.1)step += 0.25 # (!) Try changing this to 0.1 or 0.5.
except KeyboardInterrupt:sys.exit() # When Ctrl-C is pressed, end the program.
在输入源代码并运行几次之后,尝试对其进行实验性的修改。标有(!)的注释对你可以做的小改变有建议。
探索程序
试着找出下列问题的答案。尝试对代码进行一些修改,然后重新运行程序,看看这些修改有什么影响。
- 如果把第 30 行的
math.sin(step)改成math.cos(step)会怎么样? - 如果把第 30 行的
math.sin(step)改成math.sin(0)会怎么样?
六十八、滑动谜题
原文:http://inventwithpython.com/bigbookpython/project68.html

这个经典的难题依赖于一个4 × 4的板子,有 15 个编号的瓷砖和一个自由空间。目标是滑动瓷砖,直到数字按正确的顺序排列,从左到右,从上到下。瓷砖只能滑动;不允许你直接拿起来重新排列。这个益智玩具的一些版本的特点是混乱的图像,一旦解决就形成一个完整的图片。
更多关于滑动谜题的信息可以在en.wikipedia.org/wiki/Sliding_puzzle找到。
运行示例
当您运行slidingtilepuzzle.py时,输出将如下所示:
Sliding Tile Puzzle, by Al Sweigart email@protectedUse the WASD keys to move the tilesback into their original order:1 2 3 45 6 7 89 10 11 1213 14 15
Press Enter to begin...+------+------+------+------+
| | | | |
| 5 | 10 | | 11 |
| | | | |
+------+------+------+------+
| | | | |
| 6 | 3 | 7 | 2 |
| | | | |
+------+------+------+------+
| | | | |
| 14 | 1 | 15 | 8 |
| | | | |
+------+------+------+------+
| | | | |
| 9 | 13 | 4 | 12 |
| | | | |
+------+------+------+------+(W)
Enter WASD (or QUIT): (A) ( ) (D)
> w+------+------+------+------+
| | | | |
| 5 | 10 | 7 | 11 |
| | | | |
+------+------+------+------+
| | | | |
| 6 | 3 | | 2 |
| | | | |
+------+------+------+------+
| | | | |
| 14 | 1 | 15 | 8 |
| | | | |
+------+------+------+------+
| | | | |
| 9 | 13 | 4 | 12 |
| | | | |
+------+------+------+------+(W)
Enter WASD (or QUIT): (A) (S) (D)
`--snip--`
工作原理
表示滑动瓦片游戏板的数据结构是列表的列表。每个内部列表代表4 × 4棋盘的一列,并包含编号方块的字符串(或代表空白空间的BLANK字符串)。getNewBoard()函数返回列表的列表,所有的图块都在它们的起始位置,在右下角有一个空格。
Python 可以用类似于a, b = b, a的语句交换两个变量的值。该程序在第 101 到 108 行使用这种技术来交换空白空间和相邻的图块,并模拟将编号的图块滑入空白空间。getNewPuzzle()函数通过随机执行 200 次这样的交换来生成新的谜题。
"""Sliding Tile Puzzle, by Al Sweigart email@protected
Slide the numbered tiles into the correct order.
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: large, game, puzzle"""import random, sysBLANK = ' ' # Note: This string is two spaces, not one.def main():print('''Sliding Tile Puzzle, by Al Sweigart email@protectedUse the WASD keys to move the tilesback into their original order:1 2 3 45 6 7 89 10 11 1213 14 15 ''')input('Press Enter to begin...')gameBoard = getNewPuzzle()while True:displayBoard(gameBoard)playerMove = askForPlayerMove(gameBoard)makeMove(gameBoard, playerMove)if gameBoard == getNewBoard():print('You won!')sys.exit()def getNewBoard():"""Return a list of lists that represents a new tile puzzle."""return [['1 ', '5 ', '9 ', '13'], ['2 ', '6 ', '10', '14'],['3 ', '7 ', '11', '15'], ['4 ', '8 ', '12', BLANK]]def displayBoard(board):"""Display the given board on the screen."""labels = [board[0][0], board[1][0], board[2][0], board[3][0],board[0][1], board[1][1], board[2][1], board[3][1],board[0][2], board[1][2], board[2][2], board[3][2],board[0][3], board[1][3], board[2][3], board[3][3]]boardToDraw = """
+------+------+------+------+
| | | | |
| {} | {} | {} | {} |
| | | | |
+------+------+------+------+
| | | | |
| {} | {} | {} | {} |
| | | | |
+------+------+------+------+
| | | | |
| {} | {} | {} | {} |
| | | | |
+------+------+------+------+
| | | | |
| {} | {} | {} | {} |
| | | | |
+------+------+------+------+
""".format(*labels)print(boardToDraw)def findBlankSpace(board):"""Return an (x, y) tuple of the blank space's location."""for x in range(4):for y in range(4):if board[x][y] == ' ':return (x, y)def askForPlayerMove(board):"""Let the player select a tile to slide."""blankx, blanky = findBlankSpace(board)w = 'W' if blanky != 3 else ' 'a = 'A' if blankx != 3 else ' 's = 'S' if blanky != 0 else ' 'd = 'D' if blankx != 0 else ' 'while True:print(' ({})'.format(w))print('Enter WASD (or QUIT): ({}) ({}) ({})'.format(a, s, d))response = input('> ').upper()if response == 'QUIT':sys.exit()if response in (w + a + s + d).replace(' ', ''):return responsedef makeMove(board, move):"""Carry out the given move on the given board."""# Note: This function assumes that the move is valid.bx, by = findBlankSpace(board)if move == 'W':board[bx][by], board[bx][by+1] = board[bx][by+1], board[bx][by]elif move == 'A':board[bx][by], board[bx+1][by] = board[bx+1][by], board[bx][by]elif move == 'S':board[bx][by], board[bx][by-1] = board[bx][by-1], board[bx][by]elif move == 'D':board[bx][by], board[bx-1][by] = board[bx-1][by], board[bx][by]def makeRandomMove(board):"""Perform a slide in a random direction."""blankx, blanky = findBlankSpace(board)validMoves = []if blanky != 3:validMoves.append('W')if blankx != 3:validMoves.append('A')if blanky != 0:validMoves.append('S')if blankx != 0:validMoves.append('D')makeMove(board, random.choice(validMoves))def getNewPuzzle(moves=200):"""Get a new puzzle by making random slides from a solved state."""board = getNewBoard()for i in range(moves):makeRandomMove(board)return board# If this program was run (instead of imported), run the game:
if __name__ == '__main__':main()
在输入源代码并运行几次之后,尝试对其进行实验性的修改。你也可以自己想办法做到以下几点:
- 创建一个更困难的
5 × 5变种的滑动瓷砖谜题。 - 创建一个“自动解决”模式,保存当前的瓷砖排列,然后尝试多达 40 个随机移动和停止,如果他们已经解决了难题。否则,谜题将加载保存的状态,并尝试另外 40 次随机移动。
探索程序
试着找出下列问题的答案。尝试对代码进行一些修改,然后重新运行程序,看看这些修改有什么影响。
- 如果把第 22 行的
getNewPuzzle()改成getNewPuzzle(1)会怎么样? - 如果把第 22 行的
getNewPuzzle()改成getNewPuzzle(0)会怎么样? - 如果删除或注释掉第 31 行的
sys.exit()会发生什么?
六十九、蜗牛赛跑
原文:http://inventwithpython.com/bigbookpython/project69.html

你将无法承受这些比赛的快节奏刺激。。。蜗牛。但是他们在速度上的不足被 ASCII 艺术画的可爱所弥补。每只蜗牛(由贝壳的@字符和两只眼柄的v字符代表)缓慢但坚定地向终点线移动。多达八只蜗牛,每只都有一个自定义的名字,可以互相比赛,在它们身后留下一条黏液痕迹。这个程序适合初学者。
运行示例
当您运行snailrace.py时,输出将如下所示:
Snail Race, by Al Sweigart email@protected@v <-- snailHow many snails will race? Max: 8
> 3
Enter snail #1's name:
> Alice
Enter snail #2's name:
> Bob
Enter snail #3's name:
> Carol
START FINISH
| |Alice
email@protectedBob
email@protectedCarol
email@protected
`--snip--`
工作原理
这个程序使用两个数据结构,存储在两个变量中:snailNames是每个蜗牛名字的字符串列表,snailProgress是一个字典,它的关键字是蜗牛的名字,其值是表示蜗牛移动了多少个空格的整数。第 79 到 82 行读取这两个变量中的数据,在屏幕的适当位置画出蜗牛。
"""Snail Race, by Al Sweigart email@protected
Fast-paced snail racing action!
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: short, artistic, beginner, game, multiplayer"""import random, time, sys# Set up the constants:
MAX_NUM_SNAILS = 8
MAX_NAME_LENGTH = 20
FINISH_LINE = 40 # (!) Try modifying this number.print('''Snail Race, by Al Sweigart email@protected@v <-- snail''')# Ask how many snails to race:
while True: # Keep asking until the player enters a number.print('How many snails will race? Max:', MAX_NUM_SNAILS)response = input('> ')if response.isdecimal():numSnailsRacing = int(response)if 1 < numSnailsRacing <= MAX_NUM_SNAILS:breakprint('Enter a number between 2 and', MAX_NUM_SNAILS)# Enter the names of each snail:
snailNames = [] # List of the string snail names.
for i in range(1, numSnailsRacing + 1):while True: # Keep asking until the player enters a valid name.print('Enter snail #' + str(i) + "'s name:")name = input('> ')if len(name) == 0:print('Please enter a name.')elif name in snailNames:print('Choose a name that has not already been used.')else:break # The entered name is acceptable.snailNames.append(name)# Display each snail at the start line.
print('\n' * 40)
print('START' + (' ' * (FINISH_LINE - len('START')) + 'FINISH'))
print('|' + (' ' * (FINISH_LINE - len('|')) + '|'))
snailProgress = {}
for snailName in snailNames:print(snailName[:MAX_NAME_LENGTH])print('@v')snailProgress[snailName] = 0time.sleep(1.5) # The pause right before the race starts.while True: # Main program loop.# Pick random snails to move forward:for i in range(random.randint(1, numSnailsRacing // 2)):randomSnailName = random.choice(snailNames)snailProgress[randomSnailName] += 1# Check if a snail has reached the finish line:if snailProgress[randomSnailName] == FINISH_LINE:print(randomSnailName, 'has won!')sys.exit()# (!) EXPERIMENT: Add a cheat here that increases a snail's progress# if it has your name.time.sleep(0.5) # (!) EXPERIMENT: Try changing this value.# (!) EXPERIMENT: What happens if you comment this line out?print('\n' * 40)# Display the start and finish lines:print('START' + (' ' * (FINISH_LINE - len('START')) + 'FINISH'))print('|' + (' ' * (FINISH_LINE - 1) + '|'))# Display the snails (with name tags):for snailName in snailNames:spaces = snailProgress[snailName]print((' ' * spaces) + snailName[:MAX_NAME_LENGTH])print(('.' * snailProgress[snailName]) + '@v')
在输入源代码并运行几次之后,尝试对其进行实验性的修改。标有(!)的注释对你可以做的小改变有建议。你也可以自己想办法做到以下几点:
- 添加一个随机的“速度提升”,让蜗牛向前推进四格,而不是一格。
- 增加一个蜗牛在比赛过程中可以随机进入的“睡眠模式”。这种模式使它们停下来转几圈,
zzz出现在它们旁边。 - 加上领带的支撑,以防蜗牛同时到达终点。
探索程序
试着找出下列问题的答案。尝试对代码进行一些修改,然后重新运行程序,看看这些修改有什么影响。
- 如果把第 81 行的
snailName[:MAX_NAME_LENGTH]改成snailNames[0]会怎么样? - 如果把第 50 行的
print('@v')改成print('email@protected')会怎么样?
七十、日本算盘
原文:http://inventwithpython.com/bigbookpython/project70.html

算盘,也称为计数框,是一种计算工具,早在电子计算器发明之前就在许多文化中使用。图 70-1 显示了日本的算盘,叫做 soroban。每根线代表一个位置数字系统中的一个位置,线上的珠子代表该位置的数字。例如,一个 Soroban 在最右边的线上移动了两个珠子,在第二个最右边的线上移动了三个珠子,这将表示数字 32。这个程序模拟了一个 Soroban。(讽刺的是,用一台计算机来模拟一个计算机前的计算工具对我来说并非没有意义。)

soroban
soroban 中的每一列代表一个不同的数字。最右边的列是个位,左边的列是个位,左边的列是个位,以此类推。键盘顶部的Q、W、E、R、T、Y、U、I、O和P键可以增加它们各自位置的数字,而A、S、D、F、G、H、J、K、L和;按键会减少它们。虚拟 soroban 上的珠子会滑动以反映当前的数字。也可以直接输入数字。
水平分隔线下面的四个珠子是“地”珠子,将它们举到分隔线上,该数字计为 1。水平分隔线上方的珠子是一个“天”珠子,对着分隔线向下拉动它会对该数字计数为 5,因此在十位栏中向下拉动一个天堂珠子并向上拉动三个地球珠子代表数字 80。更多关于算盘以及如何使用它们的信息可以在/en.wikipedia.org/wiki/Abacus找到。
运行示例
当您运行soroban.py时,输出将如下所示:
Soroban - The Japanese Abacus
By Al Sweigart email@protected+================================+
I O O O O O O O O O O I
I | | | | | | | | | | I
I | | | | | | | | | | I
+================================+
I | | | | | | | | | | I
I | | | | | | | | | | I
I O O O O O O O O O O I
I O O O O O O O O O O I
I O O O O O O O O O O I
I O O O O O O O O O O I
+==0==0==0==0==0==0==0==0==0==0==++q w e r t y u i o p-a s d f g h j k l ;
(Enter a number, "quit", or a stream of up/down letters.)
> pppiiiii+================================+
I O O O O O O O | O O I
I | | | | | | | | | | I
I | | | | | | | O | | I
+================================+
I | | | | | | | | | O I
I | | | | | | | | | O I
I O O O O O O O O O O I
I O O O O O O O O O | I
I O O O O O O O O O | I
I O O O O O O O O O O I
+==0==0==0==0==0==0==0==5==0==3==++q w e r t y u i o p-a s d f g h j k l ;
(Enter a number, "quit", or a stream of up/down letters.)
`--snip--`
工作原理
displayAbacus()函数接受一个number参数,该参数用于计算应该在算盘上的什么位置呈现珠子。soroban 总是正好有 80 个可能的位置来放置'O'珠子或'|'杆段,如第 127 到 139 行多行字符串中的花括号({})所示。另外 10 个花括号代表number参数的数字。
我们需要创建一个字符串列表来填充这些花括号,从左到右,从上到下。displayAbacus()中的代码将用一个True值填充一个hasBead列表以显示一个'O'珠子,用一个False值显示一个'|'。该列表中的前 10 个值是针对顶部“天堂”行的。如果列的数字是 0、1、2、3 或 4,我们将在该行中放置一个珠子,因为除非该列的数字是 0 到 4,否则天堂珠子不会在该行中。对于剩余的行,我们将布尔值添加到hasBead。
第 118 到 123 行使用hasBead创建一个包含实际的'O'和'|'字符串的abacusChar列表。当与第 126 行的numberList结合时,程序形成一个chars列表,填充 soroban 的多行字符串 ASCII 艺术画的花括号({})。
"""Soroban Japanese Abacus, by Al Sweigart email@protected
A simulation of a Japanese abacus calculator tool.
More info at: https://en.wikipedia.org/wiki/Soroban
This code is available at https://nostarch.com/big-book-small-python-programming
Tags: large, artistic, math, simulation"""NUMBER_OF_DIGITS = 10def main():print('Soroban - The Japanese Abacus')print('By Al Sweigart email@protected')print()abacusNumber = 0 # This is the number represented on the abacus.while True: # Main program loop.displayAbacus(abacusNumber)displayControls()commands = input('> ')if commands == 'quit':# Quit the program:breakelif commands.isdecimal():# Set the abacus number:abacusNumber = int(commands)else:# Handle increment/decrement commands:for letter in commands:if letter == 'q':abacusNumber += 1000000000elif letter == 'a':abacusNumber -= 1000000000elif letter == 'w':abacusNumber += 100000000elif letter == 's':abacusNumber -= 100000000elif letter == 'e':abacusNumber += 10000000elif letter == 'd':abacusNumber -= 10000000elif letter == 'r':abacusNumber += 1000000elif letter == 'f':abacusNumber -= 1000000elif letter == 't':abacusNumber += 100000elif letter == 'g':abacusNumber -= 100000elif letter == 'y':abacusNumber += 10000elif letter == 'h':abacusNumber -= 10000elif letter == 'u':abacusNumber += 1000elif letter == 'j':abacusNumber -= 1000elif letter == 'i':abacusNumber += 100elif letter == 'k':abacusNumber -= 100elif letter == 'o':abacusNumber += 10elif letter == 'l':abacusNumber -= 10elif letter == 'p':abacusNumber += 1elif letter == ';':abacusNumber -= 1# The abacus can't show negative numbers:if abacusNumber < 0:abacusNumber = 0 # Change any negative numbers to 0.# The abacus can't show numbers larger than 9999999999:if abacusNumber > 9999999999:abacusNumber = 9999999999def displayAbacus(number):numberList = list(str(number).zfill(NUMBER_OF_DIGITS))hasBead = [] # Contains a True or False for each bead position.# Top heaven row has a bead for digits 0, 1, 2, 3, and 4.for i in range(NUMBER_OF_DIGITS):hasBead.append(numberList[i] in '01234')# Bottom heaven row has a bead for digits 5, 6, 7, 8, and 9.for i in range(NUMBER_OF_DIGITS):hasBead.append(numberList[i] in '56789')# 1st (topmost) earth row has a bead for all digits except 0.for i in range(NUMBER_OF_DIGITS):hasBead.append(numberList[i] in '12346789')# 2nd earth row has a bead for digits 2, 3, 4, 7, 8, and 9.for i in range(NUMBER_OF_DIGITS):hasBead.append(numberList[i] in '234789')# 3rd earth row has a bead for digits 0, 3, 4, 5, 8, and 9.for i in range(NUMBER_OF_DIGITS):hasBead.append(numberList[i] in '034589')# 4th earth row has a bead for digits 0, 1, 2, 4, 5, 6, and 9.for i in range(NUMBER_OF_DIGITS):hasBead.append(numberList[i] in '014569')# 5th earth row has a bead for digits 0, 1, 2, 5, 6, and 7.for i in range(NUMBER_OF_DIGITS):hasBead.append(numberList[i] in '012567')# 6th earth row has a bead for digits 0, 1, 2, 3, 5, 6, 7, and 8.for i in range(NUMBER_OF_DIGITS):hasBead.append(numberList[i] in '01235678')# Convert these True or False values into O or | characters.abacusChar = []for i, beadPresent in enumerate(hasBead):if beadPresent:abacusChar.append('O')else:abacusChar.append('|')# Draw the abacus with the O/| characters.chars = abacusChar + numberListprint("""
+================================+
I {} {} {} {} {} {} {} {} {} {} I
I | | | | | | | | | | I
I {} {} {} {} {} {} {} {} {} {} I
+================================+
I {} {} {} {} {} {} {} {} {} {} I
I {} {} {} {} {} {} {} {} {} {} I
I {} {} {} {} {} {} {} {} {} {} I
I {} {} {} {} {} {} {} {} {} {} I
I {} {} {} {} {} {} {} {} {} {} I
I {} {} {} {} {} {} {} {} {} {} I
+=={}=={}=={}=={}=={}=={}=={}=={}=={}=={}==+""".format(*chars))def displayControls():print(' +q w e r t y u i o p')print(' -a s d f g h j k l ;')print('(Enter a number, "quit", or a stream of up/down letters.)')if __name__ == '__main__':main()
探索程序
试着找出下列问题的答案。尝试对代码进行一些修改,然后重新运行程序,看看这些修改有什么影响。
- 如果把第 15 行的
abacusNumber = 0改成abacusNumber = 9999会怎么样? - 如果把 121 行的
abacusChar.append('O')改成abacusChar.append('@')会怎么样?
相关文章:
Python 小型项目大全 66~70
六十六、简单替换密码 原文:http://inventwithpython.com/bigbookpython/project66.html 简单替换密码用一个字母代替另一个字母。由于字母A有 26 种可能的替换,B有 25 种可能的替换,C有 24 种可能的替换,等等,所以可能…...
Barra模型因子的构建及应用系列八之Earning_Yeild因子
一、摘要 在前期的Barra模型系列文章中,我们构建了Size因子、Beta因子、Momentum因子、Residual Volatility因子、NonLinear Size因子、Book-to-Price因子和Liquidity因子,并分别创建了对应的单因子策略,其中Size因子和NonLinear Siz因子具有…...
2022蓝桥杯省赛——卡片
问题描述 小蓝有 k 种卡片, 一个班有 n 位同学, 小蓝给每位同学发了两张卡片, 一位同学的两张卡片可能是同一种, 也可能是不同种, 两张卡片没有顺序。没有两位同学的卡片都是一样的。 给定 n, 请问小蓝的卡片至少有多少种? 输入格式 输入一行包含一个正整数表示 n 。 输出…...
数据结构-快速排序
一.概要 快速排序是一种基于分治思想的排序算法,其基本思路是选取一个基准值(pivot),通过一趟排序将待排序列分成两个部分,其中左半部分都小于基准值,右半部分都大于基准值,然后对左右两部分分…...
WuThreat身份安全云-TVD每日漏洞情报-2023-04-10
漏洞名称:Apple iOS/iPadOS 越界写入 漏洞级别:高危 漏洞编号:CVE-2023-28206 相关涉及:Apple iOS <16.4.0 漏洞状态:在野 参考链接:https://tvd.wuthreat.com/#/listDetail?TVD_IDTVD-2023-08810 漏洞名称:PHPGurukul Bank Locker Management System SQL 注入 漏洞级别:高…...
IDEA中查看源码点击Download Sources时出现Cannot download sources的问题复现及解决
IDEA中查看源码点击Download Sources时出现Cannot download sources的问题复现及解决 注意:实验环境的IDEA版本:2021.3.1 1、问题描述 1.1、当想看源码时,点击Download Sources 1.2、此时出现了Cannot download sources 2、解决办法 2.1、…...
R+VIC模型融合实践技术应用及未来气候变化模型预测/SWAT/HSPF/HEC-HMS
在气候变化问题日益严重的今天,水文模型在防洪规划,未来预测等方面发挥着不可替代的重要作用。目前,无论是工程实践或是科学研究中都存在很多著名的水文模型如SWAT/HSPF/HEC-HMS等。虽然,这些软件有各自的优点;但是&am…...
Python 02 数据类型(04元组)
一、元组 元组和列表的唯一不同:不能直接对元组的元素进行修改,删除,添加。 不能修改 1.1 创建元组 1.1.1 创建一个空元组 touple1() # ‘() 里面没有元素,表示为空元组 1.1.2 元组可以容纳任意数据类型的数据的有序集合&…...
WMS:入库库作业流程状态定位
系列文章目录 例如:第一章 WMS:入库库作业流程状态定位 目录 系列文章目录 文章目录 前言 一、入库订单作业状态 二、入库任务级作业状态 1.收货作业 2.验收作业 总结 前言 WMS系统在仓储作业的管理中发挥着至关重要的作用,其核心优势在于强大…...
蓝易云:Linux系统【Centos7】如何配置完整的CC攻击防护策略
完整的CC攻击防护策略包括以下步骤: 1. 调整内核参数 在CentOS 7系统中,可以通过修改内核参数来增加系统对CC攻击的抵抗力。具体操作如下: (1)打开sysctl.conf文件: vim /etc/sysctl.conf (…...
编解码持续升级,「硬」实力铸就视频云最优解
算力时代,视频云需要怎样的 CPU? 在数据爆发式增长及算法日益精进的大背景下,属于「算力」的时代俨然到来。随着视频成为互联网流量的主角,日趋饱和的音视频场景渗透率、人类对“感官之限”的追求与突破、更多元化的场景探索及技术…...
贵金属技术分析的止损保护
前面说过我们这些小散户,最多也不过十几万或者几万美金的账户,没有必要想国际的一些大基金那样,又锁仓,又对冲什么的,我们资金小的投资者,足够灵活,自然有我们存活的方法。所以我们要注意发挥我…...
Python 进阶指南(编程轻松进阶):三、使用 Black 工具来格式化代码
原文:http://inventwithpython.com/beyond/chapter3.html 代码格式化是将一组规则应用于源代码,从而使得代码风格能够简洁统一。虽然代码格式对解析程序的计算机来说不重要,但代码格式对于可读性是至关重要的,这是维护代码所必需的…...
计算机应用辅导大纲及真题
00019考试 湖北省高等教育自学考试实践(技能)课程大纲 课程名称:计算机应用基础(实践) 课程代码:00019 实践能力的培养目标。 计算机应用基础(实践)是高等教育自学考试多…...
【Go基础】一篇文章带你全面了解学习—切片
目录 1、切片注意点 2、声明切片 3、切片初始化 4、切片的内存布局...
2022国赛28:centos8.5离线安装docker
大赛试题内容: 八、虚拟化(20分) 在Linux2上安装docker-ce,导入centos镜像。软件包和镜像存放在物理机D:\soft\DockerLinux。创建名称为skills的容器,映射Linux2的80端口到容器的80端口,在容器内安装apache2,默认网页内容为“HelloContainer”。解答过程: 下载CENTOS8镜…...
JVM专题
JVM类加载 Java里有如下几种类加载器: 引导类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如 rt.jar、charsets.jar等 扩展类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包应用程序…...
蓝桥杯模板题目
A:::::::::::::::小王子单链表(链表) 题目描述 小王子有一天迷上了排队的游戏,桌子上有标号为 1−10 的 10 个玩具,现在小王子将他们排成一列,可小王子还是太小了,他不确定他到底想把那个玩具摆在哪里&…...
SAP IDT - Building Data Foundation
To build a Data Foundation, it can be created on a Local Project view. Right-click under Local Project → New → Data Foundation. You can select a Single-source enabled or Multi-source enabled. Follow the wizard and select the connections. Data Foundatio…...
【Python】【进阶篇】三、Python爬虫的构建User-Agnet代理池
目录三、Python爬虫的构建User-Agnet代理池3.1 自定义UA代理池3.2 模块随机获取UA三、Python爬虫的构建User-Agnet代理池 在编写爬虫程序时,一般都会构建一个 User-Agent (用户代理)池,就是把多个浏览器的 UA 信息放进列表中&…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
