Estimating the Pythagorean Theorem

I wrote a function to calculate the distance between two positions:


   def distanceBetween(pos1, pos2):
        xDiff = pos2.x - pos1.x 
        yDiff = pos2.y - pos1.y
        dist = Math.sqrt(xDiff**2 + yDiff**2)
        #    self.say(dist)
        return(dist)

However, this seems to tax the system. If I use this function in Summit’s Gate, the Chrome Browser crashes. Even on my powerful desktop system.

I suggest using the following approximation:


   def distanceBetween(pos1, pos2):
        xDiff = pos2.x - pos1.x 
        yDiff = pos2.y - pos1.y
        if xDiff < 0 : 
            xDiff = -xDiff
        if yDiff < 0 : 
            yDiff = -yDiff

        if xDiff > yDiff : 
            dist = xDiff + 0.33 *yDiff
        else : 
            dist = yDiff + 0.33 *xDiff
        #    self.say(dist)
        return(dist)

The answer returned is within 6% of the exact value and avoids the square and square root functions.

(Note: I see an old topic which says that you should be able to call distanceTo on other objects, but that didn’t seem to be working for me. I will re-investigate.)

1 Like

Pretty cool! You should be able to get to our distance function if you have a Vector object, then you can do pos1.distance(pos2). If you have a unit or other visible object which has a pos, then you can do unit1.distanceTo(pos2). Note that the first is distance and the second is distanceTo, unfortunately.

If you just have two plain {x, y} objects, you can make one into a Vector to get access to distance like this: Vector(pos1.x, pos1.y).distance(pos2).

Also note that if you are just comparing distances and don’t care about the absolute value, you can always use pos1.distanceSquared(pos2) which also avoids the square root (the square root is the slow part).

Basically, everything you can do outside of player code will run a lot faster, because player code gets transpiled and error-checked and instrumented and all this stuff, whereas game engine code (even though it does the same things) just runs. CodeCombat’s implementation of Vector distance, for example, is pretty straightforward CoffeeScript:

  distance: (other, useZ) ->
    dx = @x - other.x
    dy = @y - other.y
    sum = dx * dx + dy * dy
    if useZ
      dz = @z - other.z
      sum += dz * dz
    Math.sqrt sum

  distanceSquared: (other, useZ) ->
    dx = @x - other.x
    dy = @y - other.y
    sum = dx * dx + dy * dy
    if useZ
      dz = @z - other.z
      sum += dz * dz
    sum

3 Likes

So an {x, y} object is not a vector by default? Probably that’s why some vector functions do not work with them?


I was trying to get the distance between a shells impact point and the catapult in Summit’s Gate, with varying results:

loop:
    shell = self.findNearest(self.findEnemyMissiles())
    catapult = self.findNearest(self.findByType("catapult"))
    if shell and catapult:
        self.say(shell +" "+ shell.targetPos.distance(catapult.pos))

This gives a certain value in the first few seconds, then it gives an error: “Cannot read property ‘distance’ of undefined”

I tried to make the first object a vector:

        self.say(shell +" "+ Vector(shell.targetPos).distance(catapult.pos))

This gives sometimes a NaN result, but if it “catches” a spear, I get a value.

I’m probably confusing things, but the situation is far from clear…

Hmm, I think probably you are finding the shell in the moment after it exploded but before it ceased to exist (while the explosion was ongoing). Maybe ignore shells without a targetPos? If shell.targetPos is defined, it’s already a Vector.

For reference, here’s the Vector class: https://github.com/codecombat/codecombat/blob/master/app/lib/world/vector.coffee

Thanks for the answer. I’m afraid it exceeds my understanding of code, but I will give it a try :smile: