Just a quick look at the Gosper's Glider Gun pattern.
This is running on Pharo using this program https://github.com/ldfallas/GameOfLife
Just a quick look at the Gosper's Glider Gun pattern.
This is running on Pharo using this program https://github.com/ldfallas/GameOfLife
For me, watching executions of the Conway's Game of Life is hypnotizing. It is interesting how a small set of simple rules creates such complex and beautiful patterns.
Creating a naive version of the Game of Life is a small programming task, which is ideal for learning a new programming language. I used it to create a small example in Pharo which is a Smalltalk based language. For its implementation I also used the Morphic UI environment.
The program is written as a Morph
, which is the name of an object on the screen. Here's the definition:
Morph subclass: #GameOfLifeMorph
instanceVariableNames: 'columns rows content mouseInteraction nextGrid'
classVariableNames: ''
category: 'GameOfLife'
Drawing the matrix with the contents of the game is very simple:
drawing
drawOn: canvas
"Draws the game of life widget with the current state"
| cellWidth cellHeight rectangle cellColor cellValue|
cellWidth := (self width) / columns.
cellHeight := (self height) / rows.
1 to: rows do: [ :row |
1 to: columns do: [ :column |
cellValue := (content at: row at: column).
cellColor := cellValue = 1 ifTrue: [ Color black ] ifFalse: [ Color white ].
rectangle := Rectangle left: (self bounds left) + ((column - 1)*cellWidth)
right: (self bounds left) + ((column - 1)*cellWidth) + cellWidth
top: (self bounds top) + ((row - 1)*cellHeight )
bottom: (self bounds top) + ((row - 1)*cellHeight ) + cellHeight.
cellValue = 1 ifTrue: [canvas fillRectangle: rectangle color: cellColor]
ifFalse: [canvas frameAndFillRectangle: rectangle
fillColor: (Color white)
borderWidth: 1
borderColor: (Color black)].
]
].
^self.
The implementation of the animation part of the program was created using the step
and stepTime
methods.
stepping and presenter
step
"Verifies the rules of the Game Of Life"
| tmp |
1 to: rows do: [ :row |
1 to: columns do: [ :column |
nextGrid at: row at: column put: (self getNextGenerationFor: row column: column).
]
].
tmp := content.
content := nextGrid.
nextGrid := tmp.
self changed.
The following method shows how to get the next generation for a given (row, column)
individual.
This method is going to check for the game of life rules.
game of life rules
getNextGenerationFor: row column: column
"Verifies the Game Of Life rules"
|topLeft top topRight left right bottomLeft bottomRight bottom neighbors|
topLeft := self getCellValue: (row - 1) column: (column - 1).
top := self getCellValue: (row - 1) column: column.
left := self getCellValue: row column: (column - 1).
right := self getCellValue: row column: (column + 1).
topRight := self getCellValue: (row - 1) column: (column + 1).
bottomRight := self getCellValue: (row + 1) column: (column + 1).
bottom := self getCellValue: (row + 1) column: column.
bottomLeft := self getCellValue: (row + 1) column: (column - 1).
neighbors := topLeft + top + left + right + topRight + bottomRight + bottom + bottomLeft.
^ ((content at: row at: column) = 1)
ifTrue: [ (neighbors < 2 | (neighbors > 3)) ifTrue: [ 0 ] ifFalse: [ 1 ] ]
ifFalse: [ (neighbors = 3) ifTrue: [ 1 ] ifFalse: [ 0 ] ].
The last statement verifies the rules:
To open this Morph into the Pharo environment we can evaluate:
|m|
m := GameOfLifeMorph rows: 30 columns: 30.
m width: 300 ;height: 300 ; openInWorld.
m stopStepping.
m enableMouseInteraction .
To start the execution we can evaluate:
GameOfLifeMorph allInstances last startStepping.
Programming in Pharo is a very interesting experience. This mainly because the development environment is really integrated with the program you are developing. Something that called my attention is how you can define missing code while debugging and without stopping the debugging session.
The code for this experiment can be found here: http://github.com/ldfallas/GameOfLife
Here's a series of steps I'm following for using Git to store the source code of some Pharo experiments I'm working on.
I'm starting learning about Pharo. The information on this post is based on the nice Pharo and Github using Sourcetree video and an introduction to Monticello.
We can start by creating a repository that is located in the filesystem. To define configure this repository we open the "Monticello Browser" from the "World" menu and press the "+Repository" button.
We are going to select the filetree://
repository type. This is useful to store the code in separate files.
When this option is selected the UI will prompt us for the folder where the code will be stored. We are going to specify a directory where we executed the git init
command . Other source control systems could be used to manage this directory since it will contain the source code as text files.
Now we're going to define a package where we will the create the code to be stored in source control. To define the package we open the "Monticello Browser" from the "World" menu and press the "+Package" button.
Now we can create a class inside this package. We are going to define the GameOfLifeMorph
class to be in the GameOfLife
category.
We are going to add a method to the GameOfLifeMorph
class.
After adding these elements we can save the changes to the GameOfLife
package. We can review the changes before saving by pressing the Changes
button on the "Monticello" browser.
This option opens the following screen to review the changes before saving.
After reviewing the changes we can save the changes to the file system using the Save
button in the "Monticello Browser" window. Now we can go to the command line to directory we selected when creating the repository and execute a git status command.
~/devel/pharo/GameOfLife$ git add .filetree GameOfLife.package/ ~/devel/pharo/GameOfLife$ git status On branch master Initial commit Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: .filetree new file: GameOfLife.package/.filetree new file: GameOfLife.package/GameOfLifeMorph.class/README.md new file: GameOfLife.package/GameOfLifeMorph.class/instance/initWithRows.columns..st new file: GameOfLife.package/GameOfLifeMorph.class/methodProperties.json new file: GameOfLife.package/GameOfLifeMorph.class/properties.json new file: GameOfLife.package/monticello.meta/categories.st new file: GameOfLife.package/monticello.meta/initializers.st new file: GameOfLife.package/monticello.meta/package new file: GameOfLife.package/monticello.meta/version new file: GameOfLife.package/properties.json ~/devel/pharo/GameOfLife$ git commit -m "First commit"