# frozen_string_literal: true module GameOfLife module Generators # Generate a new Universe/Board from a seed number module Seed class << self # Generate a new Universe/Board from a seed number # @param options [Hash] CLI options to generate initial conditions # @option options [Numeric] "seed" number to use for generation # @option options [Numeric] "width" (floored) and used as the width of the universe # @option options [Numeric] "height" (floored) and used as the height of the universe # @return [GameOfLife::Universe] populated with the parsed input # @see ::GameOfLife::Generators::Seed.generate_seed_data # @see ::GameOfLife::Generators::Seed.populate def new(options) width = options["width"].to_i height = options["height"].to_i seed = options["seed"].to_i input = generate_seed_data(seed: seed, width: width, height: height) populate(input: input, width: width, height: height) end # Generate the seeding data for populating the {GameOfLife::Universe} # @param seed [Integer] used to generate {Array<"0"|"1">} using Std ruby Random # @param width [Integer] width of the generated cyclic universe # @param height [Integer] height of the generated cyclic universe # @return [Array>] covering the defined size of universe # @see ::GameOfLife::Generators::Seed.populate # @see https://ruby-doc.org/core-2.4.0/Random.html private def generate_seed_data(seed:, width:, height:) # Create a pseudo(stable) random generator from the seed # Generate a sequence of bytes to cover the Game of Life Universe plane # each byte can be unpacked into binary data string (ex. "01101011") raw = Random.new(seed).bytes(width * height).unpack1("B*").chars.each_slice(width) raw.map { |row| row.map { |char| char.eql?("1") } } end # Populate the {GameOfLife::Universe} with reference to the parsed input 2D array (True/False) # @param input [Array>] # @param width [Integer] width of the generated cyclic universe # @param height [Integer] height of the generated cyclic universe # @return [GameOfLife::Universe] populated with the parsed input # @see ::GameOfLife::Generators::Seed.generate_seed_data private def populate(input:, width:, height:) # Generate a universe based on the parsed raw file and fill it with the cells universe = GameOfLife::Universe.new(height: height, width: width) (0...height).each do |i| (0...width).each do |j| cell = { x: j, y: i, alive: input.fetch(i, nil)&.fetch(j, nil) } universe[i][j] = ::GameOfLife::Cell.new(**cell) end end universe end end end end end