Class: GameOfLife::Cell

Inherits:
Object
  • Object
show all
Defined in:
lib/game_of_life/cell.rb

Overview

Class representing a cell in the GemeOfLife universe

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(alive:, x:, y:) ⇒ Cell

Initialize a cell in the game of life universe

Parameters:

  • alive (True|False)

    boolean indicating if the cell is considered alive

  • x (Integer)

    the x position on the cyclic universe plane

  • y (Integer)

    the y position on the cyclic universe plane



18
19
20
21
22
# File 'lib/game_of_life/cell.rb', line 18

def initialize(alive:, x:, y:)
  @alive = alive
  @x = x
  @y = y
end

Instance Attribute Details

#aliveTrue | False (readonly)

Returns the living state of the cell.

Returns:

  • (True | False)

    the living state of the cell



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
# File 'lib/game_of_life/cell.rb', line 11

class Cell
  attr_reader :alive, :x, :y

  # Initialize a cell in the game of life universe
  # @param alive [True|False] boolean indicating if the cell is considered alive
  # @param x [Integer] the x position on the cyclic universe plane
  # @param y [Integer] the y position on the cyclic universe plane
  def initialize(alive:, x:, y:)
    @alive = alive
    @x = x
    @y = y
  end

  # Representation of a cell
  # Both LIVE_CELL, and DEAD_CELL constant are defined on the application start from the options
  # @return [String] if a cell is alive or an empty space
  def to_s
    alive? ? LIVE_CELL : DEAD_CELL
  end

  # Evolve a cell in the game of life to the new state in the next generation
  # @param neighbors [Array<GameOfLife::Cell>] that are neighboring the current cell (size of 8)
  # @return [GameOfLife::Cell] representing the new state in the next generation
  #
  # @note There are some optimizations of returning a new object only when the state changes, otherwise returning self
  #   This optimization is done to limit the spacial complexity to `O(2n^2) = O(2*witdht*height)`
  #   in the worst case scenario, and to `O(n^2) = O(width * hight)` in the best case scenario
  #   (when the universe is stale and don't evolve anymore).
  # @see #living_neighbors
  def evolve!(neighbors)
    return repopulate! if dead? && living_neighbors(neighbors) == 3
    return survive! if alive? && [2, 3].include?(living_neighbors(neighbors))
    die!
  end

  # Helper method to define the language used in GameOfLife
  # @return [True | False] cell living state
  def alive?
    @alive
  end

  # Helper method to define the language used in GameOfLife
  # @return [True | False] cell dead state
  # @see #alive?
  def dead?
    !alive?
  end

  # Count the living neighbor cells relatively to the current cell in the {GameOfLife::Universe}
  # @param neighbors [Array<GameOfLife::Cell>] that are neighboring the current cell (size of 8)
  # @return [Integer] the number of living neighbors
  # @see GameOfLive::Universe#neighbors
  private def living_neighbors(neighbors)
    neighbors.select(&:alive?).size
  end

  # Helper method to define the language used in GameOfLife
  # @return [GameOfLife::Cell] new living cell
  # @see #survive!
  # @see #die!
  private def repopulate!
    self.class.new(x: x, y: y, alive: true)
  end

  # Helper method to define the language used in GameOfLife
  # @return [GameOfLife::Cell] self (since no change in state needed)
  # @see #repopulate!
  # @see #die!
  private def survive!
    self
  end

  # Helper method to define the language used in GameOfLife
  # When a cell is dead returns self otherwise return a new dead cell
  # @return [GameOfLife::Cell] self (if already dead) or new dead cell
  # @see #repopulate!
  # @see #survive!
  private def die!
    dead? ? self : self.class.new(x: x, y: y, alive: false)
  end
end

#xInteger (readonly)

Returns the X-axis position of the cell in the universe.

Returns:

  • (Integer)

    the X-axis position of the cell in the universe



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
# File 'lib/game_of_life/cell.rb', line 11

class Cell
  attr_reader :alive, :x, :y

  # Initialize a cell in the game of life universe
  # @param alive [True|False] boolean indicating if the cell is considered alive
  # @param x [Integer] the x position on the cyclic universe plane
  # @param y [Integer] the y position on the cyclic universe plane
  def initialize(alive:, x:, y:)
    @alive = alive
    @x = x
    @y = y
  end

  # Representation of a cell
  # Both LIVE_CELL, and DEAD_CELL constant are defined on the application start from the options
  # @return [String] if a cell is alive or an empty space
  def to_s
    alive? ? LIVE_CELL : DEAD_CELL
  end

  # Evolve a cell in the game of life to the new state in the next generation
  # @param neighbors [Array<GameOfLife::Cell>] that are neighboring the current cell (size of 8)
  # @return [GameOfLife::Cell] representing the new state in the next generation
  #
  # @note There are some optimizations of returning a new object only when the state changes, otherwise returning self
  #   This optimization is done to limit the spacial complexity to `O(2n^2) = O(2*witdht*height)`
  #   in the worst case scenario, and to `O(n^2) = O(width * hight)` in the best case scenario
  #   (when the universe is stale and don't evolve anymore).
  # @see #living_neighbors
  def evolve!(neighbors)
    return repopulate! if dead? && living_neighbors(neighbors) == 3
    return survive! if alive? && [2, 3].include?(living_neighbors(neighbors))
    die!
  end

  # Helper method to define the language used in GameOfLife
  # @return [True | False] cell living state
  def alive?
    @alive
  end

  # Helper method to define the language used in GameOfLife
  # @return [True | False] cell dead state
  # @see #alive?
  def dead?
    !alive?
  end

  # Count the living neighbor cells relatively to the current cell in the {GameOfLife::Universe}
  # @param neighbors [Array<GameOfLife::Cell>] that are neighboring the current cell (size of 8)
  # @return [Integer] the number of living neighbors
  # @see GameOfLive::Universe#neighbors
  private def living_neighbors(neighbors)
    neighbors.select(&:alive?).size
  end

  # Helper method to define the language used in GameOfLife
  # @return [GameOfLife::Cell] new living cell
  # @see #survive!
  # @see #die!
  private def repopulate!
    self.class.new(x: x, y: y, alive: true)
  end

  # Helper method to define the language used in GameOfLife
  # @return [GameOfLife::Cell] self (since no change in state needed)
  # @see #repopulate!
  # @see #die!
  private def survive!
    self
  end

  # Helper method to define the language used in GameOfLife
  # When a cell is dead returns self otherwise return a new dead cell
  # @return [GameOfLife::Cell] self (if already dead) or new dead cell
  # @see #repopulate!
  # @see #survive!
  private def die!
    dead? ? self : self.class.new(x: x, y: y, alive: false)
  end
end

#yInteger (readonly)

Returns the Y-axis position of the cell in the universe.

Returns:

  • (Integer)

    the Y-axis position of the cell in the universe



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
# File 'lib/game_of_life/cell.rb', line 11

class Cell
  attr_reader :alive, :x, :y

  # Initialize a cell in the game of life universe
  # @param alive [True|False] boolean indicating if the cell is considered alive
  # @param x [Integer] the x position on the cyclic universe plane
  # @param y [Integer] the y position on the cyclic universe plane
  def initialize(alive:, x:, y:)
    @alive = alive
    @x = x
    @y = y
  end

  # Representation of a cell
  # Both LIVE_CELL, and DEAD_CELL constant are defined on the application start from the options
  # @return [String] if a cell is alive or an empty space
  def to_s
    alive? ? LIVE_CELL : DEAD_CELL
  end

  # Evolve a cell in the game of life to the new state in the next generation
  # @param neighbors [Array<GameOfLife::Cell>] that are neighboring the current cell (size of 8)
  # @return [GameOfLife::Cell] representing the new state in the next generation
  #
  # @note There are some optimizations of returning a new object only when the state changes, otherwise returning self
  #   This optimization is done to limit the spacial complexity to `O(2n^2) = O(2*witdht*height)`
  #   in the worst case scenario, and to `O(n^2) = O(width * hight)` in the best case scenario
  #   (when the universe is stale and don't evolve anymore).
  # @see #living_neighbors
  def evolve!(neighbors)
    return repopulate! if dead? && living_neighbors(neighbors) == 3
    return survive! if alive? && [2, 3].include?(living_neighbors(neighbors))
    die!
  end

  # Helper method to define the language used in GameOfLife
  # @return [True | False] cell living state
  def alive?
    @alive
  end

  # Helper method to define the language used in GameOfLife
  # @return [True | False] cell dead state
  # @see #alive?
  def dead?
    !alive?
  end

  # Count the living neighbor cells relatively to the current cell in the {GameOfLife::Universe}
  # @param neighbors [Array<GameOfLife::Cell>] that are neighboring the current cell (size of 8)
  # @return [Integer] the number of living neighbors
  # @see GameOfLive::Universe#neighbors
  private def living_neighbors(neighbors)
    neighbors.select(&:alive?).size
  end

  # Helper method to define the language used in GameOfLife
  # @return [GameOfLife::Cell] new living cell
  # @see #survive!
  # @see #die!
  private def repopulate!
    self.class.new(x: x, y: y, alive: true)
  end

  # Helper method to define the language used in GameOfLife
  # @return [GameOfLife::Cell] self (since no change in state needed)
  # @see #repopulate!
  # @see #die!
  private def survive!
    self
  end

  # Helper method to define the language used in GameOfLife
  # When a cell is dead returns self otherwise return a new dead cell
  # @return [GameOfLife::Cell] self (if already dead) or new dead cell
  # @see #repopulate!
  # @see #survive!
  private def die!
    dead? ? self : self.class.new(x: x, y: y, alive: false)
  end
end

Instance Method Details

#alive?True | False

Helper method to define the language used in GameOfLife

Returns:

  • (True | False)

    cell living state



48
49
50
# File 'lib/game_of_life/cell.rb', line 48

def alive?
  @alive
end

#dead?True | False

Helper method to define the language used in GameOfLife

Returns:

  • (True | False)

    cell dead state

See Also:



55
56
57
# File 'lib/game_of_life/cell.rb', line 55

def dead?
  !alive?
end

#die!GameOfLife::Cell (private)

Helper method to define the language used in GameOfLife When a cell is dead returns self otherwise return a new dead cell

Returns:

See Also:



88
89
90
# File 'lib/game_of_life/cell.rb', line 88

private def die!
  dead? ? self : self.class.new(x: x, y: y, alive: false)
end

#evolve!(neighbors) ⇒ GameOfLife::Cell

Note:

There are some optimizations of returning a new object only when the state changes, otherwise returning self This optimization is done to limit the spacial complexity to O(2n^2) = O(2*witdht*height) in the worst case scenario, and to O(n^2) = O(width * hight) in the best case scenario (when the universe is stale and don't evolve anymore).

Evolve a cell in the game of life to the new state in the next generation

Parameters:

  • neighbors (Array<GameOfLife::Cell>)

    that are neighboring the current cell (size of 8)

Returns:

See Also:



40
41
42
43
44
# File 'lib/game_of_life/cell.rb', line 40

def evolve!(neighbors)
  return repopulate! if dead? && living_neighbors(neighbors) == 3
  return survive! if alive? && [2, 3].include?(living_neighbors(neighbors))
  die!
end

#living_neighbors(neighbors) ⇒ Integer (private)

Count the living neighbor cells relatively to the current cell in the Universe

Parameters:

  • neighbors (Array<GameOfLife::Cell>)

    that are neighboring the current cell (size of 8)

Returns:

  • (Integer)

    the number of living neighbors

See Also:

  • GameOfLive::Universe#neighbors


63
64
65
# File 'lib/game_of_life/cell.rb', line 63

private def living_neighbors(neighbors)
  neighbors.select(&:alive?).size
end

#repopulate!GameOfLife::Cell (private)

Helper method to define the language used in GameOfLife

Returns:

See Also:



71
72
73
# File 'lib/game_of_life/cell.rb', line 71

private def repopulate!
  self.class.new(x: x, y: y, alive: true)
end

#survive!GameOfLife::Cell (private)

Helper method to define the language used in GameOfLife

Returns:

See Also:



79
80
81
# File 'lib/game_of_life/cell.rb', line 79

private def survive!
  self
end

#to_sString

Representation of a cell Both LIVE_CELL, and DEAD_CELL constant are defined on the application start from the options

Returns:

  • (String)

    if a cell is alive or an empty space



27
28
29
# File 'lib/game_of_life/cell.rb', line 27

def to_s
  alive? ? LIVE_CELL : DEAD_CELL
end