第七部分习题 - 图1

    第七部分习题 - 图2

    第七部分习题 - 图3

    gridrover.go

    1. package main
    2. import (
    3. "fmt"
    4. "image"
    5. "log"
    6. "math/rand"
    7. "sync"
    8. "time"
    9. )
    10. func main() {
    11. gridSize := image.Point{X: 20, Y: 10}
    12. grid := NewMarsGrid(gridSize)
    13. rover := make([]*RoverDriver, 5)
    14. for i := range rover {
    15. rover[i] = startDriver(fmt.Sprint("rover", i), grid)
    16. }
    17. time.Sleep(10 * time.Second)
    18. }
    19. func startDriver(name string, grid *MarsGrid) *RoverDriver {
    20. var o *Occupier
    21. // Try a random point; continue until we've found one that's
    22. // not currently occupied.
    23. for o == nil {
    24. startPoint := image.Point{X: rand.Intn(grid.Size().X), Y: rand.Intn(grid.Size().Y)}
    25. o = grid.Occupy(startPoint)
    26. }
    27. return NewRoverDriver(name, o)
    28. }
    29. // RoverDriver drives a rover around the surface of Mars.
    30. type RoverDriver struct {
    31. commandc chan command
    32. occupier *Occupier
    33. name string
    34. }
    35. // NewRoverDriver starts a new RoverDriver and returns it.
    36. func NewRoverDriver(name string, occupier *Occupier) *RoverDriver {
    37. r := &RoverDriver{
    38. commandc: make(chan command),
    39. occupier: occupier,
    40. name: name,
    41. }
    42. go r.drive()
    43. return r
    44. }
    45. type command int
    46. const (
    47. right command = 0
    48. left command = 1
    49. )
    50. // drive is responsible for driving the rover. It
    51. // is expected to be started in a goroutine.
    52. func (r *RoverDriver) drive() {
    53. log.Printf("%s initial position %v", r.name, r.occupier.Pos())
    54. direction := image.Point{X: 1, Y: 0}
    55. updateInterval := 250 * time.Millisecond
    56. nextMove := time.After(updateInterval)
    57. for {
    58. select {
    59. case c := <-r.commandc:
    60. switch c {
    61. case right:
    62. direction = image.Point{
    63. X: -direction.Y,
    64. Y: direction.X,
    65. }
    66. case left:
    67. direction = image.Point{
    68. X: direction.Y,
    69. Y: -direction.X,
    70. }
    71. }
    72. log.Printf("%s new direction %v", r.name, direction)
    73. case <-nextMove:
    74. nextMove = time.After(updateInterval)
    75. newPos := r.occupier.Pos().Add(direction)
    76. if r.occupier.MoveTo(newPos) {
    77. log.Printf("%s moved to %v", r.name, newPos)
    78. // Successfully moved to new position.
    79. break
    80. }
    81. log.Printf("%s blocked trying to move from %v to %v", r.name, r.occupier.Pos(), newPos)
    82. // Pick one of the other directions randomly.
    83. // Next time round, we'll try to move in the new
    84. // direction.
    85. dir := rand.Intn(3) + 1
    86. for i := 0; i < dir; i++ {
    87. direction = image.Point{
    88. X: -direction.Y,
    89. Y: direction.X,
    90. }
    91. }
    92. log.Printf("%s new random direction %v", r.name, direction)
    93. }
    94. }
    95. }
    96. // Left turns the rover left (90° anticlockwise).
    97. func (r *RoverDriver) Left() {
    98. r.commandc <- left
    99. }
    100. // Right turns the rover right (90° clockwise).
    101. func (r *RoverDriver) Right() {
    102. r.commandc <- right
    103. }
    104. // MarsGrid represents a grid of some of the surface
    105. // of Mars. It may be used concurrently by different
    106. // goroutines.
    107. type MarsGrid struct {
    108. bounds image.Rectangle
    109. mu sync.Mutex
    110. cells [][]cell
    111. }
    112. // SensorData holds information about whats in
    113. // a point in the grid.
    114. type SensorData struct {
    115. Life int
    116. }
    117. type cell struct {
    118. groundData SensorData
    119. occupier *Occupier
    120. }
    121. // NewMarsGrid returns a new MarsGrid of the
    122. // given size.
    123. func NewMarsGrid(size image.Point) *MarsGrid {
    124. grid := &MarsGrid{
    125. bounds: image.Rectangle{
    126. Max: size,
    127. },
    128. cells: make([][]cell, size.Y),
    129. }
    130. for i := range grid.cells {
    131. grid.cells[i] = make([]cell, size.X)
    132. }
    133. return grid
    134. }
    135. // Size returns the size of the grid.
    136. func (g *MarsGrid) Size() image.Point {
    137. return g.bounds.Max
    138. }
    139. // Occupy occupies a cell at the given point in the grid. It
    140. // returns nil if the point is already or the point is outside
    141. // the grid. Otherwise it returns a value that can be used
    142. // to move to different places on the grid.
    143. func (g *MarsGrid) Occupy(p image.Point) *Occupier {
    144. g.mu.Lock()
    145. defer g.mu.Unlock()
    146. cell := g.cell(p)
    147. if cell == nil || cell.occupier != nil {
    148. return nil
    149. }
    150. cell.occupier = &Occupier{
    151. grid: g,
    152. pos: p,
    153. }
    154. return cell.occupier
    155. }
    156. func (g *MarsGrid) cell(p image.Point) *cell {
    157. if !p.In(g.bounds) {
    158. return nil
    159. }
    160. return &g.cells[p.Y][p.X]
    161. }
    162. // Occupier represents an occupied cell in the grid.
    163. type Occupier struct {
    164. grid *MarsGrid
    165. pos image.Point
    166. }
    167. // MoveTo moves the occupier to a different cell in the grid.
    168. // It reports whether the move was successful
    169. // It might fail because it was trying to move outside
    170. // the grid or because the cell it's trying to move into
    171. // is occupied. If it fails, the occupier remains in the same place.
    172. func (o *Occupier) MoveTo(p image.Point) bool {
    173. o.grid.mu.Lock()
    174. defer o.grid.mu.Unlock()
    175. newCell := o.grid.cell(p)
    176. if newCell == nil || newCell.occupier != nil {
    177. return false
    178. }
    179. o.grid.cell(o.pos).occupier = nil
    180. newCell.occupier = o
    181. o.pos = p
    182. return true
    183. }
    184. // Sense returns sensory data from the current cell.
    185. func (o *Occupier) Sense() SensorData {
    186. o.grid.mu.Lock()
    187. defer o.grid.mu.Unlock()
    188. return o.grid.cell(o.pos).groundData
    189. }
    190. // Pos returns the current grid position of the occupier.
    191. func (o *Occupier) Pos() image.Point {
    192. return o.pos
    193. }

    lifeonmars.go

    1. package main
    2. import (
    3. "fmt"
    4. "image"
    5. "log"
    6. "math/rand"
    7. "sync"
    8. "time"
    9. )
    10. func main() {
    11. marsToEarth := make(chan []Message)
    12. go earthReceiver(marsToEarth)
    13. gridSize := image.Point{X: 20, Y: 10}
    14. grid := NewMarsGrid(gridSize)
    15. rover := make([]*RoverDriver, 5)
    16. for i := range rover {
    17. rover[i] = startDriver(fmt.Sprint("rover", i), grid, marsToEarth)
    18. }
    19. time.Sleep(60 * time.Second)
    20. }
    21. // Message holds a message as sent from Mars to Earth.
    22. type Message struct {
    23. Pos image.Point
    24. LifeSigns int
    25. Rover string
    26. }
    27. const (
    28. // The length of a Mars day.
    29. dayLength = 24 * time.Second
    30. // The length of time per day during which
    31. // messages can be transmitted from a rover to Earth.
    32. receiveTimePerDay = 2 * time.Second
    33. )
    34. // earthReceiver receives messages sent from Mars.
    35. // As connectivity is limited, it only receives messages
    36. // for some time every Mars day.
    37. func earthReceiver(msgc chan []Message) {
    38. for {
    39. time.Sleep(dayLength - receiveTimePerDay)
    40. receiveMarsMessages(msgc)
    41. }
    42. }
    43. // receiveMarsMessages receives messages sent from Mars
    44. // for the given duration.
    45. func receiveMarsMessages(msgc chan []Message) {
    46. finished := time.After(receiveTimePerDay)
    47. for {
    48. select {
    49. case <-finished:
    50. return
    51. case ms := <-msgc:
    52. for _, m := range ms {
    53. log.Printf("earth received report of life sign level %d from %s at %v", m.LifeSigns, m.Rover, m.Pos)
    54. }
    55. }
    56. }
    57. }
    58. func startDriver(name string, grid *MarsGrid, marsToEarth chan []Message) *RoverDriver {
    59. var o *Occupier
    60. // Try a random point; continue until we've found one that's
    61. // not currently occupied.
    62. for o == nil {
    63. startPoint := image.Point{X: rand.Intn(grid.Size().X), Y: rand.Intn(grid.Size().Y)}
    64. o = grid.Occupy(startPoint)
    65. }
    66. return NewRoverDriver(name, o, marsToEarth)
    67. }
    68. // Radio represents a radio transmitter that can send
    69. // message to Earth.
    70. type Radio struct {
    71. fromRover chan Message
    72. }
    73. // SendToEarth sends a message to Earth. It always
    74. // succeeds immediately - the actual message
    75. // may be buffered and actually transmitted later.
    76. func (r *Radio) SendToEarth(m Message) {
    77. r.fromRover <- m
    78. }
    79. // NewRadio returns a new Radio instance that sends
    80. // messages on the toEarth channel.
    81. func NewRadio(toEarth chan []Message) *Radio {
    82. r := &Radio{
    83. fromRover: make(chan Message),
    84. }
    85. go r.run(toEarth)
    86. return r
    87. }
    88. // run buffers messages sent by a rover until they
    89. // can be sent to Earth.
    90. func (r *Radio) run(toEarth chan []Message) {
    91. var buffered []Message
    92. for {
    93. toEarth1 := toEarth
    94. if len(buffered) == 0 {
    95. toEarth1 = nil
    96. }
    97. select {
    98. case m := <-r.fromRover:
    99. buffered = append(buffered, m)
    100. case toEarth1 <- buffered:
    101. buffered = nil
    102. }
    103. }
    104. }
    105. // RoverDriver drives a rover around the surface of Mars.
    106. type RoverDriver struct {
    107. commandc chan command
    108. occupier *Occupier
    109. name string
    110. radio *Radio
    111. }
    112. // NewRoverDriver starts a new RoverDriver and returns it.
    113. func NewRoverDriver(
    114. name string,
    115. occupier *Occupier,
    116. marsToEarth chan []Message,
    117. ) *RoverDriver {
    118. r := &RoverDriver{
    119. commandc: make(chan command),
    120. occupier: occupier,
    121. name: name,
    122. radio: NewRadio(marsToEarth),
    123. }
    124. go r.drive()
    125. return r
    126. }
    127. type command int
    128. const (
    129. right command = 0
    130. left command = 1
    131. )
    132. // drive is responsible for driving the rover. It
    133. // is expected to be started in a goroutine.
    134. func (r *RoverDriver) drive() {
    135. log.Printf("%s initial position %v", r.name, r.occupier.Pos())
    136. direction := image.Point{X: 1, Y: 0}
    137. updateInterval := 250 * time.Millisecond
    138. nextMove := time.After(updateInterval)
    139. for {
    140. select {
    141. case c := <-r.commandc:
    142. switch c {
    143. case right:
    144. direction = image.Point{
    145. X: -direction.Y,
    146. Y: direction.X,
    147. }
    148. case left:
    149. direction = image.Point{
    150. X: direction.Y,
    151. Y: -direction.X,
    152. }
    153. }
    154. log.Printf("%s new direction %v", r.name, direction)
    155. case <-nextMove:
    156. nextMove = time.After(updateInterval)
    157. newPos := r.occupier.Pos().Add(direction)
    158. if r.occupier.MoveTo(newPos) {
    159. log.Printf("%s moved to %v", r.name, newPos)
    160. r.checkForLife()
    161. break
    162. }
    163. log.Printf("%s blocked trying to move from %v to %v", r.name, r.occupier.Pos(), newPos)
    164. // Pick one of the other directions randomly.
    165. // Next time round, we'll try to move in the new
    166. // direction.
    167. dir := rand.Intn(3) + 1
    168. for i := 0; i < dir; i++ {
    169. direction = image.Point{
    170. X: -direction.Y,
    171. Y: direction.X,
    172. }
    173. }
    174. log.Printf("%s new random direction %v", r.name, direction)
    175. }
    176. }
    177. }
    178. func (r *RoverDriver) checkForLife() {
    179. // Successfully moved to new position.
    180. sensorData := r.occupier.Sense()
    181. if sensorData.LifeSigns < 900 {
    182. return
    183. }
    184. r.radio.SendToEarth(Message{
    185. Pos: r.occupier.Pos(),
    186. LifeSigns: sensorData.LifeSigns,
    187. Rover: r.name,
    188. })
    189. }
    190. // Left turns the rover left (90° counterclockwise).
    191. func (r *RoverDriver) Left() {
    192. r.commandc <- left
    193. }
    194. // Right turns the rover right (90° clockwise).
    195. func (r *RoverDriver) Right() {
    196. r.commandc <- right
    197. }
    198. // MarsGrid represents a grid of some of the surface
    199. // of Mars. It may be used concurrently by different
    200. // goroutines.
    201. type MarsGrid struct {
    202. bounds image.Rectangle
    203. mu sync.Mutex
    204. cells [][]cell
    205. }
    206. // SensorData holds information about what's in
    207. // a point in the grid.
    208. type SensorData struct {
    209. LifeSigns int
    210. }
    211. type cell struct {
    212. groundData SensorData
    213. occupier *Occupier
    214. }
    215. // NewMarsGrid returns a new MarsGrid of the
    216. // given size.
    217. func NewMarsGrid(size image.Point) *MarsGrid {
    218. grid := &MarsGrid{
    219. bounds: image.Rectangle{
    220. Max: size,
    221. },
    222. cells: make([][]cell, size.Y),
    223. }
    224. for y := range grid.cells {
    225. grid.cells[y] = make([]cell, size.X)
    226. for x := range grid.cells[y] {
    227. cell := &grid.cells[y][x]
    228. cell.groundData.LifeSigns = rand.Intn(1000)
    229. }
    230. }
    231. return grid
    232. }
    233. // Size returns a Point representing the size of the grid.
    234. func (g *MarsGrid) Size() image.Point {
    235. return g.bounds.Max
    236. }
    237. // Occupy occupies a cell at the given point in the grid. It
    238. // returns nil if the point is already occupied or the point is outside
    239. // the grid. Otherwise it returns a value that can be used
    240. // to move to different places on the grid.
    241. func (g *MarsGrid) Occupy(p image.Point) *Occupier {
    242. g.mu.Lock()
    243. defer g.mu.Unlock()
    244. cell := g.cell(p)
    245. if cell == nil || cell.occupier != nil {
    246. return nil
    247. }
    248. cell.occupier = &Occupier{
    249. grid: g,
    250. pos: p,
    251. }
    252. return cell.occupier
    253. }
    254. func (g *MarsGrid) cell(p image.Point) *cell {
    255. if !p.In(g.bounds) {
    256. return nil
    257. }
    258. return &g.cells[p.Y][p.X]
    259. }
    260. // Occupier represents an occupied cell in the grid.
    261. type Occupier struct {
    262. grid *MarsGrid
    263. pos image.Point
    264. }
    265. // MoveTo moves the occupier to a different cell in the grid.
    266. // It reports whether the move was successful
    267. // It might fail because it was trying to move outside
    268. // the grid or because the cell it's trying to move into
    269. // is occupied. If it fails, the occupier remains in the same place.
    270. func (o *Occupier) MoveTo(p image.Point) bool {
    271. o.grid.mu.Lock()
    272. defer o.grid.mu.Unlock()
    273. newCell := o.grid.cell(p)
    274. if newCell == nil || newCell.occupier != nil {
    275. return false
    276. }
    277. o.grid.cell(o.pos).occupier = nil
    278. newCell.occupier = o
    279. o.pos = p
    280. return true
    281. }
    282. // Sense returns sensory data from the current cell.
    283. func (o *Occupier) Sense() SensorData {
    284. o.grid.mu.Lock()
    285. defer o.grid.mu.Unlock()
    286. return o.grid.cell(o.pos).groundData
    287. }
    288. // Pos returns the current grid position of the occupier.
    289. func (o *Occupier) Pos() image.Point {
    290. return o.pos
    291. }

    marsgrid.go

    1. package main
    2. import (
    3. "image"
    4. "sync"
    5. )
    6. func main() {
    7. }
    8. // MarsGrid represents a grid of some of the surface
    9. // of Mars. It may be used concurrently by different
    10. // goroutines.
    11. type MarsGrid struct {
    12. bounds image.Rectangle
    13. mu sync.Mutex
    14. cells [][]cell
    15. }
    16. // cell holds information about a given cell in
    17. // the grid.
    18. type cell struct {
    19. occupier *Occupier
    20. }
    21. // NewMarsGrid returns a new MarsGrid of the
    22. // given size.
    23. func NewMarsGrid(size image.Point) *MarsGrid {
    24. grid := &MarsGrid{
    25. bounds: image.Rectangle{
    26. Max: size,
    27. },
    28. cells: make([][]cell, size.Y),
    29. }
    30. for i := range grid.cells {
    31. grid.cells[i] = make([]cell, size.X)
    32. }
    33. return grid
    34. }
    35. // Size returns the size of the grid.
    36. func (g *MarsGrid) Size() image.Point {
    37. return g.bounds.Max
    38. }
    39. // Occupy occupies a cell at the given point in the grid. It
    40. // returns nil if the point is already or the point is outside
    41. // the grid. Otherwise it returns a value that can be used
    42. // to move to different places on the grid.
    43. func (g *MarsGrid) Occupy(p image.Point) *Occupier {
    44. g.mu.Lock()
    45. defer g.mu.Unlock()
    46. cell := g.cell(p)
    47. if cell == nil || cell.occupier != nil {
    48. return nil
    49. }
    50. cell.occupier = &Occupier{
    51. grid: g,
    52. pos: p,
    53. }
    54. return cell.occupier
    55. }
    56. // cell returns a pointer to the cell at the
    57. // given position, or nil if it's outside
    58. // the grid.
    59. func (g *MarsGrid) cell(p image.Point) *cell {
    60. if !p.In(g.bounds) {
    61. return nil
    62. }
    63. return &g.cells[p.Y][p.X]
    64. }
    65. // Occupier represents an occupied cell in the grid.
    66. type Occupier struct {
    67. grid *MarsGrid
    68. pos image.Point
    69. }
    70. // MoveTo moves the occupier to a different cell in the grid.
    71. // It reports whether the move was successful
    72. // It might fail because it was trying to move outside
    73. // the grid or because the cell it's trying to move into
    74. // is occupied. If it fails, the occupier remains in the same place.
    75. func (o *Occupier) MoveTo(p image.Point) bool {
    76. o.grid.mu.Lock()
    77. defer o.grid.mu.Unlock()
    78. newCell := o.grid.cell(p)
    79. if newCell == nil || newCell.occupier != nil {
    80. return false
    81. }
    82. o.grid.cell(o.pos).occupier = nil
    83. newCell.occupier = o
    84. o.pos = p
    85. return true
    86. }
    87. // Pos returns the current grid position of the occupier.
    88. func (o *Occupier) Pos() image.Point {
    89. return o.pos
    90. }