Python学习笔记(一):命令行界面扫雷(详细)
起因
因为最近刚刚开始学习Python,想编点东西来熟悉一下语法,想起来之前用C语言编过一个简单的命令行界面的扫雷,故用Python来重新编一个,大致效果如下图,我会在文章中梳理一下我当时的大致思路。
过程
首先我们需要构建出来一个雷阵,我们需要的参数有两个,一个是雷阵的大小,另一个就是雷数。
n = eval(input("请输入雷阵的大小"))
m = eval(input("请输入雷的个数"))
我们首先要定义一个二维数组(行列数应比雷阵大一“圈”)
mine = [([0] * (n + 2)) for i in range(0, n + 2)] # 雷阵
因为我们需要一个数组给玩家看,所以需要再定义一个一样大数组,而且该数组到时候需要判断是否开过雷,为防止函数运用到数组之外的地方,因此数组最外一圈初始化为0.
user = [(['#'] * (n + 2)) for i in range(0, n + 2)] # 用户
for i in range(0, n+2):
user[0][i] = 0
user[n + 1][i] = 0
user[i][0] = 0
user[i][n + 1] = 0
之后,我们就可以初始化 雷阵 了,该过程需要埋下雷,和使不是雷的方块可以显示四周方块中雷的个数
def build(list1, num1, num2): # 雷阵初始化
i = 0 # list1为雷阵,num1为雷阵大小,num2为雷数
while i < num2: # 循环布雷
m = randint(1, num1)
n = randint(1, num1)
if list1[m][n] != '*':
list1[m][n] = '*'
i += 1
else:
continue
for m in range(1, num1 + 1): # 为每一个非雷方块确定周围的雷数
for n in range(1, num1 + 1): # m代表数组的行数,n代表列数
if list1[m][n] != '*':
if list1[m - 1][n - 1] == '*':
list1[m][n] += 1
if list1[m - 1][n] == '*':
list1[m][n] += 1
if list1[m - 1][n + 1] == '*':
list1[m][n] += 1
if list1[m][n - 1] == '*':
list1[m][n] += 1
if list1[m][n + 1] == '*':
list1[m][n] += 1
if list1[m + 1][n - 1] == '*':
list1[m][n] += 1
if list1[m + 1][n] == '*':
list1[m][n] += 1
if list1[m + 1][n + 1] == '*':
list1[m][n] += 1
之后我们就有了一个已经布好了雷的雷阵。接下去我们需要一个函数,它可以帮我们把我们打印出我们输出数组。因为游戏进行的过程中需要用到横纵坐标,因此我们在输出数组的时候,用第一排和第一列来表示横纵坐标。而且输出数组的时候出于美观,将0输出为空格。
def print_mine(list2, num): # list2为要输出的数组,num为数组的大小
for m in range(0, num + 1):
for n in range(0, num + 1):
if m == 0: # 横坐标
print(n, end=' ')
continue
if n == 0: # 纵坐标
print(m, end=' ')
continue
if list2[m][n] == 0: # 将对应为0的元素用空格代替
print(' ', end=' ')
else:
print(list2[m][n], end=' ')
print('')
OK,现在我们就可以编写进行游戏的部分了。我们将进行游戏的主体部分交给函数来处理,这里命名为win,此函数的主要功能就是判断胜负,和进行游戏,其中落子的部分由play函数来处理。所以此函数需要自我调用,这里用flag== 0来表示输了,随即结束游戏;flag==1表示游戏可以继续进行。
def win(list_user, list_mine, num, flag, mine): # 判断胜负
i = 0 # num为数组的大小,mine为雷数
print_mine(list_user, num)
if flag == 1: # 继续游戏
for m in range(0, num+2):
for n in range(0, num+2):
if list_user[m][n] == "#" or list_user[m][n] == '@':
i += 1
if i == mine: # 当数组中未展开或者标记的元素等于雷数,宣布胜利
print("你赢了!")
return 1
else:
a = play(list_user, list_mine, num) # 进行一次落子
win(list_user, list_mine, num, a, mine) # 进行下一次判断
else: # 游戏结束
print("你输了!")
return 0
接下来编写play函数,play函数的功能有落子和标记,落子后需要判断落到的地方是否为雷,若不是,则调用open函数进行开雷处理;若是,则返回0。
def play(list_user, list_mine, num): # 落子函数
m = input("请输入横坐标(需要标记请按@)")
n = input("请输入纵坐标(需要标记请按@)")
if m == '@' or n == '@': # 触发标记功能
m1 = eval(input("请输入要标记的横坐标"))
n1 = eval(input("请输入要标记的纵坐标"))
list_user[m1][n1] = '@'
print_mine(list_user, num)
play(list_user, list_mine, num)
return 1
elif int(m) > num or int(n) > num: # 数据不合理重新输入
print("请重新输入")
play(list_user, list_mine, num)
return 1
else:
if list_mine[int(m)][int(n)] == '*': # 踩雷了
return 0
else:
open_user(list_user, list_mine, int(m), int(n)) # 开雷
return 1
然后进行开雷函数的编写,开雷函数是将user数组中的’#'显示成mine数组中对应元素的数值,若为0,则向四周执行open函数,达到开雷的效果。
def open_user(list_user, list_mine, m, n): # 开雷函数
if list_user[m][n] == '#' or list_user[m][n] == '@':
if list_mine[m][n] == 0:
list_user[m][n] = list_mine[m][n]
open_user(list_user, list_mine, m - 1, n - 1) # 向四周扩散
open_user(list_user, list_mine, m - 1, n)
open_user(list_user, list_mine, m - 1, n + 1)
open_user(list_user, list_mine, m, n + 1)
open_user(list_user, list_mine, m, n - 1)
open_user(list_user, list_mine, m + 1, n - 1)
open_user(list_user, list_mine, m + 1, n)
open_user(list_user, list_mine, m + 1, n + 1)
else:
list_user[m][n] = list_mine[m][n]
最后,因为想不结束程序而重新进入游戏,所以将游戏初始化的部分设置为一个函数。
def begin(): # 游戏进行
n = eval(input("请输入雷阵的大小"))
m = eval(input("请输入雷的个数"))
mine = [([0] * (n + 2)) for i in range(0, n + 2)] # 雷阵
user = [(['#'] * (n + 2)) for i in range(0, n + 2)] # 用户
for i in range(0, n+2):
user[0][i] = 0
user[n + 1][i] = 0
user[i][0] = 0
user[i][n + 1] = 0
build(mine, n, m)
win(user, mine, n, 1, m)
最后
begin()
if (input("是否重来(y/n)")) == 'y':
begin()
完整代码如下
from random import *
def build(list1, num1, num2): # 雷阵初始化
i = 0 # list1为雷阵,num1为雷阵大小,num2为雷数
while i < num2: # 循环布雷
m = randint(1, num1)
n = randint(1, num1)
if list1[m][n] != '*':
list1[m][n] = '*'
i += 1
else:
continue
for m in range(1, num1 + 1): # 为每一个非雷方块确定周围的雷数
for n in range(1, num1 + 1): # m代表数组的行数,n代表列数
if list1[m][n] != '*':
if list1[m - 1][n - 1] == '*':
list1[m][n] += 1
if list1[m - 1][n] == '*':
list1[m][n] += 1
if list1[m - 1][n + 1] == '*':
list1[m][n] += 1
if list1[m][n - 1] == '*':
list1[m][n] += 1
if list1[m][n + 1] == '*':
list1[m][n] += 1
if list1[m + 1][n - 1] == '*':
list1[m][n] += 1
if list1[m + 1][n] == '*':
list1[m][n] += 1
if list1[m + 1][n + 1] == '*':
list1[m][n] += 1
def print_mine(list2, num): # list2为要输出的数组,num为数组的大小
for m in range(0, num + 1):
for n in range(0, num + 1):
if m == 0: # 横坐标
print(n, end=' ')
continue
if n == 0: # 纵坐标
print(m, end=' ')
continue
if list2[m][n] == 0: # 将对应为0的元素用空格代替
print(' ', end=' ')
else:
print(list2[m][n], end=' ')
print('')
def open_user(list_user, list_mine, m, n): # 开雷函数
if list_user[m][n] == '#' or list_user[m][n] == '@':
if list_mine[m][n] == 0:
list_user[m][n] = list_mine[m][n]
open_user(list_user, list_mine, m - 1, n - 1) # 向四周扩散
open_user(list_user, list_mine, m - 1, n)
open_user(list_user, list_mine, m - 1, n + 1)
open_user(list_user, list_mine, m, n + 1)
open_user(list_user, list_mine, m, n - 1)
open_user(list_user, list_mine, m + 1, n - 1)
open_user(list_user, list_mine, m + 1, n)
open_user(list_user, list_mine, m + 1, n + 1)
else:
list_user[m][n] = list_mine[m][n]
def play(list_user, list_mine, num): # 落子函数
m = input("请输入横坐标(需要标记请按@)")
n = input("请输入纵坐标(需要标记请按@)")
if m == '@' or n == '@': # 触发标记功能
m1 = eval(input("请输入要标记的横坐标"))
n1 = eval(input("请输入要标记的纵坐标"))
list_user[m1][n1] = '@'
print_mine(list_user, num)
play(list_user, list_mine, num)
return 1
elif int(m) > num or int(n) > num: # 数据不合理重新输入
print("请重新输入")
play(list_user, list_mine, num)
return 1
else:
if list_mine[int(m)][int(n)] == '*': # 踩雷了
return 0
else:
open_user(list_user, list_mine, int(m), int(n)) # 开雷
return 1
def win(list_user, list_mine, num, flag, mine): # 判断胜负
i = 0 # num为数组的大小,mine为雷数
print_mine(list_user, num)
if flag == 1: # 继续游戏
for m in range(0, num+2):
for n in range(0, num+2):
if list_user[m][n] == "#" or list_user[m][n] == '@':
i += 1
if i == mine: # 当数组中未展开或者标记的元素等于雷数,宣布胜利
print("你赢了!")
return 1
else:
a = play(list_user, list_mine, num) # 进行一次落子
win(list_user, list_mine, num, a, mine) # 进行下一次判断
else: # 游戏结束
print("你输了!")
return 0
def begin(): # 游戏进行
n = eval(input("请输入雷阵的大小"))
m = eval(input("请输入雷的个数"))
mine = [([0] * (n + 2)) for i in range(0, n + 2)] # 雷阵
user = [(['#'] * (n + 2)) for i in range(0, n + 2)] # 用户
for i in range(0, n+2):
user[0][i] = 0
user[n + 1][i] = 0
user[i][0] = 0
user[i][n + 1] = 0
build(mine, n, m)
win(user, mine, n, 1, m)
begin()
if (input("是否重来(y/n)")) == 'y':
begin()
后记
这是第一次在CSDN上写博客,对Python的学习也才刚刚开始,其中难免有些错误,多多包容。
下一步的打算是使雷阵在每次操作完可以刷新,而不是重新输出一个。还有将该游戏图形化的打算。(等我学到了再说)