乌龟到达网格边缘时结束游戏



我必须编写一个实现乌龟图形使用的程序。我已经写了大部分程序,其中包括多个海龟的网格和创建,但是一旦乌龟到达我创建的网格的边缘,我很难结束游戏。这是我到目前为止所拥有的:

import turtle
import random
# Setting up Turtle Graphics Window
turtle.setup(800,600)
window = turtle.Screen()
window.title("Turtles Walking through Grid")
window.bgcolor("black")

# Making the turtle
grid = turtle.getturtle()
grid.shape("classic")
grid.color("white")
grid.speed(10)
# Creating the Grid (Relative Positioning)
grid.penup()
grid.setposition(-300,200)
grid.pendown()
grid.forward(600)
grid.right(90)
grid.forward(400)
grid.right(90)
grid.forward(600)
grid.right(90)
grid.forward(400)
grid.right(90)
grid.forward(40)
grid.right(90)
grid.forward(400)
grid.left(90)
grid.forward(40)
grid.left(90)
grid.forward(400)
grid.right(90)
grid.forward(40)
grid.right(90)
grid.forward(400)
grid.left(90)
grid.forward(40)
grid.left(90)
grid.forward(400)
grid.right(90)
grid.forward(40)
grid.right(90)
grid.forward(400)
grid.left(90)
grid.forward(40)
grid.left(90)
grid.forward(400)
grid.right(90)
grid.forward(40)
grid.right(90)
grid.forward(400)
grid.left(90)
grid.forward(40)
grid.left(90)
grid.forward(400)
grid.right(90)
grid.forward(40)
grid.right(90)
grid.forward(400)
grid.left(90)
grid.forward(40)
grid.left(90)
grid.forward(400)
grid.right(90)
grid.forward(40)
grid.right(90)
grid.forward(400)
grid.left(90)
grid.forward(40)
grid.left(90)
grid.forward(400)
grid.right(90)
grid.forward(40)
grid.right(90)
grid.forward(400)
grid.left(90)
grid.forward(40)
grid.left(90)
grid.forward(400)
grid.right(90)
grid.forward(40)
grid.right(90)
grid.forward(40)
grid.right(90)
grid.forward(600)
grid.left(90)
grid.forward(40)
grid.left(90)
grid.forward(600)
grid.right(90)
grid.forward(40)
grid.right(90)
grid.forward(600)
grid.left(90)
grid.forward(40)
grid.left(90)
grid.forward(600)
grid.right(90)
grid.forward(40)
grid.right(90)
grid.forward(600)
grid.left(90)
grid.forward(40)
grid.left(90)
grid.forward(600)
grid.right(90)
grid.forward(40)
grid.right(90)
grid.forward(600)
grid.left(90)
grid.forward(40)
grid.left(90)
grid.forward(600)
grid.right(90)
grid.forward(40)
grid.right(90)
grid.forward(600)
grid.left(90)
grid.forward(40)
grid.left(90)
grid.forward(600)
# User Input for Speed 
speed = int(input("Enter the speed of the turtles (1-10): "))
# Variable for choosing colors
all_colors =      ["red","white","blue","hotpink","purple","lightgreen","yellow"]
# Creating the turtles
def createTurtles(turtle_count):
    count = []
    for k in range(0, turtle_count):
        lil_guys = turtle.Turtle()
        lil_guys.shape("turtle")
        colors = random.choice(all_colors)
        lil_guys.color(colors)
        lil_guys.speed(speed)
        lil_guys.pendown()
        count.append(lil_guys)
    return count
# Determine where the Turtle should stop
def off_board(self):
    x = self.turtle.xcor()
    y = self.turtle.ycor()
    return x < -160 or 160 < x or y < -160 or 160 < y
# Set Turtle Amount to 5
count = createTurtles(5)
fun = True
while fun:
    for k in range(5):
        coin = random.randrange(0, 2)
        if coin == 0:
            count[k].left(90)
        else:
            count[k].right(90)
        count[k].forward(40)
# Exit on close window
turtle.exitonclick()

一旦五只乌龟之一到达我创建的网格的边缘,该程序应该结束。

在网格边缘退出

当乌龟到达网格边缘时,您可以退出:

while fun:
    for k in range(5):
        coin = random.randrange(0, 2)
        if coin == 0:
            count[k].left(90)
        else:
            count[k].right(90)
        count[k].forward(40)
        x = count[k].xcor()          # new lines
        y = count[k].ycor()          # |
                                     # |
        if x < -300 or 300 < x or   # |
           y < -200 or 200 < y:      # |
            fun = False              # |
            break                    # |

通过将此逻辑放入off_grid函数中,您在正确的轨道上,但是此函数不应将self作为参数(这不是类的实例)。


设计建议

我有一些一般的设计建议(赦免即兴代码评论):

  • 避免全局变量;使用参数将信息传递到函数中。这可以使功能可重复使用和安全。将每个功能视为具有可调旋钮(参数)的黑匣子;如果外部状态不可预测地变化,则该黑匣子应独立工作,而不会打破或工作不同。这减少了错误并使您的程序更容易推理。
  • 使用准确的变量名称。count实际上不是任何事物的count,而是turtle s的列表。有意义的名称使遵循逻辑并避免错误和误解变得更加容易。变量fun可以更清楚为runningfor k in range(0, turtle_count):中的变量k未使用,通常在Python中写成_
  • 优先使用Python中功能名称的snake_caseCamelCase用于类)。
  • 而不是顺序的许多命令行,使用循环绘制网格并保持代码干燥(不要重复自己)。例如:

    for _ in range(0, height + 1, grid_size):
        turtle.pendown()
        turtle.forward(width)
        turtle.penup()
        turtle.right(90)
        turtle.forward(grid_size)
        turtle.right(90)
        turtle.forward(width)
        turtle.right(180)
    
  • 避免硬编码数字和字符串;将所有这些变量放在main程序的顶部,并在整个过程中使用它们。具体来说,在此程序中,您需要heightwidthgrid_size参数,这些参数将在一个位置定义并控制整个程序的操作(包括确定乌龟何时离开网格)。现在,如果我认为我想要30个网格大小,高度为200和400的宽度,我可以在一个地方更改这些数字,一切都可以正常工作。

  • 使用Python的默认参数或字典来减轻过多参数的负担到函数。将功能放在脚本的顶部,并将其与main分开。
  • 评论很好,但是当代码已经很明显时评论通常会添加噪音:

    # Exit on close window
    turtle.exitonclick()
    
  • 牢记用户:我不知道我必须回到终端以在绘制网格后输入乌龟速度。我更喜欢提示用户以乌龟速度,然后运行程序的视觉部分。


可能的重构

将所有内容放在一起,这是一个建议的第一个重构(仍然有很多改进的空间,但这应该为思想提供一些食物):

import turtle
import random
def create_turtles(
    turtle, turtle_count, colors, speed=10, shape="turtle"
):
    turtles = []
    for _ in range(turtle_count):
        tur = turtle.Turtle()
        tur.shape(shape)
        tur.color(random.choice(colors))
        tur.speed(speed)
        tur.pendown()
        turtles.append(tur)
    return turtles
def draw_lines(turtle, turn, length_a, length_b, grid_size):
    for _ in range(0, length_a + 1, grid_size):
        turtle.pendown()
        turtle.forward(length_b)
        turtle.penup()
        turn(90)
        turtle.forward(grid_size)
        turn(90)
        turtle.forward(length_b)
        turn(180)
def draw_grid(
    turtle, width=600, height=400, grid_size=40, 
    speed=100, shape="classic", color="white"
):
    tur = turtle.getturtle()
    tur.shape(shape)
    tur.color(color)
    tur.speed(speed)
    tur.penup()
    tur.setposition(-width // 2, height // 2)
    draw_lines(tur, tur.right, height, width, grid_size)
    tur.setposition(-width // 2, height // 2)
    tur.right(90)
    draw_lines(tur, tur.left, width, height, grid_size)
    turtle.penup()
    turtle.ht()
def off_grid(turtle, width, height):
    x = turtle.xcor()
    y = turtle.ycor()
    return x < -width // 2 or x > width // 2 or 
           y < -height // 2or y > height // 2

if __name__ == "__main__":
    grid_size = 40
    height = 400
    width = 600
    all_colors = [
        "red", "white", "blue", "hotpink", 
        "purple", "lightgreen", "yellow"
    ]
    speed = int(input("Enter the speed of the turtles (1-10): "))
    turtle.setup(800, 600)
    window = turtle.Screen()
    window.title("Turtles Walking through Grid")
    window.bgcolor("black")
    draw_grid(turtle, width, height, grid_size)
    turtles = create_turtles(turtle, 5, all_colors, speed)
    running = True
    while running:
        for tur in turtles:
            random.choice([tur.left, tur.right])(90)
            tur.forward(grid_size)
            if off_grid(tur, width, height):
                running = False
                break
    turtle.exitonclick()

我不会复制 @ggorlen的所有优秀建议( 1),而是指出其他一些问题:

  • 您的海龟在上 在一个维度上的网格线,然后在另一个维>之间行走在另一个维度上的网格线。在下面的我的返工中,他们在网格线上行走。这需要基于您为网格选择的(均等)大小的(均等)进行计算。

  • 在我的返工中,当乌龟到达网格的边缘时,运动就会停止,这更清晰,因为它们在网格线上行走

  • 如果要使笔和白色的网格线条放下,请避免使用"白色"作为乌龟颜色!同上为"黑色"作为乌龟颜色。

  • 如果/何时可以,请避免使用户在程序外进入输入参数。正如@Ggorlen所指出的那样,在调用乌龟之前进行input()有帮助。但是在我的返工中,我已经使用了python 3中的numinput(),将其全部保存在GUI中。

  • 有很多算法可以用乌龟绘制网格,挑选一个算法!

重新设计的代码:

from turtle import Screen, Turtle
from random import choice
TURTLE_COUNT = 5
# Variable for choosing colors
ALL_COLORS = ['red', 'green', 'blue', 'magenta', 'yellow', 'cyan', 'purple']
WINDOW_WIDTH, WINDOW_HEIGHT = 800, 600
GRID_WIDTH, GRID_HEIGHT = 600, 400
CELL_SIZE = 40  # should be a divisor of GRID_WIDTH and GRID_HEIGHT, and probably no smaller than CURSOR_SIZE
CURSOR_SIZE = 20
# Creating the turtles
def create_turtles(turtle_count, speed):
    turtles = []
    for index in range(turtle_count):
        lil_guy = Turtle('turtle')
        lil_guy.color(ALL_COLORS[index % TURTLE_COUNT])
        lil_guy.speed(speed)
        lil_guy.penup()
        # to place a turtle cleanly on the grid lines, we have to consider the parity of the grid size
        lil_guy.goto((GRID_WIDTH / CELL_SIZE % 2) * CELL_SIZE/2, (GRID_HEIGHT / CELL_SIZE % 2) * CELL_SIZE/2)
        lil_guy.pendown()
        turtles.append(lil_guy)
    return turtles
# Determine where the Turtle should stop
def on_edge(turtle):
    x, y = turtle.position()
    return abs(x) >= (GRID_WIDTH/2 - CELL_SIZE/2) or abs(y) >= (GRID_HEIGHT/2 - CELL_SIZE/2)
# Setting up Turtle Graphics Window
window = Screen()
window.setup(WINDOW_WIDTH, WINDOW_HEIGHT)
window.title("Turtles Walking through Grid")
window.bgcolor('black')
# Create the grid via stamping
grid = Turtle(visible=False)
grid.speed('fastest')
grid.color('white')
grid.penup()
grid.setx(-GRID_WIDTH/2)
grid.shapesize(GRID_HEIGHT*2 / CURSOR_SIZE, 1/CURSOR_SIZE)
for _ in range(GRID_WIDTH // CELL_SIZE + 1):
    grid.stamp()
    grid.forward(CELL_SIZE)
grid.setheading(90)
grid.setposition(0, -GRID_HEIGHT/2)
grid.shapesize(GRID_WIDTH*2 / CURSOR_SIZE, 1/CURSOR_SIZE)
for _ in range(GRID_HEIGHT // CELL_SIZE + 1):
    grid.stamp()
    grid.forward(CELL_SIZE)
# User Input for Speed
user_speed = window.numinput("Turtle Speed", "Enter a value (1-10)", default=5, minval=1, maxval=10)
# Set Turtle Amount
turtles = create_turtles(TURTLE_COUNT, user_speed)
finished = False
while not finished:
    for k in range(5):
        angle = choice([90, -90])
        turtles[k].left(angle)
        turtles[k].forward(CELL_SIZE)
        finished = on_edge(turtles[k])
        if finished:
            break
# Exit on close window
window.exitonclick()

最新更新