Advertisement
Guest User

gol.go stage4

a guest
Dec 7th, 2019
122
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 6.88 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4.     "fmt"
  5.     "strconv"
  6.     "strings"
  7.     "time"
  8. )
  9.  
  10. func buildWorld(p golParams, height int) [][]byte {
  11.     workerWorld := make([][]byte, height)
  12.     for i := range workerWorld {
  13.         workerWorld[i] = make([]byte, p.imageWidth)
  14.     }
  15.     return workerWorld
  16. }
  17.  
  18. func countAlive(p golParams, world [][]byte, workerHeight int) int{
  19.     alive:= 0
  20.     for y := 1; y < workerHeight-1; y++ {
  21.         for x := 0; x < p.imageWidth; x++ {
  22.             if world[y][x] == 0xFF {
  23.                 alive ++
  24.             }
  25.         }
  26.     }
  27.     return alive
  28. }
  29.  
  30.  
  31. func countAliveCells(p golParams, keyChannels []chan int, out []chan byte, threadHeight int, extra int) {
  32.     notifyWorkers(p, keyChannels, 5)
  33.     alive := 0
  34.     for i := 0; i < p.threads; i++ {
  35.         alive+= <-keyChannels[i]
  36.     }
  37.     fmt.Println("Number of Alive Cells:", alive)
  38. }
  39.  
  40. func isAlive(imageWidth, x, y int, world [][]byte) bool {
  41.     x += imageWidth
  42.     x %= imageWidth
  43.     if world[y][x] != 0xFF {
  44.         return false
  45.     } else {
  46.         return true
  47.     }
  48. }
  49.  
  50. func sendWorldToPGM(p golParams, world [][] byte, d distributorChans, turn int) {
  51.     d.io.command <- ioOutput
  52.     d.io.filename <- strings.Join([]string{strconv.Itoa(p.imageWidth), strconv.Itoa(p.imageHeight), "Turn:" + strconv.Itoa(turn)}, "x")
  53.     for y := range world {
  54.         for x := range world[y] {
  55.             d.io.outputVal <- world[y][x]
  56.         }
  57.     }
  58. }
  59.  
  60. func getWorldFromPGM(p golParams, d distributorChans) [][]byte {
  61.     world := buildWorld(p, p.imageHeight)
  62.  
  63.     // Request the io goroutine to read in the image with the given filename.
  64.     d.io.command <- ioInput
  65.     d.io.filename <- strings.Join([]string{strconv.Itoa(p.imageWidth), strconv.Itoa(p.imageHeight)}, "x")
  66.  
  67.     // The io goroutine sends the requested image byte by byte, in rows.
  68.     for y := 0; y < p.imageHeight; y++ {
  69.         for x := 0; x < p.imageWidth; x++ {
  70.             val := <-d.io.inputVal
  71.             if val != 0 {
  72.                 world[y][x] = val
  73.             }
  74.         }
  75.     }
  76.     return world
  77. }
  78.  
  79.  
  80. func giveWorldToWorkers(p golParams, world [][]byte, in []chan byte, threadHeight int, extra int) {
  81.     for i := 0; i < p.threads; i++ {
  82.         yBound := threadHeight + 2
  83.         if i == p.threads-1 && !powerOfTwo(p) {
  84.             yBound += extra
  85.         }
  86.         for y := 0; y < yBound; y++ {
  87.             proposedY := y + (i * threadHeight) - 1
  88.             if proposedY < 0 {
  89.                 proposedY += p.imageHeight
  90.             }
  91.             proposedY %= p.imageHeight
  92.             for x := 0; x < p.imageWidth; x++ {
  93.                 in[i] <- world[proposedY][x]
  94.             }
  95.         }
  96.     }
  97. }
  98.  
  99. func sendWorldFromWorkers(p golParams, world [][]byte, out chan<- byte, height int) {
  100.     for y := 1; y < height-1; y++ {
  101.         for x := 0; x < p.imageWidth; x++ {
  102.             out <- world[y][x]
  103.         }
  104.     }
  105. }
  106.  
  107. func getWorldFromWorkers(p golParams, out []chan byte, threadHeight int, extra int) [][]byte {
  108.     world := buildWorld(p, p.imageHeight)
  109.     for i := 0; i < p.threads; i++ {
  110.         for y := 0; y < threadHeight; y++ {
  111.             for x := 0; x < p.imageWidth; x++ {
  112.                 world[y+(i*(threadHeight))][x] = <-out[i]
  113.             }
  114.         }
  115.     }
  116.     if !powerOfTwo(p) {
  117.         for e := 0; e < extra; e++ {
  118.             for x := 0; x < p.imageWidth; x++ {
  119.                 world[e+(p.threads*(threadHeight))][x] = <-out[p.threads-1]
  120.             }
  121.         }
  122.     }
  123.     return world
  124. }
  125.  
  126. func notifyWorkers(p golParams, keyChannels []chan int, key int) {
  127.     for i := 0; i < p.threads; i++ {
  128.         keyChannels[i] <- key
  129.     }
  130. }
  131.  
  132. func worker(haloHeight int, in <-chan byte, out chan<- byte, p golParams, sending []chan byte, receiving [2]chan byte, keyChannel chan int) {
  133.     workerWorld := buildWorld(p, haloHeight)
  134.     for y := 0; y < haloHeight; y++ {
  135.         for x := 0; x < p.imageWidth; x++ {
  136.             workerWorld[y][x] = <-in
  137.         }
  138.     }
  139.     temp := buildWorld(p, haloHeight)
  140.     running:= true
  141.     for running == true{
  142.         select {
  143.         case val := <-keyChannel:
  144.             //fmt.Println(val)
  145.             if val == 1 {
  146.                 for x := 0; x < p.imageWidth; x++ {
  147.                     sending[0] <- workerWorld[1][x]
  148.                     sending[1] <- workerWorld[haloHeight-2][x]
  149.                 }
  150.                 for x := 0; x < p.imageWidth; x++ {
  151.                     workerWorld[0][x] = <-receiving[0]
  152.                     workerWorld[haloHeight-1][x] = <-receiving[1]
  153.                 }
  154.                 //GOL Logic
  155.                 for y := 1; y < haloHeight-1; y++ {
  156.                     for x := 0; x < p.imageWidth; x++ {
  157.                         count := 0
  158.                         for i := -1; i <= 1; i++ {
  159.                             for j := -1; j <= 1; j++ {
  160.                                 if (j != 0 || i != 0) && isAlive(p.imageWidth, x+i, y+j, workerWorld) {
  161.                                     count++
  162.                                 }
  163.                             }
  164.                         }
  165.                         if count == 3 || (isAlive(p.imageWidth, x, y, workerWorld) && count == 2) {
  166.                             temp[y][x] = 0xFF
  167.                         } else {
  168.                             temp[y][x] = 0
  169.                         }
  170.                     }
  171.                 }
  172.  
  173.                 tmp := workerWorld
  174.                 workerWorld = temp
  175.                 temp = tmp
  176.             }
  177.  
  178.             if val == 2 {
  179.                 go sendWorldFromWorkers(p, workerWorld, out, haloHeight)
  180.             }
  181.             if val == 3 {
  182.                 running = false
  183.                 go sendWorldFromWorkers(p, workerWorld, out, haloHeight)
  184.             }
  185.             if val == 4 {
  186.                 paused:=true
  187.                 for paused == true{
  188.                     val := <-keyChannel
  189.                     if val == 4 {
  190.                         paused = false
  191.                     }
  192.                 }
  193.             }
  194.             if val == 5{
  195.                 keyChannel<-countAlive(p, workerWorld, haloHeight)
  196.             }
  197.  
  198.         }
  199.     }
  200. }
  201.  
  202. // distributor divides the work between workers and interacts with other goroutines.
  203. func distributor(p golParams, d distributorChans, alive chan []cell, in []chan byte, out []chan byte, keyChannels []chan int, threadHeight int) {
  204.  
  205.     // Create the 2D slice to store the world.
  206.     world := getWorldFromPGM(p, d)
  207.     extra := p.imageHeight % p.threads
  208.     giveWorldToWorkers(p, world, in, threadHeight, extra)
  209.     ticker := time.NewTicker(2 * time.Second)
  210.     running:= true
  211.  
  212.     for turn := 0; turn < p.turns && running == true; turn++ {
  213.         select {
  214.         case keyValue := <-d.key:
  215.             char := string(keyValue)
  216.             if char == "s" {
  217.                 fmt.Println("S Pressed")
  218.                 go notifyWorkers(p, keyChannels, 2)
  219.                 w:= getWorldFromWorkers(p, out, threadHeight, extra)
  220.                 go sendWorldToPGM(p, w, d, turn)
  221.             }
  222.             if char == "q" {
  223.                 fmt.Println("Q pressed, breaking from program")
  224.                 running = false
  225.             }
  226.             if char == "p" {
  227.                 fmt.Println("P pressed, pausing at turn: " + strconv.Itoa(turn))
  228.                 go notifyWorkers(p, keyChannels, 4)
  229.                 paused:=true
  230.                 for paused == true{
  231.                     char := string(<-d.key)
  232.                     if char == "p" {
  233.                         fmt.Println("Continuing")
  234.                         paused =false
  235.                         notifyWorkers(p, keyChannels, 4)
  236.                     }
  237.                 }
  238.             }
  239.         case <-ticker.C:
  240.             countAliveCells(p, keyChannels, out, threadHeight, extra)
  241.         default:
  242.             notifyWorkers(p, keyChannels, 1)
  243.         }
  244.     }
  245.  
  246.     go notifyWorkers(p, keyChannels, 3)
  247.     world = getWorldFromWorkers(p, out, threadHeight, extra)
  248.     go sendWorldToPGM(p,world, d, p.turns)
  249.  
  250.     // Create an empty slice to store coordinates of cells that are still alive after p.turns are done.
  251.     var finalAlive []cell
  252.     // Go through the world and append the cellsbreak loop that are still alive.
  253.     for y := 0; y < p.imageHeight; y++ {
  254.         for x := 0; x < p.imageWidth; x++ {
  255.             if world[y][x] != 0 {
  256.                 finalAlive = append(finalAlive, cell{x: x, y: y})
  257.             }
  258.         }
  259.     }
  260.  
  261.     // Make sure that the Io has finished any output before exiting.
  262.     d.io.command <- ioCheckIdle
  263.     <-d.io.idle
  264.  
  265.     // Return the coordinates of cells that are still alive.
  266.     alive <- finalAlive
  267. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement