2020年5月17日日曜日

Go - 並行プログラミング - チャレンジ:火星で生きるもの - ローバーが移動するグリッド - 競合状態、syncパッケージ、Lock関数、Unlock関数、defer

x

コード

```package main

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

type occupier struct {
*marsGrid
pos image.Point
}

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

type cell struct {
*occupier
}
type marsGrid struct {
rect  image.Rectangle
cells [][]cell
mu    sync.Mutex
}

func newMarsGrid(p image.Point) *marsGrid {
cells := make([][]cell, p.Y)
for y := range cells {
cells[y] = make([]cell, p.X)
}
g := marsGrid{
rect:  image.Rectangle{Max: p},
cells: cells,
}
return &g
}
func (g *marsGrid) cell(p image.Point) *cell {
if !p.In(g.rect) {
return nil
}
return &g.cells[p.Y][p.X]
}
func (g *marsGrid) occupy(p image.Point) *occupier {
g.mu.Lock()
defer g.mu.Unlock()
cell := g.cell(p)
if cell == nil || cell.occupier != nil {
return nil
}
cell.occupier = &occupier{
marsGrid: g,
pos:      p,
}
return cell.occupier
}

type command int

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

type roverDriver struct {
commandc chan command
name     string
*occupier
}

func newRoverDriver(name string, o *occupier) *roverDriver {
r := &roverDriver{
commandc: make(chan command),
name:     name,
occupier: 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 := 250 * time.Millisecond
nextMove := time.After(updateInterval)
speed := 1
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:
speed = 1
case stop:
speed = 0
}
case <-nextMove:
if speed == 0 {
fmt.Printf("%vは位置(%v,%v)で停止中\n", r.name, r.pos.X, r.pos.Y)
} else {
if r.occupier.moveTo(pos) {
fmt.Printf("%vは位置(%v,%v)に移動完了\n", r.name, pos.X, pos.Y)
} else {
n := 1 + rand.Intn(3)
for i := 0; i < n; i++ {
direction = image.Point{
X: -direction.Y,
Y: direction.X,
}
}
fmt.Printf("%vは位置(%v,%v)に移動できず方向を%vに変更\n",
r.name, pos.X, pos.Y, direction)

}
}
nextMove = time.After(updateInterval)
}
}
}

func main() {
rand.Seed(time.Now().UnixNano())
width := 20
height := 10
g := newMarsGrid(image.Point{X: width, Y: height})
o1 := occupier{
marsGrid: g,
pos: image.Point{
X: rand.Intn(width / 2),
Y: rand.Intn(height / 2),
},
}
r1 := newRoverDriver("rover1", &o1)
o2 := occupier{
marsGrid: g,
pos: image.Point{
X: width/2 + rand.Intn(width/2),
Y: height/2 + rand.Intn(height/2),
},
}
r2 := newRoverDriver("rover2", &o2)
methods := []func(){
r1.right,
r1.left,
r1.start,
r1.stop,
r2.right,
r2.left,
r2.start,
r2.stop,
}
for _, method := range methods {
time.Sleep(time.Second)
method()
}
r1.start()
r2.start()
for i := 0; i < 10; i++ {
time.Sleep(time.Second)
methods[rand.Intn(len(methods))]()
}
}
```

```% go build marsgrid.go
% ./marsgrid
rover2は位置(19,5)に移動完了
rover1は位置(5,0)に移動完了
rover1は位置(6,0)に移動完了
rover2は位置(20,5)に移動できず方向を(0,1)に変更
rover2は位置(19,6)に移動完了
rover1は位置(7,0)に移動完了
rover2は位置(19,7)に移動完了
rover1は位置(7,1)に移動完了
rover1は位置(7,2)に移動完了
rover2は位置(19,8)に移動完了
rover1は位置(7,3)に移動完了
rover2は位置(19,9)に移動完了
rover1は位置(7,4)に移動完了
rover2は位置(19,10)に移動できず方向を(1,0)に変更
rover1は位置(8,4)に移動完了
rover2は位置(20,9)に移動できず方向を(0,-1)に変更
rover2は位置(19,8)に移動完了
rover1は位置(9,4)に移動完了
rover2は位置(19,7)に移動完了
rover1は位置(10,4)に移動完了
rover2は位置(19,6)に移動完了
rover1は位置(11,4)に移動完了
rover1は位置(12,4)に移動完了
rover2は位置(19,5)に移動完了
rover2は位置(19,4)に移動完了
rover1は位置(13,4)に移動完了
rover2は位置(19,3)に移動完了
rover1は位置(14,4)に移動完了
rover1は位置(15,4)に移動完了
rover2は位置(19,2)に移動完了
rover1は位置(15,4)で停止中
rover2は位置(19,1)に移動完了
rover2は位置(19,0)に移動完了
rover1は位置(15,4)で停止中
rover1は位置(15,4)で停止中
rover2は位置(19,-1)に移動できず方向を(1,0)に変更
rover1は位置(15,4)で停止中
rover2は位置(20,0)に移動できず方向を(0,-1)に変更
rover1は位置(15,4)で停止中
rover2は位置(20,0)に移動できず方向を(0,-1)に変更
rover1は位置(15,4)で停止中
rover2は位置(19,-1)に移動できず方向を(-1,0)に変更
rover2は位置(18,0)に移動完了
rover1は位置(15,4)で停止中
rover1は位置(15,4)で停止中
rover2は位置(17,0)に移動完了
rover1は位置(15,4)で停止中
rover2は位置(17,1)に移動完了
rover1は位置(15,4)で停止中
rover2は位置(17,2)に移動完了
rover1は位置(15,4)で停止中
rover2は位置(17,3)に移動完了
rover1は位置(15,4)で停止中
rover2は位置(17,4)に移動完了
rover1は位置(15,4)で停止中
rover2は位置(17,5)に移動完了
rover1は位置(15,4)で停止中
rover2は位置(17,6)に移動完了
rover2は位置(17,7)に移動完了
rover1は位置(15,4)で停止中
rover2は位置(17,8)に移動完了
rover1は位置(15,4)で停止中
rover1は位置(16,4)に移動完了
rover2は位置(17,9)に移動完了
rover1は位置(17,4)に移動完了
rover2は位置(17,10)に移動できず方向を(-1,0)に変更
rover2は位置(16,9)に移動完了
rover1は位置(18,4)に移動完了
rover2は位置(15,9)に移動完了
rover1は位置(19,4)に移動完了
rover2は位置(14,9)に移動完了
rover1は位置(19,4)で停止中
rover1は位置(19,4)で停止中
rover2は位置(13,9)に移動完了
rover2は位置(12,9)に移動完了
rover1は位置(19,4)で停止中
rover1は位置(19,4)で停止中
rover2は位置(11,9)に移動完了
rover2は位置(10,9)に移動完了
rover1は位置(19,4)で停止中
rover1は位置(19,4)で停止中
rover2は位置(9,9)に移動完了
rover2は位置(8,9)に移動完了
rover1は位置(19,4)で停止中
rover2は位置(7,9)に移動完了
rover1は位置(19,4)で停止中
rover2は位置(6,9)に移動完了
rover1は位置(19,4)で停止中
rover1は位置(19,4)で停止中
rover2は位置(5,9)に移動完了
rover1は位置(19,4)で停止中
rover2は位置(4,9)に移動完了
rover2は位置(3,9)に移動完了
rover1は位置(19,4)で停止中
rover1は位置(19,4)で停止中
rover2は位置(2,9)に移動完了
rover2は位置(1,9)に移動完了
rover1は位置(19,4)で停止中
rover1は位置(19,4)で停止中
rover2は位置(0,9)に移動完了
rover2は位置(-1,9)に移動できず方向を(0,-1)に変更
rover1は位置(19,4)で停止中
rover1は位置(19,4)で停止中
rover2は位置(0,8)に移動完了
rover2は位置(0,7)に移動完了
rover1は位置(19,4)で停止中
rover1は位置(19,4)で停止中
rover2は位置(0,6)に移動完了
rover1は位置(19,4)で停止中
rover2は位置(0,5)に移動完了
rover2は位置(0,4)に移動完了
rover1は位置(19,3)に移動完了
rover1は位置(19,2)に移動完了
rover2は位置(0,3)に移動完了
rover1は位置(19,1)に移動完了
rover2は位置(0,2)に移動完了
rover2は位置(0,1)に移動完了
rover1は位置(19,0)に移動完了
rover2は位置(0,0)に移動完了
rover1は位置(19,-1)に移動できず方向を(-1,0)に変更
rover1は位置(18,0)に移動完了
rover2は位置(0,-1)に移動できず方向を(0,1)に変更
rover1は位置(17,0)に移動完了
rover2は位置(0,1)に移動完了
rover2は位置(0,2)に移動完了
rover1は位置(16,0)に移動完了
rover2は位置(1,2)に移動完了
rover1は位置(15,0)に移動完了
rover1は位置(14,0)に移動完了
rover2は位置(2,2)に移動完了
rover1は位置(13,0)に移動完了
rover2は位置(3,2)に移動完了
rover2は位置(4,2)に移動完了
rover1は位置(12,0)に移動完了
rover2は位置(4,1)に移動完了
rover1は位置(11,0)に移動完了
rover1は位置(10,0)に移動完了
rover2は位置(4,0)に移動完了
rover1は位置(9,0)に移動完了
rover2は位置(4,-1)に移動できず方向を(1,0)に変更
rover2は位置(5,0)に移動完了
rover1は位置(8,0)に移動完了
% ./marsgrid
rover2は位置(16,5)に移動完了
rover1は位置(6,3)に移動完了
rover1は位置(7,3)に移動完了
rover2は位置(17,5)に移動完了
rover2は位置(18,5)に移動完了
rover1は位置(8,3)に移動完了
rover1は位置(8,4)に移動完了
rover2は位置(19,5)に移動完了
rover1は位置(8,5)に移動完了
rover2は位置(20,5)に移動できず方向を(0,1)に変更
rover2は位置(19,6)に移動完了
rover1は位置(8,6)に移動完了
rover2は位置(19,7)に移動完了
rover1は位置(8,7)に移動完了
rover2は位置(19,8)に移動完了
rover1は位置(9,7)に移動完了
rover1は位置(10,7)に移動完了
rover2は位置(19,9)に移動完了
rover1は位置(11,7)に移動完了
rover2は位置(19,10)に移動できず方向を(0,-1)に変更
rover1は位置(12,7)に移動完了
rover2は位置(19,8)に移動完了
rover1は位置(13,7)に移動完了
rover2は位置(19,7)に移動完了
rover2は位置(19,6)に移動完了
rover1は位置(14,7)に移動完了
rover1は位置(15,7)に移動完了
rover2は位置(19,5)に移動完了
rover2は位置(19,4)に移動完了
rover1は位置(16,7)に移動完了
rover2は位置(19,3)に移動完了
rover1は位置(16,7)で停止中
rover1は位置(16,7)で停止中
rover2は位置(19,2)に移動完了
rover2は位置(19,1)に移動完了
rover1は位置(16,7)で停止中
rover1は位置(16,7)で停止中
rover2は位置(19,0)に移動完了
rover1は位置(16,7)で停止中
rover2は位置(20,0)に移動できず方向を(-1,0)に変更
rover2は位置(18,0)に移動完了
rover1は位置(16,7)で停止中
rover1は位置(16,7)で停止中
rover2は位置(17,0)に移動完了
rover1は位置(16,7)で停止中
rover2は位置(16,0)に移動完了
rover2は位置(16,1)に移動完了
rover1は位置(16,7)で停止中
rover1は位置(16,7)で停止中
rover2は位置(16,2)に移動完了
rover2は位置(16,3)に移動完了
rover1は位置(16,7)で停止中
rover1は位置(16,7)で停止中
rover2は位置(16,4)に移動完了
rover2は位置(16,5)に移動完了
rover1は位置(16,7)で停止中
rover1は位置(16,7)で停止中
rover2は位置(16,6)に移動完了
rover1は位置(16,7)で停止中
rover2は位置(16,7)に移動できず方向を(-1,0)に変更
rover1は位置(16,7)で停止中
rover2は位置(15,6)に移動完了
rover2は位置(14,6)に移動完了
rover1は位置(17,7)に移動完了
rover2は位置(13,6)に移動完了
rover1は位置(18,7)に移動完了
rover1は位置(19,7)に移動完了
rover2は位置(12,6)に移動完了
rover1は位置(20,7)に移動できず方向を(0,1)に変更
rover2は位置(11,6)に移動完了
rover2は位置(11,6)で停止中
rover1は位置(19,8)に移動完了
rover2は位置(11,6)で停止中
rover1は位置(19,9)に移動完了
rover2は位置(11,6)で停止中
rover1は位置(19,10)に移動できず方向を(1,0)に変更
rover1は位置(20,9)に移動できず方向を(-1,0)に変更
rover2は位置(11,6)で停止中
rover2は位置(11,6)で停止中
rover1は位置(19,8)に移動完了
rover2は位置(11,6)で停止中
rover1は位置(19,7)に移動完了
rover1は位置(19,6)に移動完了
rover2は位置(11,6)で停止中
rover1は位置(19,5)に移動完了
rover2は位置(11,6)で停止中
rover2は位置(10,6)に移動完了
rover1は位置(19,4)に移動完了
rover1は位置(19,3)に移動完了
rover2は位置(9,6)に移動完了
rover2は位置(8,6)に移動完了
rover1は位置(19,2)に移動完了
rover1は位置(19,1)に移動完了
rover2は位置(7,6)に移動完了
rover2は位置(6,6)に移動完了
rover1は位置(19,1)で停止中
rover1は位置(19,1)で停止中
rover2は位置(5,6)に移動完了
rover2は位置(4,6)に移動完了
rover1は位置(19,1)で停止中
rover1は位置(19,1)で停止中
rover2は位置(3,6)に移動完了
rover2は位置(3,6)で停止中
rover1は位置(19,1)で停止中
rover2は位置(3,6)で停止中
rover1は位置(19,1)で停止中
rover1は位置(19,1)で停止中
rover2は位置(3,6)で停止中
rover2は位置(3,6)で停止中
rover1は位置(19,1)で停止中
rover1は位置(19,0)に移動完了
rover2は位置(3,6)で停止中
rover2は位置(3,6)で停止中
rover1は位置(19,-1)に移動できず方向を(0,1)に変更
rover2は位置(3,6)で停止中
rover1は位置(19,1)に移動完了
rover1は位置(19,2)に移動完了
rover2は位置(3,6)で停止中
rover2は位置(3,6)で停止中
rover1は位置(20,2)に移動できず方向を(0,-1)に変更
rover1は位置(19,1)に移動完了
rover2は位置(3,6)で停止中
rover1は位置(19,0)に移動完了
rover2は位置(3,6)で停止中
rover2は位置(3,6)で停止中
rover1は位置(19,-1)に移動できず方向を(-1,0)に変更
rover1は位置(18,0)に移動完了
rover2は位置(3,6)で停止中
rover2は位置(3,6)で停止中
rover1は位置(17,0)に移動完了
rover1は位置(16,0)に移動完了
rover2は位置(3,6)で停止中
rover2は位置(3,6)で停止中
rover1は位置(15,0)に移動完了
rover1は位置(14,0)に移動完了
rover2は位置(3,6)で停止中
rover1は位置(13,0)に移動完了
rover2は位置(3,6)で停止中
rover2は位置(3,6)で停止中
rover1は位置(12,0)に移動完了
rover1は位置(11,0)に移動完了
rover2は位置(3,6)で停止中
%
```