Python OOP Whac-A-Mole program using turtle

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
8
down vote

favorite
2












I am trying to create an object oriented program in Python for a whac-a-mole program.



I want to keep this simple where there are just a hammer and a mole and when the hammer turtle makes contact with the mole turtle.



I have created 4 classes, one for Game which is the super class, one for sprite which inherits from Turtle and one each for hammer and mole which both inherit from Sprite.



What I am asking is how to instantiate the mole and hammer turtles I have made use of inheritance but want to minimize the amount of methods I am using:



import random
import turtle
wn=turtle.Screen()
wn.addshape("moleSmall.gif")
wn.addshape("Mole.gif")
wn.addshape("Hammer.gif")
turtle.setup(800, 600)

class Game():
def __init__(self):
self.score=0
self.pointsDisplay=Points()

def update_score(self,x,y):
self.score = self.score + 2
print("Score:", self.score)
self.callDisplayScore()
def decrease_score(self,x,y):
self.score = self.score -1
print("Score: ", self.score)
self.callDisplayScore()
def callDisplayScore(self):
score = self.score
class Sprite(turtle.Turtle):
def __init__(self):
turtle.Turtle.__init__(self)
self.x=0
self.y=0
crash =False
self.crash=crash
def randomMove(self):
leftbound = -self.wn.window_width()/2
rightbound = self.wn.window_width()/2
topbound = self.wn.window_height()/2
bottombound = -self.wn.window_height()/2
rand_x = random.randint(leftbound , rightbound)
rand_y = random.randint(bottombound, topbound)
self.mole.setpos(rand_x,rand_y)
def collisionCheck(self,turtle1, turtle2):
self.crash = False
turtle1X = turtle1.xcor()
turtle1Y = turtle1.ycor()
turtle2X = turtle2.xcor()
turtle2Y = turtle2.ycor()
turtle1Pos = (int(turtle1X), int(turtle1Y))
turtle2Pos = (int(turtle2X), int(turtle2Y))
if turtle1Pos == turtle2Pos or turtle1X < turtle2X - 50 and
turtle1Y > turtle2Y - 50 and turtle1X < turtle2X - 50 and
turtle1Y > turtle2Y + 50:
self.crash = True
return self.crash
class Mole(Sprite):
def __init__(self):
Sprite.__init__(self)
self.mole.pu()
self.mole.shape("moleSmall.gif")
self.x= self.mole.xcor()
self.y = self.mole.ycor()
self.randomMove()
class Hammer(Sprite):
def __init__(self):
Sprite.__init__(self)
self.counter = 0
self.hammer.penup()
self.hammer.shape("Hammer.gif")
self.hammer.penup()
leftbound = -self.wn.window_width()/2
rightbound = self.wn.window_width()/2
topbound = self.wn.window_height()/2
bottombound = -self.wn.window_height()/2
rand_x = random.randint(leftbound , rightbound)
rand_y = random.randint(bottombound, topbound)
self.hammer.setpos(rand_x,rand_y)
def HammerMove(self):
self.hammer.pu()
self.hammer.clear()
self.wn.onscreenclick(self.hammer.goto)
while self.collisionCheck(self.mole, self.hammer) == False:
self.randomMove()
if self.collisionCheck(self.mole, self.hammer) == True:
self.score = self.score + 1
print(self.score)






share|improve this question





















  • Maybe using from module import * to prevent clutter from the turtle.Screen() and turtle.setup()
    – VortexYT
    Jan 6 at 12:04







  • 2




    @VortexYT wildcard imports should be avoided! You can alias the import, i.e. import turtle as tl if you really want to save on typing.
    – Daniel
    Jan 6 at 12:10

















up vote
8
down vote

favorite
2












I am trying to create an object oriented program in Python for a whac-a-mole program.



I want to keep this simple where there are just a hammer and a mole and when the hammer turtle makes contact with the mole turtle.



I have created 4 classes, one for Game which is the super class, one for sprite which inherits from Turtle and one each for hammer and mole which both inherit from Sprite.



What I am asking is how to instantiate the mole and hammer turtles I have made use of inheritance but want to minimize the amount of methods I am using:



import random
import turtle
wn=turtle.Screen()
wn.addshape("moleSmall.gif")
wn.addshape("Mole.gif")
wn.addshape("Hammer.gif")
turtle.setup(800, 600)

class Game():
def __init__(self):
self.score=0
self.pointsDisplay=Points()

def update_score(self,x,y):
self.score = self.score + 2
print("Score:", self.score)
self.callDisplayScore()
def decrease_score(self,x,y):
self.score = self.score -1
print("Score: ", self.score)
self.callDisplayScore()
def callDisplayScore(self):
score = self.score
class Sprite(turtle.Turtle):
def __init__(self):
turtle.Turtle.__init__(self)
self.x=0
self.y=0
crash =False
self.crash=crash
def randomMove(self):
leftbound = -self.wn.window_width()/2
rightbound = self.wn.window_width()/2
topbound = self.wn.window_height()/2
bottombound = -self.wn.window_height()/2
rand_x = random.randint(leftbound , rightbound)
rand_y = random.randint(bottombound, topbound)
self.mole.setpos(rand_x,rand_y)
def collisionCheck(self,turtle1, turtle2):
self.crash = False
turtle1X = turtle1.xcor()
turtle1Y = turtle1.ycor()
turtle2X = turtle2.xcor()
turtle2Y = turtle2.ycor()
turtle1Pos = (int(turtle1X), int(turtle1Y))
turtle2Pos = (int(turtle2X), int(turtle2Y))
if turtle1Pos == turtle2Pos or turtle1X < turtle2X - 50 and
turtle1Y > turtle2Y - 50 and turtle1X < turtle2X - 50 and
turtle1Y > turtle2Y + 50:
self.crash = True
return self.crash
class Mole(Sprite):
def __init__(self):
Sprite.__init__(self)
self.mole.pu()
self.mole.shape("moleSmall.gif")
self.x= self.mole.xcor()
self.y = self.mole.ycor()
self.randomMove()
class Hammer(Sprite):
def __init__(self):
Sprite.__init__(self)
self.counter = 0
self.hammer.penup()
self.hammer.shape("Hammer.gif")
self.hammer.penup()
leftbound = -self.wn.window_width()/2
rightbound = self.wn.window_width()/2
topbound = self.wn.window_height()/2
bottombound = -self.wn.window_height()/2
rand_x = random.randint(leftbound , rightbound)
rand_y = random.randint(bottombound, topbound)
self.hammer.setpos(rand_x,rand_y)
def HammerMove(self):
self.hammer.pu()
self.hammer.clear()
self.wn.onscreenclick(self.hammer.goto)
while self.collisionCheck(self.mole, self.hammer) == False:
self.randomMove()
if self.collisionCheck(self.mole, self.hammer) == True:
self.score = self.score + 1
print(self.score)






share|improve this question





















  • Maybe using from module import * to prevent clutter from the turtle.Screen() and turtle.setup()
    – VortexYT
    Jan 6 at 12:04







  • 2




    @VortexYT wildcard imports should be avoided! You can alias the import, i.e. import turtle as tl if you really want to save on typing.
    – Daniel
    Jan 6 at 12:10













up vote
8
down vote

favorite
2









up vote
8
down vote

favorite
2






2





I am trying to create an object oriented program in Python for a whac-a-mole program.



I want to keep this simple where there are just a hammer and a mole and when the hammer turtle makes contact with the mole turtle.



I have created 4 classes, one for Game which is the super class, one for sprite which inherits from Turtle and one each for hammer and mole which both inherit from Sprite.



What I am asking is how to instantiate the mole and hammer turtles I have made use of inheritance but want to minimize the amount of methods I am using:



import random
import turtle
wn=turtle.Screen()
wn.addshape("moleSmall.gif")
wn.addshape("Mole.gif")
wn.addshape("Hammer.gif")
turtle.setup(800, 600)

class Game():
def __init__(self):
self.score=0
self.pointsDisplay=Points()

def update_score(self,x,y):
self.score = self.score + 2
print("Score:", self.score)
self.callDisplayScore()
def decrease_score(self,x,y):
self.score = self.score -1
print("Score: ", self.score)
self.callDisplayScore()
def callDisplayScore(self):
score = self.score
class Sprite(turtle.Turtle):
def __init__(self):
turtle.Turtle.__init__(self)
self.x=0
self.y=0
crash =False
self.crash=crash
def randomMove(self):
leftbound = -self.wn.window_width()/2
rightbound = self.wn.window_width()/2
topbound = self.wn.window_height()/2
bottombound = -self.wn.window_height()/2
rand_x = random.randint(leftbound , rightbound)
rand_y = random.randint(bottombound, topbound)
self.mole.setpos(rand_x,rand_y)
def collisionCheck(self,turtle1, turtle2):
self.crash = False
turtle1X = turtle1.xcor()
turtle1Y = turtle1.ycor()
turtle2X = turtle2.xcor()
turtle2Y = turtle2.ycor()
turtle1Pos = (int(turtle1X), int(turtle1Y))
turtle2Pos = (int(turtle2X), int(turtle2Y))
if turtle1Pos == turtle2Pos or turtle1X < turtle2X - 50 and
turtle1Y > turtle2Y - 50 and turtle1X < turtle2X - 50 and
turtle1Y > turtle2Y + 50:
self.crash = True
return self.crash
class Mole(Sprite):
def __init__(self):
Sprite.__init__(self)
self.mole.pu()
self.mole.shape("moleSmall.gif")
self.x= self.mole.xcor()
self.y = self.mole.ycor()
self.randomMove()
class Hammer(Sprite):
def __init__(self):
Sprite.__init__(self)
self.counter = 0
self.hammer.penup()
self.hammer.shape("Hammer.gif")
self.hammer.penup()
leftbound = -self.wn.window_width()/2
rightbound = self.wn.window_width()/2
topbound = self.wn.window_height()/2
bottombound = -self.wn.window_height()/2
rand_x = random.randint(leftbound , rightbound)
rand_y = random.randint(bottombound, topbound)
self.hammer.setpos(rand_x,rand_y)
def HammerMove(self):
self.hammer.pu()
self.hammer.clear()
self.wn.onscreenclick(self.hammer.goto)
while self.collisionCheck(self.mole, self.hammer) == False:
self.randomMove()
if self.collisionCheck(self.mole, self.hammer) == True:
self.score = self.score + 1
print(self.score)






share|improve this question













I am trying to create an object oriented program in Python for a whac-a-mole program.



I want to keep this simple where there are just a hammer and a mole and when the hammer turtle makes contact with the mole turtle.



I have created 4 classes, one for Game which is the super class, one for sprite which inherits from Turtle and one each for hammer and mole which both inherit from Sprite.



What I am asking is how to instantiate the mole and hammer turtles I have made use of inheritance but want to minimize the amount of methods I am using:



import random
import turtle
wn=turtle.Screen()
wn.addshape("moleSmall.gif")
wn.addshape("Mole.gif")
wn.addshape("Hammer.gif")
turtle.setup(800, 600)

class Game():
def __init__(self):
self.score=0
self.pointsDisplay=Points()

def update_score(self,x,y):
self.score = self.score + 2
print("Score:", self.score)
self.callDisplayScore()
def decrease_score(self,x,y):
self.score = self.score -1
print("Score: ", self.score)
self.callDisplayScore()
def callDisplayScore(self):
score = self.score
class Sprite(turtle.Turtle):
def __init__(self):
turtle.Turtle.__init__(self)
self.x=0
self.y=0
crash =False
self.crash=crash
def randomMove(self):
leftbound = -self.wn.window_width()/2
rightbound = self.wn.window_width()/2
topbound = self.wn.window_height()/2
bottombound = -self.wn.window_height()/2
rand_x = random.randint(leftbound , rightbound)
rand_y = random.randint(bottombound, topbound)
self.mole.setpos(rand_x,rand_y)
def collisionCheck(self,turtle1, turtle2):
self.crash = False
turtle1X = turtle1.xcor()
turtle1Y = turtle1.ycor()
turtle2X = turtle2.xcor()
turtle2Y = turtle2.ycor()
turtle1Pos = (int(turtle1X), int(turtle1Y))
turtle2Pos = (int(turtle2X), int(turtle2Y))
if turtle1Pos == turtle2Pos or turtle1X < turtle2X - 50 and
turtle1Y > turtle2Y - 50 and turtle1X < turtle2X - 50 and
turtle1Y > turtle2Y + 50:
self.crash = True
return self.crash
class Mole(Sprite):
def __init__(self):
Sprite.__init__(self)
self.mole.pu()
self.mole.shape("moleSmall.gif")
self.x= self.mole.xcor()
self.y = self.mole.ycor()
self.randomMove()
class Hammer(Sprite):
def __init__(self):
Sprite.__init__(self)
self.counter = 0
self.hammer.penup()
self.hammer.shape("Hammer.gif")
self.hammer.penup()
leftbound = -self.wn.window_width()/2
rightbound = self.wn.window_width()/2
topbound = self.wn.window_height()/2
bottombound = -self.wn.window_height()/2
rand_x = random.randint(leftbound , rightbound)
rand_y = random.randint(bottombound, topbound)
self.hammer.setpos(rand_x,rand_y)
def HammerMove(self):
self.hammer.pu()
self.hammer.clear()
self.wn.onscreenclick(self.hammer.goto)
while self.collisionCheck(self.mole, self.hammer) == False:
self.randomMove()
if self.collisionCheck(self.mole, self.hammer) == True:
self.score = self.score + 1
print(self.score)








share|improve this question












share|improve this question




share|improve this question








edited Jan 8 at 18:46









200_success

123k14143401




123k14143401









asked Jan 6 at 9:46









da axe man

411




411











  • Maybe using from module import * to prevent clutter from the turtle.Screen() and turtle.setup()
    – VortexYT
    Jan 6 at 12:04







  • 2




    @VortexYT wildcard imports should be avoided! You can alias the import, i.e. import turtle as tl if you really want to save on typing.
    – Daniel
    Jan 6 at 12:10

















  • Maybe using from module import * to prevent clutter from the turtle.Screen() and turtle.setup()
    – VortexYT
    Jan 6 at 12:04







  • 2




    @VortexYT wildcard imports should be avoided! You can alias the import, i.e. import turtle as tl if you really want to save on typing.
    – Daniel
    Jan 6 at 12:10
















Maybe using from module import * to prevent clutter from the turtle.Screen() and turtle.setup()
– VortexYT
Jan 6 at 12:04





Maybe using from module import * to prevent clutter from the turtle.Screen() and turtle.setup()
– VortexYT
Jan 6 at 12:04





2




2




@VortexYT wildcard imports should be avoided! You can alias the import, i.e. import turtle as tl if you really want to save on typing.
– Daniel
Jan 6 at 12:10





@VortexYT wildcard imports should be avoided! You can alias the import, i.e. import turtle as tl if you really want to save on typing.
– Daniel
Jan 6 at 12:10











1 Answer
1






active

oldest

votes

















up vote
5
down vote













Terminology




one [class] for Game which is the super class




What you probably mean is that it is the class that controls everything and such is on top of the logical class hierarchy. But when talking about super classes, you usually mean classes from which other classes inherit and thus are on top of (or further up) the inheritance hierarchy. In your code for example, Sprite is a super class of Mole.



White space



To make your code more readible, you should add blank lines appropriately, to separate logically related blocks of code. For example, add a blank line between methods, and two blank lines between classes. Inside of methods you can add single blank lines wherever it seems appropriate, for example around loops.



You should add spaces around operators (like self.pointsDisplay = Points() instead of self.pointsDisplay=Points()) and after commas (e. g. def update_score(self, x, y): instead of def update_score(self,x,y):), however not before commas, as you did here random.randint(leftbound , rightbound).



Refer to PEP 8, which is the Python style guide.



Naming



Your naming scheme is inconsistent. Python uses snake_case, not camelCase, for member names (see also PEP 8). You mixed both schemes, for both methods and member variables. It is always better to be consistent with one naming scheme, and prefered to follow the conventions of the language.




You are using x and y as parameter names. It is better to use speaking names that tell you what they are for or what they contain, e. g. position_x, position_y. In some cases x and y can be sufficient if the method name is explicit enough, like move_to_position(self, x, y), but I wouldn't say this is the case with update_score. Furthermore, you aren't even using the parameters in update_score and decrease_score.




update_score and decrease_score seems a bit confusing. Isn't decreasing also a kind of updating? Shouldn't the opposite be called increase_score? Maybe you can use just one method update_score for both cases, and control the amount how much it is increased or decreased with a parameter.



Logic



Your method callDisplayScore does not do anything, because all that happens when you call it is that a local variable is assigned a value, but it is not used afterwards. After the method had been called, the local variable does not exist anymore. So you could remove that method alltogether, and remove the calls to it from the methods update_score and decrease_score. Then all that remains in those two methods can basically be done without methods, because you can simply change the value of the score and then print it, which is hardly worth a method. Not using a method there will probably also make the code more readible, because it is hard to find a method name that describes well what these two lones of code do.




This is redundant:



crash =False
self.crash=crash


You can just write self.crash = False instead.




This expression is way too long to understand what it means:



if turtle1Pos == turtle2Pos or turtle1X < turtle2X - 50 and 
turtle1Y > turtle2Y - 50 and turtle1X < turtle2X - 50 and
turtle1Y > turtle2Y + 50:
self.crash = True


Better save the result in a variable with a speaking name, or define a method that returns the result of the expression, again with a speaking name. Such a name could be is_colliding. Also using parantheses to group parts of the expression (even if they are technically not needed) can improve readability a lot.




This method also contains a lot of redundant logic, and also has not a very good name:



def collisionCheck(self,turtle1, turtle2):
self.crash = False
turtle1X = turtle1.xcor()
turtle1Y = turtle1.ycor()
turtle2X = turtle2.xcor()
turtle2Y = turtle2.ycor()
turtle1Pos = (int(turtle1X), int(turtle1Y))
turtle2Pos = (int(turtle2X), int(turtle2Y))
if turtle1Pos == turtle2Pos or turtle1X < turtle2X - 50 and
turtle1Y > turtle2Y - 50 and turtle1X < turtle2X - 50 and
turtle1Y > turtle2Y + 50:
self.crash = True
return self.crash


Method names should be verbs (in most cases), so check_collision is better than collisionCheck. Even better: is_colliding or is_collision, because check_collision is not explicit about what a result of True means.



All of these variables you assign in the first 7 lines of the method are not needed. Your self.crash is not even used anywhere else, so a local variable (without self.) would be enough even if you needed the variable at all. In some cases it can be good to save values from method calls into variables in order to not have to call the methods multiple times, but if the method is just an accessor to a member variable, like turtle1.xcor(), the overhead from the method call is negligible, and readability is much more important as long as performance is not an issue. And instead of returning a boolean value depending in the result of a logical expression, just return the result of the expression instead.



Checking whether the position is the same (turtle1Pos == turtle2Pos) is obsolete if you then check with a threshold anyway. By the way, you have a bug here: turtle1X < turtle2X - 50 occures twice in the expression, perhaps on of the minuses should be a plus. And since turtle1Y > turtle2Y - 50 and turtle1Y > turtle2Y + 50 are combined with and I assume that you have another bug leading to false collisions in some cases. Here one of the > should be a <. You can simplify your collision detection logic by just checking whether the absolute distance is lower than your threshold. Optionally you could define the threshold somewhere as a variable or inject it as a parameter.



Simplifying the method, I get this:



def is_collision(self, turtle1, turtle2):
return abs(turtle1.xcor() - turtle2.xcor()) < 50 and
abs(turtle1.ycor() - turtle2.ycor()) < 50





share|improve this answer























    Your Answer




    StackExchange.ifUsing("editor", function ()
    return StackExchange.using("mathjaxEditing", function ()
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    );
    );
    , "mathjax-editing");

    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "196"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );








     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f184430%2fpython-oop-whac-a-mole-program-using-turtle%23new-answer', 'question_page');

    );

    Post as a guest






























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    5
    down vote













    Terminology




    one [class] for Game which is the super class




    What you probably mean is that it is the class that controls everything and such is on top of the logical class hierarchy. But when talking about super classes, you usually mean classes from which other classes inherit and thus are on top of (or further up) the inheritance hierarchy. In your code for example, Sprite is a super class of Mole.



    White space



    To make your code more readible, you should add blank lines appropriately, to separate logically related blocks of code. For example, add a blank line between methods, and two blank lines between classes. Inside of methods you can add single blank lines wherever it seems appropriate, for example around loops.



    You should add spaces around operators (like self.pointsDisplay = Points() instead of self.pointsDisplay=Points()) and after commas (e. g. def update_score(self, x, y): instead of def update_score(self,x,y):), however not before commas, as you did here random.randint(leftbound , rightbound).



    Refer to PEP 8, which is the Python style guide.



    Naming



    Your naming scheme is inconsistent. Python uses snake_case, not camelCase, for member names (see also PEP 8). You mixed both schemes, for both methods and member variables. It is always better to be consistent with one naming scheme, and prefered to follow the conventions of the language.




    You are using x and y as parameter names. It is better to use speaking names that tell you what they are for or what they contain, e. g. position_x, position_y. In some cases x and y can be sufficient if the method name is explicit enough, like move_to_position(self, x, y), but I wouldn't say this is the case with update_score. Furthermore, you aren't even using the parameters in update_score and decrease_score.




    update_score and decrease_score seems a bit confusing. Isn't decreasing also a kind of updating? Shouldn't the opposite be called increase_score? Maybe you can use just one method update_score for both cases, and control the amount how much it is increased or decreased with a parameter.



    Logic



    Your method callDisplayScore does not do anything, because all that happens when you call it is that a local variable is assigned a value, but it is not used afterwards. After the method had been called, the local variable does not exist anymore. So you could remove that method alltogether, and remove the calls to it from the methods update_score and decrease_score. Then all that remains in those two methods can basically be done without methods, because you can simply change the value of the score and then print it, which is hardly worth a method. Not using a method there will probably also make the code more readible, because it is hard to find a method name that describes well what these two lones of code do.




    This is redundant:



    crash =False
    self.crash=crash


    You can just write self.crash = False instead.




    This expression is way too long to understand what it means:



    if turtle1Pos == turtle2Pos or turtle1X < turtle2X - 50 and 
    turtle1Y > turtle2Y - 50 and turtle1X < turtle2X - 50 and
    turtle1Y > turtle2Y + 50:
    self.crash = True


    Better save the result in a variable with a speaking name, or define a method that returns the result of the expression, again with a speaking name. Such a name could be is_colliding. Also using parantheses to group parts of the expression (even if they are technically not needed) can improve readability a lot.




    This method also contains a lot of redundant logic, and also has not a very good name:



    def collisionCheck(self,turtle1, turtle2):
    self.crash = False
    turtle1X = turtle1.xcor()
    turtle1Y = turtle1.ycor()
    turtle2X = turtle2.xcor()
    turtle2Y = turtle2.ycor()
    turtle1Pos = (int(turtle1X), int(turtle1Y))
    turtle2Pos = (int(turtle2X), int(turtle2Y))
    if turtle1Pos == turtle2Pos or turtle1X < turtle2X - 50 and
    turtle1Y > turtle2Y - 50 and turtle1X < turtle2X - 50 and
    turtle1Y > turtle2Y + 50:
    self.crash = True
    return self.crash


    Method names should be verbs (in most cases), so check_collision is better than collisionCheck. Even better: is_colliding or is_collision, because check_collision is not explicit about what a result of True means.



    All of these variables you assign in the first 7 lines of the method are not needed. Your self.crash is not even used anywhere else, so a local variable (without self.) would be enough even if you needed the variable at all. In some cases it can be good to save values from method calls into variables in order to not have to call the methods multiple times, but if the method is just an accessor to a member variable, like turtle1.xcor(), the overhead from the method call is negligible, and readability is much more important as long as performance is not an issue. And instead of returning a boolean value depending in the result of a logical expression, just return the result of the expression instead.



    Checking whether the position is the same (turtle1Pos == turtle2Pos) is obsolete if you then check with a threshold anyway. By the way, you have a bug here: turtle1X < turtle2X - 50 occures twice in the expression, perhaps on of the minuses should be a plus. And since turtle1Y > turtle2Y - 50 and turtle1Y > turtle2Y + 50 are combined with and I assume that you have another bug leading to false collisions in some cases. Here one of the > should be a <. You can simplify your collision detection logic by just checking whether the absolute distance is lower than your threshold. Optionally you could define the threshold somewhere as a variable or inject it as a parameter.



    Simplifying the method, I get this:



    def is_collision(self, turtle1, turtle2):
    return abs(turtle1.xcor() - turtle2.xcor()) < 50 and
    abs(turtle1.ycor() - turtle2.ycor()) < 50





    share|improve this answer



























      up vote
      5
      down vote













      Terminology




      one [class] for Game which is the super class




      What you probably mean is that it is the class that controls everything and such is on top of the logical class hierarchy. But when talking about super classes, you usually mean classes from which other classes inherit and thus are on top of (or further up) the inheritance hierarchy. In your code for example, Sprite is a super class of Mole.



      White space



      To make your code more readible, you should add blank lines appropriately, to separate logically related blocks of code. For example, add a blank line between methods, and two blank lines between classes. Inside of methods you can add single blank lines wherever it seems appropriate, for example around loops.



      You should add spaces around operators (like self.pointsDisplay = Points() instead of self.pointsDisplay=Points()) and after commas (e. g. def update_score(self, x, y): instead of def update_score(self,x,y):), however not before commas, as you did here random.randint(leftbound , rightbound).



      Refer to PEP 8, which is the Python style guide.



      Naming



      Your naming scheme is inconsistent. Python uses snake_case, not camelCase, for member names (see also PEP 8). You mixed both schemes, for both methods and member variables. It is always better to be consistent with one naming scheme, and prefered to follow the conventions of the language.




      You are using x and y as parameter names. It is better to use speaking names that tell you what they are for or what they contain, e. g. position_x, position_y. In some cases x and y can be sufficient if the method name is explicit enough, like move_to_position(self, x, y), but I wouldn't say this is the case with update_score. Furthermore, you aren't even using the parameters in update_score and decrease_score.




      update_score and decrease_score seems a bit confusing. Isn't decreasing also a kind of updating? Shouldn't the opposite be called increase_score? Maybe you can use just one method update_score for both cases, and control the amount how much it is increased or decreased with a parameter.



      Logic



      Your method callDisplayScore does not do anything, because all that happens when you call it is that a local variable is assigned a value, but it is not used afterwards. After the method had been called, the local variable does not exist anymore. So you could remove that method alltogether, and remove the calls to it from the methods update_score and decrease_score. Then all that remains in those two methods can basically be done without methods, because you can simply change the value of the score and then print it, which is hardly worth a method. Not using a method there will probably also make the code more readible, because it is hard to find a method name that describes well what these two lones of code do.




      This is redundant:



      crash =False
      self.crash=crash


      You can just write self.crash = False instead.




      This expression is way too long to understand what it means:



      if turtle1Pos == turtle2Pos or turtle1X < turtle2X - 50 and 
      turtle1Y > turtle2Y - 50 and turtle1X < turtle2X - 50 and
      turtle1Y > turtle2Y + 50:
      self.crash = True


      Better save the result in a variable with a speaking name, or define a method that returns the result of the expression, again with a speaking name. Such a name could be is_colliding. Also using parantheses to group parts of the expression (even if they are technically not needed) can improve readability a lot.




      This method also contains a lot of redundant logic, and also has not a very good name:



      def collisionCheck(self,turtle1, turtle2):
      self.crash = False
      turtle1X = turtle1.xcor()
      turtle1Y = turtle1.ycor()
      turtle2X = turtle2.xcor()
      turtle2Y = turtle2.ycor()
      turtle1Pos = (int(turtle1X), int(turtle1Y))
      turtle2Pos = (int(turtle2X), int(turtle2Y))
      if turtle1Pos == turtle2Pos or turtle1X < turtle2X - 50 and
      turtle1Y > turtle2Y - 50 and turtle1X < turtle2X - 50 and
      turtle1Y > turtle2Y + 50:
      self.crash = True
      return self.crash


      Method names should be verbs (in most cases), so check_collision is better than collisionCheck. Even better: is_colliding or is_collision, because check_collision is not explicit about what a result of True means.



      All of these variables you assign in the first 7 lines of the method are not needed. Your self.crash is not even used anywhere else, so a local variable (without self.) would be enough even if you needed the variable at all. In some cases it can be good to save values from method calls into variables in order to not have to call the methods multiple times, but if the method is just an accessor to a member variable, like turtle1.xcor(), the overhead from the method call is negligible, and readability is much more important as long as performance is not an issue. And instead of returning a boolean value depending in the result of a logical expression, just return the result of the expression instead.



      Checking whether the position is the same (turtle1Pos == turtle2Pos) is obsolete if you then check with a threshold anyway. By the way, you have a bug here: turtle1X < turtle2X - 50 occures twice in the expression, perhaps on of the minuses should be a plus. And since turtle1Y > turtle2Y - 50 and turtle1Y > turtle2Y + 50 are combined with and I assume that you have another bug leading to false collisions in some cases. Here one of the > should be a <. You can simplify your collision detection logic by just checking whether the absolute distance is lower than your threshold. Optionally you could define the threshold somewhere as a variable or inject it as a parameter.



      Simplifying the method, I get this:



      def is_collision(self, turtle1, turtle2):
      return abs(turtle1.xcor() - turtle2.xcor()) < 50 and
      abs(turtle1.ycor() - turtle2.ycor()) < 50





      share|improve this answer

























        up vote
        5
        down vote










        up vote
        5
        down vote









        Terminology




        one [class] for Game which is the super class




        What you probably mean is that it is the class that controls everything and such is on top of the logical class hierarchy. But when talking about super classes, you usually mean classes from which other classes inherit and thus are on top of (or further up) the inheritance hierarchy. In your code for example, Sprite is a super class of Mole.



        White space



        To make your code more readible, you should add blank lines appropriately, to separate logically related blocks of code. For example, add a blank line between methods, and two blank lines between classes. Inside of methods you can add single blank lines wherever it seems appropriate, for example around loops.



        You should add spaces around operators (like self.pointsDisplay = Points() instead of self.pointsDisplay=Points()) and after commas (e. g. def update_score(self, x, y): instead of def update_score(self,x,y):), however not before commas, as you did here random.randint(leftbound , rightbound).



        Refer to PEP 8, which is the Python style guide.



        Naming



        Your naming scheme is inconsistent. Python uses snake_case, not camelCase, for member names (see also PEP 8). You mixed both schemes, for both methods and member variables. It is always better to be consistent with one naming scheme, and prefered to follow the conventions of the language.




        You are using x and y as parameter names. It is better to use speaking names that tell you what they are for or what they contain, e. g. position_x, position_y. In some cases x and y can be sufficient if the method name is explicit enough, like move_to_position(self, x, y), but I wouldn't say this is the case with update_score. Furthermore, you aren't even using the parameters in update_score and decrease_score.




        update_score and decrease_score seems a bit confusing. Isn't decreasing also a kind of updating? Shouldn't the opposite be called increase_score? Maybe you can use just one method update_score for both cases, and control the amount how much it is increased or decreased with a parameter.



        Logic



        Your method callDisplayScore does not do anything, because all that happens when you call it is that a local variable is assigned a value, but it is not used afterwards. After the method had been called, the local variable does not exist anymore. So you could remove that method alltogether, and remove the calls to it from the methods update_score and decrease_score. Then all that remains in those two methods can basically be done without methods, because you can simply change the value of the score and then print it, which is hardly worth a method. Not using a method there will probably also make the code more readible, because it is hard to find a method name that describes well what these two lones of code do.




        This is redundant:



        crash =False
        self.crash=crash


        You can just write self.crash = False instead.




        This expression is way too long to understand what it means:



        if turtle1Pos == turtle2Pos or turtle1X < turtle2X - 50 and 
        turtle1Y > turtle2Y - 50 and turtle1X < turtle2X - 50 and
        turtle1Y > turtle2Y + 50:
        self.crash = True


        Better save the result in a variable with a speaking name, or define a method that returns the result of the expression, again with a speaking name. Such a name could be is_colliding. Also using parantheses to group parts of the expression (even if they are technically not needed) can improve readability a lot.




        This method also contains a lot of redundant logic, and also has not a very good name:



        def collisionCheck(self,turtle1, turtle2):
        self.crash = False
        turtle1X = turtle1.xcor()
        turtle1Y = turtle1.ycor()
        turtle2X = turtle2.xcor()
        turtle2Y = turtle2.ycor()
        turtle1Pos = (int(turtle1X), int(turtle1Y))
        turtle2Pos = (int(turtle2X), int(turtle2Y))
        if turtle1Pos == turtle2Pos or turtle1X < turtle2X - 50 and
        turtle1Y > turtle2Y - 50 and turtle1X < turtle2X - 50 and
        turtle1Y > turtle2Y + 50:
        self.crash = True
        return self.crash


        Method names should be verbs (in most cases), so check_collision is better than collisionCheck. Even better: is_colliding or is_collision, because check_collision is not explicit about what a result of True means.



        All of these variables you assign in the first 7 lines of the method are not needed. Your self.crash is not even used anywhere else, so a local variable (without self.) would be enough even if you needed the variable at all. In some cases it can be good to save values from method calls into variables in order to not have to call the methods multiple times, but if the method is just an accessor to a member variable, like turtle1.xcor(), the overhead from the method call is negligible, and readability is much more important as long as performance is not an issue. And instead of returning a boolean value depending in the result of a logical expression, just return the result of the expression instead.



        Checking whether the position is the same (turtle1Pos == turtle2Pos) is obsolete if you then check with a threshold anyway. By the way, you have a bug here: turtle1X < turtle2X - 50 occures twice in the expression, perhaps on of the minuses should be a plus. And since turtle1Y > turtle2Y - 50 and turtle1Y > turtle2Y + 50 are combined with and I assume that you have another bug leading to false collisions in some cases. Here one of the > should be a <. You can simplify your collision detection logic by just checking whether the absolute distance is lower than your threshold. Optionally you could define the threshold somewhere as a variable or inject it as a parameter.



        Simplifying the method, I get this:



        def is_collision(self, turtle1, turtle2):
        return abs(turtle1.xcor() - turtle2.xcor()) < 50 and
        abs(turtle1.ycor() - turtle2.ycor()) < 50





        share|improve this answer















        Terminology




        one [class] for Game which is the super class




        What you probably mean is that it is the class that controls everything and such is on top of the logical class hierarchy. But when talking about super classes, you usually mean classes from which other classes inherit and thus are on top of (or further up) the inheritance hierarchy. In your code for example, Sprite is a super class of Mole.



        White space



        To make your code more readible, you should add blank lines appropriately, to separate logically related blocks of code. For example, add a blank line between methods, and two blank lines between classes. Inside of methods you can add single blank lines wherever it seems appropriate, for example around loops.



        You should add spaces around operators (like self.pointsDisplay = Points() instead of self.pointsDisplay=Points()) and after commas (e. g. def update_score(self, x, y): instead of def update_score(self,x,y):), however not before commas, as you did here random.randint(leftbound , rightbound).



        Refer to PEP 8, which is the Python style guide.



        Naming



        Your naming scheme is inconsistent. Python uses snake_case, not camelCase, for member names (see also PEP 8). You mixed both schemes, for both methods and member variables. It is always better to be consistent with one naming scheme, and prefered to follow the conventions of the language.




        You are using x and y as parameter names. It is better to use speaking names that tell you what they are for or what they contain, e. g. position_x, position_y. In some cases x and y can be sufficient if the method name is explicit enough, like move_to_position(self, x, y), but I wouldn't say this is the case with update_score. Furthermore, you aren't even using the parameters in update_score and decrease_score.




        update_score and decrease_score seems a bit confusing. Isn't decreasing also a kind of updating? Shouldn't the opposite be called increase_score? Maybe you can use just one method update_score for both cases, and control the amount how much it is increased or decreased with a parameter.



        Logic



        Your method callDisplayScore does not do anything, because all that happens when you call it is that a local variable is assigned a value, but it is not used afterwards. After the method had been called, the local variable does not exist anymore. So you could remove that method alltogether, and remove the calls to it from the methods update_score and decrease_score. Then all that remains in those two methods can basically be done without methods, because you can simply change the value of the score and then print it, which is hardly worth a method. Not using a method there will probably also make the code more readible, because it is hard to find a method name that describes well what these two lones of code do.




        This is redundant:



        crash =False
        self.crash=crash


        You can just write self.crash = False instead.




        This expression is way too long to understand what it means:



        if turtle1Pos == turtle2Pos or turtle1X < turtle2X - 50 and 
        turtle1Y > turtle2Y - 50 and turtle1X < turtle2X - 50 and
        turtle1Y > turtle2Y + 50:
        self.crash = True


        Better save the result in a variable with a speaking name, or define a method that returns the result of the expression, again with a speaking name. Such a name could be is_colliding. Also using parantheses to group parts of the expression (even if they are technically not needed) can improve readability a lot.




        This method also contains a lot of redundant logic, and also has not a very good name:



        def collisionCheck(self,turtle1, turtle2):
        self.crash = False
        turtle1X = turtle1.xcor()
        turtle1Y = turtle1.ycor()
        turtle2X = turtle2.xcor()
        turtle2Y = turtle2.ycor()
        turtle1Pos = (int(turtle1X), int(turtle1Y))
        turtle2Pos = (int(turtle2X), int(turtle2Y))
        if turtle1Pos == turtle2Pos or turtle1X < turtle2X - 50 and
        turtle1Y > turtle2Y - 50 and turtle1X < turtle2X - 50 and
        turtle1Y > turtle2Y + 50:
        self.crash = True
        return self.crash


        Method names should be verbs (in most cases), so check_collision is better than collisionCheck. Even better: is_colliding or is_collision, because check_collision is not explicit about what a result of True means.



        All of these variables you assign in the first 7 lines of the method are not needed. Your self.crash is not even used anywhere else, so a local variable (without self.) would be enough even if you needed the variable at all. In some cases it can be good to save values from method calls into variables in order to not have to call the methods multiple times, but if the method is just an accessor to a member variable, like turtle1.xcor(), the overhead from the method call is negligible, and readability is much more important as long as performance is not an issue. And instead of returning a boolean value depending in the result of a logical expression, just return the result of the expression instead.



        Checking whether the position is the same (turtle1Pos == turtle2Pos) is obsolete if you then check with a threshold anyway. By the way, you have a bug here: turtle1X < turtle2X - 50 occures twice in the expression, perhaps on of the minuses should be a plus. And since turtle1Y > turtle2Y - 50 and turtle1Y > turtle2Y + 50 are combined with and I assume that you have another bug leading to false collisions in some cases. Here one of the > should be a <. You can simplify your collision detection logic by just checking whether the absolute distance is lower than your threshold. Optionally you could define the threshold somewhere as a variable or inject it as a parameter.



        Simplifying the method, I get this:



        def is_collision(self, turtle1, turtle2):
        return abs(turtle1.xcor() - turtle2.xcor()) < 50 and
        abs(turtle1.ycor() - turtle2.ycor()) < 50






        share|improve this answer















        share|improve this answer



        share|improve this answer








        edited Jan 8 at 9:49


























        answered Jan 6 at 12:13









        Raimund Krämer

        1,808321




        1,808321






















             

            draft saved


            draft discarded


























             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f184430%2fpython-oop-whac-a-mole-program-using-turtle%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            Greedy Best First Search implementation in Rust

            Function to Return a JSON Like Objects Using VBA Collections and Arrays

            C++11 CLH Lock Implementation