curriculum/challenges/english/blocks/learn-encapsulation-by-building-a-projectile-trajectory-calculator/662fc35902038376c7a00b3c.md
Once you have the getters, you can write the setters, which allow you to set the value of an attribute in an indirect manner. Following the example of the last step, a setter would be written as:
class Nest:
...
@number_of_eggs.setter
def number_of_eggs(self, new_value):
self.__number_of_eggs = new_value
Same as the getter, a setter is not called like a method but used like an attribute:
nest = Nest()
nest.number_of_eggs = 12
This way of writing calls the setter and set the new value.
For this step you will have to write the setters for the three private attributes. Remember that for the angle the value is received in degrees but saved internally in radians.
You should define a new speed method.
({test: () => assert(runPython(`
len(_Node(_code).find_class('Projectile').find_functions('speed')) == 2
`))})
Your new speed method should have a @speed.setter decorator.
({test: () => assert(runPython(`
_Node(_code).find_class('Projectile').find_functions('speed')[1].has_decorators('speed.setter')
`))})
Your new speed method should set the value of the private __speed property.
({test: () => assert(runPython(`
a = Projectile(22, 23, 24)
a.speed = 33
a.speed == 33
`))})
You should define a new height method.
({test: () => assert(runPython(`
len(_Node(_code).find_class('Projectile').find_functions('height')) == 2
`))})
Your new height method should have a @height.setter decorator.
({test: () => assert(runPython(`
_Node(_code).find_class('Projectile').find_functions('height')[1].has_decorators('height.setter')
`))})
Your new height method should set the value of the private __height property.
({test: () => assert(runPython(`
a = Projectile(22, 23, 24)
a.height = 44
a.height == 44
`))})
You should define a new angle method.
({test: () => assert(runPython(`
len(_Node(_code).find_class('Projectile').find_functions('angle')) == 2
`))})
Your new angle method should have a @angle.setter decorator.
({test: () => assert(runPython(`
_Node(_code).find_class('Projectile').find_functions('angle')[1].has_decorators('angle.setter')
`))})
Your angle method should set the value of the private __angle property.
({test: () => assert(runPython(`
a = Projectile(22, 23, 24)
a.angle = 12
a.angle == 12
`))})
import math
GRAVITATIONAL_ACCELERATION = 9.81
PROJECTILE = "∙"
x_axis_tick = "T"
y_axis_tick = "⊣"
class Projectile:
__slots__ = ('__speed', '__height', '__angle')
def __init__(self, speed, height, angle):
self.__speed = speed
self.__height = height
self.__angle = math.radians(angle)
def __str__(self):
return f'''
Projectile details:
speed: {self.__speed} m/s
height: {self.__height} m
angle: {round(math.degrees(self.__angle))}°
displacement: {round(self.__calculate_displacement(), 1)} m
'''
def __calculate_displacement(self):
horizontal_component = self.__speed * math.cos(self.__angle)
vertical_component = self.__speed * math.sin(self.__angle)
squared_component = vertical_component**2
gh_component = 2 * GRAVITATIONAL_ACCELERATION * self.__height
sqrt_component = math.sqrt(squared_component + gh_component)
return horizontal_component * (vertical_component + sqrt_component) / GRAVITATIONAL_ACCELERATION
def __calculate_y_coordinate(self, x):
height_component = self.__height
angle_component = math.tan(self.__angle) * x
acceleration_component = GRAVITATIONAL_ACCELERATION * x ** 2 / (
2 * self.__speed ** 2 * math.cos(self.__angle) ** 2)
y_coordinate = height_component + angle_component - acceleration_component
return y_coordinate
def calculate_all_coordinates(self):
return [
(x, self.__calculate_y_coordinate(x))
for x in range(math.ceil(self.__calculate_displacement()))
]
@property
def height(self):
return self.__height
@property
def angle(self):
return round(math.degrees(self.__angle))
@property
def speed(self):
return self.__speed
--fcc-editable-region--
--fcc-editable-region--
ball = Projectile(10, 3, 45)
print(ball)
coordinates = ball.calculate_all_coordinates()