Creating turn() method to change horizontal direction - python

I'm working on a class that includes a turn() method that's supposed to change the direction horizontally. The bug is moving left or right on a horizontal line.
Here's my code, I know it's wrong but I can't figure out how to change horizontal direction
class Bug:
def __init__(self, position):
self.__name = ''
self.__position = 0
self.__direction = 180
**def turn(self):
if(self.__direction == 180):
self.__direction = self.__direction - 180
else:
self.__direction = self.__direction + 180**
def move(self):
self.__position = self.__position + 1
def getPosition(self):
return self.__position
Would someone mind pointing me in the right direction? I know it's super simple but I hit a block and can't figure it out!
Edit: I apologize for not being more clear! The move() method is just supposed to move the bug one unit in it's current direction. I also made an edit and removed self.__direction, as there are only supposed to be 2 instance variables, not 3. So basically all I need to fix is the turn() method, making my bug change direction (left or right on the horizontal line).

I can only guess what you are trying to achieve, and I suppose that in the move method the actual direction should be taken into consideration:
#! /usr/bin/python3.2
class Bug:
def __init__(self, position):
self.__name = ''
self.__position = position
self.__direction = 1
def turn(self):
self.__direction = -self.__direction
def move(self):
self.__position = self.__position + self.__direction
def getPosition(self):
return self.__position
b = Bug (100)
for _ in range(5):
b.move()
print(b.getPosition())
b.turn()
for _ in range(5):
b.move()
print(b.getPosition())
This outputs:
101
102
103
104
105
104
103
102
101
100

Related

Writing a test in python

Im currently taking a python class and im new in programming. I have written the code below and want to write a code that tests if the ResilientPlayer actually does what it is supposed to. The code is from a chutes and ladders board game where the ResilientPlayer is a "special" type of player that gets a "superpower" in its next move afther falling down a chute. The next round afther he has fallen down a chute, he will add a given or a default number to the die_roll, and I want to test if my code actually does this! Hope someone can help me with this problem :)
class Player:
def __init__(self, board):
self.board = board
self.position = 0
self.n_steps = 0
def move(self):
die_roll = random.randint(1, 6)
self.position = self.get_position() + die_roll
self.board.position_adjustment(self.position)
self.n_steps += 1
def get_position(self):
return self.position
def get_steps(self):
return self.n_steps
class ResilientPlayer(Player):
default_extra_steps = 1
def __init__(self, board, extra_steps=None):
super().__init__(board)
self.extra_steps = extra_steps
if self.extra_steps is None:
self.extra_steps = self.default_extra_steps
def move(self):
if self.get_position() in self.board.chutes.values():
die_roll = random.randint(1, 6)
self.position = self.get_position() + die_roll + self.extra_steps
self.board.position_adjustment(self.position)
self.n_steps += 1
else:
super().move()
def get_position(self):
return self.position
def get_steps(self):
return self.n_steps
The best way to do this is using the unittest class, I do this as following:
import unittest
from .... import ResilientPlayer
class TestResilientPlayer(unittest.TestCase):
def setUp(self):
self.resilient_player = ResilientPlayer(....)
def test_move(self):
# Do stuff
self.assertEqual(1, 1)
if __name__ == '__main__':
unittest.main()
Here, unittest.main() will run all the tests in the file. setUp is run before each test (so you can have multiple tests with the same starting conditions).
This is an incredible useful module and I strongly suggest reading more on it, check the documentation

Having difficulty understanding Python OOP

I'm fairly green to OOP and I was just playing around with it in Python and came across something I can't explain so hopefully you guys will be able to help.
I was playing with the code below:
class Car():
def __init__(self, brand, model, speed):
self.brand = brand
self.model = model
self.speed = speed
def increase_speed(self):
return self.speed + 1
def decrease_speed(self, decrease_by):
return self.speed - decrease_by
car1 = Car("tesla","x",30)
print(car1.brand)
print(car1.speed)
print(car1.increase_speed())
print(car1.speed)
print(car1.decrease_speed(10))
My question is, I am expecting after increasing the speed, car1's speed will be 31 but instead it prints out 30. Why is it that way and how should the code be written for the speed to be 31 instead?
def increase_speed(self):
self.speed += 1
return self.speed
Previously you did not increase your speed, rather you just return a value that is equal to the speed plus 1. Similarly, change your decrease_speed function.
Instead of returning the values, set them on the attributes:
class Car():
def __init__(self, brand, model, speed):
self.brand = brand
self.model = model
self.speed = speed
def increase_speed(self):
self.speed = self.speed + 1
def decrease_speed(self, decrease_by):
self.speed = self.speed - decrease_by
I deliberately don't return the changed speed anymore, as it's good style (at least with methods mainly setting attributes) to either return something or change state:
car1 = Car("tesla","x",30)
print(car1.brand)
print(car1.speed)
car1.increase_speed()
print(car1.speed)
car1.decrease_speed(10)
print(car1.speed)
The method increase_speed is just returning self.speed + 1, if you wish to update the speed you need to self.speed = self.speed + 1 into the method increase speed.

Crop a collection of lines using another collection of lines

First of all, here is a quick graphical description of what I intend to do. I will use Python, but feel free to use pseudo code in your answers.
I have 2 collections of 2D segments, stored as the following: [ [start_point, end_point], [...] ].
For the first step, I have to detect each segment of the blue collection which is colliding with the black collection. For this I use LeMothe's line/line intersection algorithm.
Then comes my first problem: Having a segment AB which intersects with my line in C, I don't know how to determine using code if I have to trim my segment as AC or as CB , ie: I don't know which part of my segment I need to keep and which one I need to remove.
Then for the second step, I have really no ideas how to achieve this.
Any help would be greatly appreciated, so thank you in advance!
The second step is trivial once you figure what to keep and what not, you just need to keep track of the segments you clipped and see where they were originally joined (e.g. assume that the segments are in order and form a connected line).
On the other hand, given that your black line is in fact a line and not a polygon, in your first step, choosing what is "outside" and what is "inside" seems completely arbitrary; is it possible to close that into a polygon? Otherwise, you may need to artificially create two polygons (one for each side of the line) and then do clipping inside those polygons. You could use something like the Cyrus and Beck line clipping algorithm (see this tutorial for an overview: https://www.tutorialspoint.com/computer_graphics/viewing_and_clipping.htm)
Feel free to use any of the code below as a starting point (you have an intersect function and some useful classes). Implements Sutherland and Hodgman.
class Point2(object):
"""Structure for a 2D point"""
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __copy__(self):
return self.__class__(self.x, self.y)
copy = __copy__
def __repr__(self):
return 'Point2(%d, %d)' % (self.x, self.y)
def __getitem__(self, key):
return (self.x, self.y)[key]
def __setitem__(self, key, value):
l = [self.x, self.y]
l[key] = value
self.x, self.y = l
def __eq__(self, other):
if isinstance(other, Point2):
return self.x == other.x and \
self.y == other.y
else:
assert hasattr(other, '__len__') and len(other) == 2
return self.x == other[0] and \
self.y == other[1]
def __ne__(self, other):
return not self.__eq__(other)
def __nonzero__(self):
return self.x != 0 or self.y != 0
def __len__(self):
return 2
class Line2(object):
"""Structure for a 2D line"""
def __init__(self,pt1,pt2):
self.pt1,self.pt2=pt1,pt2
def __repr__(self):
return 'Line2(%s, %s)' % (self.pt1, self.pt2)
class Polygon2(object):
def __init__(self,points):
self.points = points
def __repr__(self):
return '[\n %s\n]' % '\n '.join([str(i) for i in self.points])
def lines(self):
lines = []
e = self.points[-1].copy()
for p in self.points:
lines.append(Line2(e,p))
e = p.copy()
return lines
#return [Line2(a,b) for a,b in zip(self.points,self.points[1:]+[self.points[0]])]
def __copy__(self):
return self.__class__(list(self.points))
copy = __copy__
class Renderer(object):
"""Rendering algorithm implementations"""
def __init__(self,world,img,color=1):
self.world,self.img,self.color=world,img,color
def transform(self,s,r,m,n):
"""Homogeneous transformation operations"""
for i in self.world.points():
j = Matrix3.new_translate(m, n)*Matrix3.new_rotate(r)*Matrix3.new_scale(s)*i
i.x,i.y = j.x,j.y
def clip(self,a,b,c,d):
"""Clipping for the world window defined by a,b,c,d"""
self.clip_lines(a, b, c, d)
self.clip_polygons(a, b, c, d)
def shift(self,a,b,c,d):
"""Shift the world window"""
for i in self.world.points():
i.x -= a
i.y -= b
def clip_lines(self,a,b,c,d):
"""Clipping for lines (i.e. open polygons)"""
clipped = []
for i in self.world.lines:
clipped += [self.clip_lines_cohen_sutherland(i.pt1, i.pt2, a, b, c, d)]
self.world.lines = [i for i in clipped if i]
def clip_polygons(self,a,b,c,d):
"""Clipping for polygons"""
polygons = []
for polygon in self.world.polygons:
new_polygon = self.clip_polygon_sutherland_hodgman(polygon, a, b, c, d)
polygons.append(new_polygon)
self.world.polygons = polygons
def clip_polygon_sutherland_hodgman(self,polygon,xmin,ymin,xmax,ymax):
edges = [Line2(Point2(xmax,ymax),Point2(xmin,ymax)), #top
Line2(Point2(xmin,ymax),Point2(xmin,ymin)), #left
Line2(Point2(xmin,ymin),Point2(xmax,ymin)), #bottom
Line2(Point2(xmax,ymin),Point2(xmax,ymax)), #right
]
def is_inside(pt,line):
# uses the determinant of the vectors (AB,AQ), Q(X,Y) is the query
# left is inside
det = (line.pt2.x-line.pt1.x)*(pt.y-line.pt1.y) - (line.pt2.y-line.pt1.y)*(pt.x-line.pt1.x)
return det>=0
def intersect(pt0,pt1,line):
x1,x2,x3,x4 = pt0.x,pt1.x,line.pt1.x,line.pt2.x
y1,y2,y3,y4 = pt0.y,pt1.y,line.pt1.y,line.pt2.y
x = ((x1*y2-y1*x2)*(x3-x4)-(x1-x2)*(x3*y4-y3*x4)) / ((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4))
y = ((x1*y2-y1*x2)*(y3-y4)-(y1-y2)*(x3*y4-y3*x4)) / ((x1-x2)*(y3-y4)-(y1-y2)*(x3-x4))
return Point2(int(x),int(y))
polygon_new = polygon.copy()
for edge in edges:
polygon_copy = polygon_new.copy()
polygon_new = Polygon2([])
s = polygon_copy.points[-1]
for p in polygon_copy.points:
if is_inside(s,edge) and is_inside(p,edge):
polygon_new.points.append(p)
elif is_inside(s,edge) and not is_inside(p,edge):
polygon_new.points.append(intersect(s,p,edge))
elif not is_inside(s,edge) and not is_inside(p,edge):
pass
else:
polygon_new.points.append(intersect(s,p,edge))
polygon_new.points.append(p)
s = p
return polygon_new
def clip_lines_cohen_sutherland(self,pt0,pt1,xmin,ymin,xmax,ymax):
"""Cohen-Sutherland clipping algorithm for line pt0 to pt1 and clip rectangle with diagonal from (xmin,ymin) to (xmax,ymax)."""
TOP = 1
BOTTOM = 2
RIGHT = 4
LEFT = 8
def ComputeOutCode(pt):
code = 0
if pt.y > ymax: code += TOP
elif pt.y < ymin: code += BOTTOM
if pt.x > xmax: code += RIGHT
elif pt.x < xmin: code += LEFT
return code
accept = False
outcode0, outcode1 = ComputeOutCode(pt0), ComputeOutCode(pt1)
while True:
if outcode0==outcode1==0:
accept=True
break
elif outcode0&outcode1:
accept=False
break
else:
#Failed both tests, so calculate the line segment to clip from an outside point to an intersection with clip edge.
outcodeOut = outcode0 if not outcode0 == 0 else outcode1
if TOP & outcodeOut:
x = pt0.x + (pt1.x - pt0.x) * (ymax - pt0.y) / (pt1.y - pt0.y)
y = ymax
elif BOTTOM & outcodeOut:
x = pt0.x + (pt1.x - pt0.x) * (ymin - pt0.y) / (pt1.y - pt0.y)
y = ymin
elif RIGHT & outcodeOut:
y = pt0.y + (pt1.y - pt0.y) * (xmax - pt0.x) / (pt1.x - pt0.x);
x = xmax;
elif LEFT & outcodeOut:
y = pt0.y + (pt1.y - pt0.y) * (xmin - pt0.x) / (pt1.x - pt0.x);
x = xmin;
if outcodeOut == outcode0:
pt0 = Point2(x,y)
outcode0 = ComputeOutCode(pt0)
else:
pt1 = Point2(x,y)
outcode1 = ComputeOutCode(pt1);
if accept:
return Line2(pt0,pt1)
else:
return False
I think what you'll need to do is find a line from the center of the blue object to the line segment in question. If that new line from the center to the segment AB or BC hits a black line on its way to the blue line segment, then that segment is outside and is trimmed. You would want to check this at a point between A and B or between B and C, so that you don't hit the intersection point.
As for the python aspect, I would recommend defining a line object class with some midpoint attributes and a shape class that's made up of lines with a center attribute, (Actually come to think of it, then a line would count as a shape so you could make line a child class of the shape class and preserve code), that way you can make methods that compare two lines as part of each object.
line_a = Line((4,2),(6,9))
line_b = Line((8,1),(2,10))
line_a.intersects(line.b) #Could return Boolean, or the point of intersection
In my mind that just feels like a really comfortable way to go about this problem since it lets you keep track of what everything's doing.

How to make panda3d accept controls faster?

Hi I am trying to make a game on panda3d v 1.8.1 (python) but the controls seem to be very sloppy. One has to keep the keys pressed for a second or two to make things happen. Is there any way to make panda3d accept controls faster ?
Here's my code of my key handler :
class KeyHandler(DirectObject):
def __init__(self):
self.accept('arrow_left-repeat', self.lookLeft)
self.accept('arrow_right-repeat', self.lookRight)
self.accept('arrow_up-repeat', self.lookUp)
self.accept('arrow_down-repeat', self.lookDown)
self.accept('w-repeat', self.Moveforward)
self.accept('s-repeat', self.Movebackward)
self.accept('a-repeat', self.Moveleft)
self.accept('d-repeat', self.Moveright)
self.accept('q-repeat', self.MoveDown)
self.accept('e-repeat', self.MoveUp)
self.accept('space', self.Dotask)
def lookLeft(self):
global camxy
camxy += 2
def lookRight(self):
global camxy
camxy -= 2
def lookUp(self):
global camyz
camyz += 2
def lookDown(self):
global camyz
camyz -= 2
def Moveforward(self):
global camx
if camx < 57 :
camx += 1
def Movebackward(self):
global camx
if camx > -32 :
camx -= 1
def Moveleft(self):
global camy
if camy < 42 :
camy += 1
def Moveright(self):
global camy
if camy > -36 :
camy -= 1
def MoveUp(self):
global camz
if camz < 15 :
camz += 0.5
def MoveDown(self):
global camz
if camz >1 :
camz -= 0.5
a = KeyHandler()
def set_cam(task) :
camera.setPos(camx,camy,camz)
camera.setHpr(camxy,camyz,camzx)
taskMgr.add(set_cam, "setcamTask")
The camera which I am using is the default camera of panda3d.
Any help would be appreciated !
You should avoid using the "-repeat" handlers. They take just as long to trigger as more letters take to appear if you hold a key down in any textbox.
The usual way is to use a dict keeping key state:
class KeyHandler(DirectObject):
keys = {"lookLeft": False, "lookRight": False} # etcetera
def __init__(self):
DirectObject.__init__(self)
self.accept('arrow_left', self.pressKey, ["lookLeft"])
self.accept('arrow_left-up', self.releaseKey, ["lookRight"])
taskMgr.add(self.set_cam, "setcamTask")
def pressKey(self, key):
self.keys[key] = True
def releaseKey(self, key):
self.keys[key] = False
# Hopefully method will be passed bound
def set_cam(self, task):
dt = globalClock.getDt()
if self.keys["lookLeft"]:
camera.setH(camera.getH() + 2 * dt)
elif self.keys["lookRight"]:
camera.setH(camera.getH() + 2 * dt)
a = KeyHandler()
This will also allow you to define user settings for keys more easily.
This is not the first or even most important issue with that code though. set_cam should really be a method of KeyHandler instead of declaring every variable global, and you should multiply movement by each frame's dt to keep the game looking the same speed with different framerates.

Fixing class method loop

I've encountered a problem with my class file and I can't seem to find a fix around it. I was hoping someone could point me to the right direction.
Here's my code:
class Car:
def __init__(self, year_model, make, speed):
self.__year_model = year_model
self.__make = make
self.__speed = 0
def set_year_model(self, year_model):
self.__year_model = year_model
def set_make(self, make):
self.__make = make
def get_year_model(self):
return self.__year_model
def get_make(self):
return self.__make
def accelerate(self):
self.__speed + 5
return self.__speed
def decelerate(self):
self.__speed - 5
return self.__speed
def get_speed(self):
return self.__speed
Essentially, I want the speed attribute set to 0, and have 3 methods (accelerate, decelerate, and get_speed) which add and subtract 5 to the speed attribute and eventually return the speed attribute so it can be printed.
I would guess there's a problem with my formatting but I can't seem to find the correct arrangement that would fix the class.
The real program is suppose to loop the accelerate method 5 times, but the class method is supposed to handle the sequential addition and return the final speed.
import car
user_year = 1995
user_make = "toyota"
user_speed = 0
user_car = car.Car(user_year, user_make, user_speed)
for count in range(1,6):
user_car.accelerate()
print user_car.get_speed()
I know this code is very weak, but it's all makeshift to help make my problem clearer.
So hopefully it's not too confusing and I can get an answer.
self._speed + 5 computes the current speed plus 5. But you're not actually storing the computed value anywhere. You want to use self._speed = self._speed + 5, or the more commonly used form, self._speed += 5.
The problem is, of course, the "+=" and "-=" portions that are missing, but I'd go a step further and suggest that if you're writing new python code, you become familiar with new style classes. In a new style class, your code could be written as follows:
class Car(object):
def __init__(self, year_model, make, speed):
self.year_model = year_model
self.make = make
self.speed = 0
def __set_year_model(self, year_model):
self.__year_model = year_model
def __set_make(self, make):
self.__make = make
def __set_speed(self, speed):
self.__speed = speed
def __get_year_model(self):
return self.__year_model
def __get_make(self):
return self.__make
def accelerate(self):
self.speed += 5
def decelerate(self):
self.speed -= 5
def __get_speed(self):
return self.__speed
speed = property(fget=__get_speed,fset=__set_speed,fdoc="Set or Retrieve the current speed of this instance of the Car object")
make = property(fget=__get_make,fset=__set_make,fdoc="Set or Retrieve the make of this instance of the Car object")
year_model = property(fget=__get_year_model,fset=__set_year_model,fdoc="Set or Retrieve the Year and Model of this instance of the Car object")
In addition, the code changes in the main file:
import car
user_year = 1995
user_make = "toyota"
user_speed = 0
user_car = car.Car(user_year, user_make, user_speed)
for count in range(1,6):
user_car.accelerate()
print user_car.speed

Categories