# go mars rover kata go

A kata is an exercise. In martial art is form. In software development is a way to practicing. For example in TDD.

Mars rover kata aims to solve some problem in the context of the mars rover. Here you can find a list of kata. kata-log.rocks/mars-rover-kata Kata are exercises you can use to practicing in tdd, in pair or alone.

Mars rover kata rules are:

• You are given the initial starting point (x,y) of a rover and the direction (N,S,E,W) it is facing.
• The rover receives a character array of commands.
• Implement commands that move the rover forward/backward (f,b).
• Implement commands that turn the rover left/right (l,r).
• Implement wrapping at edges. But be careful, planets are spheres. - Connect the x edge to the other x edge, so (1,1) for x-1 to (5,1), but connect vertical edges towards themselves in inverted coordinates, so (1,1) for y-1 connects to (5,1).
• Implement obstacle detection before each move to a new square. If a given sequence of commands encounters an obstacle, the rover moves up to the last possible point, aborts the sequence and reports the obstacle.

I am playing with mars rover kata and this is the complete result:

package main

import (
"fmt"
)

type Point struct {
x int
y int
}

type Sphere struct {
firstCorner Point
lastCorner Point
obstacles []Point
}

type Rover struct {
position Point
direction string
world Sphere
}

func (r *Rover) moves (moves []string) {
for _, m := range moves {
r.move(m)
}
}

func (r *Rover) move (command string) {
if command == "l" {
if r.direction == "e" { r.direction = "n"; return }
if r.direction == "s" { r.direction = "e"; return }
if r.direction == "w" { r.direction = "s"; return }
if r.direction == "n" { r.direction = "w"; return }
}
if command == "r" {
if r.direction == "n" { r.direction = "e"; return }
if r.direction == "e" { r.direction = "s"; return }
if r.direction == "s" { r.direction = "w"; return }
if r.direction == "w" { r.direction = "n"; return }
}
if command == "f" {
if r.direction == "n" { r.update(r.position.x,r.position.y+1) }
if r.direction == "s" { r.update(r.position.x,r.position.y-1) }
if r.direction == "w" { r.update(r.position.x-1,r.position.y) }
if r.direction == "e" { r.update(r.position.x+1,r.position.y) }
}
if command == "b" {
if r.direction == "n" { r.update(r.position.x,r.position.y-1) }
if r.direction == "s" { r.update(r.position.x,r.position.y+1) }
if r.direction == "w" { r.update(r.position.x+1,r.position.y) }
if r.direction == "e" { r.update(r.position.x-1,r.position.y) }
}
}

func (r *Rover) update (x int, y int) {
if y > r.world.lastCorner.y {
x,y = r.world.lastCorner.y,x
}

if y < r.world.firstCorner.y {
x,y = r.world.lastCorner.y,r.world.lastCorner.x
}

if x < r.world.firstCorner.x {
x,y = r.world.lastCorner.x, r.world.firstCorner.y
}

if x > r.world.lastCorner.x {
x,y = r.world.firstCorner.x, r.world.firstCorner.y
}

isFree := true
destination := Point{x,y}
for _, obstacle := range r.world.obstacles {
if obstacle.x == destination.x && obstacle.y == destination.y {
isFree = false
}
}
if isFree == true {
r.position = destination
}
}

func main() {
fmt.Println("Mars Rover Kata!")
}


I guess there is a way to simplify this code:


func (r *Rover) move (command string) {
if command == "l" {
if r.direction == "e" { r.direction = "n"; return }
if r.direction == "s" { r.direction = "e"; return }
if r.direction == "w" { r.direction = "s"; return }
if r.direction == "n" { r.direction = "w"; return }
}
if command == "r" {
if r.direction == "n" { r.direction = "e"; return }
if r.direction == "e" { r.direction = "s"; return }
if r.direction == "s" { r.direction = "w"; return }
if r.direction == "w" { r.direction = "n"; return }
}
if command == "f" {
if r.direction == "n" { r.update(r.position.x,r.position.y+1) }
if r.direction == "s" { r.update(r.position.x,r.position.y-1) }
if r.direction == "w" { r.update(r.position.x-1,r.position.y) }
if r.direction == "e" { r.update(r.position.x+1,r.position.y) }
}
if command == "b" {
if r.direction == "n" { r.update(r.position.x,r.position.y-1) }
if r.direction == "s" { r.update(r.position.x,r.position.y+1) }
if r.direction == "w" { r.update(r.position.x+1,r.position.y) }
if r.direction == "e" { r.update(r.position.x-1,r.position.y) }
}
}


But I am also afraid to move into unnecessary simplification. I mean: code could be better for computers but worst for humans. And since I am on the side of humans I think this code is good enough. But I also know that go have some idiomatic stuff that can make this code better. Any suggestion?

• When x wraps around on a sphere, y should stay put. The topology defined by the code looks more like a projective plane to me. Correct me if I am wrong.
– vnp
Jun 25 at 2:17

Represent a direction as a dx, dy tuple (rather than special-casing n,s,w,e. This way, a left turn is dx, dy = -dy, dx and a right turn is dx, dy = dy, -dx.
Likewise, a forward move is x += dx, y += dy and a backward one is x -= dx, y -= dy.
Your update doesn't seem to describe the sphere. For example, passing the North Pole on the way to North shall make the rover face South. I don't see the change of direction whatsoever.