package main
import (
"bufio"
"fmt"
"math/rand"
"os"
"time"
)
//ドアにはノブがついている
//ノブを回すとラッチ解除、戻すとラッチ復元
//ラッチON→ドア開かない
//ドアストッパー
// ドア閉まらない
// ドア開けたら解除
//ドアクローザー
//一定時間でドアしまる
type eventMsg interface {
opname() string
}
//オペレーションたち
type push struct{}
func (push) opname() string { return "Push" }
type pull struct{}
func (pull) opname() string { return "Pull" }
type dooropen struct{}
func (dooropen) opname() string { return "doorOpen" }
type dooropened struct{}
func (dooropened) opname() string { return "doorOpened" }
type dooropenfail struct{}
func (dooropenfail) opname() string { return "doorOpenFail" }
type doorclose struct{}
func (doorclose) opname() string { return "doorClose" }
type doorclosed struct{}
func (doorclosed) opname() string { return "doorClosed" }
type doorclosefail struct{}
func (doorclosefail) opname() string { return "doorCloseFail" }
type twist struct{}
func (twist) opname() string { return "twist" }
type twistback struct{}
func (twistback) opname() string { return "twistback" }
type lockopen struct{}
func (lockopen) opname() string { return "lock_open" }
type unlockopen struct{}
func (unlockopen) opname() string { return "unlock_open" }
type lockclose struct{}
func (lockclose) opname() string { return "lock_close" }
type unlockclose struct{}
func (unlockclose) opname() string { return "unlock_close" }
type setautoclose struct{}
func (setautoclose) opname() string { return "set_autoclose" }
type removeautoclose struct{}
func (removeautoclose) opname() string { return "remove_autoclose" }
//Enum
type doorStat int
const (
Opened doorStat = iota
Closed
)
type lockStat int
const (
UnLocked lockStat = iota
Locked
)
func createAndExecProcMulti(inch chan eventMsg, outch []chan eventMsg, proc func(op eventMsg, outch []chan eventMsg)) {
go func(inch chan eventMsg, outch []chan eventMsg) {
for {
go proc(<-inch, outch)
}
}(inch, outch)
}
func createAndExecProc(inch chan eventMsg, outch chan eventMsg, proc func(op eventMsg, outch chan eventMsg)) {
go func(inch chan eventMsg, outch chan eventMsg) {
for {
go proc(<-inch, outch)
}
}(inch, outch)
}
func main() {
//ドア
doorCh := make(chan eventMsg, 0)
//ストッパー
stopperCh := make(chan eventMsg, 0)
//ラッチ?
latchCh := make(chan eventMsg, 0)
//ドアノブ
knobCh := make(chan eventMsg, 0)
//オートクローザー
autocloserCh := make(chan eventMsg, 0)
//Door処理
go func(inch chan eventMsg, outch []chan eventMsg) {
//ドアの都合変数を隠したいので、createAndExecProcMulti使わず
doorStatus := Closed
openLockStat := Locked
closeLockStat := UnLocked
for {
op := <-inch
go func(op eventMsg) {
switch op.(type) {
case push:
var msg eventMsg
if doorStatus == Closed && openLockStat == UnLocked {
doorStatus = Opened
fmt.Println("****Door open!!")
msg = dooropen{}
} else {
if doorStatus == Opened {
fmt.Println("Door already open")
msg = dooropened{}
} else {
fmt.Println("Door try to open,but failed")
msg = dooropenfail{}
}
}
for _, ch := range outch {
ch <- msg
}
case pull:
var msg eventMsg
if doorStatus == Opened && closeLockStat == UnLocked {
doorStatus = Closed
fmt.Println("****Door Close!!")
msg = doorclose{}
} else {
if doorStatus == Closed {
fmt.Println("Door already closed")
msg = doorclosed{}
} else {
fmt.Println("Door try to close,but failed")
msg = doorclosefail{}
}
}
for _, ch := range outch {
ch <- msg
}
case lockopen:
openLockStat = Locked
fmt.Println("Door Open Locked")
case unlockopen:
openLockStat = UnLocked
fmt.Println("Door Open UnLocked")
case lockclose:
closeLockStat = Locked
fmt.Println("Door Close Locked")
case unlockclose:
closeLockStat = UnLocked
fmt.Println("Door Close UnLocked")
default:
fmt.Printf("Door don't recognize %s\n", op.opname())
}
}(op)
}
}(doorCh, []chan eventMsg{stopperCh}) //ドア→いろんなもの。オートクローザとか?
//Knob
//ノブ→ラッチ
createAndExecProc(knobCh, latchCh, func(op eventMsg, outch chan eventMsg) {
switch op.(type) {
case twist:
fmt.Println("knob twisted")
outch <- unlockopen{}
case twistback:
fmt.Println("knob untwisted")
outch <- lockopen{}
default:
fmt.Printf("knob don't recognize %s\n", op.opname())
}
})
//ラッチ→ドア
createAndExecProc(latchCh, doorCh, func(op eventMsg, outch chan eventMsg) {
switch op.(type) {
case unlockopen:
fmt.Println("latch open")
outch <- unlockopen{}
case lockopen:
fmt.Println("latch lock")
outch <- lockopen{}
default:
fmt.Printf("Latch don't recognize %s\n", op.opname())
}
})
//stopper
createAndExecProc(stopperCh, doorCh, func(op eventMsg, outch chan eventMsg) {
switch op.(type) {
case dooropen, dooropened, unlockclose:
fmt.Println("stopper unlock")
outch <- unlockclose{}
case lockclose:
fmt.Println("stopper lock")
outch <- lockclose{}
default:
fmt.Printf("stopper don't recognize %s\n", op.opname())
}
})
//オートクローザーとやら
createAndExecProc(autocloserCh, doorCh, func(op eventMsg, outch chan eventMsg) {
switch op.(type) {
case setautoclose:
fmt.Println("3")
fmt.Println("2")
fmt.Println("1")
fmt.Println("autocloser pulls door")
outch <- pull{}
default:
fmt.Printf("stopper don't recognize %s\n", op.opname())
}
})
//ユーザ入力
scanner := bufio.NewScanner(os.Stdin)
fmt.Println("You can input [Object] [Verbs] ")
fmt.Println("door push/pull ")
fmt.Println("knob twist/release")
fmt.Println("stopper set/release")
fmt.Println("autocloser set")
fmt.Println("monkey !")
for {
for scanner.Scan() {
var o = ""
var v = ""
_, err := fmt.Sscanf(scanner.Text(), "%s %s\n", &o, &v)
if err != nil {
//fmt.Printf("%+v", err)
continue
}
fmt.Printf(">>%s,%s\n", o, v)
if o == "monkey" && v == "!" {
for {
n
:= rand.
Intn(3) //Autocloserは面白くない var ch chan eventMsg
var cmd eventMsg
switch n {
case 0:
ch = doorCh
if p == 0 {
cmd = push{}
} else {
cmd = pull{}
}
case 1:
ch = knobCh
if p == 0 {
cmd = twist{}
} else {
cmd = twistback{}
}
case 2:
ch = stopperCh
if p == 0 {
cmd = lockclose{}
} else {
cmd = unlockclose{}
}
case 3:
ch = autocloserCh
cmd = setautoclose{}
}
ch <- cmd
//これはずすとGC間に合わない
}
}
if o == "door" {
if v == "push" {
doorCh <- push{}
}
if v == "pull" {
doorCh <- pull{}
}
}
if o == "knob" {
if v == "twist" {
knobCh <- twist{}
}
if v == "release" {
knobCh <- twistback{}
}
}
if o == "stopper" {
if v == "set" {
stopperCh <- lockclose{}
}
if v == "release" {
stopperCh <- unlockclose{}
}
}
if o == "autocloser" {
if v == "set" {
autocloserCh <- setautoclose{}
}
}
time.
Sleep(time.
Millisecond * 500) //ideone早いから。ターミナルでは不要 }
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading standard input:", err)
}
}
}