2

I'm in the process of creating a minesweeper style game using a turtle-based grid setup. I need to find the closest cell within the grid and reveal the icon located under it whether that be a bomb or a number icons. I'm not looking to make it exact, I just need the mouse click to find the nearest cell in the grid even if the click isn't directly on the board. Currently my code only reveals the icon of the last turtle created on the board and then does nothing else with further clicks.

What can I do to make it recognize the real closest click and do it multiple times until the last bomb is found?

import random
import turtle
import cell

class Game:

def __init__(self, size):

    registershapes()
    self.__boardsize = size
    self.__boardlist = []
    self.__bombnum = 0
    self.__probe = 0
    self.__probelist = []
    offset = (size-1) * 17
    for x in range(size):
        for y in range(size):
            t = cell.Cell(x,y)
            t.up()
            t.shape('question.gif')
            t.goto(y*34-offset, offset-x*34)
            self.__boardlist.append(t)
def hideMines(self, num):
    if num > self.__boardsize ** 2:
        return False
    self.__bombnum = num
    self.__rnums = []
    i = 0
    while i < self.__bombnum:
        currentnum = random.randrange(0, (self.__boardsize**2) - 1)
        if currentnum not in self.__rnums:
            self.__rnums.append(currentnum)
            i += 1
    return True

def probe(self, x, y):
    for t in self.__boardlist:
        pos = t.position()
        distx = abs(x - pos[0])
        disty = abs(y - pos[1])
        distfinal = (distx ** 2 + disty ** 2) ** 0.5
        curdist = 0
        if curdist < distfinal:
            curdist = distfinal
            closest = t
    if closest in self.__probelist:
        return (self.__probe, self.__bombnum)
    elif closest in self.__rnums:
        closest.shape("bomb.gif")
        self.__bombnum -= 1
        self.__probe += 1
        self.__probelist.append(closest)
        return (self.__probe, self.__bombnum)

    else:
        closest.shape("0.gif")
        self.__probe += 1
        self.__probelist.append(closest)
        return (self.__probe, self.__bombnum)


def registershapes():
    wn = turtle.Screen()
    wn.register_shape('0.gif')
    wn.register_shape('1.gif')
    wn.register_shape('2.gif')
    wn.register_shape('3.gif')
    wn.register_shape('4.gif')
    wn.register_shape('5.gif')
    wn.register_shape('6.gif')
    wn.register_shape('7.gif')
    wn.register_shape('8.gif')
    wn.register_shape('9.gif')
    wn.register_shape('bomb.gif')
    wn.register_shape('question.gif')
ggorlen
  • 44,755
  • 7
  • 76
  • 106
ruen125
  • 35
  • 4
  • Although there turned out to be a better solution for this particular problem (`onclick`), future visitors may wish to see [this answer](https://stackoverflow.com/questions/57348137/how-to-see-if-a-mouse-click-is-on-a-turtle-in-python/73819453#73819453) for a simple distance test for turtles near a click. – ggorlen Sep 22 '22 at 19:12

1 Answers1

0

I believe you're approaching this problem the wrong way. You're activating screen.onclick() and trying to map it to a turtle. Instead, activate turtle.onclick() on the individual turtles, deactivating it when a turtle is selected. Then you don't have to search for the turtle in question, and not actively ignore turtles that have already been selected.

Below is my rework of your code from this and your previous question into an example you can run. I had to guess about the definition of the Cell class:

from turtle import Turtle, Screen
import random

class Cell(Turtle):

    def __init__(self, number):
        super().__init__("question.gif")
        self.__number = number
        self.penup()

    def number(self):
        return self.__number

class Game:

    def __init__(self, size):
        registershapes()
        self.__boardsize = size
        self.__boardlist = []
        self.__bombnum = 0
        self.__probe = 0
        self.__rnums = None

        offset = (size - 1) * 17

        for y in range(size):
            for x in range(size):
                t = Cell(x + y * size)
                t.goto(x * 34 - offset, offset - y * 34)
                t.onclick(lambda x, y, self=t: closure(self))
                self.__boardlist.append(t)

    def hideMines(self, num):
        if num > self.__boardsize ** 2:
            return False

        self.__bombnum = num
        self.__rnums = []
        i = 0

        while i < self.__bombnum:
            currentnum = random.randrange(0, self.__boardsize ** 2 - 1)

            if currentnum not in self.__rnums:
                self.__rnums.append(currentnum)
                i += 1
        return True

    def probe(self, closest):
        closest.onclick(None)

        if closest.number() in self.__rnums:
            closest.shape("bomb.gif")
            self.__bombnum -= 1
        else:
            closest.shape("0.gif")

        self.__probe += 1
        return (self.__probe, self.__bombnum)

def registershapes():
    screen.register_shape('0.gif')
    # ...
    screen.register_shape('bomb.gif')
    screen.register_shape('question.gif')

def closure(closest):
    _, rem = mine.probe(closest)

    if rem == 0:

        over = screen.textinput("Text Input", "Would you like to play again? (Y)es or (N)o")

        if over.upper() == 'Y':
            main()
        else:
            screen.bye()

def main():
    global mine

    board = screen.numinput("Numeric Input", "Enter desired board size: ")
    mine = Game(int(board))

    nummine = screen.numinput("Numeric Input", "Enter desired number of mines: ")
    mine.hideMines(int(nummine))

screen = Screen()

mine = None
main()

screen.mainloop()

enter image description here

cdlane
  • 40,441
  • 5
  • 32
  • 81