Or the game of life
written in Scala with a little bit of Swing for the gui.
Let’s explore this code a little bit…
The basic idea is to visualize a Set[Coord] instances on the graphical
grid and obtain, with every iteration, the new Set of alive cells.
In order to do that let’s define our beginning state inside the Life
main object and create an iterable element using Iterator.iterate method..
123456
objectLifeextendsSimpleSwingApplication{valstartData:Set[Coord]=Set(/* initial state */)valit=Iterator.iterate(Generation(startData))(_.nextGeneration)// setup swing window components and // a runnable element to use as an "updater"}
The Generation class is a extended Set[Coord] which is able to obtain
the nextGeneration concatenating (still) alive cells with newborn cells
12345678910111213141516
classGeneration(valalive:Set[Coord])extendsSet[Coord]{// Set contract methods...// get all neighbors for every cell, group by cell// and get a tuple with Coord and neighbors countprivatevalneighbors=alive.toListflatMap(_.neighbors)groupBy(identity)map{case(c,l)=>(c,l.size)}// define a generic method to obtain a filtered selection of cellsprivatedefneighborhood(filter:Filter)=for(filter(coord)<-neighbors)yieldcoord// obtain new born cells // (ie the ones that meet newborn filter requirements)privatedefbabies=neighborhood(newborn)// obtain current alive cells, watch out for the "alive &" stuff...privatedefadults=alive&neighborhood(stable).toSet// concatenate adults with babiesdefnextGeneration=Generation(adults++babies)}
Filters are defined in Generation Object as
12345678910111213141516171819202122
objectGeneration{// case class already defines an apply() method so// let's only define an unapply method which// accepts a function((Coord, Int)) to Option[Coord]// as filtering logiccaseclassFilter(f:((Coord,Int))=>Option[Coord]){defunapply(t:(Coord,Int)):Option[Coord]=f(t)}defapply(alive:Set[Coord])=newGeneration(alive)// if a cell has 3 neighbors it's ok for a new birthvalnewborn=Filter{case(c,3)=>Some(c)case_=>None}// 2 or 3 neighbors are ok...valstable=Filter{case(c,2)=>Some(c)case(c,3)=>Some(c)case_=>None}}
The last interesting stuff is the implicit conversion from Tuple to Coord
objects