開発環境
- macOS Catalina - Apple (OS)
- Emacs (Text Editor)
- Windows 10 Pro (OS)
- Visual Studio Code (Text Editor)
- Go (プログラミング言語)
入門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 コメント:
コメントを投稿