# Ryan Martin
# macid: abcd123
# student number: #######
# November 23, 2011
#
#
# This is a solution for Major Assignment 5 (Lab 11) on Thursday.

class particle1D:

    def __init__(self, m, r0, v0, a0):
        self.m = float(m)
        self.r = float(r0)
        self.v = float(v0)
        self.a = float(a0)

    def getM(self):
        return self.m

    def getR(self):
        return self.r
    
    def getV(self):
        return self.v
    
    def getA(self):
        return self.a

    def update(self, delta_t):
        self.r = self.r + self.v * delta_t + 0.5 * self.a * delta_t**2
        self.v = self.v + self.a * delta_t

    def inelasticCollision(self, p):
        newM = self.m + p.getM()
        newV = (self.m * self.v + p.getM() * p.getV()) / newM
        return particle1D(newM, self.r, newV, 0)

def runInelasticCollisionSim(p1, p2, radius, delta_t):
    while abs(p1.getR() - p2.getR()) > radius:
        p1.update(delta_t)
        p2.update(delta_t)

    p3 = p1.inelasticCollision(p2)
    return p3


'''
Design Question

There are many ways of preventing the 'infinite loop' problem
in runInelasticCollisionSim. One obvious method would be to 
perform a check before the simulation starts, that returns
a message if one of the conditions that cause infinite loops
are true. However, there are many possible cases where an
infinite loop could occur, so this check could be quite large.
The cleanest way to do this would be to add an additional function
willCollide(p1, p2), that performs the check and returns a boolean
result, for instance.

Another solution could be to implement a maxTime parameter in
runInelasticCollision, that causes the simulation to exit
after running for a certain time or number of cycles. This
method takes out the need for a lengthy condition check,
but requires that the user estimate value for maxTime sufficiently
large enough that their simulation completes. If maxTime is 
set incorrectly, the simulation could exit even when it would
finish eventually.
'''
##Note: This format is used by our automated marking system.
##You will see that, for inputs, the class/function/method name is
##given with the corresponding inputs to that class/function/method
##listed right after it. The expected outputs are the state
##variables of the object after calling the function/method.
'''
Testing Report

THU = {'test1': 
       {'inputs': ['particle1D', [1, 0, 2, 0], 'update', [0.1]],
       'outputs': [testingClass(1, 0.2, 2, 0)]},
       'test2':
       {'inputs': ['particle1D', [2.5, -1.5, -1.5, 2], 'update', [0.2]],
       'outputs': [testingClass(2.5, -1.76, -1.1, 2.0)]},
       'test3':
       {'inputs': ['particle1D', [3, 0, 1, 1], 'inelasticCollision', [('particle1D', [2, 1, -2, -3])]],
       'outputs': [testingClass(5, 0, -0.2, 0)]},
       'test4':
       {'inputs': ['runInelasticCollisionSim', [('particle1D', [2, 1, 0.5, 0]), ('particle1D', [3, 0, 0, 1]), 0.1, 0.1]],
       'outputs': [testingClass(5, 2, 1.4, 0)]}}

'''