lindenmayer 0.0.1 → 0.0.3
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/lib/context_sensitive_production.rb +41 -0
- data/lib/lsystem.rb +15 -64
- data/lib/production.rb +70 -0
- metadata +5 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 95df1a1c15fc4519606572a2e4cbc4fe35b4b80b
|
|
4
|
+
data.tar.gz: 48d0f8d96dc349250baf47341cd1ddffc85066df
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e3bbedc5d9b2c5a03592fe82bc87b8de5613d81ccc580e50f9a32368054ac93def2f8f04cc997fce6c27ee28866bb678c6362df993ad75d5c5ba8cfb6f7298f8
|
|
7
|
+
data.tar.gz: a671493315675fe32c89f6b20d4a8942dbff4db2d11b8c7d487f0e7f3a141f28b37cb465af794f321ba421f1940d7581bfc3573fd6101768b50b61e1c12d4370
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Lindenmayer
|
|
2
|
+
|
|
3
|
+
# Context-Sensitive Production, checks if value matches in context
|
|
4
|
+
# Handles left-only, right-only, and left-right context
|
|
5
|
+
class ContextSensitiveProduction < Production
|
|
6
|
+
attr_reader :key
|
|
7
|
+
|
|
8
|
+
# key - (string) Full key, e.g. "AB<C>DE"
|
|
9
|
+
# transform - (string) Replacement if matching
|
|
10
|
+
def initialize(key, transform, options = {})
|
|
11
|
+
@lookahead = key.include?('>') ? key.rpartition('>').last : nil
|
|
12
|
+
@lookbehind = key.include?('<') ? key.partition('<').first : nil
|
|
13
|
+
@key = key.rpartition('<').last.partition('>').first
|
|
14
|
+
@transform = transform
|
|
15
|
+
post_init(options)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def transform(idx, context)
|
|
19
|
+
if (@lookbehind.nil? ||
|
|
20
|
+
includes_full_context?(context[0, idx], @lookbehind)) &&
|
|
21
|
+
(@lookahead.nil? ||
|
|
22
|
+
includes_full_context?(context[(idx + 1)..-1], @lookahead))
|
|
23
|
+
apply_transform
|
|
24
|
+
else
|
|
25
|
+
@key
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def includes_full_context?(context, required_context)
|
|
32
|
+
required_context = required_context.dup.split('')
|
|
33
|
+
|
|
34
|
+
context.split('').each do |char|
|
|
35
|
+
required_context.shift if required_context[0] == char
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
required_context.empty?
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
data/lib/lsystem.rb
CHANGED
|
@@ -1,79 +1,30 @@
|
|
|
1
|
-
require 'pry'
|
|
2
1
|
require 'ostruct'
|
|
2
|
+
require 'production'
|
|
3
|
+
require 'context_sensitive_production'
|
|
3
4
|
|
|
4
5
|
module Lindenmayer
|
|
5
|
-
|
|
6
|
-
# Basic Production
|
|
7
|
-
class Production
|
|
8
|
-
attr_reader :transform
|
|
9
|
-
|
|
10
|
-
# transform - (string) Replacement if matching
|
|
11
|
-
def initialize(transform)
|
|
12
|
-
@transform = transform
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
# Context-Sensitive Production, checks if value matches in context
|
|
17
|
-
# Handles left-only, right-only, and left-right context
|
|
18
|
-
class ContextSensitiveProduction
|
|
19
|
-
attr_reader :key
|
|
20
|
-
|
|
21
|
-
# key - (string) Full key, e.g. "AB<C>DE"
|
|
22
|
-
# transform - (string) Replacement if matching
|
|
23
|
-
def initialize(key, transform)
|
|
24
|
-
@lookahead = key.include?('>') ? key.rpartition('>').last : nil
|
|
25
|
-
@lookbehind = key.include?('<') ? key.partition('<').first : nil
|
|
26
|
-
@key = key.rpartition('<').last.partition('>').first
|
|
27
|
-
@transform = transform
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def transform(idx, context)
|
|
31
|
-
if (@lookbehind.nil? ||
|
|
32
|
-
includes_full_context?(context[0, idx], @lookbehind)) &&
|
|
33
|
-
(@lookahead.nil? ||
|
|
34
|
-
includes_full_context?(context[(idx + 1)..-1], @lookahead))
|
|
35
|
-
@transform
|
|
36
|
-
else
|
|
37
|
-
@key
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
private
|
|
42
|
-
|
|
43
|
-
def includes_full_context?(context, required_context)
|
|
44
|
-
required_context = required_context.dup.split('')
|
|
45
|
-
|
|
46
|
-
context.split('').each do |char|
|
|
47
|
-
required_context.shift if required_context[0] == char
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
required_context.empty?
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
6
|
# Lindenmayer System
|
|
55
7
|
class LSystem
|
|
56
|
-
def initialize(axiom, productions)
|
|
8
|
+
def initialize(axiom, productions, options = {})
|
|
57
9
|
@axiom = axiom
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
10
|
+
@random = options[:random]
|
|
11
|
+
|
|
12
|
+
@productions = productions.map do |key, transform|
|
|
13
|
+
k, production = if key.match(/[<>]/)
|
|
14
|
+
cs_prod = ContextSensitiveProduction.new(key, transform, random: @random)
|
|
15
|
+
[cs_prod.key, cs_prod]
|
|
16
|
+
else
|
|
17
|
+
[key, Production.new(transform, random: @random)]
|
|
18
|
+
end
|
|
19
|
+
[k, production]
|
|
20
|
+
end.to_h
|
|
68
21
|
end
|
|
69
22
|
|
|
70
23
|
def iterate(count = 1)
|
|
71
24
|
count.times do
|
|
72
25
|
@axiom = @axiom.split('').each_with_index.map do |c, c_idx|
|
|
73
26
|
if @productions[c]
|
|
74
|
-
@productions[c].transform
|
|
75
|
-
elsif @cs_productions[c]
|
|
76
|
-
@cs_productions[c].transform(c_idx, @axiom)
|
|
27
|
+
@productions[c].transform(c_idx, @axiom)
|
|
77
28
|
else
|
|
78
29
|
c
|
|
79
30
|
end
|
data/lib/production.rb
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Lindenmayer
|
|
2
|
+
class InvalidProductionError < StandardError
|
|
3
|
+
end
|
|
4
|
+
|
|
5
|
+
# Base Production
|
|
6
|
+
# Replaces a single character with a string, or applies stochastic weighting
|
|
7
|
+
class Production
|
|
8
|
+
attr_reader :transform
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# transform - (string) Replacement if matching
|
|
12
|
+
def initialize(transform, options = {})
|
|
13
|
+
@transform = transform
|
|
14
|
+
post_init(options)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def transform(idx, context)
|
|
18
|
+
apply_transform
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
protected
|
|
22
|
+
|
|
23
|
+
def post_init(options)
|
|
24
|
+
@random = options[:random] || Random.new
|
|
25
|
+
validate_stochastic if stochastic?
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def apply_transform
|
|
29
|
+
if stochastic?
|
|
30
|
+
apply_stochastic_transform
|
|
31
|
+
else
|
|
32
|
+
@transform
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def apply_stochastic_transform
|
|
37
|
+
random_value = @random.rand
|
|
38
|
+
|
|
39
|
+
transform_idx = nil
|
|
40
|
+
summed_stochastic_weights.each_with_index do |weight, weight_idx|
|
|
41
|
+
transform_idx = weight_idx and break if random_value <= weight
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
@transform[:successors][transform_idx][:successor]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def summed_stochastic_weights
|
|
48
|
+
@summed_weights ||= stochastic_weights.each_with_index.map { |weight, idx| stochastic_weights[0..idx].reduce(:+) }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def stochastic_weights
|
|
52
|
+
@stochastic_weights ||= @transform[:successors].map { |s| s[:weight] }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def stochastic?
|
|
56
|
+
return false if @transform.is_a?(String)
|
|
57
|
+
if @transform.is_a?(Hash) && @transform[:successors].any?
|
|
58
|
+
true
|
|
59
|
+
else
|
|
60
|
+
# Whatever you are, we don't suppor it
|
|
61
|
+
raise InvalidProductionError
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def validate_stochastic
|
|
66
|
+
raise InvalidProductionError unless summed_stochastic_weights.last == 1
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lindenmayer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Zach Dicklin
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2017-05-
|
|
11
|
+
date: 2017-05-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: L-System implementation
|
|
14
14
|
email: zdicklin@gmail.com
|
|
@@ -16,8 +16,10 @@ executables: []
|
|
|
16
16
|
extensions: []
|
|
17
17
|
extra_rdoc_files: []
|
|
18
18
|
files:
|
|
19
|
+
- lib/context_sensitive_production.rb
|
|
19
20
|
- lib/lsystem.rb
|
|
20
|
-
|
|
21
|
+
- lib/production.rb
|
|
22
|
+
homepage: https://github.com/LastZactionHero/lindenmayer
|
|
21
23
|
licenses:
|
|
22
24
|
- MIT
|
|
23
25
|
metadata: {}
|