大爽Python入门教程 6-8 实例演示二 控制台——走迷宫游戏

python

大爽Python入门公开课教案 点击查看教程总目录

1 游戏介绍

实现一个控制台版本的走迷宫小游戏。

代码量:100行左右。

迷宫介绍

这是一个迷宫文件maze01.txt, 如下

########

#____#_E

#_#__#_#

#_#_##_#

S_#____#

########

其中#是墙,不可穿越,
_是路,可以在路与路中上下左右移动,不能对角线(斜着)移动。
S是起点,玩家的初始地点,代表玩家,过程中移动玩家,这个S也跟着玩家动。
E是终点,玩家到达这里即为胜利。

进入游戏

运行游戏,

先展示欢迎语。

再展示迷宫面板,

以及提醒用户输入。

如下

Welcome to maze game!

########

#____#_E

#_#__#_#

#_#_##_#

S_#____#

########

Enter command:

游戏中有移动命令和退出游戏命令

移动命令

移动命令的语法为:
方位 + 步数:尝试向指定方向移动指定步数,移动中前方有墙则停止。

方位值及意义如下:

  • w: 向上移动

  • a: 向左移动

  • s: 向下移动

  • d: 向右移动

步数是一个正整数

举例:
d2: 尝试向右移动2格。
w3: 尝试向上移动3格。

对这个迷宫

########

#____#_E

#_#__#_#

#_#_##_#

S_#____#

########

执行d2命令后如下

########

#____#_E

#_#__#_#

#_#_##_#

_S#____#

########

实际只往右移动了一格,因为再往右就是墙了

再执行w3命令后如下

########

#S___#_E

#_#__#_#

#_#_##_#

__#____#

########

往上移动了3格

退出命令

退出命令是e

输入该命令,

游戏界面展示结束语并结束

效果如下

Enter command: e

Bye!

找到终点

对于上面展示的迷宫。

找到终点的一系列命令为

d1

w3

d2

s3

d3

w3

d1

找到终点的时候,再次展示面板,

并输出成功信息。

########

#____#_S

#_#__#_#

#_#_##_#

__#____#

########

Win!Successfully walked out of the maze.

整体运行效果

走出该迷宫的命令

Welcome to maze game!

########

#____#_E

#_#__#_#

#_#_##_#

S_#____#

########

Enter command: d1

########

#____#_E

#_#__#_#

#_#_##_#

_S#____#

########

Enter command: w3

########

#S___#_E

#_#__#_#

#_#_##_#

__#____#

########

Enter command: d2

########

#__S_#_E

#_#__#_#

#_#_##_#

__#____#

########

Enter command: s3

########

#____#_E

#_#__#_#

#_#_##_#

__#S___#

########

Enter command: d3

########

#____#_E

#_#__#_#

#_#_##_#

__#___S#

########

Enter command: w3

########

#____#SE

#_#__#_#

#_#_##_#

__#____#

########

Enter command: d1

########

#____#_S

#_#__#_#

#_#_##_#

__#____#

########

Win!Successfully walked out of the maze.

2 初步分析

大概步骤

  1. 首先要读取迷宫信息,存到一个二维列表board中,如下

python">[

['#', '#', '#', '#', '#', '#', '#', '#'],

['#', '_', '_', '_', '_', '#', '_', 'E'],

['#', '_', '#', '_', '_', '#', '_', '#'],

['#', '_', '#', '_', '#', '#', '_', '#'],

['S', '_', '#', '_', '_', '_', '_', '#'],

['#', '#', '#', '#', '#', '#', '#', '#']

]

  1. 要得到起点位置,和终点位置,用其行列序号表示。

    第一个坐标为行序号,第二个坐标为列序号。上面例子中的

    起点位置是[4, 0],

    终点位置是[1, 7]

  2. 要想办法实现移动。
  3. 主函数,通过循环反复接受输入。
  4. 把迷宫面板展示(输出)出来。

函数设计

对应的,需要以下几个函数

  • read_maze_file: 读取文件

  • show_board: 展示迷宫面板

  • get_rc: 得到起点或终点的坐标(行列坐标)

  • move: 实现移动功能

  • main: 主函数或者说主逻辑

参数分析

这些函数需要哪些参数

  • read_maze_file(maze_file): 迷宫文本文件路径

  • show_board(board): 迷宫面板的二位列表

  • get_rc(board, symbol): symbol为起点或终点的符号。

  • move(?): 尚不明确。

  • main(maze_file): 迷宫文本文件路径。

3 细节分析

移动动作分析

wasd对应的上下左右的移动怎么实现呢。

w: 上移,S的行序号坐标减1,列序号不变。
a: 左移,S的行序号不变,列序号坐标减1。
s: 上移,S的行序号坐标加1,列序号不变。
d: 左移,S的行序号不变,列序号坐标加1。

这些操作本质上就是再S的原坐标基础上修改行序号和列序号。

如果把一次移动中,行的变化量叫做dr,列的变化量叫做dc

实现一次变化的代码如下

# 原来的坐标

start = [start_r, start_c]

new_r = start[0] + dr

new_c = start[1] + dc

# 移动后的坐标

new_start = [new_r, new_c]

方向, 和行的变化量dr,列的变化量dc之间是一种对应关系。

一个方向,对应一种行变化量dr和列变化量dc
drdc作为一组,可以存到元组中。

故方向的移动信息DIRECTION可以定义如下

DIRECTION = {

# direction: (dr, dc)

"w": (-1, 0),

"a": (0, -1),

"s": (1, 0),

"d": (0, 1),

}

移动命令解析

移动命令分为方位步数

命令的变量名一般叫做command或者cmd(前面的简写)。

这里我们用cmd

方位是命令的第一个字符串。

步数是之后的,通过[1:]切片操作能从命令字符串中取出步骤字符串。

这里有三个要检查的,

0. 检查命令字符串长度是否大于0。

  1. 检查方位字符串是否是wasd之一
  2. 再检查步数字符串是否是数字构成,然后转化成int

这部分对应的代码如下

if len(cmd) > 0:

direction = cmd[0]

step = cmd[1:]

if direction in DIRECTION:

drc = DIRECTION[direction]

if step.isdigit():

step = int(step)

主函数流程逻辑

主函数中要做的

  1. 获取迷宫对应的二维列表
  2. 获取起点和终点坐标
  3. 展示欢迎语
  4. 使用循环,循环中展示面板,接受用户输入,处理用户输入。

4 逐步实现

字符串和其他信息

先在代码开头定义要用的的字符串和和方位移动的信息字典。

如下

WELCOME = "Welcome to maze game!"

ENTER = "Enter command: "

Invalid = "Invalid command"

WIN = "Win!Successfully walked out of the maze."

BYE = "Bye!"

DIRECTION = {

# direction: (dr, dc)

"w": (-1, 0),

"a": (0, -1),

"s": (1, 0),

"d": (0, 1),

}

主函数main

代码如下

def main(maze_file):

# 1. 获取迷宫对应的二维列表

board = read_maze_file(maze_file)

# 2. 获取起点和终点坐标

start = get_rc(board, "S") # r, c

end = get_rc(board, "E") # r, c

# 3. 展示欢迎语

print(WELCOME)

# 4. 使用循环

while True:

# 4-a. 循环中展示面板

show_board(board)

if start == end: # 4-b. 到达终点,胜利并结束游戏

print(WIN)

return

# 4-c. 接受用户输入

cmd = input(ENTER)

cmd = cmd.lower()

# 4-d. 处理用户输入

if len(cmd) > 0:

if cmd[0] == "e": # 4-e. 直接退出游戏

print(BYE)

return

# 4-f. 尝试解析移动命令

direction = cmd[0]

step = cmd[1:]

if direction in DIRECTION:

drc = DIRECTION[direction]

if step.isdigit(): #

# 4-g. 解析成功,移动并直接进入下一轮循环

step = int(step)

move(board, start, drc, step)

continue

# 4-h. 处理中失败了,提醒输入不符合规范。

print(Invalid)

实现到4-g时,

明确move函数接受参数为(board, start, drc, step)

read_maze_file

代码如下

def read_maze_file(maze_file):

""""""

with open(maze_file, 'r') as f:

fr = f.read()

board = []

lines = fr.split("\n")

for line in lines:

line = line.strip()

if line:

row = [cell for cell in line]

board.append(row)

return board

show_board

代码如下

def show_board(board):

for row in board:

for cell in row:

print(cell, end="")

print()

get_rc

代码如下

def get_rc(board, start_or_end):

r, c = len(board), len(board[1])

for ri in range(r):

for ci in range(c):

if board[ri][ci] == start_or_end:

return [ri, ci]

return None

move

使用循环即可移动多步,但是有个问题要解决。

那就是遇到前方是墙要停止(还有隐藏限制,不能超过迷宫边界),

这个的解决思路为:

先算出下一步位置,再检查下一步是否是墙或边界外,

是墙或边界外,就停止。

否则更新位置为下一步的位置。

移动中,S字符的移动实现原理为。

移动开始时,把原位置设置为_

移动结束时,把当前位置设置为S

代码如下

def move(board, start, drc, step):

r, c = len(board), len(board[1])

sr, sc = start

dr, dc = drc

board[sr][sc] = "_"

for i in range(step):

new_r = sr + dr

new_c = sc + dc

if board[new_r][new_c] == "#":

break

if new_r < 0 or new_r >= r or new_c < 0 or new_c >= c:

break

sr = new_r

sc = new_c

start[0] = sr

start[1] = sc

board[sr][sc] = "S"

调用代码

调用代码如下

maze_file = "maze01.txt"

main(maze_file)

5 最终代码

最终代码如下(运行效果第一部分已展示,不再额外展示)。

WELCOME = "Welcome to maze game!"

ENTER = "Enter command: "

Invalid = "Invalid command"

WIN = "Win!Successfully walked out of the maze."

BYE = "Bye!"

DIRECTION = {

# direction: (dr, dc)

"w": (-1, 0),

"a": (0, -1),

"s": (1, 0),

"d": (0, 1),

}

def read_maze_file(maze_file):

""""""

with open(maze_file, 'r') as f:

fr = f.read()

board = []

lines = fr.split("\n")

for line in lines:

line = line.strip()

if line:

row = [cell for cell in line]

board.append(row)

return board

def show_board(board):

for row in board:

for cell in row:

print(cell, end="")

print()

def get_rc(board, start_or_end):

r, c = len(board), len(board[1])

for ri in range(r):

for ci in range(c):

if board[ri][ci] == start_or_end:

return [ri, ci]

return None

def move(board, start, drc, step):

r, c = len(board), len(board[1])

sr, sc = start

dr, dc = drc

board[sr][sc] = "_"

for i in range(step):

new_r = sr + dr

new_c = sc + dc

if board[new_r][new_c] == "#":

break

if new_r < 0 or new_r >= r or new_c < 0 or new_c >= c:

break

sr = new_r

sc = new_c

start[0] = sr

start[1] = sc

board[sr][sc] = "S"

def main(maze_file):

# 1. 获取迷宫对应的二维列表

board = read_maze_file(maze_file)

# 2. 获取起点和终点坐标

start = get_rc(board, "S") # r, c

end = get_rc(board, "E") # r, c

# 3. 展示欢迎语

print(WELCOME)

# 4. 使用循环

while True:

# 4-a. 循环中展示面板

show_board(board)

if start == end: # 4-b. 到达终点,胜利并结束游戏

print(WIN)

return

# 4-c. 接受用户输入

cmd = input(ENTER)

cmd = cmd.lower()

# 4-d. 处理用户输入

if len(cmd) > 0:

if cmd[0] == "e": # 4-e. 直接退出游戏

print(BYE)

return

# 4-f. 尝试解析移动命令

direction = cmd[0]

step = cmd[1:]

if direction in DIRECTION:

drc = DIRECTION[direction]

if step.isdigit(): #

# 4-g. 解析成功,移动并直接进入下一轮循环

step = int(step)

move(board, start, drc, step)

continue

# 4-h. 处理中失败了,提醒输入不符合规范。

print(Invalid)

maze_file = "maze01.txt"

main(maze_file)

以上是 大爽Python入门教程 6-8 实例演示二 控制台——走迷宫游戏 的全部内容, 来源链接: utcz.com/z/388168.html

回到顶部