5

Whenever I try and run my program, it draws the two turtles and then the window stops responding.

What I was expecting is that, until one of the pieces touches the other one based on me dragging it close to the other one, I will be able to drag both of them by themselves. What's happening though is that whenever I run the program, after drawing both of the turtles, the window stops responding. I don't get any errors, it just closes after freezing until I click the close button. I've looked at other people's post where they had this problem but they haven't had screen.mainloop() at the end and I do.

import turtle

captured_pieces = []

blue = turtle.Turtle()
black = turtle.Turtle()
screen = turtle.Screen()

blue.penup()
black.penup()

blue.shape('square')
black.shape('triangle')

blue.setpos(100,100)
black.setpos(-100,-100)

blue.color('blue')
black.color('black')

def bmove():
    black.ondrag(black.goto)
    if black.distance(blue) < 30:
            captured_pieces.append("BlC")
            print(captured_pieces)
            check()

def blmove():
    blue.ondrag(blue.goto)
    if blue.distance(black) < 30:
            captured_pieces.append("BC")
            print(captured_pieces)
            check()

def check():
      if "BlC" in captured_pieces:
            print("blue captured")

def check():
      if "BC" in captured_pieces:
            print("black captured")

while "BlC" not in captured_pieces and "BC" not in captured_pieces:
      bmove()
      blmove()

screen.mainloop()
  • When will your `while` loop end? – ggorlen Apr 30 '23 at 23:57
  • @ggorlen whenever blue or black gets "captured". I should've added ` else: print("winner") ` to the end after the while loop – PlebSlayer55 May 01 '23 at 00:00
  • I suggest adding a counter to the loop and a break after a fixed number of iterations to have an easier time debugging – Caridorc May 01 '23 at 00:07
  • @Caridorc that seemed to fix the "stopped responding" problem but now none of them will capture each other – PlebSlayer55 May 01 '23 at 00:12
  • Can you drag the turtles at all? – Caridorc May 01 '23 at 00:13
  • You're defining the function `check()` twice. The second definition overwrites the first one... – John Gordon May 01 '23 at 00:14
  • @PlebSlayer55 The loop just keeps slamming more and more `ondrag` calls and never gives the turtle loop a chance to do anything though. `screen.mainloop()` isn't reached. – ggorlen May 01 '23 at 00:18
  • @JohnGordon yeah realized that and fixed it. Caridorc yeah I can but there is no output (none are registering as captured), even after doing what JohnGordon suggested – PlebSlayer55 May 01 '23 at 00:19
  • I think the simplest thing is using this code; https://www.geeksforgeeks.org/turtle-ondrag-function-in-python/ and generalizing it to two turltles – Caridorc May 01 '23 at 00:21
  • @ggorlen I'm decently new to coding, why does it not reaching screen.mainloop matter? from my understanding, (keep in mind not the best understanding), doesn't screen.mainloop just mean the window stays open? – PlebSlayer55 May 01 '23 at 00:22
  • @PlebSlayer55 It technically doesn't since you're using the native turtle event loop, but without some sort of turtle action in the loop that yields to the turtle repaint it becomes an infinite loop. Adding event handlers doesn't run the turtle loop. But I'd probably disable the turtle loop anyway since it seems you want to make a real time application, and the builtin loop has delay on movements. What's sort of app are you making here? – ggorlen May 01 '23 at 00:23
  • @ggorlen My project is making chess, (pretty difficult for my experience), and this is just a very simplified version of the code I'd be using to capture the chess pieces. Even after adding a counter to make it a non-infinite loop, it just makes my capturing code not work – PlebSlayer55 May 01 '23 at 00:25
  • @Caridorc using the geeksforgeeks thing, it creates an error saying that I need an x and y value, and in their code, it doesn't show them having an x or y value. The error specifically being: **bmove() missing 2 required positional arguments: 'x' and 'y'** – PlebSlayer55 May 01 '23 at 00:32

1 Answers1

1

The while loop does two things over and over: add drag handlers, and check distance. The loop doesn't call any turtle methods that cause turtle's rendering/event loop to run (for example, .forward() or .goto()), so the distance checks can't be true to break the loop. We want to get to mainloop() to enable user interaction, but we can't get there unless user interaction is allowed--we're stuck.

Avoid the loop (you generally don't want to use while in a real-time turtle program) and check for collisions inside the drag handlers rather than in the loop, then let mainloop() run the turtle rendering loop.

This reveals a new problem: the internal loop's "gliding" speed causes dragging to be very glitchy. You can use tracer(0) to disable the internal loop and turtle.update() to manually trigger repaints when you need them, eliminating any gliding behavior and giving you full control of rerenders.

Here's a simple example:

import turtle


turtle.tracer(0)
blue = turtle.Turtle()
black = turtle.Turtle()
screen = turtle.Screen()
blue.penup()
black.penup()
blue.shape("square")
black.shape("triangle")
blue.setpos(100, 100)
black.setpos(-100, -100)
blue.color("blue")
black.color("black")


def handle_drag(piece, other, x, y):
    piece.goto(x, y)
    turtle.update()

    if piece.distance(other) < 30:
        print("capture:", piece.color()[0], other.color()[0])


black.ondrag(lambda x, y: handle_drag(black, blue, x, y))
blue.ondrag(lambda x, y: handle_drag(blue, black, x, y))
turtle.update()
screen.mainloop()

Before long, you'll likely need custom classes (like a Piece class, which might be subclassed by various types of pieces with different characteristics) and data structures. The approach above with separate variables isn't scalable. But I'll leave it as is for now in the interest of keeping it scoped to your immediate problem.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
  • That seemed to work, how would I possibly add, lets say red, to the mix, I took your thing and added a new turtle called red, made it a circle, startpos = (100,50), but I cant figure out how to make it so that red can capture both blue and black and vice versa – PlebSlayer55 May 01 '23 at 00:49
  • As I hinted at the end of the post, you will want to use a data structure, like a list of pieces. When a drag occurs for a piece, loop over the list and find any piece that isn't the same as the dragged piece and test whether they're colliding. Designing chess is non-trivial--you'll need to be able to drop pieces in a grid and implement movement rules. I'd start with [hexapawn](https://en.wikipedia.org/wiki/Hexapawn) first, but even that will not be simple. – ggorlen May 01 '23 at 00:50
  • I edited this code to make it work for what I wanna do. Thank you SO SO SO much! – PlebSlayer55 May 01 '23 at 02:21