cryptopunks 2.1.0 → 3.0.0

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.
Binary file
@@ -1,309 +0,0 @@
1
-
2
- module Cryptopunks
3
-
4
- class Metadata
5
- ### todo/fix:
6
- ## move into Punks::Metadata or such
7
- class Sprite
8
- attr_reader :id, :name, :type, :gender, :size, :more_names
9
-
10
-
11
- def initialize( id:,
12
- name:,
13
- type:,
14
- gender:,
15
- size:,
16
- more_names: [] )
17
- @id = id # zero-based index eg. 0,1,2,3, etc.
18
- @name = name
19
- @type = type
20
- @gender = gender
21
- @size = size
22
- @more_names = more_names
23
- end
24
-
25
- ## todo/check - find better names for type attribute/archetypes?
26
- ## use (alternate name/alias) base or face for archetypes? any others?
27
- def attribute?() @type.downcase.start_with?( 'attribute' ); end
28
- def archetype?() @type.downcase.start_with?( 'archetype' ); end
29
-
30
- def small?() @size == 's'; end
31
- def large?() @size == 'l'; end
32
- def universal?() @size == 'u'; end
33
- alias_method :unisize?, :universal? ## add unisize or allsizes or such - why? why not?
34
-
35
- def male?() @gender == 'm'; end
36
- def female?() @gender == 'f'; end
37
- def unisex?() @gender == 'u'; end
38
- end # class Metadata::Sprite
39
- end # class Metadata
40
-
41
-
42
-
43
-
44
- class Generator
45
-
46
- ######
47
- # static helpers - (turn into "true" static self.class methods - why? why not?)
48
- #
49
- def self.normalize_key( str )
50
- ## add & e.g. B&W
51
- str.downcase.gsub(/[ ()&°_-]/, '').strip
52
- end
53
-
54
- def self.normalize_gender( str )
55
- ## e.g. Female => f
56
- ## F => f
57
- ## always return f/m
58
- str.downcase[0]
59
- end
60
-
61
- def self.normalize_size( str )
62
- ## e.g. U or Unisize or Univeral => u
63
- ## S or Small => s
64
- ## L or Large => l
65
- ## always return u/l/s
66
- str.downcase[0]
67
- end
68
-
69
- def self.normalize_name( str )
70
- ## normalize spaces in more names
71
- str.strip.gsub( /[ ]{2,}/, ' ' )
72
- end
73
-
74
- def normalize_key( str ) self.class.normalize_key( str ); end
75
- def normalize_gender( str ) self.class.normalize_gender( str ); end
76
- def normalize_size( str ) self.class.normalize_size( str ); end
77
- def normalize_name( str ) self.class.normalize_name( str ); end
78
-
79
-
80
-
81
-
82
-
83
-
84
- def build_attributes_by_name( recs )
85
- h = {}
86
- recs.each_with_index do |rec|
87
- names = [rec.name] + rec.more_names
88
-
89
- names.each do |name|
90
- key = normalize_key( name )
91
- key << "_(#{rec.gender}+#{rec.size})" if rec.attribute?
92
-
93
- if h[ key ]
94
- puts "!!! ERROR - attribute name is not unique:"
95
- pp rec
96
- puts "duplicate:"
97
- pp h[key]
98
- exit 1
99
- end
100
- h[ key ] = rec
101
- end
102
- end
103
- ## pp h
104
- h
105
- end
106
-
107
-
108
- def build_recs( recs ) ## build and normalize (meta data) records
109
-
110
- ## sort by id
111
- recs = recs.sort do |l,r|
112
- l['id'].to_i( 10 ) <=> r['id'].to_i( 10 ) # use base10 (decimal)
113
- end
114
-
115
- ## assert all recs are in order by id (0 to size)
116
- recs.each_with_index do |rec, exp_id|
117
- id = rec['id'].to_i(10)
118
- if id != exp_id
119
- puts "!! ERROR - meta data record ids out-of-order - expected id #{exp_id}; got #{id}"
120
- exit 1
121
- end
122
- end
123
-
124
- ## convert to "wrapped / immutable" kind-of struct
125
- recs = recs.map do |rec|
126
- id = rec['id'].to_i( 10 )
127
- name = normalize_name( rec['name'] )
128
- gender = normalize_gender( rec['gender'] )
129
- size = normalize_size( rec['size'] )
130
- type = rec['type']
131
-
132
- more_names = (rec['more_names'] || '').split( '|' )
133
- more_names = more_names.map {|str| normalize_name( str ) }
134
-
135
- Metadata::Sprite.new(
136
- id: id,
137
- name: name,
138
- type: type,
139
- gender: gender,
140
- size: size,
141
- more_names: more_names )
142
- end
143
- recs
144
- end # method build_recs
145
-
146
-
147
-
148
-
149
- def initialize( image_path="./spritesheet.png",
150
- meta_path="./spritesheet.csv" )
151
- @sheet = Pixelart::ImageComposite.read( image_path )
152
- recs = CsvHash.read( meta_path )
153
-
154
- @recs = build_recs( recs )
155
-
156
- ## lookup by "case/space-insensitive" name / key
157
- @attributes_by_name = build_attributes_by_name( @recs )
158
- end
159
-
160
-
161
- def spritesheet() @sheet; end
162
- alias_method :sheet, :spritesheet
163
-
164
-
165
- def records() @recs; end
166
- alias_method :meta, :records
167
-
168
-
169
-
170
-
171
- def find_meta( q, gender: nil,
172
- size: nil,
173
- style: nil ) ## note: gender (m/f) required for attributes!!!
174
-
175
- key = normalize_key( q ) ## normalize q(uery) string/symbol
176
-
177
- keys = [] ## note allow lookup by more than one keys
178
- ## e.g. if gender set try f/m first and than try unisex as fallback
179
- if gender
180
- gender = normalize_gender( gender )
181
- ## auto-fill size if not passed in
182
- ## for f(emale) => s(mall)
183
- ## m(ale) => l(arge)
184
- size = if size.nil?
185
- gender == 'f' ? 's' : 'l'
186
- else
187
- normalize_size( size )
188
- end
189
-
190
- ###
191
- # try (auto-add) style-specific version first (fallback to "regular" if not found)
192
- if style
193
- ## for now only support natural series
194
- style_key = if style.downcase.start_with?( 'natural' )
195
- 'natural'
196
- else
197
- puts "!! ERROR - unknown attribute style #{style}; sorry"
198
- exit 1
199
- end
200
-
201
- keys << "#{key}#{style_key}_(#{gender}+#{size})"
202
- ## auto-add (u)niversal size as fallback
203
- keys << "#{key}#{style_key}_(#{gender}+u)" if size == 's' || size == 'l'
204
- ## auto-add u(nisex) as fallback
205
- keys << "#{key}#{style_key}_(u+#{size})" if gender == 'f' || gender == 'm'
206
- end
207
-
208
-
209
- keys << "#{key}_(#{gender}+#{size})"
210
- ## auto-add (u)niversal size as fallback
211
- keys << "#{key}_(#{gender}+u)" if size == 's' || size == 'l'
212
- ## auto-add u(nisex) as fallback
213
- keys << "#{key}_(u+#{size})" if gender == 'f' || gender == 'm'
214
- else
215
- keys << key
216
- end
217
-
218
-
219
- rec = nil
220
- keys.each do |key|
221
- rec = @attributes_by_name[ key ]
222
- if rec
223
- puts " lookup >#{key}< => #{rec.id}: #{rec.name} / #{rec.type} (#{rec.gender}+#{rec.size})"
224
- # pp rec
225
- break
226
- end
227
- end
228
-
229
- if rec.nil?
230
- puts "!! WARN - no lookup found for #{keys.size} key(s) >#{keys.inspect}<"
231
- end
232
-
233
- rec
234
- end
235
-
236
-
237
- def find( q, gender: nil, size: nil, style: nil ) ## gender (m/f) required for attributes!!!
238
- rec = find_meta( q, gender: gender, size: size, style: style )
239
-
240
- ## return image if record found
241
- rec ? @sheet[ rec.id ] : nil
242
- end
243
-
244
-
245
-
246
-
247
- def to_recs( *values, style: nil )
248
- archetype_name = values[0]
249
-
250
- ### todo/fix: check for nil/not found!!!!
251
- ## todo/check/fix: assert meta record returned is archetype NOT attribute!!!!
252
- archetype = find_meta( archetype_name )
253
- if archetype.nil?
254
- puts "!! ERROR - archetype >#{archetype}< not found; sorry"
255
- exit 1
256
- end
257
-
258
- recs = [archetype]
259
-
260
- attribute_names = values[1..-1]
261
- ## note: attribute lookup requires gender from archetype!!!!
262
- attribute_gender = archetype.gender
263
- attribute_size = archetype.size
264
-
265
- attribute_names.each do |attribute_name|
266
- attribute = find_meta( attribute_name,
267
- gender: attribute_gender,
268
- size: attribute_size,
269
- style: style )
270
- if attribute.nil?
271
- puts "!! ERROR - attribute >#{attribute_name}< for (#{attribute_gender}+#{attribute_size}) not found; sorry"
272
- exit 1
273
- end
274
- recs << attribute
275
- end
276
-
277
- recs
278
- end
279
-
280
-
281
-
282
-
283
- def generate_image( *values, style: nil,
284
- background: nil )
285
-
286
- ids = if values[0].is_a?( Integer ) ## assume integer number (indexes)
287
- values
288
- else ## assume strings (names)
289
- to_recs( *values, style: style ).map { |rec| rec.id }
290
- end
291
-
292
-
293
- punk = Pixelart::Image.new( 24, 24 )
294
-
295
- if background ## for now assume background is (simply) color
296
- punk.compose!( Pixelart::Image.new( 24, 24, background ) )
297
- end
298
-
299
- ids.each do |id|
300
- punk.compose!( @sheet[ id ] )
301
- end
302
-
303
- punk
304
- end
305
- alias_method :generate, :generate_image
306
-
307
- end # class Generator
308
-
309
- end # module Cryptopunks