大爽Python入门公开课教案 点击查看教程总目录
1 双层循环
双层循环,或者说嵌套循环,
在一个循环里套一个循环。
介绍嵌套容器之前,先介绍下嵌套循环。
这有什么用呢。
举一个例子,如何输出9x9乘法表。
1x1= 1
1x2= 2 2x2= 4
1x3= 3 2x3= 6 3x3= 9
1x4= 4 2x4= 8 3x4=12 4x4=16
1x5= 5 2x5=10 3x5=15 4x5=20 5x5=25
1x6= 6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36
1x7= 7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49
1x8= 8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64
1x9= 9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81
其实现代码如下
for i in range(1, 10):
for j in range(1, 10):
if j <= i:
print("{}x{}={:>2} ".format(j, i, i*j), end=" ")
print()
此时再来分析下代码,
两层循环中的i和j分别代表了什么。
i代表的是其中蓝色的1-9
j代表的是绿色的1-9
两层循环:
第二层循环,用于输出一行上的具体的列,
即第二层循环执行完,就输出了一行。
第一层循环,用于输出多行,
具体是让第二层循环多次执行,从而输出多行。
理解i和j,最好从行与列的角度去理解。
2 认识嵌套列表
初步介绍
列表里面嵌套列表,也常称为二维列表。
举个例子,这是个3x3(3行3列)的二位列表。
[
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
]
那么这样的列表有什么意义呢,
二维列表,常常用于去表示二维的格子游戏。
比如上面的3x3就可以用来表示井字棋。
实例一 井字棋
比如下面的井字棋。
怎么用二维列表表示呢
这个时候其实有比较大的灵活度。
就是哪种棋子用哪个符号表示是我们可以选择的,
当然,不同的表示方式,
可能会让相关问题解决方式的难度也变得不同。
这里介绍两种表示方式(并不唯一,可以自由定义)。
- 用数字
没有棋子的格子用0
表示
有X
棋子的格子用1
表示
有O
棋子的格子用2
表示
那么上面的井字棋用列表表示如下
board = [
[1, 1, 1],
[2, 1, 0],
[2, 0, 2],
]
- 用字母
没有棋子的格子用空格" "
表示
有X
棋子的格子用"X"
表示
有O
棋子的格子用"O"
表示
那么上面的井字棋用列表表示如下
board = [
["X", "X", "X"],
["O", "X", " "],
["O", " ", "O"],
]
实例二 俄罗斯方块
之前做过一个俄罗斯方块的教程
但那整个教程对现阶段来讲,比较复杂。
这里只取其中的二维列表过来认识与分析。
这是一个该游戏中间过程截图(没有实现检查与清理功能)
这个时候游戏面板中的方格面板对应的二维列表情况如下。
board = [
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', 'L', '', '', '', ''],
['', '', '', '', '', 'L', 'L', 'L', '', '', '', ''],
['', '', 'I', '', 'Z', 'Z', 'Z', 'Z', '', '', '', 'Z'],
['', 'T', 'I', 'I', 'S', 'Z', 'Z', 'Z', 'Z', '', 'Z', 'Z'],
['T', 'T', 'I', 'I', 'S', 'S', 'S', 'T', 'T', 'T', 'Z', 'L'],
['J', 'T', 'I', 'I', 'J', 'S', 'S', 'S', 'T', 'L', 'L', 'L'],
['J', 'J', 'J', 'I', 'J', 'J', 'J', 'S', 'I', 'I', 'I', 'I']
]
这是一个20x12 (20行12列) 的二维列表。
其中''
空字符串对应空白格子。
'O', 'S', 'T', 'I', 'L', 'J', 'Z'
等字母对应不同种类的俄罗斯方块,
有不同的颜色。
3 快速新建二维列表
使用列表生成式
创建3行4列的空字符串组成的二位列表。
board = [
["" for ci in range(4)] for ri in range(3)
]
board
如下
[
['', '', '', ''],
['', '', '', ''],
['', '', '', '']
]
使用二层循环
创建3行4列的空字符串组成的二位列表。
board = []
for ri in range(3):
row = []
for ci in range(4):
row.append("")
board.append(row)
board
如下
[
['', '', '', ''],
['', '', '', ''],
['', '', '', '']
]
4 嵌套列表初步使用
本小部分用到的二维列表如下
board_1 = [
['1', '2', '3', '4'],
['A', 'B', 'C', 'D'],
['+', '-', '*', '/']
]
0. 得到二维列表的行列总数(总行数,总列数)。
r = len(board_1)
c = len(board_1[0])
1. 根据行序号,列序号得到对应的值
得到C
ri, ci = 1, 2
cell = board_1[ri][ci]
2. 找到某个值对应的行列序号, 比如找到-
的
find_r, find_c = -1, -1 # 默认值,用于处理没找到的情况
r = len(board_1)
c = len(board_1[0])
for ri in range(r):
for ci in range(c):
if board[ri][ci] == "-":
find_r, find_c = ri, ci
break
3. 得到某一行、某一列
得到某一行的所有格子,代码比较容易,如下(比如第一行)
row1 = board[1] # 结果为:['A', 'B', 'C', 'D']
得到一列相对麻烦一点,如下(得到第一列)
column1 = [board[ri][1] for ri in range(r)] # 结果为:['2', 'B', '-']
5 使用嵌套使用实例
井字棋检测
以上面举得例子为例
board = [
["X", "X", "X"],
["O", "X", " "],
["O", " ", "O"],
]
这个我们能看出来,是"X"
对应得玩家赢了。
那么能不能实现一个程序,来判断是哪个玩家赢了呢?
具体一点,实现一个函数get_ttt_winner(board)
,
接受一个3x3的二维列表board
作为参数,
返回胜利玩家的棋子符号:"X"
, "O"
, " "
(没有人赢)。
补充: ttt
是因为井字棋对应的英文是Tic-Tac-Toe
。。。
思路分析:
这个时候,需要检查的是所有行,所有列,以及两个对角线。
这些本质上,都是三个格子组成的一串。
那么这里设计出一个对应的子函数check_bunch_match(bunch, symbol)
。
能够检查三个格子组成的一串bunch
是否是某个玩家的棋子symbol
。
这样的解决总问题中的子问题的函数,常称为辅助函数help function
。
def check_bunch_match(bunch, symbol):
res = True
for one in bunch:
if one != symbol:
res = False
break
return res
然后主函数就好写些了。
get_ttt_winner(board)
实现代码如下
def get_ttt_winner(board):
r, c = len(board), len(board[0])
for symbol in "XO":
for ri in range(r):
row = board[ri]
if check_bunch_match(row, symbol):
return symbol
for ci in range(c):
column = [board[ri][ci] for ri in range(r)]
if check_bunch_match(column, symbol):
return symbol
diagonal_1 = [board[ri][ri] for ri in range(r)]
diagonal_2 = [board[ri][c-ri-1] for ri in range(r)]
if check_bunch_match(diagonal_1, symbol):
return symbol
if check_bunch_match(diagonal_2, symbol):
return symbol
return "N"
调用语句如下
board = [
["X", "X", "X"],
["O", "X", " "],
["O", " ", "O"],
]
r = get_ttt_winner(board)
print(r)
输出如下
X
俄罗斯方块检测
上面给的俄罗斯方块例子中,没有实现检查与清理功能。
那么我们接下来实现这个功能。
具体一点,实现一个函数check_and_clear(board)
,
接受一个二维列表board
作为参数(board
的行列数不确定,但都大于0),
检测是否有行上占满了俄罗斯方格,有则清理,
直接在board
上操作,不用返回。
为了方便看到效果,函数中,清理完毕后,直接以可读性比较高的格式来展示board
。
空格子展示为_
, 有俄罗斯方块的格子,用方块对应的字符展示。
思路分析:
需要一个子函数check_row_complete(row)
,检查一行row
是否填满。
def check_row_complete(row):
for cell in row:
if cell=='':
return False
return True
然后主函数check_and_clear(board)
如下
def check_and_clear(board):
has_complete_row = False
r, c = len(board), len(board[0])
for ri in range(r):
if check_row_complete(board[ri]):
# 当前行可消除
if ri > 0:
for cur_ri in range(ri, 0, -1):
board[cur_ri] = board[cur_ri-1][:]
board[0] = ['' for j in range(c)]
else:
board[ri] = ['' for j in range(c)]
# display
for row in board:
for cell in row:
if cell:
print(cell, end="")
else:
print("_", end="")
print()
调用代码如下
board = [
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', '', '', '', '', ''],
['', '', '', '', '', '', '', 'L', '', '', '', ''],
['', '', '', '', '', 'L', 'L', 'L', '', '', '', ''],
['', '', 'I', '', 'Z', 'Z', 'Z', 'Z', '', '', '', 'Z'],
['', 'T', 'I', 'I', 'S', 'Z', 'Z', 'Z', 'Z', '', 'Z', 'Z'],
['T', 'T', 'I', 'I', 'S', 'S', 'S', 'T', 'T', 'T', 'Z', 'L'],
['J', 'T', 'I', 'I', 'J', 'S', 'S', 'S', 'T', 'L', 'L', 'L'],
['J', 'J', 'J', 'I', 'J', 'J', 'J', 'S', 'I', 'I', 'I', 'I']
]
check_and_clear(board)
输出如下
____________
____________
____________
____________
____________
____________
____________
____________
____________
____________
____________
____________
____________
____________
____________
____________
_______L____
_____LLL____
__I_ZZZZ___Z
_TIISZZZZ_ZZ
6 简单回顾
二维列表常用语法
获取总行数和总列数。
r = len(board)
c = len(board[0])
得到第ri
行,第ci
的内容: board[ri][ci]