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
|
# 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<Array<True|False>>] 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*").split("").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<Array<True|False>>]
# @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
|