2020年2月20日木曜日

開発環境

入門Goプログラミング (Nathan Youngman(著)、Roger Peppé(著)、吉川 邦夫(監修, 翻訳)、翔泳社)のUNIT 7(並行プログラミング)、LESSON 32(チャレンジ:火星で生きるもの)の32.2(発見を報告する)の解答を求めてみる。

コード

package main

import (
 "fmt"
 "image"
 "math/rand"
 "sync"
 "time"
)

type marsGrid struct {
 mu         sync.Mutex
 rows, cols int
 cells      [][]cell
}
type cell struct {
 o    *occupier
 life int
}
type occupier struct {
 gridPtr *marsGrid
 pos     image.Point
}

func newMarsGrid(rows, cols int) *marsGrid {
 cells := [][]cell{}
 for i := 0; i < rows; i++ {
  cells = append(cells, []cell{})
  for j := 0; j < cols; j++ {
   cells[i] = append(cells[i], cell{o: nil, life: rand.Intn(1001)})
  }
 }
 return &marsGrid{rows: rows, cols: cols, cells: cells}
}

func (g *marsGrid) in(p image.Point) bool {
 return p.X >= 0 && p.X < g.cols && p.Y >= 0 && p.Y < g.rows
}
func (g *marsGrid) cell(p image.Point) *cell {
 if !g.in(p) {
  return nil
 }
 return &g.cells[p.Y][p.X]
}
func (g *marsGrid) occupy(p image.Point) *occupier {
 defer g.mu.Unlock()
 g.mu.Lock()
 cellPtr := g.cell(p)
 if cellPtr == nil || cellPtr.o != nil {
  return nil
 }
 cellPtr.o = &occupier{gridPtr: g, pos: p}
 return cellPtr.o
}

func (o *occupier) moveTo(p image.Point) bool {
 defer o.gridPtr.mu.Unlock()
 o.gridPtr.mu.Lock()
 cellPtr := o.gridPtr.cell(p)
 if cellPtr == nil || cellPtr.o != nil {
  return false
 }
 o.gridPtr.cell(o.pos).o = nil
 cellPtr.o = o
 o.pos = p
 return true
}

type command int

const (
 right = command(0)
 left  = command(1)
 start = command(2)
 stop  = command(3)
)

type roverDriver struct {
 commandc chan command
 n        int
 o        *occupier
 working  bool
}

func newRoverDriver(n int, o *occupier, msgc chan string) *roverDriver {
 r := &roverDriver{
  commandc: make(chan command),
  n:        n,
  o:        o,
 }
 go r.drive(msgc)
 return r
}

func (r *roverDriver) right() {
 r.commandc <- right
}
func (r *roverDriver) left() {
 r.commandc <- left
}
func (r *roverDriver) start() {
 r.commandc <- start
}
func (r *roverDriver) stop() {
 r.commandc <- stop
}
func (r *roverDriver) drive(msgc chan string) {
 direction := image.Point{X: 1, Y: 0}
 updateInterval := time.Second
 nextMove := time.After(updateInterval / 2)
 for {
  select {
  case c := <-r.commandc:
   switch c {
   case right:
    direction = image.Point{
     X: -direction.Y,
     Y: direction.X,
    }
   case left:
    direction = image.Point{
     X: direction.Y,
     Y: -direction.X,
    }
   case start:
    r.working = true
   default:
    r.working = false
   }
  case <-nextMove:
   if r.working {
    p := r.o.pos.Add(direction)
    moved := r.o.moveTo(p)
    if moved {
     fmt.Printf("%v号 %vへ移動\n", r.n, r.o.pos)
     life := r.o.gridPtr.cell(p).life
     if life >= 900 {
      msgc <- fmt.Sprintf(
       "%v号 位置%vに生命が存在する可能性があります。生命値%v",
       r.n, r.o.pos, life)
     }
    }
   }
   nextMove = time.After(updateInterval)
  }
 }
}

func receive(msgc chan string) {
 time.Sleep(time.Second * 10)
 fmt.Println(<-msgc)
}
func main() {
 rand.Seed(time.Now().UnixNano())
 rows := 50
 cols := 50
 gridPtr := newMarsGrid(rows, cols)
 roverDrivers := []*roverDriver{}
 msgc := make(chan string)
 go receive(msgc)

 for i := 1; i < 6; i++ {
  var o *occupier = nil
  for o == nil {
   y := rand.Intn(rows)
   x := rand.Intn(cols)
   o = gridPtr.occupy(image.Point{X: x, Y: y})
  }
  roverDrivers = append(roverDrivers, newRoverDriver(i, o, msgc))
 }
 for {
  r := roverDrivers[rand.Intn(len(roverDrivers))]
  switch command(rand.Intn(4)) {
  case right:
   r.right()
  case left:
   r.left()
  case start:
   r.start()
  default:
   r.stop()
  }
  time.Sleep(time.Second)
 }
}

入出力結果(Zsh、PowerShell、Terminal)

% go build rover.go
% ./rover          
3号 (45,2)へ移動
3号 (45,1)へ移動
3号 (45,0)へ移動
3号 位置(45,0)に生命が存在する可能性があります。生命値951
3号 (44,0)へ移動
2号 (47,9)へ移動
3号 (43,0)へ移動
2号 (46,9)へ移動
3号 (42,0)へ移動
2号 (45,9)へ移動
3号 (42,1)へ移動
2号 (44,9)へ移動
3号 (41,1)へ移動
3号 (40,1)へ移動
3号 (39,1)へ移動
3号 (38,1)へ移動
3号 (37,1)へ移動
3号 (36,1)へ移動
3号 (35,1)へ移動
3号 (34,1)へ移動
3号 (33,1)へ移動
^C
% ./rover
4号 (30,48)へ移動
4号 (31,48)へ移動
3号 (16,5)へ移動
4号 (31,47)へ移動
4号 (31,46)へ移動
4号 (31,45)へ移動
4号 (31,44)へ移動
4号 (31,43)へ移動
4号 (31,42)へ移動
3号 位置(16,5)に生命が存在する可能性があります。生命値956
3号 (16,6)へ移動
3号 (16,7)へ移動
3号 (16,8)へ移動
1号 (28,4)へ移動
1号 (29,4)へ移動
1号 (30,4)へ移動
^C
% 

0 コメント:

コメントを投稿