95 lines
3.4 KiB
Go
95 lines
3.4 KiB
Go
// +build step2 !step1,!step3
|
|
|
|
package robot
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
)
|
|
|
|
// For step 1 you implement robot movements, but it's not much of a simulation.
|
|
// For example where in the source code is "the robot"? Where is "the grid"?
|
|
// Where are the computations that turn robot actions into grid positions,
|
|
// in the robot or in the grid? The physical world is different.
|
|
//
|
|
// Step 2 introduces a "room." It seems a small addition, but we'll make
|
|
// big changes to clarify the rolls of "room", "robot", and "test program"
|
|
// and begin to clarify the physics of the simulation. You will define Room
|
|
// and Robot as functions which the test program "brings into existence" by
|
|
// launching them as goroutines. Information moves between test program,
|
|
// robot, and room over Go channels.
|
|
//
|
|
// Think of Room as a "physics engine," something that models and simulates
|
|
// a physical room with walls and a robot. It should somehow model the
|
|
// coordinate space of the room, the location of the robot and the walls,
|
|
// and ensure for example that the robot doesn't walk through walls.
|
|
// We want Robot to be an agent that performs actions, but we want Room to
|
|
// maintain a coherent truth.
|
|
//
|
|
// Step 2 API:
|
|
//
|
|
// StartRobot(chan Command, chan Action)
|
|
// Room(extent Rect, robot Step2Robot, act chan Action, rep chan Step2Robot)
|
|
//
|
|
// You get to define Action; see defs.go for other definitions.
|
|
//
|
|
// The test program creates the channels and starts both Room and Robot.
|
|
// The test program then sends commands to Robot. When it is done sending
|
|
// commands, it closes the command channel. Robot must accept commands and
|
|
// inform Room of actions it is attempting. When it senses the command channel
|
|
// closing, it must shut down itself. The room must interpret the physical
|
|
// consequences of the robot actions. When it senses the robot shutting down,
|
|
// it sends a final report back to the test program, telling the robot's final
|
|
// position and direction.
|
|
|
|
var test2 = []struct {
|
|
Command
|
|
Step2Robot
|
|
}{
|
|
0: {' ', Step2Robot{N, Pos{1, 1}}}, // no command, this is the start DirAt
|
|
1: {'A', Step2Robot{N, Pos{1, 2}}},
|
|
2: {'R', Step2Robot{E, Pos{1, 2}}},
|
|
3: {'A', Step2Robot{E, Pos{2, 2}}},
|
|
4: {'L', Step2Robot{N, Pos{2, 2}}},
|
|
5: {'L', Step2Robot{W, Pos{2, 2}}},
|
|
6: {'L', Step2Robot{S, Pos{2, 2}}},
|
|
7: {'A', Step2Robot{S, Pos{2, 1}}},
|
|
8: {'R', Step2Robot{W, Pos{2, 1}}},
|
|
9: {'A', Step2Robot{W, Pos{1, 1}}},
|
|
10: {'A', Step2Robot{W, Pos{1, 1}}}, // bump W wall
|
|
11: {'L', Step2Robot{S, Pos{1, 1}}},
|
|
12: {'A', Step2Robot{S, Pos{1, 1}}}, // bump S wall
|
|
13: {'L', Step2Robot{E, Pos{1, 1}}},
|
|
14: {'A', Step2Robot{E, Pos{2, 1}}},
|
|
15: {'A', Step2Robot{E, Pos{2, 1}}}, // bump E wall
|
|
16: {'L', Step2Robot{N, Pos{2, 1}}},
|
|
17: {'A', Step2Robot{N, Pos{2, 2}}},
|
|
18: {'A', Step2Robot{N, Pos{2, 2}}}, // bump N wall
|
|
}
|
|
|
|
func TestStep2(t *testing.T) {
|
|
// run incrementally longer tests
|
|
for i := 1; i <= len(test2); i++ {
|
|
cmd := make(chan Command)
|
|
act := make(chan Action)
|
|
rep := make(chan Step2Robot)
|
|
go StartRobot(cmd, act)
|
|
go Room(Rect{Pos{1, 1}, Pos{2, 2}}, test2[0].Step2Robot, act, rep)
|
|
fmt.Println("Starting Tests")
|
|
for j := 1; j < i; j++ {
|
|
fmt.Println("Channeling: ", test2[j])
|
|
cmd <- test2[j].Command
|
|
}
|
|
close(cmd)
|
|
da := <-rep
|
|
last := i - 1
|
|
want := test2[last].Step2Robot
|
|
if da.Pos != want.Pos {
|
|
t.Fatalf("Command #%d, Pos = %v, want %v", last, da.Pos, want.Pos)
|
|
}
|
|
if da.Dir != want.Dir {
|
|
t.Fatalf("Command #%d, Dir = %v, want %v", last, da.Dir, want.Dir)
|
|
}
|
|
}
|
|
}
|