1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
| package net.ilbanshee.gol
import swing._
import java.awt.Color
import java.awt.Dimension
import scala.collection.immutable.HashSet
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit._
object Life extends SimpleSwingApplication {
val startData: Set[Coord] = Set(
(2,6),(3,6),(2,7),(3,7),
(12,6),(12,7),(12,8),(13,5),(13,9),(14,4),(15,4),(14,10),(15,10),(16,7),
(17,5),(17,9),(18,6),(18,7),(18,8),(19,7),
(22,6),(22,5),(22,4),(23,6),(23,5),(23,4),(24,3),(24,7),(26,7),(26,8),(26,3),(26,2),
(36,4),(37,4),(36,5),(37,5))
val it = Iterator.iterate(Generation(startData))(_.nextGeneration)
val board = new Board
def top = new MainFrame {
title = "Game of Life"
contents = board
}
val marketDataRequest = new java.lang.Runnable {
def run() = board.updateStatus(it.next)
}
val es = Executors.newScheduledThreadPool(1);
es.scheduleAtFixedRate(marketDataRequest, 0, 130, MILLISECONDS)
}
class Board extends Component {
var status: Set[Coord] = new HashSet[Coord]
preferredSize = new Dimension(500, 250)
override def paintComponent(g: Graphics2D) = {
super.paintComponent(g)
g.setColor(new Color(100, 100, 100))
for (i <- 0 to size.width / 10)
g.drawLine(i * 10, 0, i * 10, size.height)
for (i <- 0 to size.height / 10)
g.drawLine(0, i * 10, size.width, i * 10)
g.setColor(Color.red)
g.drawString("There are %d cells alive".format(status.size), 10, size.height - 10)
g.setColor(Color.green)
for (coord <- status) {
val x = coord.x * 10 - 9
val y = coord.y * 10 - 9
g.fillRect(x, y, 9, 9)
}
}
def updateStatus(newCoords: Set[Coord]) = {
status = newCoords
repaint
}
}
class Coord(val x: Int, val y: Int) {
private val offsets = List(-1, 0, 1)
private def offsetsOf(n: Int) = offsets map (_ + n)
def neighbors = for {
xn <- offsetsOf(x)
yn <- offsetsOf(y) if (x, y) != (xn, yn)
} yield Coord(xn, yn)
override def equals(other: Any) = other match {
case c: Coord => x == c.x && y == c.y
case _ => false
}
override def hashCode = ((x * 31) + y) * 61
}
object Coord {
implicit def tupleToCoord(t: (Int, Int)): Coord = apply(t._1, t._2)
private val board = new scala.collection.mutable.HashMap[(Int, Int), Coord]
def apply(x: Int, y: Int) = board getOrElseUpdate ((x, y), new Coord(x, y))
}
class Generation(val alive: Set[Coord]) extends Set[Coord] {
import Generation._
def contains(elem: Coord): Boolean = alive contains elem
def iterator: Iterator[Coord] = alive.iterator
def +(elem: Coord): Generation = if (alive contains elem) this else Generation(alive + elem)
def -(elem: Coord): Generation = if (alive contains elem) Generation(alive - elem) else this
override def hashCode = alive.hashCode
private val neighbors = alive.toList flatMap(_.neighbors) groupBy (identity) map { case (c, l) => (c, l.size) }
private def neighborhood(filter: Filter) = for (filter(coord) <- neighbors) yield coord
private def babies = neighborhood(newborn)
private def adults = alive & neighborhood(stable).toSet
def nextGeneration = Generation(adults ++ babies)
}
object Generation {
case class Filter(f: ((Coord, Int)) => Option[Coord]) {
def unapply(t: (Coord, Int)): Option[Coord] = f(t)
}
def apply(alive: Set[Coord]) = new Generation(alive)
val newborn = Filter {
case (c, 3) => Some(c)
case _ => None
}
val stable = Filter {
case (c, 2) => Some(c)
case (c, 3) => Some(c)
case _ => None
}
}
|