2020年2月19日水曜日

開発環境

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

コード

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
}
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})
  }
 }
 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
}

func newRoverDriver(n int, o *occupier) *roverDriver {
 r := &roverDriver{
  commandc: make(chan command),
  n:        n,
  o:        o,
 }
 go r.drive()
 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() {
 direction := image.Point{X: 1, Y: 0}
 updateInterval := time.Second / 2
 nextMove := time.After(updateInterval)
 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 <-nextMove:
   p := r.o.pos.Add(direction)
   moved := r.o.moveTo(p)
   if moved {
    fmt.Printf("%v番 %vへ移動\n", r.n, r.o.pos)
   }
   nextMove = time.After(updateInterval)
  }
 }
}

func main() {
 rand.Seed(time.Now().UnixNano())
 rows := 10
 cols := 10
 gridPtr := newMarsGrid(rows, cols)
 roverDrivers := []*roverDriver{}
 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))
 }
 for i := 0; i < 20; i++ {
  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 run ./rover.go
1番 (6,0)へ移動
5番 (5,2)へ移動
2番 (9,3)へ移動
3番 (1,7)へ移動
4番 (3,6)へ移動
5番 (6,2)へ移動
4番 (4,6)へ移動
1番 (7,0)へ移動
3番 (2,7)へ移動
3番 (3,7)へ移動
5番 (7,2)へ移動
4番 (5,6)へ移動
3番 (4,7)へ移動
5番 (8,2)へ移動
4番 (6,6)へ移動
4番 (7,6)へ移動
3番 (5,7)へ移動
1番 (6,0)へ移動
5番 (9,2)へ移動
3番 (6,7)へ移動
1番 (5,0)へ移動
4番 (8,6)へ移動
3番 (7,7)へ移動
4番 (9,6)へ移動
1番 (4,0)へ移動
1番 (3,0)へ移動
3番 (8,7)へ移動
1番 (2,0)へ移動
3番 (8,8)へ移動
3番 (8,9)へ移動
1番 (1,0)へ移動
1番 (0,0)へ移動
1番 (0,1)へ移動
1番 (0,2)へ移動
1番 (0,3)へ移動
1番 (0,4)へ移動
1番 (0,5)へ移動
1番 (0,6)へ移動
4番 (9,7)へ移動
4番 (9,8)へ移動
4番 (9,9)へ移動
5番 (9,1)へ移動
5番 (9,0)へ移動
2番 (9,4)へ移動
2番 (9,5)へ移動
2番 (9,6)へ移動
2番 (9,7)へ移動
2番 (9,8)へ移動
1番 (0,7)へ移動
1番 (0,8)へ移動
1番 (0,9)へ移動
% go run ./rover.go
3番 (1,0)へ移動
4番 (2,7)へ移動
5番 (5,7)へ移動
1番 (1,8)へ移動
2番 (5,4)へ移動
2番 (6,4)へ移動
4番 (3,7)へ移動
1番 (2,8)へ移動
3番 (2,0)へ移動
5番 (6,7)へ移動
2番 (7,4)へ移動
4番 (4,7)へ移動
5番 (7,7)へ移動
1番 (3,8)へ移動
3番 (3,0)へ移動
4番 (5,7)へ移動
2番 (7,3)へ移動
1番 (4,8)へ移動
5番 (8,7)へ移動
3番 (4,0)へ移動
2番 (7,2)へ移動
4番 (6,7)へ移動
5番 (9,7)へ移動
3番 (5,0)へ移動
1番 (5,8)へ移動
3番 (6,0)へ移動
1番 (6,8)へ移動
2番 (7,1)へ移動
4番 (7,7)へ移動
4番 (8,7)へ移動
1番 (7,8)へ移動
2番 (7,0)へ移動
2番 (8,0)へ移動
1番 (8,8)へ移動
2番 (9,0)へ移動
1番 (9,8)へ移動
3番 (7,0)へ移動
3番 (8,0)へ移動
4番 (9,7)へ移動
5番 (9,6)へ移動
5番 (9,5)へ移動
5番 (9,4)へ移動
5番 (9,3)へ移動
5番 (9,2)へ移動
5番 (9,1)へ移動
% 

0 コメント:

コメントを投稿