rlife 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README ADDED
@@ -0,0 +1,5 @@
1
+ To launch the application execute the following command:
2
+
3
+ rake run
4
+
5
+
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ task :default => [:run_tests]
5
+
6
+ desc "Run unit tests"
7
+ Rake::TestTask.new("run_tests")
8
+
9
+ desc "Launches the Conway GUI"
10
+ task :run do
11
+ ruby "-Clib conway_fx_gui.rb"
12
+ end
data/lib/cell.rb ADDED
@@ -0,0 +1,44 @@
1
+ class Cell
2
+ attr_accessor :cell_state
3
+ attr_writer :queued_state
4
+ attr_reader :neighbors
5
+ protected :neighbors
6
+
7
+ # creates a new Cell with a state of "dead"
8
+ def initialize
9
+ @neighbors = []
10
+ @cell_state = :dead
11
+ @queued_state = nil
12
+ end
13
+
14
+ # adds a neighbor to this cell. this
15
+ # method takes care of hooking up the bi-directional
16
+ # relationship so the 2 cells do not need to be added
17
+ # to each other as neighbors, only 1 of them needs
18
+ # to be notified of the relationship
19
+ def add_neighbor(cell)
20
+ unless @neighbors.include? cell
21
+ @neighbors << cell
22
+ cell.neighbors << self
23
+ end
24
+ end
25
+
26
+ # return the number of neighbors that this cell has
27
+ def number_of_neighbors
28
+ @neighbors.size
29
+ end
30
+
31
+ # returns the number of live neighbors this cell has
32
+ def number_of_live_neighbors
33
+ live_neighbors = @neighbors.find_all {|cell| cell.cell_state == :live}
34
+ live_neighbors.size
35
+ end
36
+
37
+ # Transitions this cell to its next state of evolution
38
+ def transition_state
39
+ if @queued_state != nil
40
+ @cell_state = @queued_state
41
+ @queued_state = nil
42
+ end
43
+ end
44
+ end
data/lib/cellgrid.rb ADDED
@@ -0,0 +1,66 @@
1
+ require 'cell'
2
+
3
+ class CellGrid
4
+
5
+ def initialize (rows, columns)
6
+ @cells = Array.new rows
7
+ for row in 0...rows
8
+ @cells[row] = Array.new columns
9
+ for column in 0...columns
10
+ cell = Cell.new
11
+ @cells[row][column] = cell
12
+ if row > 0
13
+ cell.add_neighbor @cells[row-1][column]
14
+ cell.add_neighbor @cells[row-1][column+1] if column <= columns - 2
15
+ end
16
+ if column > 0
17
+ cell.add_neighbor @cells[row][column-1]
18
+ cell.add_neighbor @cells[row-1][column-1] if row > 0
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ def cell_at (row, column)
25
+ @cells[row][column]
26
+ end
27
+
28
+ def row_count
29
+ @cells.size
30
+ end
31
+
32
+ def column_count
33
+ @cells[0].size
34
+ end
35
+
36
+ def evolve
37
+ each_cell do |cell|
38
+ # kill the lonely
39
+ cell.queued_state = :dead if cell.cell_state == :live && cell.number_of_live_neighbors < 2
40
+
41
+ # kill the overcrowded
42
+ cell.queued_state = :dead if cell.cell_state == :live && cell.number_of_live_neighbors > 3
43
+
44
+ # give birth
45
+ cell.queued_state = :live if cell.cell_state == :dead && cell.number_of_live_neighbors == 3
46
+ end
47
+ each_cell do |cell|
48
+ cell.transition_state
49
+ end
50
+ end
51
+
52
+ def kill_all
53
+ each_cell do |cell|
54
+ cell.cell_state = :dead
55
+ cell.queued_state = nil
56
+ end
57
+ end
58
+
59
+ def each_cell
60
+ @cells.each do |row|
61
+ row.each do |cell|
62
+ yield cell
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,89 @@
1
+ require 'fox14'
2
+ require 'fx_grid_canvas'
3
+ require 'cellgrid'
4
+ include Fox
5
+
6
+ class ConwayWindow < FXMainWindow
7
+ WIDTH = 769
8
+ HEIGHT = 430
9
+ GRIDSIZE = 25
10
+ def initialize(app)
11
+ super(app, "RLife - Conways Game Of Life", nil, nil, DECOR_TITLE | DECOR_BORDER | DECOR_CLOSE |LAYOUT_FILL_X|LAYOUT_FILL_Y, 0, 0, WIDTH, HEIGHT)
12
+ FXToolTip.new(app)
13
+ FXStatusBar.new(self, LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X)
14
+ @cell_grid = CellGrid.new(16, 16)
15
+
16
+ rightFrame = FXVerticalFrame.new(self,LAYOUT_SIDE_TOP|LAYOUT_SIDE_RIGHT|LAYOUT_FILL_Y)
17
+ desc = <<EOS
18
+ Conway's Game Of Life is a cellular automaton originally conceived by
19
+ John Conway in the early 1970's.
20
+
21
+ Use the mouse to interactively define a starting grid by clicking on
22
+ cells in the grid to bring them to life. Clicking on a cell toggles its
23
+ live state. Click and drag to bring a bunch of cells to life. Live
24
+ cells are represented with green circles.
25
+
26
+ The rules of evolution are as follows:
27
+
28
+ - If a live cell has more than 3 live neighbors, it dies from overcrowding
29
+ - If a live cell has fewer than 2 live neighbors, it dies from loneliness
30
+ - If a dead cell has exactly 3 live neighbors, it comes to life
31
+
32
+ Click the \"Evolve\" button to iterate through generations one at a time.
33
+ Click the "Clear" button to clear the grid.
34
+ EOS
35
+ FXLabel.new(rightFrame, desc, nil, JUSTIFY_LEFT)
36
+ buttonFrame = FXHorizontalFrame.new(rightFrame,
37
+ LAYOUT_SIDE_TOP|LAYOUT_SIDE_RIGHT|LAYOUT_FILL_Y)
38
+ nextGenerationButton = FXButton.new(buttonFrame,
39
+ "&Evolve\tEvolve The System\tEvolve The System",
40
+ nil, nil, 0,FRAME_RAISED|FRAME_THICK|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT,0, 0,
41
+ 70, 30)
42
+ clearButton = FXButton.new(buttonFrame,
43
+ "&Clear\tClear all live cells\tClear all live cells",
44
+ nil, nil, 0,FRAME_RAISED|FRAME_THICK|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT,0, 0,
45
+ 70, 30)
46
+ quitButton = FXButton.new(buttonFrame,
47
+ "&Quit\tExit the Program\tExit the Program",
48
+ nil, nil, 0,FRAME_RAISED|FRAME_THICK|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT,0, 0,
49
+ 70, 30)
50
+ canvasFrame = FXVerticalFrame.new(self,
51
+ FRAME_RIDGE|LAYOUT_FILL_X|LAYOUT_FILL_Y|
52
+ LAYOUT_TOP|LAYOUT_LEFT,
53
+ 0, 0, 0, 0, 0,0,0,0)
54
+ @canvas = GridCanvas.new(canvasFrame, @cell_grid)
55
+
56
+ quitButton.connect(SEL_COMMAND) {
57
+ getApp().exit(0)
58
+ }
59
+
60
+ nextGenerationButton.connect(SEL_COMMAND) {
61
+ @cell_grid.evolve
62
+ @canvas.draw_grid
63
+ }
64
+
65
+ clearButton.connect(SEL_COMMAND) {
66
+ @cell_grid.kill_all
67
+ @canvas.draw_grid
68
+ }
69
+ end
70
+
71
+ def create
72
+ super
73
+ show(PLACEMENT_SCREEN)
74
+ end
75
+ end
76
+
77
+ if __FILE__ == $0
78
+ # Construct an application
79
+ application = FXApp.new("RLife", "rubygroup")
80
+
81
+ # Construct the main window
82
+ ConwayWindow.new(application)
83
+
84
+ # Create the application
85
+ application.create
86
+
87
+ # Run it
88
+ application.run
89
+ end
@@ -0,0 +1,89 @@
1
+ require 'fox14'
2
+ require 'fox14/colors'
3
+ require 'cellgrid'
4
+
5
+ include Fox
6
+
7
+ class GridCanvas < FXCanvas
8
+ GRIDSIZE = 25
9
+ def initialize(frame, cell_grid)
10
+ super(frame, nil, 0, FRAME_RAISED|LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_TOP|LAYOUT_LEFT)
11
+ @cell_grid = cell_grid
12
+ @width = @cell_grid.column_count * GRIDSIZE
13
+ @height = @cell_grid.row_count * GRIDSIZE
14
+ @grid_background = FXColor::DarkGray
15
+ @grid_foreground = FXColor::LightGray
16
+ @live_cell_color = FXColor::SpringGreen
17
+ @dragging = false
18
+ connect(SEL_PAINT) do |sender, sel, event|
19
+ draw_grid
20
+ end
21
+
22
+ # the dragging stuff here is almost certainly not the
23
+ # "correct" way to git-r-dun... pending enlightenment
24
+ connect(SEL_LEFTBUTTONPRESS) do |sender, sel, event|
25
+ toggle_cell_at_location(event.click_x, event.click_y)
26
+ @dragging = true
27
+ end
28
+ connect(SEL_LEFTBUTTONRELEASE) do |sender, sel, event|
29
+ @dragging = false
30
+ end
31
+ connect(SEL_MOTION) do |sender, sel, event|
32
+ handle_drag(event.win_x, event.win_y) if @dragging
33
+ end
34
+ end
35
+
36
+ def draw_grid
37
+ FXDCWindow.new(self) do |dc|
38
+ self.backColor = @grid_background
39
+ dc.foreground = self.backColor
40
+ dc.fillRectangle(0, 0, width, height)
41
+ dc.foreground = @grid_foreground
42
+ 0.step(@width, GRIDSIZE) do |column|
43
+ dc.drawLine(column, 0, column, @height)
44
+ end
45
+ 0.step(@height, GRIDSIZE) do |row|
46
+ dc.drawLine(0, row, @width, row)
47
+ end
48
+ dc.foreground = @live_cell_color
49
+ for row in 0...@cell_grid.row_count
50
+ for column in 0...@cell_grid.column_count
51
+ cell = @cell_grid.cell_at(row, column)
52
+ if(cell.cell_state == :live)
53
+ x = (column * GRIDSIZE) + (GRIDSIZE / 2)
54
+ y = (row * GRIDSIZE) + (GRIDSIZE / 2)
55
+ dc.fillCircle(x, y, GRIDSIZE / 3)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ def handle_drag(x, y)
63
+ cell = cell_at_location(x, y)
64
+ if cell && cell.cell_state == :dead
65
+ cell.cell_state = :live
66
+ draw_grid
67
+ end
68
+ end
69
+
70
+ def toggle_cell_at_location(x, y)
71
+ cell = cell_at_location(x, y)
72
+ if cell
73
+ if cell.cell_state == :dead
74
+ cell.cell_state = :live
75
+ else
76
+ cell.cell_state = :dead
77
+ end
78
+ draw_grid
79
+ end
80
+ end
81
+
82
+ def cell_at_location(x, y)
83
+ cell = nil
84
+ column = x / GRIDSIZE
85
+ row = y / GRIDSIZE
86
+ cell = @cell_grid.cell_at(row, column) if column < @cell_grid.column_count && row < @cell_grid.row_count
87
+ cell
88
+ end
89
+ end
data/test/test_cell.rb ADDED
@@ -0,0 +1,83 @@
1
+ require 'test/unit'
2
+ require 'cell'
3
+
4
+ class CellTest < Test::Unit::TestCase
5
+
6
+ def test_initial_state
7
+ c = Cell.new
8
+ assert_equal :dead, c.cell_state
9
+ end
10
+
11
+ def test_add_neighbor
12
+ c1 = Cell.new
13
+ c2 = Cell.new
14
+ assert_equal 0, c1.number_of_neighbors
15
+ assert_equal 0, c2.number_of_neighbors
16
+
17
+ c1.add_neighbor c2
18
+
19
+ assert_equal 1, c1.number_of_neighbors
20
+ assert_equal 1, c2.number_of_neighbors
21
+ end
22
+
23
+ def test_add_neighbor_multiple_times
24
+ c1 = Cell.new
25
+ c2 = Cell.new
26
+ assert_equal 0, c1.number_of_neighbors
27
+ assert_equal 0, c2.number_of_neighbors
28
+
29
+ c1.add_neighbor c2
30
+ c1.add_neighbor c2
31
+
32
+ assert_equal 1, c1.number_of_neighbors
33
+ assert_equal 1, c2.number_of_neighbors
34
+ end
35
+
36
+ def test_number_of_live_neighbors
37
+ c1 = Cell.new
38
+ c2 = Cell.new
39
+ c3 = Cell.new
40
+
41
+ c1.add_neighbor c2
42
+
43
+ assert_equal 0, c1.number_of_live_neighbors
44
+
45
+ c2.cell_state = :live
46
+
47
+ assert_equal 1, c1.number_of_live_neighbors
48
+
49
+ c3.cell_state = :live
50
+ c1.add_neighbor c3
51
+ assert_equal 2, c1.number_of_live_neighbors
52
+ end
53
+
54
+ def test_state_queuing
55
+ c1 = Cell.new
56
+ assert_equal :dead, c1.cell_state
57
+
58
+ c1.cell_state = :live
59
+ assert_equal :live, c1.cell_state
60
+
61
+ c1.queued_state = :dead
62
+ assert_equal :live, c1.cell_state
63
+
64
+ c1.transition_state
65
+ assert_equal :dead, c1.cell_state
66
+
67
+ c1.queued_state = :live
68
+ assert_equal :dead, c1.cell_state
69
+
70
+ c1.transition_state
71
+ assert_equal :live, c1.cell_state
72
+
73
+ c1.transition_state
74
+ assert_equal :live, c1.cell_state
75
+
76
+ c1.cell_state = :dead
77
+ assert_equal :dead, c1.cell_state
78
+
79
+ c1.transition_state
80
+ assert_equal :dead, c1.cell_state
81
+ end
82
+
83
+ end
@@ -0,0 +1,110 @@
1
+ require 'cell'
2
+ require 'cellgrid'
3
+ require 'test/unit'
4
+
5
+ class CellGridTest < Test::Unit::TestCase
6
+ ROWS = 10
7
+ COLUMNS = 5
8
+
9
+ def setup
10
+ @cell_grid = CellGrid.new ROWS, COLUMNS
11
+ end
12
+
13
+ def test_get_cell_at
14
+ cell = @cell_grid.cell_at(2, 2)
15
+ assert_not_nil cell
16
+ assert_equal :dead, cell.cell_state
17
+ end
18
+
19
+ def test_column_count
20
+ assert_equal COLUMNS, @cell_grid.column_count
21
+ end
22
+
23
+ def test_row_count
24
+ assert_equal ROWS, @cell_grid.row_count
25
+ end
26
+
27
+ def test_number_of_neighbors
28
+ cell = @cell_grid.cell_at(0, 0)
29
+
30
+ # corner cells should all have 3 neighbors
31
+ assert_equal 3, cell.number_of_neighbors
32
+ cell = @cell_grid.cell_at(0, COLUMNS - 1)
33
+ assert_equal 3, cell.number_of_neighbors
34
+ cell = @cell_grid.cell_at(ROWS - 1, COLUMNS - 1)
35
+ assert_equal 3, cell.number_of_neighbors
36
+ cell = @cell_grid.cell_at(ROWS - 1, 0)
37
+ assert_equal 3, cell.number_of_neighbors
38
+
39
+ # cells in the first and last row (except corners) should all have 5 neighbors
40
+ for column in 1...COLUMNS-1
41
+ cell = @cell_grid.cell_at(0, column)
42
+ assert_equal 5, cell.number_of_neighbors
43
+ cell = @cell_grid.cell_at(ROWS - 1, column)
44
+ assert_equal 5, cell.number_of_neighbors
45
+ end
46
+
47
+ # cells in the first and last column (except corners) should all ahve 5 neighbors
48
+ for row in 1...ROWS-1
49
+ cell = @cell_grid.cell_at(row, 0)
50
+ assert_equal 5, cell.number_of_neighbors
51
+ cell = @cell_grid.cell_at(row, COLUMNS-1)
52
+ assert_equal 5, cell.number_of_neighbors
53
+ end
54
+
55
+ # cells not along the edges should each have 8 neighbors
56
+ for row in 1...ROWS-1
57
+ for column in 1...COLUMNS-1
58
+ cell = @cell_grid.cell_at(row, column)
59
+ assert_equal 8, cell.number_of_neighbors
60
+ end
61
+ end
62
+ end
63
+
64
+ def test_lonely_cell
65
+ cell = @cell_grid.cell_at(3, 3)
66
+ assert_equal :dead, cell.cell_state
67
+ cell.cell_state = :live
68
+ @cell_grid.evolve
69
+ assert_equal :dead, cell.cell_state
70
+ end
71
+
72
+ def test_overcrowded_cell
73
+ c1 = @cell_grid.cell_at(0, 0)
74
+ c1.cell_state = :live
75
+ c2 = @cell_grid.cell_at(1, 0)
76
+ c2.cell_state = :live
77
+ c3 = @cell_grid.cell_at(2, 0)
78
+ c3.cell_state = :live
79
+ c4 = @cell_grid.cell_at(0, 1)
80
+ c4.cell_state = :live
81
+ crowded_cell = @cell_grid.cell_at(1, 1)
82
+ crowded_cell.cell_state = :live
83
+
84
+ @cell_grid.evolve
85
+
86
+ assert_equal :dead, crowded_cell.cell_state
87
+ end
88
+
89
+ def test_new_birth
90
+ c1 = @cell_grid.cell_at(0, 0)
91
+ c1.cell_state = :live
92
+ c2 = @cell_grid.cell_at(1, 0)
93
+ c2.cell_state = :live
94
+ c3 = @cell_grid.cell_at(2, 0)
95
+ c3.cell_state = :live
96
+
97
+ candidate_cell = @cell_grid.cell_at(1, 1)
98
+
99
+ assert_equal :dead, candidate_cell.cell_state
100
+ @cell_grid.evolve
101
+ assert_equal :live, candidate_cell.cell_state
102
+ end
103
+
104
+ def test_kill_all
105
+ c1 = @cell_grid.cell_at(3, 3)
106
+ c1.cell_state = :live
107
+ @cell_grid.kill_all
108
+ assert_equal :dead, c1.cell_state
109
+ end
110
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: rlife
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2006-06-14 00:00:00 -05:00
8
+ summary: A Ruby implementation of Conway's Game Of Life
9
+ require_paths:
10
+ - lib
11
+ email: brown_j@ociweb.com
12
+ homepage: http://rubyforge.org/projects/rlife
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: conway_fx_gui
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ authors:
29
+ - Jeff S. Brown
30
+ files:
31
+ - lib/cell.rb
32
+ - lib/cellgrid.rb
33
+ - lib/conway_fx_gui.rb
34
+ - lib/fx_grid_canvas.rb
35
+ - Rakefile
36
+ - README
37
+ - test/test_cell.rb
38
+ - test/test_cellgrid.rb
39
+ test_files:
40
+ - test/test_cell.rb
41
+ - test/test_cellgrid.rb
42
+ rdoc_options: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ executables: []
47
+
48
+ extensions: []
49
+
50
+ requirements: []
51
+
52
+ dependencies:
53
+ - !ruby/object:Gem::Dependency
54
+ name: fxruby
55
+ version_requirement:
56
+ version_requirements: !ruby/object:Gem::Version::Requirement
57
+ requirements:
58
+ - - "="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.4.4
61
+ version: