Open exklamationmark opened 6 years ago
I agree we should fix the problem of the description not matching well with the tests, but I'd like to think this through a bit before we launch into it.
How about if we make this problem a multi-step problem, changing the robot types as we go? I think it's fine to have them solve the easier problem first, then move on to the more difficult.
However... a fundamental tenant of exercism is that we try to avoid imposing any specific solution on the learner. I was concerned that the original version of the problem imposed too much structure. Your version imposes even more!
Can you come up with a way (try thinking in interfaces rather than in data structures) to test without imposing a solution? I'll take a thwack at it too 😈
hi @hilary, thanks for taking a stab at this.
I think it'd be interesting to make this a multi-step problem. Below is my take on a more proper exercise. Feel free to add your critiques.
Implement a simulation involving a bunch of named robots, a central controller and a room with obstacles (think Amazon warehouse). The controller operates in an environment with obstacles (some static, some dynamic, plus the robots are obstacle to other robots). It receives a command (e.g: robot A: advance
, robot B: turn left
, robot B: advance
, etc) and try to execute them.
We design the controller as a deterministic process: given an initial state and a sequence of commands, there is only one outcome. Our test will verify this.
Levels of difficulty is added by adding complexity into the situation.
Assuming the environment can be modelled as a grid and each robot occupy one single cell. We can progress like this:
This part is tricky to define as an exercism exercise. If I do this IRL, I would probably define the types used to model the system (e.g: Position, Direction, Command, etc), plus what interfaces are exposed to an external user.
Here, I made a decision not to allow individual robots to be controlled and to force all commands through a central controller. It'd be nice to see more suggestions on how to make this more flexible to students.
What I would define
type Position {
X, Y int
}
type Direction int
const (
North Direction = iota
East
South
East
)
type RobotCommand int
const (
Advance RobotCommand = iota
TurnLeft
TurnRight
)
type Command struct {
RobotName string
Cmd RobotCommand
}
// RobotManager handles one or more robots
type RobotManager interface {
// AddRobot add a single named robot. Adding might fail if the position is occupied.
AddRobot(name string, pos Position, direction Direction) error
// QueryLocation returns the location & direction of a named robot.
QueryLocation(name string) (Position, Direction)
// Execute try to perform an single command. Asking a robot to move out-of-bound or run into an obstacle should fail.
Execute(cmd Command) error
}
// RoomManager controls robots in a room with obstacle(s).
type RoomManager interface {
RobotManager
SetBoundary(bottomLeft, topRight Position)
AddStaticObstacle(pos Position) error // can't add on top of another obstacle
}
func NewRobotManager() RobotManager {
// TBD
}
func NewRoomManager() RoomManager {
// TBD
}
tests will probably be like this
func TestStage1(t *testing.T) {
mng := NewRobotManager()
// mng.AddRobot( ... )
// mng.Execute( ... )
// mng.Execute( ... )
// pos, direction := QueryLocation ( ... )
// assert
}
func TestStage2(t *testing.T) {
mng := NewRoomManager()
// mng.AddRobot( ... )
// mng.SetBoundary ( ... )
// mng.AddStaticObstacle ( ... )
// mng.Execute( ... )
// mng.Execute( ... )
// pos, direction := QueryLocation ( ... )
// assert
}
func TestStage3(t *testing.T) {
mng := NewRoomManager()
// mng.AddRobot( "alice" )
// mng.AddRobot( "bob" )
// mng.AddRobot( "eve" )
// mng.SetBoundary ( ... )
// mng.AddStaticObstacle ( ... )
// mng.Execute( "alice", ... )
// mng.Execute( "bob", ... )
// mng.Execute( "alice", ... )
// mng.Execute( "eve", ... )
// pos, direction := QueryLocation ( "alice", ... )
// assert
// pos, direction := QueryLocation ( "bob", ... )
// assert
// pos, direction := QueryLocation ( "eve", ... )
// assert
}
It's worth nothing that adding concurrency to this problem will be pretty hard, as the final state depends on some kind of execution order. Thus I left it out (compared to the current test).
wdyt? 😛
Short note: This issue still exists and should be addressed.
Hi,
I'm was trying to do the
robot-simulator
exercise. However, I found what was written in the README && what's in the test are very different.While I appreciate a more complex & closer-to-life simulation, which was presented in the test, it was not very clear what to do from the instructions alone.
What do you think about updating the exercise, such that:
P.S: I also don't fully agree with some of the types && test defined, so I made some changes