kittyverse 0.4.3 → 1.0.1

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.
@@ -1,205 +1,206 @@
1
- # encoding: utf-8
2
-
3
-
4
- class Fancy
5
-
6
- def self.fancies_by_key() @@fancies_by_key ||= {}; end
7
- def self.fancies_by_name() @@fancies_by_name ||= {}; end
8
-
9
- def self.find_by_key( key )
10
- ## note: use (always) a **symbol** for key lookup for now
11
- @@fancies_by_key[ key.downcase.to_sym ]
12
- end
13
-
14
- def self.find_by_name( name )
15
- ## note: allow string AND symbols (thus, use .to_s !!!)
16
- ## allow spaces e.g. Bug Cat is the same as BugCat
17
- ## note: downcase name e.g. allow BugCat too (not just Bug Cat)
18
- @@fancies_by_name[ name.gsub( / /, '' ).downcase.to_s ]
19
- end
20
-
21
- ## add "generic" convenience find helper
22
- def self.find_by( **kwargs )
23
- if kwargs[ :key ]
24
- find_by_key( kwargs[ :key ] )
25
- elsif kwargs[ :name ]
26
- find_by_name( kwargs[ :name] )
27
- else
28
- ## todo/fix: throw argument except!!!
29
- nil
30
- end
31
- end
32
-
33
- def self.[]( key )
34
- if key.is_a? Symbol ## e.g. :genesis, :bugcat, etc.
35
- f = find_by_key( key )
36
- f = find_by_name( key ) if f.nil? ## try fancy name next - why? why not?
37
- f
38
- else ## assume string
39
- f = find_by_name( key ) ## search by key next - why? why not?
40
- f
41
- end
42
- end
43
-
44
-
45
- def self.each
46
- @@fancies_by_key.each do |(key,fancy)|
47
- yield( fancy )
48
- end
49
- end
50
-
51
-
52
- def self.special_editions # special edition fancies
53
- @@fancies_by_key.values.select { |fancy| fancy.special_edition? }
54
- end
55
- def self.exclusives # exclusive fancies
56
- @@fancies_by_key.values.select { |fancy| fancy.exclusive? }
57
- end
58
- def self.fancies # "normal" fancies
59
- @@fancies_by_key.values.select { |fancy| fancy.recipe? }
60
- end
61
-
62
- def self.breedable ## todo: find a better name (or add alias) e.g. use unlocked why? why not?
63
- today = Date.today
64
- @@fancies_by_key.values.select { |fancy| fancy.breedable?( today ) }
65
- end
66
-
67
-
68
- def self.size() @@fancies_by_key.size; end ## todo: add length alias too? why? why not?
69
-
70
-
71
-
72
-
73
-
74
- attr_accessor :key,
75
- :name,
76
- :name_cn,
77
- :date,
78
- :desc,
79
- :exclusive,
80
- :specialedition,
81
- :recipe,
82
- :count,
83
- :limit,
84
- :ids,
85
- :time_start,
86
- :time_end
87
-
88
- def initialize( **kwargs )
89
- @exclusive = @specialedition = @recipe = nil
90
- update( kwargs )
91
- end
92
-
93
- def update( **kwargs )
94
- kwargs.each do |name,value|
95
- send( "#{name}=", value ) ## use "regular" plain/classic attribute setter
96
- end
97
- self ## return self for chaining
98
- end
99
-
100
- def exclusive?() @exclusive.nil? == false; end
101
- def specialedition?() @specialedition.nil? == false; end
102
- alias_method :special_edition?, :specialedition?
103
- def recipe?() @recipe.nil? == false; end
104
-
105
- def overflow?() @count && @limit && @count > @limit; end
106
- def overflow() @count - @limit; end ## todo: check for count limit set - why? why not?
107
- def limit?() @limit; end
108
- def count?() @count; end
109
-
110
- def time?() @time_start && @time_end; end ## is fancy(recipe,specialedition) time windowed? true/false
111
-
112
- def time_days() (@time_end.jd - @time_start.jd) + 1; end
113
-
114
-
115
- def unlocked?( today=Date.today )
116
- if @recipe
117
- if @recipe.time? ## time windowed recipe
118
- if @recipe.time_end >= today
119
- true
120
- else
121
- false
122
- end
123
- else ## assume limit
124
- if @count && @count < @limit
125
- true
126
- else
127
- false
128
- end
129
- end
130
- else
131
- false
132
- end
133
- end
134
-
135
- alias_method :breedable?, :unlocked?
136
-
137
- def locked?( today=Date.today ) !unlocked?( today ); end
138
-
139
-
140
- ###########################################
141
- ## auto-fill fancies
142
- FANCIES.each do |key,h|
143
-
144
- name = h[:name]
145
- name_cn = h[:name_cn] # add chinese name if present
146
-
147
- date_str = h[:date]
148
- date_str = h[:recipe][:time][:start] if date_str.nil? && h[:recipe]
149
- date_str = h[:specialedition][:time][:start] if date_str.nil? && h[:specialedition]
150
-
151
- date = Date.strptime( date_str, '%Y-%m-%d' )
152
-
153
- attribs = {
154
- key: key,
155
- name: name,
156
- name_cn: name_cn,
157
- date: date,
158
- desc: h[:desc]
159
- }
160
-
161
- attribs = if h[:exclusive]
162
- attribs.merge( exclusive: true,
163
- limit: h[:exclusive][:limit],
164
- ids: h[:exclusive][:ids] )
165
- elsif h[:specialedition]
166
- attribs.merge( specialedition: true,
167
- limit: h[:specialedition][:limit],
168
- time_start: h[:specialedition][:time] && h[:specialedition][:time][:start] ? Date.strptime( h[:specialedition][:time][:start], '%Y-%m-%d' ) : nil,
169
- time_end: h[:specialedition][:time] && h[:specialedition][:time][:end] ? Date.strptime( h[:specialedition][:time][:end], '%Y-%m-%d' ) : nil )
170
- else ## assume "normal/regular" fancy with recipes
171
- pp h[:recipe]
172
- recipe = Recipe.new(
173
- traits: h[:recipe][:traits], ## todo/fix: turn strings into trait objs!!!!
174
- variants: h[:recipe][:variants], ## todo/fix: turn variant hash into variant ??? - why? why not?
175
- limit: h[:recipe][:limit],
176
- time_start: h[:recipe][:time] && h[:recipe][:time][:start] ? Date.strptime( h[:recipe][:time][:start], '%Y-%m-%d' ) : nil,
177
- time_end: h[:recipe][:time] && h[:recipe][:time][:end] ? Date.strptime( h[:recipe][:time][:end], '%Y-%m-%d' ) : nil )
178
-
179
- ## note: support overflow "shortcut" - overflow+limit => count
180
- count = if h[:recipe][:overflow]
181
- recipe.limit + h[:recipe][:overflow]
182
- else
183
- h[:recipe][:count]
184
- end
185
-
186
- attribs.merge( recipe: recipe,
187
- limit: recipe.limit,
188
- time_start: recipe.time_start,
189
- time_end: recipe.time_end,
190
- count: count )
191
- end
192
-
193
-
194
- fancy = Fancy.new( **attribs )
195
- ## pp fancy
196
-
197
- ## note: key MUST be a symbol (NOT a string)
198
- fancies_by_key[key] = fancy
199
-
200
- ## note: downcase name and remove all spaces e.g. Bug Cat => bugcat
201
- fancies_by_name[name.gsub( / /, '' ).downcase] = fancy
202
- fancies_by_name[name_cn] = fancy if name_cn ## add chinese name too if present
203
- end
204
-
205
- end # class Fancy
1
+
2
+ class Fancy
3
+
4
+ def self.fancies_by_key() @@fancies_by_key ||= {}; end
5
+ def self.fancies_by_name() @@fancies_by_name ||= {}; end
6
+
7
+ def self.find_by_key( key )
8
+ ## note: use (always) a **symbol** for key lookup for now
9
+ @@fancies_by_key[ key.downcase.to_sym ]
10
+ end
11
+
12
+ def self.find_by_name( name )
13
+ ## note: allow string AND symbols (thus, use .to_s !!!)
14
+ ## allow spaces e.g. Bug Cat is the same as BugCat
15
+ ## note: downcase name e.g. allow BugCat too (not just Bug Cat)
16
+ @@fancies_by_name[ name.gsub( / /, '' ).downcase.to_s ]
17
+ end
18
+
19
+ ## add "generic" convenience find helper
20
+ def self.find_by( **kwargs )
21
+ if kwargs[ :key ]
22
+ find_by_key( kwargs[ :key ] )
23
+ elsif kwargs[ :name ]
24
+ find_by_name( kwargs[ :name] )
25
+ else
26
+ ## todo/fix: throw argument except!!!
27
+ nil
28
+ end
29
+ end
30
+
31
+ def self.[]( key )
32
+ if key.is_a? Symbol ## e.g. :genesis, :bugcat, etc.
33
+ f = find_by_key( key )
34
+ f = find_by_name( key ) if f.nil? ## try fancy name next - why? why not?
35
+ f
36
+ else ## assume string
37
+ f = find_by_name( key ) ## search by key next - why? why not?
38
+ f
39
+ end
40
+ end
41
+
42
+
43
+ def self.each
44
+ @@fancies_by_key.each do |(key,fancy)|
45
+ yield( fancy )
46
+ end
47
+ end
48
+
49
+
50
+ def self.special_editions # special edition fancies
51
+ @@fancies_by_key.values.select { |fancy| fancy.special_edition? }
52
+ end
53
+ def self.exclusives # exclusive fancies
54
+ @@fancies_by_key.values.select { |fancy| fancy.exclusive? }
55
+ end
56
+ def self.fancies # "normal" fancies
57
+ @@fancies_by_key.values.select { |fancy| fancy.recipe? }
58
+ end
59
+
60
+ def self.breedable ## todo: find a better name (or add alias) e.g. use unlocked why? why not?
61
+ today = Date.today
62
+ @@fancies_by_key.values.select { |fancy| fancy.breedable?( today ) }
63
+ end
64
+
65
+
66
+ def self.size() @@fancies_by_key.size; end ## todo: add length alias too? why? why not?
67
+
68
+
69
+
70
+
71
+
72
+ attr_accessor :key,
73
+ :name,
74
+ :name_cn,
75
+ :date,
76
+ :desc,
77
+ :exclusive,
78
+ :specialedition,
79
+ :recipe,
80
+ :count,
81
+ :limit,
82
+ :ids,
83
+ :time_start,
84
+ :time_end
85
+
86
+ def initialize( **kwargs )
87
+ @exclusive = @specialedition = @recipe = nil
88
+ update( kwargs )
89
+ end
90
+
91
+ def update( **kwargs )
92
+ kwargs.each do |name,value|
93
+ send( "#{name}=", value ) ## use "regular" plain/classic attribute setter
94
+ end
95
+ self ## return self for chaining
96
+ end
97
+
98
+ def exclusive?() @exclusive.nil? == false; end
99
+ def specialedition?() @specialedition.nil? == false; end
100
+ alias_method :special_edition?, :specialedition?
101
+ def recipe?() @recipe.nil? == false; end
102
+
103
+ def overflow?() @count && @limit && @count > @limit; end
104
+ def overflow() @count - @limit; end ## todo: check for count limit set - why? why not?
105
+ def limit?() @limit; end
106
+ def count?() @count; end
107
+
108
+ def time?() @time_start && @time_end; end ## is fancy(recipe,specialedition) time windowed? true/false
109
+
110
+ def time_days() (@time_end.jd - @time_start.jd) + 1; end
111
+
112
+
113
+ def unlocked?( today=Date.today )
114
+ if @recipe
115
+ if @recipe.time? ## time windowed recipe
116
+ if @recipe.time_end >= today
117
+ true
118
+ else
119
+ false
120
+ end
121
+ else ## assume limit
122
+ if @count && @count < @limit
123
+ true
124
+ else
125
+ false
126
+ end
127
+ end
128
+ else
129
+ false
130
+ end
131
+ end
132
+
133
+ alias_method :breedable?, :unlocked?
134
+
135
+ def locked?( today=Date.today ) !unlocked?( today ); end
136
+
137
+
138
+ ###########################################
139
+ ## auto-fill fancies
140
+ FANCIES.each do |key,h|
141
+
142
+ puts "fancy:"
143
+ pp h
144
+
145
+ name = h[:name]
146
+ name_cn = h[:name_cn] # add chinese name if present
147
+
148
+ date_str = h[:date]
149
+ date_str = h[:recipe][:time][:start] if date_str.nil? && h[:recipe]
150
+ date_str = h[:specialedition][:time][:start] if date_str.nil? && h[:specialedition]
151
+
152
+ date = Date.strptime( date_str, '%Y-%m-%d' )
153
+
154
+ attribs = {
155
+ key: key,
156
+ name: name,
157
+ name_cn: name_cn,
158
+ date: date,
159
+ desc: h[:desc]
160
+ }
161
+
162
+ attribs = if h[:exclusive]
163
+ attribs.merge( exclusive: true,
164
+ limit: h[:exclusive][:limit],
165
+ ids: h[:exclusive][:ids] )
166
+ elsif h[:specialedition]
167
+ attribs.merge( specialedition: true,
168
+ limit: h[:specialedition][:limit],
169
+ time_start: h[:specialedition][:time] && h[:specialedition][:time][:start] ? Date.strptime( h[:specialedition][:time][:start], '%Y-%m-%d' ) : nil,
170
+ time_end: h[:specialedition][:time] && h[:specialedition][:time][:end] ? Date.strptime( h[:specialedition][:time][:end], '%Y-%m-%d' ) : nil )
171
+ else ## assume "normal/regular" fancy with recipes
172
+ pp h[:recipe]
173
+ recipe = Recipe.new(
174
+ traits: h[:recipe][:traits], ## todo/fix: turn strings into trait objs!!!!
175
+ variants: h[:recipe][:variants], ## todo/fix: turn variant hash into variant ??? - why? why not?
176
+ limit: h[:recipe][:limit],
177
+ time_start: h[:recipe][:time] && h[:recipe][:time][:start] ? Date.strptime( h[:recipe][:time][:start], '%Y-%m-%d' ) : nil,
178
+ time_end: h[:recipe][:time] && h[:recipe][:time][:end] && h[:recipe][:time][:end] != '?' ? Date.strptime( h[:recipe][:time][:end], '%Y-%m-%d' ) : nil )
179
+
180
+ ## note: support overflow "shortcut" - overflow+limit => count
181
+ count = if h[:recipe][:overflow]
182
+ recipe.limit + h[:recipe][:overflow]
183
+ else
184
+ h[:recipe][:count]
185
+ end
186
+
187
+ attribs.merge( recipe: recipe,
188
+ limit: recipe.limit,
189
+ time_start: recipe.time_start,
190
+ time_end: recipe.time_end,
191
+ count: count )
192
+ end
193
+
194
+
195
+ fancy = Fancy.new( **attribs )
196
+ ## pp fancy
197
+
198
+ ## note: key MUST be a symbol (NOT a string)
199
+ fancies_by_key[key] = fancy
200
+
201
+ ## note: downcase name and remove all spaces e.g. Bug Cat => bugcat
202
+ fancies_by_name[name.gsub( / /, '' ).downcase] = fancy
203
+ fancies_by_name[name_cn] = fancy if name_cn ## add chinese name too if present
204
+ end
205
+
206
+ end # class Fancy
@@ -0,0 +1,53 @@
1
+
2
+ class Gene
3
+
4
+ ### todo/check:
5
+ ## find a better name for Slice(incl.4 genes)
6
+ ## e.g. GeneFour, Gene4, GeneGroup, GeneSlice,TraitGenes,... - why? why not?
7
+
8
+ class Slice ## Gene::Slice (nested class)
9
+
10
+ attr_reader :type # trait type (tt)
11
+ attr_reader :d, :r1, :r2, :r3
12
+ # d (dominant gene) -- todo/check: rename to just d instead of d0 - why? why not?
13
+ # r1 (1st order recessive gene)
14
+ # r2 (2nd order recessive gene)
15
+ # r3 (3rd order recessive gene)
16
+ alias_method :d0, :d # allow "classic" alias for d too
17
+
18
+ ## compat: add alias for ("new/modern") p, h1, h2, h3
19
+ ## p(rimary), h(idden) 1, h(idden) 2, h(idden) 3
20
+ alias_method :p, :d
21
+ alias_method :h1, :r1
22
+ alias_method :h2, :r2
23
+ alias_method :h3, :r3
24
+
25
+
26
+ def initialize( type, d, r1, r2, r3 )
27
+ @type = TraitType[type] ## lookup trait type by key (e.g. :body, :pattern, etc.)
28
+ @d = @type[d] ## lookup trait (from trait type) by kai code (e.g. "1", "a", etc.)
29
+ @r1 = @type[r1]
30
+ @r2 = @type[r2]
31
+ @r3 = @type[r3]
32
+ end
33
+
34
+ def [](index)
35
+ case index
36
+ when 0 then @d
37
+ when 1 then @r1
38
+ when 2 then @r2
39
+ when 3 then @r3
40
+ else nil ## return nil for unknown index for now (raise except - why? why not?)
41
+ end
42
+ end
43
+
44
+ def purebred?() @d == @r1 && @d == @r2 && @d == @r3; end
45
+ alias_method :pure?, :purebred?
46
+
47
+
48
+ def to_kai
49
+ @r3.kai + @r2.kai + @r1.kai + @d.kai
50
+ end ## return a string in kai/base32 notation
51
+
52
+ end # class Slice
53
+ end # class Gene