【问题标题】:Managing when Python turtle checks for events管理 Python turtle 何时检查事件
【发布时间】:2018-06-19 23:40:19
【问题描述】:

我正在使用 Python 海龟图形创建一个 Connect 4 游戏。出现的主要问题是,当您使用onkeyonclick 之类的事件时,会立即检查它们,然后是其余代码。有没有办法暂停代码,直到事件发生,然后继续,循环后,等待另一个事件发生?

在下面的代码中,游戏设置完毕,然后运行play() 函数。在play() 函数中,程序侦听onkey() 事件,这些事件允许用户更改它在哪一列结束,并在准备好时放下该片段。然后,它开始在水平、垂直或对角线上连续检查 4 个。它会产生一个错误,因为列列表是空的,直到我按下向下键将一块放入棋盘的一列并将该块附加到该列。我可以创建已经用None'' 或零填充的列,但随后我将不得不更改我的 drop 函数的工作方式,因为它当前基于它被丢弃的位置的 y 值与项目数无关在列表中。有没有办法在每件掉落后只运行一次检查功能?

附:我对编码比较陌生,这是我第一次使用这个网站。我已复制并粘贴以下代码:

import turtle
class Connect4:
  "A connect 4 game"
  def __init__(self):
    self.pen = turtle.Turtle()
    self.scr = turtle.Screen()
    self.board = Connect4Board(self.pen, self.scr)
    self.moves = 0
    self.playing = True
    self.piece = Connect4Piece(self.scr, self.board, self)

    self.setup()
    self.play()

  def setup(self):
    self.board.draw_board()

  def play(self):
    if self.moves == self.board.rows*self.board.columns:
      game_over()
    self.piece.st()
    self.piece.goto(0, self.board.board_height/2)
    while True:

      self.scr.onkey(self.piece.prev_col, 'Left')
      self.scr.onkey(self.piece.next_col, 'Right')
      self.scr.onkey(self.piece.drop, 'Down')
      self.scr.onkey(self.reset, 'r')
      self.scr.listen()
      self.check()

  "Check if there is 4 pieces in a line horizontally, vertically or diagonally"
  def check(self):
    self.check_horizontal()
    self.check_vertical()
    self.check_diagonal()

  def check_horizontal(self):
    print("Checking horizontally")
    for rows in range(self.board.rows):
      for columns in range(self.board.columns - 3):
        if self.board.squares[columns][rows] == 0:
          continue
        elif (self.board.squares[columns][rows] == self.board.squares[columns+1][rows] == self.board.squares[columns+2][rows] == self.board.squares[columns+3][rows]):
          print(self.board.squares[columns][rows].color())
          if self.board.squares[columns][rows].color() == ('red','red'):
            print("Red wins!")
          if self.board.squares[columns][rows].color() == ('black','black'):
            print("Black wins!")

  def check_vertical(self):
    print("Checking vertically")

  def check_diagonal(self):
    print("Checking diagonally")

  def reset(self):

    self.board.reset()
    self.piece.clear()

    self.moves = 0
    self.play()

  def game_over(self):
    self.pen.pu()
    self.pen.goto(0, board_height/2 + 20)
    self.pen.pd()
    self.pen.write("Black wins!", align='center', font = ('Arial', 24, 'normal'))
    self.pen.pu()
    to.goto(0, board_height/2 + 10)
    self.pen.write("Play Again?", align='center', font = ('Arial', 24, 'normal'))
    self.playing = False

class Connect4Board:
  def __init__(self, pen, screen):
      #Used to create the board
    self.square_size = 60
    self.rows = 6
    self.columns = 7
    self.pen = pen
    self.frame_color = 'blue'
    self.board_length = self.square_size*self.columns
    self.board_height = self.square_size*self.rows
    self.squares = [[] for cols in range(self.columns)] 
    """for cols in range(self.columns):
      empty = []
      self.squares.append(empty)"""

    self.pen.speed(0)
    self.pen.ht()

  def _draw_square(self, x, y):
    self.pen.pu()
    self.pen.goto(x-self.square_size/2, y-self.square_size/2)
    self.pen.pd()
    self.pen.fillcolor(self.frame_color)
    self.pen.begin_fill()
    for sides in range(4):
      self.pen.fd(self.square_size)
      self.pen.left(90)
    self.pen.end_fill()

  def _draw_circle(self, x, y):
    self.pen.pu()
    self.pen.goto(x, y)
    self.pen.pd()
    self.pen.fillcolor('white')
    self.pen.begin_fill()
    self.pen.circle(self.square_size/2)
    self.pen.end_fill()

  def draw_board(self):
    for row in range(self.rows):
      for col in range(self.columns):
        x = col*self.square_size - self.board_length/2 + self.square_size/2
        y = row*self.square_size - self.board_length/2
        self._draw_square(x, y)
        self._draw_circle(x, y - self.square_size/2)

  def reset(self):
    self.squares = []
    for cols in range(self.columns):
      empty = []
      self.squares.append(empty)

class Connect4Piece(turtle.Turtle):

  def __init__(self, screen, board, game):
    turtle.Turtle.__init__(self, screen)
    self.board = board
    self.speed(0)
    self.pu()
    self.shape('turtle')
    self.cnum = 3
    self.game = game
    self.ht()

  "Moves the piece to the left and updates it's column number"
  def prev_col(self):
    if self.xcor() - self.board.square_size > -self.board.board_length/2:
      self.setx(self.xcor() - self.board.square_size)
      self.cnum -= 1

  "Moves the piece to the right and updates it's column number"
  def next_col(self):
    if self.xcor() + self.board.square_size < self.board.board_length/2:
      self.setx(self.xcor() + self.board.square_size)
      self.cnum += 1

  def drop(self):
    "Make sure the column isn't full. If it's not then move the turtle to the next available space in the row."
    if len(self.board.squares[self.cnum]) != self.board.rows:
      self.sety(len(self.board.squares[self.cnum])              *self.board.square_size - self.board.board_height/2 - self.board.square_size/2 )

      "Stamp an image of the turtle to represent placing a piece"
      self.stamp()
      self.board.squares[self.cnum].append(self.color())

      "Move the piece back above the middle column and set it's column back to 3"
      self.goto(0, self.board.board_height/2)
      self.cnum = 3

      "Change the piece's color"
      if self.color() == ('red','red'):
        self.color('black')
      else:
        self.color('red')

      self.game.moves += 1
      print(self.game.moves, "moves")

game = Connect4()

【问题讨论】:

  • 请尝试做一个最小的例子,例如如果您要询问对事件的反应,请制作一个仅执行此操作的应用程序 - 如果这是重现问题的最低限度,则仅对一个事件或两个事件做出反应。然后问这个问题,这可能已经简单得多了。见How to create a Minimal, Complete, and Verifiable example

标签: python event-handling turtle-graphics


【解决方案1】:

你的程序结构不正确,正如这个循环的缩影:

while True:

  self.scr.onkey(self.piece.prev_col, 'Left')
  self.scr.onkey(self.piece.next_col, 'Right')
  self.scr.onkey(self.piece.drop, 'Down')
  self.scr.onkey(self.reset, 'r')
  self.scr.listen()
  self.check()

首先,while True: 在像turtle 这样的事件驱动环境中没有位置。其次,这些onkey 调用只需要在初始化期间执行一次——它们在运行时不执行任何操作。 (同上listen()

我已将您的以下代码重组为基于事件的。您需要添加(返回)检查代码以确定是否有获胜者:

from turtle import Turtle, Screen

class Connect4:
    "A connect 4 game"

    def __init__(self, screen):
        self.pen = Turtle()
        self.scr = screen
        self.board = Connect4Board(self.pen)
        self.moves = 0
        self.playing = False
        self.piece = Connect4Piece(self.board, self)

        self.scr.tracer(False)
        self.board.draw_board()
        self.scr.tracer(True)

        self.scr.onkey(self.piece.prev_col, 'Left')
        self.scr.onkey(self.piece.next_col, 'Right')
        self.scr.onkey(self.piece.drop, 'Down')
        self.scr.onkey(self.reset, 'r')

        self.scr.listen()

    def play(self):

        self.piece.showturtle()
        self.piece.goto(0, self.board.board_height/2)
        self.playing = True

    def check(self):
        "Check if there are 4 pieces in a line horizontally, vertically or diagonally"

        if self.moves == self.board.rows * self.board.columns:
            self.game_over()

        if self.check_horizontal():
            self.game_over()

        if self.check_vertical():
            self.game_over()

        if self.check_diagonal():
            self.game_over()

    def check_horizontal(self):
        print("Checking horizontally")

        # implement this correctly

        return False

    def check_vertical(self):
        print("Checking vertically")

        # implement this

        return False

    def check_diagonal(self):
        print("Checking diagonally")

        # implement this

        return False

    def reset(self):

        self.playing = False

        self.board.reset()
        self.piece.clear()

        self.moves = 0
        self.play()

    def game_over(self):
        self.playing = False
        self.pen.penup()
        self.pen.goto(0, self.board.board_height/2 + 20)
        self.pen.pendown()
        self.pen.write("Black wins!", align='center', font=('Arial', 24, 'normal'))
        self.pen.penup()
        self.pen.goto(0, self.board.board_height/2 + 10)
        self.pen.write("Play Again?", align='center', font=('Arial', 24, 'normal'))

class Connect4Board:
    def __init__(self, pen):
        # Used to create the board
        self.square_size = 60
        self.rows = 6
        self.columns = 7
        self.pen = pen
        self.frame_color = 'blue'
        self.board_length = self.square_size * self.columns
        self.board_height = self.square_size * self.rows
        self.squares = [[] for _ in range(self.columns)]

        self.pen.speed('fastest')
        self.pen.hideturtle()

    def _draw_square(self, x, y):
        self.pen.penup()
        self.pen.goto(x - self.square_size/2, y - self.square_size/2)
        self.pen.pendown()
        self.pen.fillcolor(self.frame_color)

        self.pen.begin_fill()
        for _ in range(4):
            self.pen.forward(self.square_size)
            self.pen.left(90)
        self.pen.end_fill()

    def _draw_circle(self, x, y):
        self.pen.penup()
        self.pen.goto(x, y)
        self.pen.pendown()
        self.pen.fillcolor('white')

        self.pen.begin_fill()
        self.pen.circle(self.square_size/2)
        self.pen.end_fill()

    def draw_board(self):
        for row in range(self.rows):
            for col in range(self.columns):
                x = col * self.square_size - self.board_length/2 + self.square_size/2
                y = row * self.square_size - self.board_length/2
                self._draw_square(x, y)
                self._draw_circle(x, y - self.square_size/2)

    def reset(self):
        self.squares = [[] for _ in range(self.columns)]

class Connect4Piece(Turtle):

    def __init__(self, board, game):
        super().__init__(shape='turtle', visible=False)
        self.board = board
        self.game = game
        self.speed('fastest')
        self.penup()
        self.cnum = 3

    def prev_col(self):
        "Moves the piece to the left and updates it's column number"

        if self.xcor() - self.board.square_size > -self.board.board_length/2:
            self.setx(self.xcor() - self.board.square_size)
            self.cnum -= 1

    def next_col(self):
        "Moves the piece to the right and updates it's column number"

        if self.xcor() + self.board.square_size < self.board.board_length/2:
            self.setx(self.xcor() + self.board.square_size)
            self.cnum += 1

    def drop(self):
        "Make sure the column isn't full. If it's not then move the turtle to the next available space in the row."

        if len(self.board.squares[self.cnum]) != self.board.rows:
            self.sety(len(self.board.squares[self.cnum]) * self.board.square_size - self.board.board_height/2 - self.board.square_size/2)

            # Stamp an image of the turtle to represent placing a piece
            self.stamp()
            self.board.squares[self.cnum].append(self.color())

            # Move the piece back above the middle column and set it's column back to 3
            self.goto(0, self.board.board_height/2)
            self.cnum = 3

            # Change the piece's color
            self.color('black' if self.pencolor() == 'red' else 'red')

            self.game.moves += 1
            print(self.game.moves, "moves")

            self.game.check()

screen = Screen()

game = Connect4(screen)
game.play()

screen.mainloop()

图形表现如预期,但当您放下海龟时,您会看到存根检查函数被调用并且播放器切换。

另外,请阅读有关 Python cmets 与文档字符串的信息——您将它们混为一谈。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多