terminal_game_of_life 1.0.0 → 1.0.5
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.
- checksums.yaml +4 -4
- data/README.md +14 -9
- data/bin/game-of-life +7 -27
- data/game_of_life.gemspec +7 -3
- data/lib/game_of_life.rb +60 -3
- data/lib/game_of_life/version.rb +1 -1
- metadata +52 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f01833ac38b2fcfb9f8ea6581642e2d95a9f40521d79773178c5499e23a2530
|
4
|
+
data.tar.gz: 5f8540b420def7ca4eb0a9371140419bd47489089bed0c5f68f204a266d9946c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3fbf0db73b5fb37de4b2565813f4ba5ab5500930630fea8151f627b972ed7ef1bdfd95253675da6160451734b9d24d688802e92a36532140b1920fdb4b45d00e
|
7
|
+
data.tar.gz: ec4959be702a801f10229c9f85edcd148326d60d919c6b099c1bcd0b06a8f2b1efb24fa225121d14ab28f6239583ab05aacde14c659e74c77ff2262e7b466e8f
|
data/README.md
CHANGED
@@ -9,7 +9,11 @@ $ gem install terminal_game_of_life
|
|
9
9
|
|
10
10
|
## Usage
|
11
11
|
|
12
|
-
|
12
|
+
```bash
|
13
|
+
$game-of-life -i https://meta.sr.ht/~a14m.keys --live-cell +
|
14
|
+
$game-of-life -i /path/to/file.txt --height 35 --width 35
|
15
|
+
$game-of-life -s 1337 --delay 250
|
16
|
+
```
|
13
17
|
|
14
18
|
Check `game-of-life --help` for usage info.
|
15
19
|
|
@@ -26,7 +30,7 @@ Options:
|
|
26
30
|
[--height=HEIGHT] # Specify the hight of generated universe. (default to terminal height)
|
27
31
|
[--dead-cell=CHAR] # Specify the dead-cell representation
|
28
32
|
# Default:
|
29
|
-
[--live-cell=CHAR] # Specify the
|
33
|
+
[--live-cell=CHAR] # Specify the live-cell representation
|
30
34
|
# Default: █
|
31
35
|
-d, [--delay=Milli-Seconds] # Specify the introduced delay between each generation
|
32
36
|
# Default: 50
|
@@ -40,14 +44,15 @@ Options:
|
|
40
44
|
- Clone the repo.
|
41
45
|
- Navigate to the ruby CLI implementation `cd game-of-life/CLI/ruby`.
|
42
46
|
- run `bundle install` to install dependencies.
|
43
|
-
- run `bundle rake build` to build the gem/CLI into the `pkg` directory.
|
44
|
-
- run `bundle rake install` to build and install gem/CLI into system gems.
|
47
|
+
- you can run `bundle rake build` to build the gem/CLI into the `pkg` directory.
|
48
|
+
- you can run `bundle rake install` to build and install gem/CLI into system gems.
|
49
|
+
- you can run `bundle exec ./bin/game-of-life` to run the code for development/testing purposes
|
45
50
|
|
46
51
|
## Linting
|
47
52
|
Run `bundle exec rubocop`
|
48
53
|
|
49
54
|
## Testing
|
50
|
-
Run `bundle exec rspec`
|
55
|
+
Run `bundle exec rspec`
|
51
56
|
|
52
57
|
## Documentation
|
53
58
|
Run `bundle exec yard`
|
@@ -56,12 +61,12 @@ Run `bundle exec yard`
|
|
56
61
|
- Update the [version](./lib/game_of_live/version.rb) number
|
57
62
|
- Run `bundle install` and commit changes
|
58
63
|
- Update the [CHANGELOG](./CHANGELOG.md)
|
59
|
-
- Create a git
|
64
|
+
- Create a git tag `ruby/v#{version_number}` ex: `ruby/v0.1.1-pre`
|
60
65
|
|
61
66
|
The tag will automatically trigger the release workflow after successful build/test
|
62
67
|
and release the changes to [rubygems.org](https://rubygems.org/gems/terminal_game_of_life)
|
63
68
|
|
64
69
|
## Extra information
|
65
|
-
### [Contributing](
|
66
|
-
### [License](
|
67
|
-
### [Code of Conduct](
|
70
|
+
### [Contributing](../../CONTRIBUTING.md)
|
71
|
+
### [License](../../LICENSE.md)
|
72
|
+
### [Code of Conduct](../../CODE_OF_CONDUCT.md)
|
data/bin/game-of-life
CHANGED
@@ -3,13 +3,12 @@
|
|
3
3
|
|
4
4
|
require "game_of_life"
|
5
5
|
require "thor"
|
6
|
-
require "io/console"
|
7
6
|
|
8
7
|
class CLI < Thor
|
9
8
|
map %w[-v --version] => :version
|
10
9
|
desc "--version, -v", "Prints the Game of Life version information"
|
11
10
|
def version
|
12
|
-
|
11
|
+
print "Game of Life version #{GameOfLife::VERSION}"
|
13
12
|
end
|
14
13
|
|
15
14
|
default_task :start
|
@@ -30,35 +29,14 @@ class CLI < Thor
|
|
30
29
|
desc: "Specify the dead-cell representation"
|
31
30
|
|
32
31
|
class_option "live-cell", type: :string, banner: :CHAR, default: "\u2588",
|
33
|
-
desc: "Specify the
|
32
|
+
desc: "Specify the live-cell representation"
|
34
33
|
|
35
34
|
class_option "delay", aliases: "-d", type: :numeric, banner: "Milli-Seconds", default: 50,
|
36
35
|
desc: "Specify the introduced delay between each generation"
|
37
|
-
# rubocop:disable Metrics/AbcSize
|
38
|
-
# rubocop:disable Metrics/MethodLength
|
39
36
|
def start
|
40
|
-
|
41
|
-
max_width = IO.console.winsize[1]
|
42
|
-
if options["width"]&.> max_width
|
43
|
-
fail GameOfLife::Error, "Invalid --width value, must not exceed current terminal width: #{max_width}"
|
44
|
-
end
|
45
|
-
if options["height"]&.> max_height
|
46
|
-
fail GameOfLife::Error, "Invalid --height value, must not exceed current terminal height: #{max_height}"
|
47
|
-
end
|
48
|
-
|
49
|
-
options_with_console_defaults = {
|
50
|
-
# Defaults the hight to less then the height of the terminal to allow banner info
|
51
|
-
# and an extra emtpy line to avoid triggering terminal scroll while flushing
|
52
|
-
"height" => max_height,
|
53
|
-
"width" => max_width,
|
54
|
-
"seed" => rand(100_000),
|
55
|
-
}.merge(options)
|
56
|
-
|
57
|
-
universe = GameOfLife.generate(options_with_console_defaults)
|
37
|
+
universe = GameOfLife.generate(GameOfLife.parsed_options(options))
|
58
38
|
GameOfLife.run(universe)
|
59
39
|
end
|
60
|
-
# rubocop:enable Metrics/AbcSize
|
61
|
-
# rubocop:enable Metrics/MethodLength
|
62
40
|
|
63
41
|
class << self
|
64
42
|
# Allow exit with status 1 on failure
|
@@ -72,8 +50,10 @@ end
|
|
72
50
|
begin
|
73
51
|
CLI.start(ARGV)
|
74
52
|
rescue SystemExit, Interrupt
|
75
|
-
|
53
|
+
# Print Seed/File used in previous run when user exits with Interrupt (CMD/Ctrl + C)
|
54
|
+
print "\e[?1049l"
|
55
|
+
print "#{GameOfLife::BANNER}\n\e[0m"
|
76
56
|
rescue NotImplementedError, GameOfLife::Error => e
|
77
|
-
|
57
|
+
print e.message
|
78
58
|
exit(-1)
|
79
59
|
end
|
data/game_of_life.gemspec
CHANGED
@@ -10,15 +10,15 @@ Gem::Specification.new do |spec|
|
|
10
10
|
|
11
11
|
spec.summary = "Game of Life CLI"
|
12
12
|
spec.description = "Conway's game of life implementation as a CLI ruby gem."
|
13
|
-
spec.homepage = "https://
|
13
|
+
spec.homepage = "https://git.sr.ht/~a14m/game-of-life/tree/master/CLI/ruby/README.md"
|
14
14
|
spec.license = "MIT"
|
15
15
|
spec.required_ruby_version = ">= 2.5.0"
|
16
16
|
|
17
17
|
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
18
18
|
spec.metadata["homepage_uri"] = spec.homepage
|
19
|
-
spec.metadata["source_code_uri"] = "https://
|
19
|
+
spec.metadata["source_code_uri"] = "https://git.sr.ht/~a14m/game-of-life/tree/master/CLI/ruby"
|
20
20
|
spec.metadata["documentation_uri"] = "https://rubydoc.info/gems/terminal_game_of_life"
|
21
|
-
spec.metadata["changelog_uri"] = "https://
|
21
|
+
spec.metadata["changelog_uri"] = "https://git.sr.ht/~a14m/game-of-life/tree/master/CLI/ruby/CHANGELOG.md"
|
22
22
|
|
23
23
|
spec.executables = ["game-of-life"]
|
24
24
|
spec.require_paths = ["lib"]
|
@@ -31,6 +31,10 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_development_dependency "rake"
|
32
32
|
spec.add_development_dependency "rspec"
|
33
33
|
spec.add_development_dependency "rubocop"
|
34
|
+
spec.add_development_dependency "rubocop-rspec"
|
35
|
+
# Code Coverage dependencies
|
36
|
+
spec.add_development_dependency "codecov"
|
37
|
+
spec.add_development_dependency "simplecov"
|
34
38
|
# Documentation dependencies
|
35
39
|
spec.add_development_dependency "redcarpet"
|
36
40
|
spec.add_development_dependency "yard"
|
data/lib/game_of_life.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "io/console"
|
3
4
|
require "game_of_life/version"
|
4
5
|
require "game_of_life/plane"
|
5
6
|
require "game_of_life/universe"
|
@@ -11,6 +12,58 @@ module GameOfLife
|
|
11
12
|
class Error < StandardError; end
|
12
13
|
|
13
14
|
class << self
|
15
|
+
# Validate and parse the CLI options and set defaults for the dynamic options.
|
16
|
+
# @param options [Hash] CLI options to generate initial conditions
|
17
|
+
# @option options [String | nil] "input" path to a local file or URL to open
|
18
|
+
# @option options [Numeric | nil] "seed" number to use if no "input" is provided
|
19
|
+
# @option options [Numeric] "width" of the universe
|
20
|
+
# @option options [Numeric] "height" of the universe
|
21
|
+
# @option options [Numeric] "delay" introduced after each cycle
|
22
|
+
# @option options [String] "live-cell" representation
|
23
|
+
# @option options [String] "dead-cell" representation
|
24
|
+
# @smell AbcSize, MethodLenght, Cyclomatic and Perceived Complexity needed for parsing and validating options
|
25
|
+
# rubocop:disable Metrics/AbcSize
|
26
|
+
# rubocop:disable Metrics/MethodLength
|
27
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
28
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
29
|
+
# return [Hash] of the parsed options with dynamic defaults based on window size and kernel random
|
30
|
+
def parsed_options(options)
|
31
|
+
max_height = IO.console.winsize[0] - 2
|
32
|
+
max_width = IO.console.winsize[1]
|
33
|
+
|
34
|
+
if options["delay"].to_i.negative?
|
35
|
+
fail GameOfLife::Error, "Invalid --delay value. must be positive value (sadly this is how time works -so far-)"
|
36
|
+
end
|
37
|
+
if (options["width"]&.< 1) || (options["width"]&.> max_width)
|
38
|
+
fail GameOfLife::Error, "Invalid --width value. " \
|
39
|
+
"must be between 1 and #{max_width} (current terminal width)"
|
40
|
+
end
|
41
|
+
if (options["height"]&.< 1) || (options["height"]&.> max_height)
|
42
|
+
fail GameOfLife::Error, "Invalid --height value. " \
|
43
|
+
"must be between 1 and #{max_height} (current terminal height)"
|
44
|
+
end
|
45
|
+
|
46
|
+
fail GameOfLife::Error, "Invalid --live-cell value. must be a single character" if options["live-cell"].length > 1
|
47
|
+
|
48
|
+
fail GameOfLife::Error, "Invalid --dead-cell value. must be a single character" if options["dead-cell"].length > 1
|
49
|
+
|
50
|
+
if options["dead-cell"] == options["live-cell"]
|
51
|
+
fail GameOfLife::Error, "Invalid --dead-cell value. must be a different character than --live-cell"
|
52
|
+
end
|
53
|
+
|
54
|
+
{
|
55
|
+
# Defaults the hight to less then the height of the terminal to allow banner info
|
56
|
+
# and an extra emtpy line to avoid triggering terminal scroll while flushing
|
57
|
+
"height" => max_height,
|
58
|
+
"width" => max_width,
|
59
|
+
"seed" => rand(100_000),
|
60
|
+
}.merge(options)
|
61
|
+
end
|
62
|
+
# rubocop:enable Metrics/AbcSize
|
63
|
+
# rubocop:enable Metrics/MethodLength
|
64
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
65
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
66
|
+
|
14
67
|
# Generate a universe based on the options (from an input file/URI) or using a random/passed seed
|
15
68
|
# This method also sets the Classes/Modules constants for the run defining the options for
|
16
69
|
# Cell (Dead/Live) state representations, and the delay introduced after rendering each universe/generation
|
@@ -53,9 +106,13 @@ module GameOfLife
|
|
53
106
|
# and rendering of the current universe/banner info
|
54
107
|
# based on the delay/cell configured by the user
|
55
108
|
def render(universe)
|
56
|
-
|
57
|
-
|
58
|
-
|
109
|
+
# Use Alternate Screen (\e[?1049h) and move cursor to top left (\e[H)
|
110
|
+
# Ref: https://github.com/ruby/ruby/blob/ruby_2_7/lib/irb/easter-egg.rb#L112-L131
|
111
|
+
# Ref: https://stackoverflow.com/questions/11023929/using-the-alternate-screen-in-a-bash-script
|
112
|
+
# Ref: https://superuser.com/questions/122911/what-commands-can-i-use-to-reset-and-clear-my-terminal
|
113
|
+
print "\e[?1049h\e[H"
|
114
|
+
print universe.to_s
|
115
|
+
print "\n #{BANNER}"
|
59
116
|
sleep(DELAY / 1000.0)
|
60
117
|
end
|
61
118
|
end
|
data/lib/game_of_life/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: terminal_game_of_life
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- a14m
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -94,6 +94,48 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop-rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: codecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: simplecov
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
97
139
|
- !ruby/object:Gem::Dependency
|
98
140
|
name: redcarpet
|
99
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -141,16 +183,16 @@ files:
|
|
141
183
|
- lib/game_of_life/plane.rb
|
142
184
|
- lib/game_of_life/universe.rb
|
143
185
|
- lib/game_of_life/version.rb
|
144
|
-
homepage: https://
|
186
|
+
homepage: https://git.sr.ht/~a14m/game-of-life/tree/master/CLI/ruby/README.md
|
145
187
|
licenses:
|
146
188
|
- MIT
|
147
189
|
metadata:
|
148
190
|
allowed_push_host: https://rubygems.org
|
149
|
-
homepage_uri: https://
|
150
|
-
source_code_uri: https://
|
191
|
+
homepage_uri: https://git.sr.ht/~a14m/game-of-life/tree/master/CLI/ruby/README.md
|
192
|
+
source_code_uri: https://git.sr.ht/~a14m/game-of-life/tree/master/CLI/ruby
|
151
193
|
documentation_uri: https://rubydoc.info/gems/terminal_game_of_life
|
152
|
-
changelog_uri: https://
|
153
|
-
post_install_message:
|
194
|
+
changelog_uri: https://git.sr.ht/~a14m/game-of-life/tree/master/CLI/ruby/CHANGELOG.md
|
195
|
+
post_install_message:
|
154
196
|
rdoc_options: []
|
155
197
|
require_paths:
|
156
198
|
- lib
|
@@ -165,8 +207,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
165
207
|
- !ruby/object:Gem::Version
|
166
208
|
version: '0'
|
167
209
|
requirements: []
|
168
|
-
rubygems_version: 3.
|
169
|
-
signing_key:
|
210
|
+
rubygems_version: 3.1.4
|
211
|
+
signing_key:
|
170
212
|
specification_version: 4
|
171
213
|
summary: Game of Life CLI
|
172
214
|
test_files: []
|