summaryrefslogtreecommitdiffstats
path: root/CLI/ruby/lib/game_of_life.rb
blob: d61834aa5e829c01e9da3ba547fe665a7b5aa71f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
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
# frozen_string_literal: true

require "game_of_life/version"
require "game_of_life/plane"
require "game_of_life/universe"
require "game_of_life/cell"

# Game of Life module entry point
module GameOfLife
  # Base Error class
  class Error < StandardError; end

  class << self
    # Generate a universe based on the options (from an input file/URI) or using a random/passed seed
    # This method also sets the Classes/Modules constants for the run defining the options for
    # Cell (Dead/Live) state representations, and the delay introduced after rendering each universe/generation
    # and the banner for the info/options
    #
    # @param options [Hash] CLI options to generate initial conditions
    # @option options [String | nil] "input" path to a local file or URL to open
    # @option options [Numeric] "seed" number to use if no "input" is provided (defaults to random)
    # @option options [Numeric] "width" of the universe
    # @option options [Numeric] "height" of the universe
    # @option options [Numeric] "delay" introduced after each cycle
    # @option options [String] "live-cell" representation
    # @option options [String] "dead-cell" representation
    # @return [GameOfLife::Universe] populated with the parsed input/seed
    def generate(options)
      # Define the constants for Cell representation
      GameOfLife::Cell.const_set(:LIVE_CELL, options["live-cell"])
      GameOfLife::Cell.const_set(:DEAD_CELL, options["dead-cell"])
      # Define the constant used for delay
      GameOfLife.const_set(:DELAY, options["delay"].to_f)

      banner = options["input"] ? "Input: #{options['input']}" : "Seed: #{options['seed']}"
      # Define the constant used for banner info
      GameOfLife.const_set(:BANNER, banner)

      return GameOfLife::Generators::Input.new(options) if options["input"]
      GameOfLife::Generators::Seed.new(options)
    end

    # The infinite running loop for rendering the current state of a universe
    # and then evolving it and repeating.
    def run(universe)
      Kernel.loop do
        GameOfLife.render(universe)
        universe.evolve!
      end
    end

    # Private method to do the terminal screen/scrollback buffer cleaning
    # and rendering of the current universe/banner info
    # based on the delay configured by the user
    def render(universe)
      puts "\33c\e[3J" # Clears the screen and scrollback buffer.
      puts universe.to_s
      puts BANNER
      sleep(DELAY / 1000.0)
    end
  end

  # Generators module for generating the universe initial state
  module Generators
    autoload :Input, "game_of_life/generators/input.rb"
    autoload :Seed,  "game_of_life/generators/seed.rb"
  end
end