All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
examples.Life.src.main.gosu.life.LifeModel.gs Maven / Gradle / Ivy
package life
uses java.awt.Dimension
uses gw.util.concurrent.ConcurrentHashSet
uses java.util.concurrent.ConcurrentHashMap
uses java.awt.Point
uses java.awt.EventQueue
uses java.util.concurrent.atomic.AtomicInteger
uses java.util.stream.Stream
class LifeModel {
var _infinite: boolean as Infinite
var _cellSize: int as CellSize
var _size: Dimension as Size
var _live: Set as LiveCells
var _dead: Cell[] as DeadNeighbors
var _cellCache: Cell[][]
var _cellCacheInfinite: ConcurrentHashMap
var _listeners: Set
var _cellSizeListeners: Set
var _multithreaded: boolean as Multithreaded
construct( infinite = false, multithreaded = true, cellSize = 4, size: Dimension = null, liveCells: Collection = {} ) {
_infinite = infinite
_multithreaded = multithreaded
_size = size ?: new( 400, 400 )
_cellSize = cellSize
_listeners = new ConcurrentHashSet()
_cellSizeListeners = new ConcurrentHashSet()
initCellCache()
reset( liveCells.map( \ pt -> getCell( pt.x, pt.y ) ) )
}
function getCell( x: int, y: int ) : Cell {
if( _infinite ) {
var cell = new InfinitiCell( x, y )
var prev = _cellCacheInfinite.putIfAbsent( cell, cell )
return prev ?: cell
}
else {
return _cellCache[x][y]
}
}
private function initCellCache() {
if( Infinite ) {
_cellCacheInfinite = new( 10000 )
}
else {
var cells = new Cell[Size.width][Size.height]
for( x in 0..|Size.width ) {
for( y in 0..|Size.height ) {
cells[x][y] = new Cell( x, y )
}
}
_cellCache = cells
}
}
final function reset( locations: Collection ) {
LiveCells = new ConcurrentHashSet( new HashSet( locations ) )
LiveCells.each( \ cell -> {cell.Live = true} )
addDeadNeighbors()
}
function process() {
var newLive = processNewLive( new ConcurrentHashSet( 1024 ) )
reviveTheDead( newLive )
stream( LiveCells ).forEach( \ l -> {l.Live = newLive.contains( l )} )
stream( newLive ).forEach( \ l -> {l.Live = true} )
LiveCells = newLive
addDeadNeighbors()
notifyListeners( _listeners )
}
private function processNewLive( newLive: Set ) : Set {
stream( LiveCells ).forEach( \ cell -> {
var neighbors = findNeighbors( cell )
var count = 0
for( neighbor in neighbors ) {
if( neighbor.Live ) {
count++
}
}
if( count == 2 || count == 3 ) {
newLive.add( cell )
}
} )
return newLive
}
private function reviveTheDead( newLive: Set ) {
stream( DeadNeighbors ).forEach( \ cell -> {
var neighbors = findNeighbors( cell )
var count = 0
for( neighbor in neighbors ) {
if( neighbor.Live ) {
count++
}
}
if( count == 3 ) {
newLive.add( cell )
}
} )
}
private function addDeadNeighbors() {
var dead = new Cell[LiveCells.size() * 8]
var i = new AtomicInteger( 0 )
stream( LiveCells ).forEach( \ cell -> {
var neighbors = findNeighbors( cell )
for( neighbor in neighbors ) {
if( !neighbor.Live ) {
dead[i.AndIncrement] = neighbor
}
}
} )
var copy = new Cell[i.get()]
System.arraycopy( dead, 0, copy, 0, copy.length )
DeadNeighbors = copy
}
private function stream( c: Collection ) : Stream {
return _multithreaded ? c.parallelStream() : c.stream()
}
private function stream( c: T[] ) : Stream {
return _multithreaded ? Arrays.stream( c ).parallel() : Arrays.stream( c )
}
private function findNeighbors( cell: Cell ): ArrayList {
var neighbors = new ArrayList( 8 )
var x = cell.X
var y = cell.Y
if( _infinite ) {
neighbors.add( getCell( x-1, y ) )
neighbors.add( getCell( x-1, y-1 ) )
neighbors.add( getCell( x-1, y+1 ) )
neighbors.add( getCell( x+1, y ) )
neighbors.add( getCell( x+1, y-1 ) )
neighbors.add( getCell( x+1, y+1 ) )
neighbors.add( getCell( x, y-1 ) )
neighbors.add( getCell( x, y+1 ) )
}
else {
if( cell.X > 0 ) {
neighbors.add( getCell( x-1, y ) )
if( cell.Y > 0 ) {
neighbors.add( getCell( x-1, y-1 ) )
}
if( cell.Y < Size.height-1 ) {
neighbors.add( getCell( x-1, y+1 ) )
}
}
if( cell.X < Size.width-1 ) {
neighbors.add( getCell( x+1, y ) )
if( cell.Y > 0 ) {
neighbors.add( getCell( x+1, y-1 ) )
}
if( cell.Y < Size.height-1 ) {
neighbors.add( getCell( x+1, y+1 ) )
}
}
if( cell.Y > 0 ) {
neighbors.add( getCell( x, y-1 ) )
}
if( cell.Y < Size.height-1 ) {
neighbors.add( getCell( x, y+1 ) )
}
}
return neighbors
}
function addLiveCells( cells: Collection ) {
cells.each( \ cell -> {cell.Live = true} )
LiveCells.addAll( cells )
addDeadNeighbors()
}
function killLiveCells( cells: Collection ) {
cells.each( \ cell -> {cell.Live = false} )
LiveCells.removeAll( cells )
addDeadNeighbors()
}
function updateCellSize( value: int, size: Dimension ) {
var oldSize = _cellSize
_cellSize = value
_size = size
if( !Infinite ) {
retainCacheCells( oldSize )
}
notifyListeners( _cellSizeListeners )
}
private function retainCacheCells( oldRes: int ) {
var oldCache = _cellCache
if( Size.width > oldCache.length ) {
var height = Math.max( Size.height, oldCache[0].length )
var cells = new Cell[Size.width][height]
for( x in 0..|Size.width ) {
if( x < oldCache.length ) {
System.arraycopy( oldCache[x], 0, cells[x], 0, oldCache[x].length )
for( y in oldCache[x].length..|height ) {
cells[x][y] = new Cell( x, y )
}
}
else {
for( y in 0..|height ) {
cells[x][y] = new Cell( x, y )
}
}
}
_cellCache = cells
}
else if( Size.height > oldCache[0].length ) {
var width = Math.max(Size.width, oldCache.length)
var cells = new Cell[width][Size.height]
for( x in 0..|width ) {
for( y in 0..|Size.height ) {
if( y < oldCache[x].length ) {
System.arraycopy( oldCache[x], 0, cells[x], 0, oldCache[x].length )
}
else {
cells[x][y] = new Cell( x, y )
}
}
}
_cellCache = cells
}
}
function addGenerationListener( listener() ) {
_listeners.add( listener )
}
function addCellSizeListener( listener(size: int) ) {
_cellSizeListeners.add( \-> listener( CellSize ) )
}
private function notifyListeners( listeners: Collection ) {
var post = \-> {
for( listener in listeners ) {
listener()
}
}
if( EventQueue.isDispatchThread() ) {
post()
}
else {
EventQueue.invokeLater( post )
}
}
} | | | | | | | | | | | |