Back to Freecodecamp

Step 10

curriculum/challenges/english/blocks/learn-encapsulation-by-building-a-projectile-trajectory-calculator/662fc35902038376c7a00b3c.md

latest4.4 KB
Original Source

--description--

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:

py
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:

py
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.

--hints--

You should define a new speed method.

js
({test: () => assert(runPython(`
len(_Node(_code).find_class('Projectile').find_functions('speed')) == 2
`))})

Your new speed method should have a @speed.setter decorator.

js
({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.

js
({test: () => assert(runPython(`
a = Projectile(22, 23, 24)
a.speed = 33
a.speed == 33
`))})

You should define a new height method.

js
({test: () => assert(runPython(`
len(_Node(_code).find_class('Projectile').find_functions('height')) == 2
`))})

Your new height method should have a @height.setter decorator.

js
({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.

js
({test: () => assert(runPython(`
a = Projectile(22, 23, 24)
a.height = 44
a.height == 44
`))})

You should define a new angle method.

js
({test: () => assert(runPython(`
len(_Node(_code).find_class('Projectile').find_functions('angle')) == 2
`))})

Your new angle method should have a @angle.setter decorator.

js
({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.

js
({test: () => assert(runPython(`
a = Projectile(22, 23, 24)
a.angle = 12
a.angle == 12
`))})

--seed--

--seed-contents--

py
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()