Hi,

I am trying to code an observer pattern or a publish/submit pattern for a 
sort of cellular automaton.

The classical observer pattern does not to the trick because if a cell A 
subscribes to changes in a cell B and vice-versa, the application will run 
out of stack owing to the recursive approach (B.update() will call 
A.update() and so on and the app will run out of stack). 

So I though about using a publish/subscribe pattern where respective cells 
pass each other messages, rather than calling each other's update() methods.

Here is a simple example with two cells A and B:

```
package main

import (
"fmt"
ps "publish/pubsub"
)

func main() {

fmt.Printf("Starting\n")

chEnd := make(chan int)

// initialize
a := ps.NewNode(1, 0)
b := ps.NewNode(2, 0)

// connect nodes
a.Connect(b.ChOut)
b.Connect(a.ChOut)

// Start listening
a.Listen()
b.Listen()

// Start sending data on one arbitrary node
// to start the process.
a.ChIn <- 10

<-chEnd
}
```
and the corresponding lib

```package lib

import (
"fmt"
)

type Node struct {
Id int
State int
ChOut chan int
ChIn chan int
}

func NewNode(id int, state int) Node {
chout := make(chan int)
var chin chan int
return Node{id, state, chout, chin}
}

func (p *Node) Broadcast(inItem int) {
p.ChOut <- inItem + 1
//time.Sleep(100 * time.Millisecond)
}

func (p *Node) Listen() {
go func() {
for {
select {
case inItem := <-p.ChIn:
fmt.Printf("%d: %d\n", p.Id, inItem)
p.Broadcast(inItem)
}
}
}()
}

func (p *Node) Connect(ch chan int) {
p.ChIn = ch
}
```
Each node has a input and an output channe.
The input channel of B is the output channel of A and vice-versa.

Every update consists merely of incrementing the data passed by the other 
cell.

It seems to work. So far, so good.

I tried to with a set of 4 cells A, B, C, D, in order to simulate a one 
dimensional cellular automaton of sorts.

In this second attempt, 

   - each cell has two input channels (let and right) to listen to its 
   closest left- and right-hand neighbour, respectively (ChinL and ChinR).
   - each cell has to output channels to communicate its latest updated 
   state to its closest neighbours (ChoutL and ChoutR).

I must have done something wrong in the implementation of that scheme with 
4 cells, because it yields odd results : the values passed back and forth 
between the 4 cells seem to hit a threshold instead of increasing at every 
consecutive step: here is the code:

```
package main

import (
"fmt"
ps "publish/pubsub"
)

func main() {

fmt.Printf("Starting\n")

chEnd := make(chan int)

// initialize
a := ps.NewNode(1, 0)
b := ps.NewNode(2, 0)
c := ps.NewNode(3, 0)
d := ps.NewNode(4, 0)

// connect nodes
a.ChInL = d.ChOutR
a.ChInR = b.ChOutL

b.ChInL = a.ChOutR
b.ChInR = c.ChOutL

c.ChInL = b.ChOutR
c.ChInR = d.ChOutL

d.ChInL = c.ChOutR
d.ChInR = a.ChOutL

// Start listening
go a.Listen()
go b.Listen()
go c.Listen()
go d.Listen()

go a.Broadcast()
go b.Broadcast()
go c.Broadcast()
go d.Broadcast()

// Start sending data on one arbitrary node
// to start the process.
a.ChInL <- 1

// Dummy read on channel to make main() wait
<-chEnd
}

/*
A B C D
LR LR LR LR
*/

```

and the corresponding lib

```
package main

import (
"fmt"
ps "publish/pubsub"
)

func main() {

fmt.Printf("Starting\n")

chEnd := make(chan int)

// initialize
a := ps.NewNode(1, 0)
b := ps.NewNode(2, 0)
c := ps.NewNode(3, 0)
d := ps.NewNode(4, 0)

// connect nodes
a.ChInL = d.ChOutR
a.ChInR = b.ChOutL

b.ChInL = a.ChOutR
b.ChInR = c.ChOutL

c.ChInL = b.ChOutR
c.ChInR = d.ChOutL

d.ChInL = c.ChOutR
d.ChInR = a.ChOutL

// Start listening
go a.Listen()
go b.Listen()
go c.Listen()
go d.Listen()

go a.Broadcast()
go b.Broadcast()
go c.Broadcast()
go d.Broadcast()

// Start sending data on one arbitrary node
// to start the process.
a.ChInL <- 1

// Dummy read on channel to make main() wait
<-chEnd
}

/*
A B C D
LR LR LR LR
*/

```

package pubsub

import (
"fmt"
"strings"
)

type Node struct {
Id int
State int
ChOutL chan int
ChOutR chan int
ChInL chan int
ChInR chan int
ChIO chan int
}

func NewNode(id int, state int) Node {
choutL := make(chan int)
choutR := make(chan int)
var chinL chan int
var chinR chan int
chIO := make(chan int)
return Node{id, state, choutL, choutR, chinL, chinR, chIO}
}

func (p *Node) Broadcast() {
for item := range p.ChIO {
p.ChOutL <- item + 1
p.ChOutR <- item + 1
fmt.Printf("%d: %d %s\n", p.Id, item, strings.Repeat("*", item))
}
}

func (p *Node) Listen() {
for {
//time.Sleep(100 * time.Millisecond)
select {
case inItem := <-p.ChInL:
go func() {
p.ChIO <- inItem
}()
case inItem := <-p.ChInR:
go func() {
p.ChIO <- inItem
}()
}
}
}

```






-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/0eecb599-2827-40e6-881b-affeb41962fcn%40googlegroups.com.

Reply via email to