nlife 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: adee4e0a608c42f3780cf331194e63b8e788e604
4
- data.tar.gz: a59630d9e1f36ae189afc28db948423a7ce29f24
3
+ metadata.gz: bb3319cf910fe04786b885de262b96e56f69e56d
4
+ data.tar.gz: e4cc2675fc16bcfb6e5b33d7cd48f6acc33f99ac
5
5
  SHA512:
6
- metadata.gz: 093eabd1b18af761c77d3e6ad046f344aa840ffc656203ea077c8df5a98f76dc505cc84d4a13858865ba68ef92e79249fa52e3dd95113d391a0564c34e264e03
7
- data.tar.gz: 140fbdc9ccea78efd8350979dec45853b5c05686ea75808ef3c4085a274f521d46664434f086a98feb0427020269d1f24a16b2ec5e1c23ec22776904248de042
6
+ metadata.gz: 49f7c216349321a856e2f9900bc00d9959ea5458d22cd2ffab0e8bf9ec3c69f7eecfa071268bc274549e93e7a18bd697085d0e03c1f0cabc2e2de0acb64f37d5
7
+ data.tar.gz: 40705b57e94c5a6b14c1ba640b60a057d7d08ac995eddf97a2e16c32d93ddfa33861da2d7c03e18cf2fb9ccba0227178964dc84b9bda84e194a010ac18e74806
@@ -0,0 +1,17 @@
1
+ GAME OF LIFE WITH CURSES VIEWER
2
+ ===============================
3
+
4
+ ### Controls
5
+ - p: pause
6
+ - s: seed
7
+ - q: quit
8
+
9
+ ### Documentation
10
+ To be added
11
+
12
+ ### Tests
13
+ To be added
14
+
15
+ ### How to use
16
+ $ gem install nlife
17
+ $ nlife
data/TODO.md ADDED
@@ -0,0 +1,31 @@
1
+ TODO
2
+ ====
3
+
4
+ ### Tests
5
+ - add rspec tests
6
+
7
+ ### Game features
8
+ - resizing grid
9
+ - load/save file
10
+ - set cell state
11
+ - yank/paste/clear region
12
+
13
+ ### Render features
14
+ - make render a separate class
15
+ - options for live/dead cell characters
16
+ - zoom/viewport settings
17
+ - show density
18
+
19
+ ### Bin features
20
+ - use Thor in bin/nlife
21
+ - manual setting
22
+ - grid size
23
+ - delay
24
+ - input file
25
+
26
+ ### UI features
27
+ - add more controls
28
+ - speed control
29
+ - scroll
30
+ - mouse support
31
+ - draw/clear/yank/paste tool
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "../lib/nlife"
4
+
5
+ NLife::UI.new.start
@@ -1,5 +1 @@
1
- class NLife
2
- def self.hi
3
- puts "Hello, world!"
4
- end
5
- end
1
+ require_relative "nlife/ui"
@@ -0,0 +1,74 @@
1
+ require "narray"
2
+ require "numru/fftw3"
3
+ include NumRu
4
+
5
+ require_relative "./helper.rb"
6
+
7
+ module NLife
8
+ class Game
9
+ attr_reader :state
10
+ attr_accessor :density
11
+
12
+ def initialize(rows, cols, surround = nil, rule = nil)
13
+ @state = NArray.int(cols, rows)
14
+ @density = NArray.int(cols, rows)
15
+ surround ||= default_surround(rows, cols)
16
+ @t_surround = FFTW3.fft(surround.to_f, -1) / surround.size
17
+ @rule = rule || default_rule
18
+ end
19
+
20
+ def default_surround(rows, cols)
21
+ return Helper.surround_from_block(rows, cols) do |row, col|
22
+ [row.abs, col.abs].max == 1
23
+ end
24
+ end
25
+
26
+ def default_rule
27
+ return Helper.rule_from_golly("B3/S23")
28
+ end
29
+
30
+ def seed
31
+ @state.shape[1].times do |row|
32
+ @state.shape[0].times do |col|
33
+ @state[col, row] = rand.round
34
+ end
35
+ end
36
+ end
37
+
38
+ def step
39
+ calc_density
40
+ calc_next_state
41
+ end
42
+
43
+ def calc_density
44
+ t_state = FFTW3.fft(@state, -1)
45
+ t_density = t_state * @t_surround
46
+ @density = FFTW3.fft(t_density, 1).real.round
47
+ end
48
+
49
+ def calc_next_state
50
+ @state.shape[1].times do |row|
51
+ @state.shape[0].times do |col|
52
+ @state[col, row] = @rule.call(@state[col, row], @density[col, row])
53
+ end
54
+ end
55
+ end
56
+
57
+ # use for debug only
58
+ def print
59
+ puts "#" * (@state.shape[0] + 2)
60
+ @state.shape[1].times do |i|
61
+ puts "#" + @state[true, i].each.map { |e| e > 0 ? "*" : " " }.join + "#"
62
+ end
63
+ puts "#" * (@state.shape[0] + 2)
64
+ end
65
+
66
+ def rows
67
+ @state.shape[1]
68
+ end
69
+
70
+ def cols
71
+ @state.shape[0]
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,34 @@
1
+ require "narray"
2
+
3
+ module NLife
4
+ module Helper
5
+ def self.surround_from_block(rows, cols)
6
+ result = NArray.int(cols, rows)
7
+ result.shape[1].times do |row|
8
+ result.shape[0].times do |col|
9
+ result[col, row] = yield((row + rows / 2) % rows - rows / 2,
10
+ (col + cols / 2) % cols - cols / 2) ? 1 : 0
11
+ end
12
+ end
13
+ result
14
+ end
15
+
16
+ # constructs rules from two arrays, birth/survival densities
17
+ def self.rule_from_arrays(birth, survival)
18
+ proc do |state, density|
19
+ birth[density.round] || state > 0 && survival[density.round] ? 1 : 0
20
+ end
21
+ end
22
+
23
+ # constructs rules from string, describing birth/survival densities
24
+ def self.rule_from_golly(string)
25
+ match = /^B([0-8]*)\/S([0-8]*)$/.match(string)
26
+ Raise ArgumentError "Wrong input format" unless match
27
+ birth = Array.new(9, false)
28
+ survival = Array.new(9, false)
29
+ match[1].split(//).map(&:to_i).each { |i| birth[i] = true }
30
+ match[2].split(//).map(&:to_i).each { |i| survival[i] = true }
31
+ return rule_from_arrays(birth, survival)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,72 @@
1
+ require 'curses'
2
+
3
+ require_relative "./game.rb"
4
+
5
+ module NLife
6
+ class UI
7
+ RENDER_DEAD = " "
8
+ RENDER_LIVE = "\u2588"
9
+
10
+ def initialize
11
+ init_settings
12
+ init_window
13
+ init_life
14
+ end
15
+
16
+ def init_window
17
+ Curses.init_screen
18
+ Curses.curs_set(0)
19
+ Curses.noecho
20
+ @window_lines = Curses.lines
21
+ @window_cols = Curses.cols
22
+ @window = Curses::Window.new(@window_lines, @window_cols, 0, 0)
23
+ @window.box("|", "-")
24
+ @window.timeout = 0
25
+ end
26
+
27
+ def init_life
28
+ @life = NLife::Game.new(@window_lines - 2, @window_cols - 2) # padding
29
+ @life.seed
30
+ end
31
+
32
+ def init_settings
33
+ @pause = false
34
+ @delay = 0.04
35
+ end
36
+
37
+ def start
38
+ loop do
39
+ break unless dispatch_key(@window.getch)
40
+ step
41
+ render
42
+ sleep(@delay)
43
+ end
44
+ end
45
+
46
+ def dispatch_key(key)
47
+ case key
48
+ when "p" then @pause = !@pause
49
+ when "s" then @life.seed
50
+ when "q" then return false
51
+ end
52
+ return true
53
+ end
54
+
55
+ def step
56
+ unless @pause
57
+ @life.step
58
+ end
59
+ end
60
+
61
+ def render
62
+ @life.rows.times do |i|
63
+ string = ""
64
+ @life.cols.times do |j|
65
+ string += @life.state[j, i] > 0 ? RENDER_LIVE : RENDER_DEAD
66
+ end
67
+ @window.setpos(i + 1, 1)
68
+ @window.addstr(string)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,3 @@
1
+ module NLife
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,20 @@
1
+ require_relative './lib/nlife/version'
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'nlife'
5
+ s.version = NLife::VERSION
6
+ s.licenses = ['LGPL-3.0']
7
+ s.authors = ["Oleg Zubchenko"]
8
+ s.email = 'RedGreenBlueDiamond@gmail.com'
9
+ s.homepage = 'http://rubygems.org/gems/nlife'
10
+ s.summary = "Generalized Game of Life"
11
+ s.description = "Customizable Game of Life with ncurses viewer"
12
+ s.files = Dir["lib/**/*.rb"] + Dir["bin/*"] + Dir["*.md"] +
13
+ Dir["*.gemspec"]
14
+ s.executables << 'nlife'
15
+
16
+ s.add_runtime_dependency 'curses', '~> 1.0', '>= 1.0.1'
17
+ s.add_runtime_dependency 'narray', '~>0.6.1'
18
+ s.add_runtime_dependency 'numru-misc', '~>0.1.2'
19
+ s.add_runtime_dependency 'ruby-fftw3', '~>0.4.2'
20
+ end
metadata CHANGED
@@ -1,25 +1,96 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nlife
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oleg Zubchenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-13 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2015-05-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: curses
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.0.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: narray
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 0.6.1
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: 0.6.1
47
+ - !ruby/object:Gem::Dependency
48
+ name: numru-misc
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 0.1.2
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.1.2
61
+ - !ruby/object:Gem::Dependency
62
+ name: ruby-fftw3
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: 0.4.2
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: 0.4.2
13
75
  description: Customizable Game of Life with ncurses viewer
14
76
  email: RedGreenBlueDiamond@gmail.com
15
- executables: []
77
+ executables:
78
+ - nlife
16
79
  extensions: []
17
80
  extra_rdoc_files: []
18
81
  files:
82
+ - README.md
83
+ - TODO.md
84
+ - bin/nlife
19
85
  - lib/nlife.rb
86
+ - lib/nlife/game.rb
87
+ - lib/nlife/helper.rb
88
+ - lib/nlife/ui.rb
89
+ - lib/nlife/version.rb
90
+ - nlife.gemspec
20
91
  homepage: http://rubygems.org/gems/nlife
21
92
  licenses:
22
- - MIT
93
+ - LGPL-3.0
23
94
  metadata: {}
24
95
  post_install_message:
25
96
  rdoc_options: []