The Spirit of the Assignment

I'm lazy. I used to argue that I was merely strategically lazy: that I knew enough about the problem domain to optimize out the rest of the work. Like tonight's homework in physics, which came down to a lot of operations on vectors such as rotations by arbitrary angles (in degrees OFC) and subsequent additions and soforth. Now vector math isn't hard at all. I've been doing it since high school, however it is laborious and rather easy to muck unless done carefully.

Usually when I encounter a set of problems which involve doing a tedious amount of work by hand I will resort to a program. Such as this one which I just "happen" to have lying around after this latest batch of homework.

#!/usr/bin/env python3

import math

class Vector():
    def fromXYZ(self, X, Y, Z):
        self.__x__ = X
        self.__y__ = Y
        self.__z__ = Z

    def fromPolar2D(self, mag, theta):
        self.__z__ = 0
        self.__y__ = math.sin(math.radians(theta)) * mag
        self.__x__ = math.cos(math.radians(theta)) * mag

    def thetaXY(self):
        return math.atan(self.__y__/self.__x__)

    def rotateX(self, deg):
        # Rotates the vector by `deg` degrees on the XY plane.
        magXY   = math.sqrt(self.__x__**2 + self.__y__**2)
        deltaXY = (deg*math.pi)/180.0

        theta = self.thetaXY() + deltaXY
        self.__y__ = math.sin(theta) * magXY
        self.__x__ = math.cos(theta) * magXY

    def magnatude(self):
        # computes the scalar magnatude of the vector
        return math.sqrt(self.__z__**2 +
        # this used to be math.sqrt(self.__x__**2+self.__y**2)**2
        # but then I realized that's stupid

    def normalize(self):
        v =  Vector()
        v.fromXYZ(self.__x__ / self.magnatude(),
                  self.__y__ / self.magnatude(),
                  self.__z__ / self.magnatude())
        return v

    def __add__(self, other):
        if(type(other) is Vector):
            v = Vector()
            v.fromXYZ(self.__x__ + other.__x__,
                      self.__y__ + other.__y__,
                      self.__z__ + other.__z__)
            return v

            raise Exception("can't add HUR DUR")

    def __iadd__(self, other):
        self = self.__add__(other)
        return self

    def __sub__(self, other):
        return other * -1 + self

    def __isub__(self, other):
        self = self - other

    def __mul__(self, other):
        if(type(other) is Vector):
            raise Exception("HUR DUR can't do dot product")
            v = Vector()
            v.fromXYZ(self.__x__ * other,
                      self.__y__ * other,
                      self.__z__ * other)
            return v

    def __imul__(self, other):
        self = self.__mul__(other)
        return self

    def __str__(self):
        return "< {0} {1} {2} >".format(self.__x__, self.__y__, self.__z__)

    def __repr__(self):
        return self.__str__()

It isn't much, and it sure isn't especially CPU efficient, but cranking out that implementation probably saved me 50% or so of the time I would otherwise have spent crunching the numbers by hand with a calculator. Strictly speaking I was less distracted while doing the homework because the distraction of the moment was productive with regards to completing the assignment.

But it violates the spirit of the assignment. The work was deliberately chosen to hammer into myself and the other physics students the mech