Class cross referencing? - python

I come from a C++ background and I am a bit lost without the whole pointer concept in python. Or at least it's unclear.
For instance, I want to create a game of tick tack toe using OOP in Python. I have a couple classes like so:
class Game(object):
def __init__(self, player1, player2):
self.board = [['','',''],
['','',''],
['','','']]
self.players = [player1, player2]
class Player(object):
def __init__(self, game, marking):
self.game = game
self.marking = marking # either 'X' or 'O'
It seems obvious that the game needs to have a reference to the two players and that a player is also part of a game, and should, therefore, have a reference to the game. However, the above code doesn't work because there is no way I can create a player without a creating a game first. But to create a game I need two players.
I could add in these references afterwards by doing something like: player.game = some_game_reference but this seems unpythonic and tedious to keep up with.
What is the best and most pythonic way of accomplishing this?

You can just have one class or the other updates its arguments. For example, create the players first, then have the game update the players with itself:
class Game(object):
def __init__(self, player1, player2):
self.board = [['','',''],
['','',''],
['','','']]
self.players = [player1, player2]
player1.game = self
player2.game = self
player1.marking = 'X'
player2.marking = 'O'
# Neither game nor marking make sense to set initially, until
# the players are added to a game.
class Player(object):
def __init__(self):
pass
p1 = Player()
p2 = Player()
g = Game(p1, p2)
(Whether you need this kind of coupling is, as others have pointed out, a separate design issue.)
Just to show the other direction is just as feasible:
class Player(object):
def __init__(self, game, marking):
self.game = game
self.marking = marking
game.players.append(self)
class Game(object):
def __init__(self):
self.board = [['','',''],
['','',''],
['','','']]
g = Game()
p1 = Player(g, 'X')
p2 = Player(g, 'O')
Hopefully, though, you'll agree that it makes more sense for the game to assign each player a marking. Here, you might try to add more than 2 players to a game, or add two X or two O players.

Related

Drawing Basic Animations in Python

Hello I am trying to create something like this box with controllable dots
I need to be able to move and interact with the dots. I have tried turtle and pyglet, but neither of them seem to do what I want them to do.
Turtle is letting me create dots but it doesnt seem to play well with oop. I'm a super noob at python oop so maybe I'm just doing it wrong but I can't seem to make an turtle object that I can actually use how I want. I would ideally be able to use my own methods built off of the turtle methods, and create and call on data unique to each turtle.
import turtle
import time
import random
wn = turtle.Screen()
wn.title("simulation")
wn.bgcolor("tan")
def rng(whatisrandom):
match whatisrandom:
case 'coords': return(random.randint(-400,400) , random.randint(-400,400))
case 'heading':return(random.randint(0,359))
case 'forward':return(random.randint(0,50))
class bug():
def __init__(self) -> None:
self = turtle.Turtle(shape = "circle",visible=False)
self.speed(0)
self.penup()
self.setpos(rng('coords'))
self.showturtle()
self.speed(1)
self.forward(20)
def move(self):
self.setheading(rng('heading'))
self.forward(rng('forward'))
bug1 = bug()
bug1.move()
wn.mainloop()
this is the error message.
self.setheading(rng('heading'))
^^^^^^^^^^^^
AttributeError: 'bug' object has no attribute 'heading'
I ultimately want to animate these little bugs with neural nets and train them to do different movements, and eventually interact with each other.
This appears to be a misunderstanding of how to subclass an object in Python. Let's rearrange things a bit:
from turtle import Screen, Turtle
from random import randint
class Bug(Turtle):
def __init__(self):
super().__init__(shape='circle', visible=False)
self.speed('fastest')
self.penup()
self.setposition(Bug.rng('coords'))
self.showturtle()
self.speed('slowest')
self.forward(20)
def move(self):
self.setheading(Bug.rng('heading'))
self.forward(Bug.rng('forward'))
#staticmethod
def rng(whatisrandom):
if whatisrandom == 'coords':
return randint(-400, 400), randint(-400, 400)
if whatisrandom == 'heading':
return randint(0, 359)
if whatisrandom == 'forward':
return randint(0, 50)
return None
screen = Screen()
screen.title("Simulation")
screen.bgcolor('tan')
bug1 = Bug()
bug1.move()
screen.mainloop()
I don't have an issue with your match statement, I'm just unfamiliar with it and haven't updated my Python sufficiently!

How can I call a class method on an instance within a different class __init__

I am creating a tic-tac-toe game in python. I'm trying to call the update method from my Board class on my boardState object within the class init of my Turn class.
When I run it I get NameError: name boardState is not defined.
class Board:
def __init__(self, player1 = "player1", player2 = "player2"):
self.p1 = player1
self.p2 = player2
self.matrix = MATRIX
self.winner = 'none'
self.available = getAvailable(self.matrix)
def update(self):
clear()
getAvailable(self.matrix)
self.show()
class Turn:
def __init__(self, sym):
self.sym = sym
boardState.update()
terminalState(boardState, self.sym, available)
print(f"{self.sym}'s turn:")
def main():
boardState = Board()
altTurns()
you are getting this error siense you haven't defined "boardState" before referencing it,
you need to set it to be a new Board Object before using it
class Board:
def __init__(self, player1 = "player1", player2 = "player2"):
self.p1 = player1
self.p2 = player2
self.matrix = MATRIX
self.winner = 'none'
self.available = getAvailable(self.matrix)
def update(self):
clear()
getAvailable(self.matrix)
self.show()
class Turn:
def __init__(self, sym):
self.sym = sym
boardState = Board() #the line I added
boardState.update()
terminalState(boardState, self.sym, available)
print(f"{self.sym}'s turn:")
this should fix your problem
If you want your Turn object to have access to the boardState object you've created in main() (and for main in turn to have access to the updated boardState), you should pass it in as a parameter to give all of the relevant functions access to it.
I assume the Turn is created by altTurns, so altTurns should itself take a board object that it can use to create the initial Turn.
class Turn:
def __init__(self, sym, boardState):
self.sym = sym
boardState.update()
terminalState(boardState, self.sym, available)
print(f"{self.sym}'s turn:")
def altTurns(boardState):
sym = None # or something?
turn = Turn(sym, boardState)
# more turns happen?
def main():
boardState = Board()
altTurns(boardState)
# our boardState has now been updated by Turn()

Python Turtle class inheritance not working

I am trying to create a snake with an edited Turtles class. So I create a SnakeSegment class which has Turtle class as a parent. I then add a variable to the SnakeSegment class and also I set things like the colour and speed of the Turtle.
I then create my snake class where I bring in my SnakeSegments. The problem is the snake segments don't bring in their colour which I initiated in the snake segment class.
I think I have got the inheritance wrong, but I am not sure.
I have 2 files: components.py and main.py
components.py:
from turtle import Turtle
class SnakeSegment(Turtle):
def __init__(self, givenListPosition):
super().__init__()
self.segment = Turtle()
self.segment.shape("square")
self.segment.color('white')
self.segment.speed(1)
self.segment.penup()
self.listPosition = givenListPosition
class Snake:
def __init__(self, screen):
self.theScreen = screen
self.pastPositions = [(0.00, 0.00), (-20.00, 0.00), (-30.00, 0.00)]
self.t1 = SnakeSegment(0)
self.t2 = SnakeSegment(1)
self.t2.goto(self.pastPositions[int(self.t2.listPosition)])
self.t3 = SnakeSegment(2)
self.t2.goto(self.pastPositions[int(self.t3.listPosition)])
main.py:
from components import *
from turtle import Screen
screen = Screen()
screen.setup(width=600, height=600)
screen.bgcolor("black")
screen.title("Snake Game")
snake = Snake(screen)
snake.theScreen.exitonclick()
I'm not sure I get your final goal and you did not show how your Turtle class looks. However, it appears you are using a mix of inheritance and composition which doesn't seem correct whatever your goal is. You have to decide if SnakeSegment is a Turtle (inheritance) or has a Turtle (composition) in your data model.
With inheritance, SnakeSegment will have all methods and attributes of the base Turtle class (which I assume has some of the "shape", "color" etc methods) and will "be" a Turtle from any point of view. You could then write something like this
class SnakeSegment(Turtle):
def __init__(self, givenListPosition):
super().__init__()
self.shape("square")
self.color('white')
self.speed(1)
self.penup()
self.listPosition = givenListPosition
With composition instead, SnakeSegment doesn't inherit from anything, it just has a member which is an instance of the Turtle class. In that case, something like that would be used
class SnakeSegment:
def __init__(self, givenListPosition):
self.segment = Turtle()
self.segment.shape("square")
self.segment.color('white')
self.segment.speed(1)
self.segment.penup()
self.listPosition = givenListPosition
I'd suggest you start from that and before taking a decision on your data model, have a read about mixins as well (i.e. https://www.pythontutorial.net/python-oop/python-mixin/)

How update variable within another class

I have these classes :
class Game():
def __init__(self):
self.player = Player("name")
class Turn():
def __init__(self):
pass
def end(self):
#how update xp player
class Player():
def __init__(self, name):
self.name = name
self.xp = 0
And my question is how when turn is terminated, how update the player
If these classes are in the same module you can define a global variable in the module that can be used in both classes. Otherwise you need to explicitly pass the variable on the instances of both classes.
Your Game class appears to have a reference to a player in its self.player attribute. If you want to update that player's xp attribute, you can do something like this:
def end(self):
self.player.xp += 5

Importing an object to a class

How do I import an object into the class's namespace and make it available for every function? Say I have a singleton object called terrain in terrain.py and I want all the creatures in a game to know something about the map.
In creatures.py:
class Creature:
'''
Basic class for mobile active things like player and monsters
'''
from terrain import terrain
# ... some more code ...
def move(self, dx, dy):
'''
move creature by dx and|or dy
'''
if terrain.item(self.x+dx, self.y+dy).passable==True:
self.x+=dx
self.y+=dy
Now terrain is not defined within move and throws NameError. Of course, it could've been:
def move(self, dx, dy):
'''
move creature by dx and|or dy
'''
from terrain import terrain
self.x+=dx
self.y+=dy
It works, but that way I have to import it in every single function. That's kind of ugly, so what's the correct way?
It would be better if all your imports are at the top of your script, but if you want to do like this so much...
class SomeClass:
def __init__(self):
from Smith import John
self.imp=John
def run(self, args):
self.imp.dosmth()

Categories