開発環境
- 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.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 コメント:
コメントを投稿