HI all, 

So I figured Conways game of life would be a good exercise to get my feet 
wet with go. Specifically i wanted to make the calculation of the next 
board state to be concurrent. 
I started a separate goroutine for each cell and then used a pair of 
channels to synchronize updating to the next state and displaying the 
board. 

Would love to hear opinions on this approach? are their better or more 
effective ways to do the same thing? 

Thanks in advance,
CR


package main

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

type Cell struct {
    x            int
    y            int
    currentState bool
    nw           *Cell
    n            *Cell
    ne           *Cell
    e            *Cell
    se           *Cell
    s            *Cell
    sw           *Cell
    w            *Cell
}

func (c *Cell) cell(runChan chan string, doneChan chan string) {
    for {
        // wait until we're allowed to proceed
        _ = <-runChan

        // count the number of neighbours
        var i int = 0
        if c.nw.currentState {
            i++
        }
        if c.n.currentState {
            i++
        }
        if c.ne.currentState {
            i++
        }
        if c.e.currentState {
            i++
        }
        if c.se.currentState {
            i++
        }
        if c.s.currentState {
            i++
        }
        if c.sw.currentState {
            i++
        }
        if c.w.currentState {
            i++
        }

        //  Any live cell with fewer than two live neighbours dies, as if 
caused by under-population.
        //  Any live cell with two or three live neighbours lives on to the 
next generation.
        //  Any live cell with more than three live neighbours dies, as if 
by over-population.
        //  Any dead cell with exactly three live neighbours becomes a live 
cell, as if by reproduction.

        nextState := c.currentState
        if c.currentState == true {
            if i < 2 {
                nextState = false
            } else if i == 2 {
                nextState = true
            } else if i == 3 {
                nextState = true
            } else if i > 3 {
                nextState = false
            }
        } else {
            if i == 3 {
                nextState = true
            }
        }

        //fmt.Println("calc for ", c.x, c.y, c.currentState, nextState, i)

        // report that we're finished the calc
        doneChan <- "done"

        // wait for permission to continue
        _ = <-runChan
        c.currentState = nextState

        // report that we've done the transition
        doneChan <- "done"

        //fmt.Println("assign")
    }
}

func ring(x int, size int) int {
    // this corrects x to be in the range 0..size-1
    if x < 0 {
        return size + x
    } else if x >= size {
        return 0
    } else {
        return x
    }
}

func main() {
    const iterations = 10
    const gridSize = 50
    const numCells = gridSize * gridSize

    r := rand.New(rand.NewSource(123))
    var cells [numCells]Cell

    // set up the cells
    for y := 0; y < gridSize; y++ {
        for x := 0; x < gridSize; x++ {
            cells[x+gridSize*y].x = x
            cells[x+gridSize*y].y = y
            cells[x*gridSize+y].currentState = r.Intn(4) == 0

            cells[x+gridSize*y].nw = &cells[ring(x-1, gridSize)+gridSize*
ring(y-1, gridSize)]
            cells[x+gridSize*y].n = &cells[ring(x, gridSize)+gridSize*ring(y
-1, gridSize)]
            cells[x+gridSize*y].ne = &cells[ring(x+1, gridSize)+gridSize*
ring(y-1, gridSize)]
            cells[x+gridSize*y].e = &cells[ring(x+1, gridSize)+gridSize*ring
(y, gridSize)]
            cells[x+gridSize*y].se = &cells[ring(x+1, gridSize)+gridSize*
ring(y+1, gridSize)]
            cells[x+gridSize*y].s = &cells[ring(x, gridSize)+gridSize*ring(y
+1, gridSize)]
            cells[x+gridSize*y].sw = &cells[ring(x-1, gridSize)+gridSize*
ring(y+1, gridSize)]
            cells[x+gridSize*y].w = &cells[ring(x-1, gridSize)+gridSize*ring
(y, gridSize)]
        }
    }

    calcChan := make(chan string)
    readyChan := make(chan string)

    // start a goroutine for each cell
    for i := 0; i < numCells; i++ {
        go cells[i].cell(calcChan, readyChan)
    }

    for x := 0; x < iterations; x++ {

        // display board
        for y := 0; y < gridSize; y++ {
            for x := 0; x < gridSize; x++ {
                if cells[x+gridSize*y].currentState {
                    fmt.Print("X")
                } else {
                    fmt.Print(" ")
                }
            }
            fmt.Println("")
        }

        fmt.Println("start the calucation")
        for i := 0; i < numCells; i++ {
            calcChan <- ""
        }

        fmt.Println("waiting for calculations to complate")
        for i := 0; i < numCells; i++ {
            _ = <-readyChan
        }

        fmt.Println("start the transition")
        for i := 0; i < numCells; i++ {
            calcChan <- ""
        }

        fmt.Println("waiting for transition to complate")
        for i := 0; i < numCells; i++ {
            _ = <-readyChan
        }

        fmt.Println("calculations done. ")
    }
    time.Sleep(2000)

    fmt.Println("Done")

}



-- 
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.
For more options, visit https://groups.google.com/d/optout.

Reply via email to