Python-turtle迷宫小游戏

简介:

这是一个简单的迷宫小游戏,通过 numpy.ndarray 来存储迷宫的格点信息,通过 turtle 来展示迷宫信息并通过上下左右按键来进行移动。格点信息是通过随机产生的,所以可以做很大规模;另外通过 opencv 的水漫来检测随机产生的迷宫是否是通的。迷宫的起点在左下角,终点是右上角。
效果如下:
在这里插入图片描述

整体介绍

0. 导入库

import turtle as tt
import numpy as np
import cv2

1. 通过numpy创建迷宫格点信息

# 设置迷宫
Size = 100
Threshold = 0.6
def set_maze(size=Size, threshold=Threshold) -> np.ndarray:
    maze = np.ones(shape=[size, size], dtype=int)*255
    a = np.random.random(size=[size, size])
    a[0, 0] = 0
    a[-1, -1] = 0
    maze[np.where(a<threshold)] = 0
    return maze

这里,产生的 maze 矩阵即为记录 0 和 1 的格点,Size 即为迷宫的尺寸(正方形)。
threshold 是随机数比较的阈值,这个值不能太小,不然迷宫会堵死。

2. 通过opencv检验迷宫的连通性

# 水漫,检验连通性
def flood(A:np.ndarray, seed=(0,0)) -> np.ndarray:
    mat_temp = A.copy()
    N = mat_temp.shape[0]
    mask = np.zeros(shape=(N+2,N+2), dtype=np.uint8)
    cv2.floodFill(mat_temp, mask, seedPoint=seed, newVal=100)
    return mask[1:-1,1:-1]

# 设置可用的迷宫
for i in range(1000):
    maze = set_maze()
    mask = flood(maze)
    if mask[-1, -1]>0:
        print(i, 'create')
        break

if mask[-1, -1]<0:
    print('YOUR MAZE DOES NOT WORK!')

我们将左下角 [0,0] 作为起点,右上角 [N-1, N-1] 作为终点。用 opencv 的 floodFill 函数检验连通性,如果随机出来的矩阵不连通,那就继续随机。
如果你的输出里面没有显示 create,那就不要玩下去了,因为是堵死的……
当然你也可以直接手动输入迷宫信息,创建一个固定的迷宫,但那样太费事而且没啥意思了。

3. 画迷宫

# 画图setup
n_show = 10
size_show = 50
tt.tracer(False)
tt.setworldcoordinates(0, 0, n_show*size_show, n_show*size_show)
tt.bgcolor('gray')
tt.penup()
tt.hideturtle()

def draw_rect(size=size_show, color='white') -> None:
    tt.setheading(0)
    tt.fillcolor(color)
    
    tt.begin_fill()
    for _ in range(4):
        tt.forward(size)
        tt.left(90)
    tt.end_fill()

# 画迷宫
Maze = np.array(np.where(maze==0)).T
for xy in Maze:
    tt.goto(xy[0]*size_show, xy[1]*size_show)
    draw_rect()
tt.goto(Maze[-1][0]*size_show, Maze[-1][1]*size_show)
draw_rect(color='#66ccff')

这里就是很普通的 turtle 画图啦,画出来差不多是这样的:
在这里插入图片描述
灰色方块代表封闭的地方,白色方块是能走的,一个方块是一个点。
另外注意,画图需要点时间。对于尺寸为 100,也就是有1万个点,画图大概要1秒钟;如果你的迷宫尺寸很大,可能得稍等个几秒。

4. 开始走迷宫

# 迷宫开始,移动
class Moving():
    def __init__(self, size=40) -> None:
        self.pos = np.array([0, 0])
        self.size = size
        self.show_range = np.array([0, 0, n_show*size_show, n_show*size_show])
    
    # 移动
    def move(self, direction):
        temp = self.pos + np.array(direction)
        temp = np.clip(temp, 0, Size-1)
        if maze[temp[0], temp[1]] == 0:
            tt.dot(self.size, 'white')
            self.pos = temp
        self.show()

    def show(self):
        print('x:{}\ty:{}'.format(*self.pos))
        tt.goto((self.pos[0]+1/2)*size_show, (self.pos[1]+1/2)*size_show)
        tt.dot(self.size, 'green')
        
        self.show_range[:2] = (self.pos-n_show/2)*size_show
        self.show_range[2:] = (self.pos+n_show/2)*size_show

        tt.setworldcoordinates(*self.show_range)
        tt.update()
        if (self.pos==Size-1).all():
            print('Success!')

    # 按键用到的接口
    def up(self):
        self.move([0, 1])
    def down(self):
        self.move([0, -1])
    def left(self):
        self.move([-1, 0])
    def right(self):
        self.move([1, 0])


# 按键移动
Mov = Moving()
Mov.show()
tt.onkey(Mov.up, 'Up')
tt.onkey(Mov.down, 'Down')
tt.onkey(Mov.left, 'Left')
tt.onkey(Mov.right, 'Right')
tt.listen()

tt.mainloop()

这个就不多说了,要注意的几个点是:

  • 窗口的视图要随着你的位置而移动(当然如果能一下子展示完的话也不用这样。
  • 每移动到下一个点,要抹去前一步的痕迹……
  • 要写函数来对接 turtle 的按键接口。

全部代码:

有问题欢迎指出 ~

import turtle as tt
import numpy as np
import cv2

# 设置迷宫
Size = 10
Threshold = 0.6
def set_maze(size=Size, threshold=Threshold) -> np.ndarray:
    maze = np.ones(shape=[size, size], dtype=int)*255
    a = np.random.random(size=[size, size])
    a[0, 0] = 0
    a[-1, -1] = 0
    maze[np.where(a<threshold)] = 0
    return maze

# 水漫,检验连通性
def flood(A:np.ndarray, seed=(0,0)) -> np.ndarray:
    mat_temp = A.copy()
    N = mat_temp.shape[0]
    mask = np.zeros(shape=(N+2,N+2), dtype=np.uint8)
    cv2.floodFill(mat_temp, mask, seedPoint=seed, newVal=100)
    return mask[1:-1,1:-1]

# 设置可用的迷宫
for i in range(1000):
    maze = set_maze()
    mask = flood(maze)
    if mask[-1, -1]>0:
        print(i, 'create')
        break

if mask[-1, -1]<0:
    print('YOUR MAZE DOES NOT WORK!')


# 画图setup
n_show = 10
size_show = 50
tt.tracer(False)
tt.setworldcoordinates(0, 0, n_show*size_show, n_show*size_show)
tt.bgcolor('gray')
tt.penup()
tt.hideturtle()

def draw_rect(size=size_show, color='white') -> None:
    tt.setheading(0)
    tt.fillcolor(color)
    
    tt.begin_fill()
    for _ in range(4):
        tt.forward(size)
        tt.left(90)
    tt.end_fill()

# 画迷宫
Maze = np.array(np.where(maze==0)).T
for xy in Maze:
    tt.goto(xy[0]*size_show, xy[1]*size_show)
    draw_rect()
tt.goto(Maze[-1][0]*size_show, Maze[-1][1]*size_show)
draw_rect(color='#66ccff')


# 迷宫开始,移动
class Moving():
    def __init__(self, size=40) -> None:
        self.pos = np.array([0, 0])
        self.size = size
        self.show_range = np.array([0, 0, n_show*size_show, n_show*size_show])
    
    # 移动
    def move(self, direction):
        temp = self.pos + np.array(direction)
        temp = np.clip(temp, 0, Size-1)
        if maze[temp[0], temp[1]] == 0:
            tt.dot(self.size, 'white')
            self.pos = temp
        self.show()

    def show(self):
        print('x:{}\ty:{}'.format(*self.pos))
        tt.goto((self.pos[0]+1/2)*size_show, (self.pos[1]+1/2)*size_show)
        tt.dot(self.size, 'green')
        
        self.show_range[:2] = (self.pos-n_show/2)*size_show
        self.show_range[2:] = (self.pos+n_show/2)*size_show

        tt.setworldcoordinates(*self.show_range)
        tt.update()
        if (self.pos==Size-1).all():
            print('Success!')

    # 按键用到的接口
    def up(self):
        self.move([0, 1])
    def down(self):
        self.move([0, -1])
    def left(self):
        self.move([-1, 0])
    def right(self):
        self.move([1, 0])


# 按键移动
Mov = Moving()
Mov.show()
tt.onkey(Mov.up, 'Up')
tt.onkey(Mov.down, 'Down')
tt.onkey(Mov.left, 'Left')
tt.onkey(Mov.right, 'Right')
tt.listen()

tt.mainloop()
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python turtle 是一个绘制图形的模块,可以用来编写小游戏。 下面是一个使用 Python turtle 实现的简单井字棋小游戏的示例代码: ```python import turtle # 初始化游戏界面 window = turtle.Screen() window.title("井字棋小游戏") window.setup(600, 600) # 绘制网格线 pen = turtle.Turtle() pen.speed(0) pen.hideturtle() pen.penup() pen.goto(-300, 100) pen.pendown() pen.color("black") pen.pensize(3) for _ in range(2): pen.forward(600) pen.right(90) pen.forward(200) pen.right(90) pen.penup() pen.goto(-300, 0) pen.pendown() pen.forward(600) pen.penup() pen.goto(-300, -100) pen.pendown() pen.forward(600) pen.penup() pen.goto(-100, 200) pen.right(90) pen.pendown() pen.forward(400) pen.penup() pen.goto(100, 200) pen.pendown() pen.forward(400) # 定义玩家类 class Player: def __init__(self, symbol): self.symbol = symbol # 定义游戏状态 class Game: def __init__(self): self.board = [[' ']*3 for _ in range(3)] self.current_player = Player('X') def draw(self, row, col): if self.board[row][col] == ' ': self.board[row][col] = self.current_player.symbol self.draw_symbol(row, col) if self.check_winner(row, col): pen.penup() pen.goto(-100, -250) pen.write(f"玩家 {self.current_player.symbol} 获胜!", align="center", font=("Courier", 24, "normal")) return True self.switch_player() return False def draw_symbol(self, row, col): pen.penup() pen.goto(col * 200 - 200, -row * 200 + 100) pen.pendown() pen.write(self.current_player.symbol, align="center", font=("Courier", 96, "normal")) def switch_player(self): if self.current_player.symbol == 'X': self.current_player.symbol = 'O' else: self.current_player.symbol = 'X' def check_winner(self, row, col): symbol = self.current_player.symbol # 检查同行 if self.board[row][0] == symbol and self.board[row][1] == symbol and self.board[row][2] == symbol: return True # 检查同列 if self.board[0][col] == symbol and self.board[1][col] == symbol and self.board[2][col] == symbol: return True # 检查对角线 if row == col and self.board[0][0] == symbol and self.board[1][1] == symbol and self.board[2][2] == symbol: return True if row + col == 2 and self.board[0][2] == symbol and self.board[1][1] == symbol and self.board[2][0] == symbol: return True return False # 创建游戏对象 game = Game() # 注册点击事件处理函数 def click_handler(x, y): if -300 <= x <= 300 and -300 <= y <= 300: row = -int(y // 200 - 1) col = int(x // 200) game.draw(row, col) # 绑定点击事件 turtle.onscreenclick(click_handler) turtle.listen() # 启动游戏主循环 turtle.mainloop() ``` 这个小游戏使用 turtle 绘制了一个井字棋的游戏界面,并实现了玩家的交替下棋和判断胜负的功能。玩家可以通过点击界面上的格子来下棋,并显示结果。 希望以上示例代码能帮助您理解 Python turtle 的基本用法以及如何编写一个简单的小游戏
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值