Simulating pod racing over a 2D map : am I implementing OOP in a GO-like fashion? I'm learning Go and I wrote this for a programming challenge. It is working (building and running) but I feel the code is not what Go code should be.

I used an OOP design. Is it correctly implemented in GO ? 

In my main, I will call the method pod.playTurn(target, speed)

package main

import (
    "fmt"
    "math"
    "os"
    "strconv"
)
// Dot is king
type Dot struct {
    x, y int
}
// Pod is life
type Pod struct {
    position                Dot
    vx, vy, angle, nextCpID int
    hasShieldOn             bool
}

func squaredDist(a, b Dot) int {
    return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y)
}
func distance(a, b Dot) float64 {
    return math.Sqrt(float64(squaredDist(a, b)))
}

func (pod Pod) getAngle(p Dot) float64 {
    d := distance(p, pod.position)
    dx := float64(p.x-pod.position.x) / d
    dy := float64(p.y-pod.position.y) / d
    a := math.Acos(dx) * 180.0 / math.Pi

    // If the point I want is below me, I have to shift the angle for it to be correct
    if dy &lt; 0 {
        a = 360.0 - a
    }
    return a
}

func (pod Pod) diffAngle(p Dot) float64 {
    a := pod.getAngle(p)
    pangle := float64(pod.angle)

    right := 0.0
    if pangle &lt;= a {
        right = a - pangle
    } else {
        right = 360.0 - pangle + a
    }

    left := 0.0
    if pangle &gt;= a {
        left = pangle - a
    } else {
        left = pangle + 360.0 - a
    }

    if right &lt; left {
        return right
    }
    return -left
}

func (pod Pod) rotate(p Dot) int {
    a := pod.diffAngle(p)

    // Can't turn more than 18° in one turn !
    if a &gt; 18.0 {
        a = 18.0
    } else if a &lt; -18.0 {
        a = -18.0
    }

    pod.angle += int(math.Round(a))

    if pod.angle &gt;= 360.0 {
        pod.angle = pod.angle - 360.0
    } else if pod.angle &lt; 0.0 {
        pod.angle += 360.0
    }
    return pod.angle
}

func (pod Pod) boost(t int) (int, int) {
    if pod.hasShieldOn {
        return pod.vx, pod.vy
    }
    pangle := float64(pod.angle)
    pod.vx += int(math.Round(math.Cos(pangle) * float64(t)))
    pod.vy += int(math.Round(math.Sin(pangle) * float64(t)))
    return pod.vx, pod.vy
}

// t shoud become a float later on
func (pod Pod) move(t int) (int, int) {
    pod.position.x += pod.vx * t
    pod.position.y += pod.vy * t
    return pod.position.x, pod.position.y
}

func (pod Pod) endTurn() (int, int) {
    // todo rounding position if needed
    pod.vx = int(float64(pod.vx) * 0.85)
    pod.vy = int(float64(pod.vy) * 0.85)
    return pod.vx, pod.vy
}

func (pod Pod) playTurn(p Dot, t int) {
    pod.angle = pod.rotate(p)
    pod.vx, pod.vy = pod.boost(t)
    pod.position.x, pod.position.y = pod.move(1)
    pod.vx, pod.vy = pod.endTurn()
    fmt.Fprintf(os.Stderr, "\nPredicted Pod position : ")
    fmt.Fprintf(os.Stderr, "\n(%d, %d) speed (%d,%d)", pod.position.x, pod.position.y, pod.vx, pod.vy)
}


Am I using struct correctly ? Is it acceptable object oriented code ?
As per request in the comment, here's an implementation of the rotate function in a more idiomatic golang way (ie using a pointer receiver):

// let's use constants so code becomes self-documenting
const (
    maxRotation float64 = 18 // max rotation as typed constant
    fullCircle  int     = 360 // just like all hard-coded values, let's use constants
    semiCircle  int     = fullCirle/2 // do this for all hard-coded values
)

// note the receiver is a pointer, and there's no return value
func (pod *Pod) rotate(p Dot) {
    a := pod.diffAngle(p)

    if a &gt; maxRotation {
        a = maxRotation
    } else if a &lt; -maxRotation {
        a = -maxRotation
    }

    pod.angle += int(math.Round(a))

    var add int // add this value, defaults to 0
    // you are comparing pod.angle (an int) to a float64 (360.0)
    // that shouldn't be happening. I'd say angle should be a float64
    // but keeping the fields in pod the types they are for now
    if pod.angle &gt;= fullCircle {
        add -= fullCircle
    } else if pod.angle &lt; 0 {
        add = fullCircle
    }
    pod.angle += add // adds 0, 360, or -360 depending on the new value for pod.angle
}


That's all there is to it, really. Instead of calling it like this:

pod.angle = pod.rotate(p)


You simply call it like this:

pod.rotate(p)


The value of pod.angle will be updated. If you start doing this stuff concurrently, you'll need to ensure that pod.rotate() is "thread-safe" (ignoring the fact that goroutines aren't really threads for a second). The easiest way to do this is using a sync.Mutex (or sync.RWMutex), to make sure that you're not accidentally updating pod.angle in 2 routines etc...

I might revisit this stuff to give a more detailed review, so stay tuned for updates.