0
\$\begingroup\$

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?

\$\endgroup\$
1
  • \$\begingroup\$ 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. \$\endgroup\$
    – vnp
    Jun 25 at 2:17

1 Answer 1

0
\$\begingroup\$

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.

Once the move is performed, ypu may check if you fell of the map, and adjust according to a topology.


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.

\$\endgroup\$
1
  • \$\begingroup\$ Ok thank you. I know that works because tests works. Maybe also tests should be placed here? But, .. your snippets are very go idiomatic. I really thank you! \$\endgroup\$
    – sensorario
    Jun 25 at 23:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.