cryptopunks 3.0.1 → 2024.3.2
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/Manifest.txt +0 -4
- data/README.md +33 -29
- data/Rakefile +3 -3
- data/lib/cryptopunks/tool.rb +145 -205
- data/lib/cryptopunks/version.rb +3 -3
- data/lib/cryptopunks.rb +1 -17
- metadata +16 -18
- data/lib/cryptopunks/composite.rb +0 -38
- data/lib/cryptopunks/dataset.rb +0 -67
- data/lib/cryptopunks/image.rb +0 -35
- data/lib/cryptopunks/structs.rb +0 -161
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1fc2a706ce8c4e9ec5947d4bde3a88b4529b1d3af04b092a71de20bbdd28bca6
|
|
4
|
+
data.tar.gz: 03f0600b6564f8d1d25fccf624adca0bd38b38c52754135aae9dd8b04d63e4b4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dced1456b9cb0755cc9ec34c8efede1c6d355ce93ff2b295b0dec2b354f6e0d982ec7390e2a1823377cf6f551519e14786507a24d59b8a297c5d8c80ecedd2b0
|
|
7
|
+
data.tar.gz: '088061933c9355d88ea903fbc6e679b938d8cce1b4176919ffda66cc750efb53f300bac149bc42c9214934e617d8378d124e491be960aec1d338f6ed0a92ee0c'
|
data/Manifest.txt
CHANGED
|
@@ -7,12 +7,8 @@ bin/punk
|
|
|
7
7
|
lib/cryptopunks.rb
|
|
8
8
|
lib/cryptopunks/attributes.rb
|
|
9
9
|
lib/cryptopunks/colors.rb
|
|
10
|
-
lib/cryptopunks/composite.rb
|
|
11
10
|
lib/cryptopunks/contract/punksdata-assets.rb
|
|
12
11
|
lib/cryptopunks/contract/punksdata-contract.rb
|
|
13
12
|
lib/cryptopunks/contract/punksdata-meta.rb
|
|
14
|
-
lib/cryptopunks/dataset.rb
|
|
15
|
-
lib/cryptopunks/image.rb
|
|
16
|
-
lib/cryptopunks/structs.rb
|
|
17
13
|
lib/cryptopunks/tool.rb
|
|
18
14
|
lib/cryptopunks/version.rb
|
data/README.md
CHANGED
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
|
|
34
34
|
# Crypto Punks
|
|
35
35
|
|
|
36
|
-
cryptopunks - generate your own 24×24 pixel punk images (
|
|
36
|
+
cryptopunks - generate your own 24×24 pixel punk images from text prompts incl. 2x/4x/8x zoom for bigger sizes (or crop 'n' save tiles from all-in-one composites incl. the True Official Matt & John's® Punks sha256-verified original 10 000 unique character collection)
|
|
37
37
|
|
|
38
38
|
* home :: [github.com/cryptopunksnotdead/cryptopunks](https://github.com/cryptopunksnotdead/cryptopunks)
|
|
39
39
|
* bugs :: [github.com/cryptopunksnotdead/cryptopunks/issues](https://github.com/cryptopunksnotdead/cryptopunks/issues)
|
|
@@ -67,24 +67,23 @@ VERSION
|
|
|
67
67
|
3.0.0
|
|
68
68
|
|
|
69
69
|
GLOBAL OPTIONS
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
--
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
-z, --zoom=ZOOM - Zoom factor x2, x4, x8, etc. (default: 1)
|
|
70
|
+
-o, --out, --dir, --outdir=DIR - Output directory (default: .)
|
|
71
|
+
-f, --file=FILE - All-in-one
|
|
72
|
+
composite image (default: ./punks.png)
|
|
73
|
+
--offset=NUM - Start counting at offset (default: 0)
|
|
74
|
+
--seed=NUM - Seed for random number generation /
|
|
75
|
+
shuffle (default: 4142)
|
|
76
|
+
-z, --zoom=NUM - Zoom factor x2, x4, x8, etc. (default: 1)
|
|
78
77
|
|
|
79
|
-
--help
|
|
80
|
-
--version
|
|
81
|
-
--verbose
|
|
78
|
+
--help - Show this message
|
|
79
|
+
--version - Display the program version
|
|
80
|
+
--verbose - (Debug) Show debug messages
|
|
82
81
|
|
|
83
82
|
|
|
84
83
|
COMMANDS
|
|
85
|
-
g, gen,
|
|
84
|
+
g, gen, - Generate punk characters from text attributes (from
|
|
86
85
|
scratch / zero) via builtin punk spritesheet
|
|
87
|
-
l, ls
|
|
86
|
+
l, ls - List all punk archetype and attribute names from builtin
|
|
88
87
|
punk spritesheet
|
|
89
88
|
q, query - Query (builtin off-chain) punk contract for punk text
|
|
90
89
|
attributes by IDs - use 0 to 9999
|
|
@@ -107,7 +106,7 @@ _Generate punk characters from text attributes (from scratch / zero) via builtin
|
|
|
107
106
|
Let's try punk #0:
|
|
108
107
|
|
|
109
108
|
```
|
|
110
|
-
$ punk
|
|
109
|
+
$ punk gen female_2 earring blonde_bob green_eye_shadow
|
|
111
110
|
```
|
|
112
111
|
|
|
113
112
|
resulting in:
|
|
@@ -117,9 +116,9 @@ resulting in:
|
|
|
117
116
|
Let's try the `-z/--zoom` factor 2x, 4x, 8x, etc.:
|
|
118
117
|
|
|
119
118
|
```
|
|
120
|
-
$ punk --zoom
|
|
119
|
+
$ punk --zoom=4 gen female_2 earring blonde_bob green_eye_shadow
|
|
121
120
|
# -or-
|
|
122
|
-
$ punk -
|
|
121
|
+
$ punk -z4 g female_2 earring blonde_bob green_eye_shadow
|
|
123
122
|
```
|
|
124
123
|
|
|
125
124
|
resulting in:
|
|
@@ -132,8 +131,8 @@ resulting in:
|
|
|
132
131
|
Let's try never-before-seen super-rare punks:
|
|
133
132
|
|
|
134
133
|
```
|
|
135
|
-
$ punk
|
|
136
|
-
$ punk
|
|
134
|
+
$ punk gen demon heart_shades
|
|
135
|
+
$ punk gen vampire_female wild_hair
|
|
137
136
|
```
|
|
138
137
|
|
|
139
138
|
resulting in:
|
|
@@ -156,9 +155,9 @@ _List all punk archetype and attribute names from builtin punk spritesheet_
|
|
|
156
155
|
Let's try:
|
|
157
156
|
|
|
158
157
|
```
|
|
159
|
-
$ punk list
|
|
160
|
-
# -or-
|
|
161
158
|
$ punk ls
|
|
159
|
+
# -or-
|
|
160
|
+
$ punk l
|
|
162
161
|
```
|
|
163
162
|
|
|
164
163
|
resulting in:
|
|
@@ -391,7 +390,7 @@ And voila!
|
|
|
391
390
|
Let's give it a try. Let's save punk #0, #2890, and #8219 in 2x format:
|
|
392
391
|
|
|
393
392
|
```
|
|
394
|
-
$ punk --zoom
|
|
393
|
+
$ punk --zoom=2 tile 0 2890 8219
|
|
395
394
|
# -or-
|
|
396
395
|
$ punk -z2 t 0 2890 8219
|
|
397
396
|
```
|
|
@@ -456,7 +455,7 @@ and let's add an offset of 10000
|
|
|
456
455
|
(to start counting at 10000 instead of 0):
|
|
457
456
|
|
|
458
457
|
```
|
|
459
|
-
$ punk --file
|
|
458
|
+
$ punk --file=./more-punks-1.png --offset=10000 tile 0 18 40 88
|
|
460
459
|
```
|
|
461
460
|
|
|
462
461
|
printing:
|
|
@@ -500,7 +499,7 @@ and let's add an offset of 10100
|
|
|
500
499
|
(to start counting at 10000 plus 100 instead of 0):
|
|
501
500
|
|
|
502
501
|
```
|
|
503
|
-
$ punk --file
|
|
502
|
+
$ punk --file=./more-punks-2.png --offset=10100 tile 0 79 80 90
|
|
504
503
|
```
|
|
505
504
|
|
|
506
505
|
printing:
|
|
@@ -550,7 +549,7 @@ all punks. Phree the phunks! Let's give it a try:
|
|
|
550
549
|
```
|
|
551
550
|
$ punk flip
|
|
552
551
|
# - same as -
|
|
553
|
-
$ punk --file
|
|
552
|
+
$ punk --file=./punks.png flip
|
|
554
553
|
```
|
|
555
554
|
|
|
556
555
|
printing:
|
|
@@ -571,7 +570,7 @@ Yes, you can. Use any all-in-one composite image in the 24x24 format. Use the `
|
|
|
571
570
|
Example - let's flip the 1000 More Punks collection:
|
|
572
571
|
|
|
573
572
|
```
|
|
574
|
-
$ punk --file
|
|
573
|
+
$ punk --file=./morepunks.png flip
|
|
575
574
|
```
|
|
576
575
|
|
|
577
576
|
And so on.
|
|
@@ -590,7 +589,7 @@ Let's give it a try:
|
|
|
590
589
|
```
|
|
591
590
|
$ punk shuffle
|
|
592
591
|
# - same as -
|
|
593
|
-
$ punk --file
|
|
592
|
+
$ punk --file=./punks.png --seed=4142 shuffle
|
|
594
593
|
```
|
|
595
594
|
|
|
596
595
|
printing:
|
|
@@ -630,7 +629,7 @@ Yes, you can. Use any all-in-one composite image in the 24x24 format. Use the `
|
|
|
630
629
|
Example - let's shuffle the 1000 More Punks collection:
|
|
631
630
|
|
|
632
631
|
```
|
|
633
|
-
$ punk --file
|
|
632
|
+
$ punk --file=./morepunks.png shuffle
|
|
634
633
|
```
|
|
635
634
|
|
|
636
635
|
And so on.
|
|
@@ -663,4 +662,9 @@ Use it as you please with no restrictions whatsoever.
|
|
|
663
662
|
|
|
664
663
|
## Questions? Comments?
|
|
665
664
|
|
|
666
|
-
|
|
665
|
+
Join us in the [Punk Art discord (chat server)]( https://discord.gg/FE3HeXNKRa). Yes you can.
|
|
666
|
+
Your questions and commentary welcome.
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
Or post them over at the [Help & Support](https://github.com/geraldb/help) page. Thanks.
|
|
670
|
+
|
data/Rakefile
CHANGED
|
@@ -13,7 +13,7 @@ Hoe.spec 'cryptopunks' do
|
|
|
13
13
|
|
|
14
14
|
self.version = Pixelart::Module::Cryptopunks::VERSION
|
|
15
15
|
|
|
16
|
-
self.summary = "cryptopunks - generate your own 24×24 pixel punk images (
|
|
16
|
+
self.summary = "cryptopunks - generate your own 24×24 pixel punk images from text prompts incl. 2x/4x/8x zoom for bigger sizes (or crop 'n' save tiles from all-in-one composites incl. the True Official Matt & John's® Punks sha256-verified original 10 000 unique character collection)"
|
|
17
17
|
self.description = summary
|
|
18
18
|
|
|
19
19
|
self.urls = { home: 'https://github.com/cryptopunksnotdead/cryptopunks' }
|
|
@@ -27,8 +27,8 @@ Hoe.spec 'cryptopunks' do
|
|
|
27
27
|
|
|
28
28
|
self.extra_deps = [
|
|
29
29
|
['pixelart', '>= 1.3.2'],
|
|
30
|
-
['punks', '>=
|
|
31
|
-
['
|
|
30
|
+
['punks', '>= 2024.2.29'],
|
|
31
|
+
['cmdparse'],
|
|
32
32
|
]
|
|
33
33
|
|
|
34
34
|
self.licenses = ['Public Domain']
|
data/lib/cryptopunks/tool.rb
CHANGED
|
@@ -1,127 +1,112 @@
|
|
|
1
1
|
|
|
2
2
|
module Punk
|
|
3
3
|
|
|
4
|
-
|
|
5
4
|
class Tool
|
|
6
|
-
def run( args )
|
|
7
|
-
Toolii.run( args )
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class Opts
|
|
14
|
-
def merge_gli_options!( options = {} )
|
|
15
|
-
# puts " update options:"
|
|
16
|
-
# puts options.inspect
|
|
17
|
-
|
|
18
|
-
@file = options[:file] if options[:file]
|
|
19
|
-
@outdir = options[:dir] if options[:dir]
|
|
20
|
-
|
|
21
|
-
@zoom = options[:zoom] if options[:zoom]
|
|
22
|
-
@offset = options[:offset] if options[:offset]
|
|
23
|
-
|
|
24
|
-
@seed = options[:seed] if options[:seed]
|
|
25
|
-
|
|
26
|
-
@verbose = true if options[:verbose] == true
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def verbose=(boolean) # add: alias for debug ??
|
|
31
|
-
@verbose = boolean
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def verbose?
|
|
35
|
-
return false if @verbose.nil? # default verbose/debug flag is false
|
|
36
|
-
@verbose == true
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def file() @file || './punks.png'; end
|
|
40
|
-
def file?() @file; end ## note: let's you check if file is set (or "untouched")
|
|
41
|
-
|
|
42
|
-
def zoom() @zoom || 1; end
|
|
43
|
-
def zoom?() @zoom; end
|
|
44
|
-
|
|
45
|
-
def offset() @offset || 0; end
|
|
46
|
-
def offset?() @offset; end
|
|
47
|
-
|
|
48
|
-
def outdir() @outdir || '.'; end
|
|
49
|
-
def outdir?() @outdir; end
|
|
50
|
-
|
|
51
|
-
### use a standard (default) seed - why? why not?
|
|
52
|
-
def seed() @seed || 4142; end
|
|
53
|
-
def seed?() @seed; end
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
end # class Opts
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
## note: use gli "dsl" inside a class / namespace
|
|
62
|
-
class Toolii
|
|
63
|
-
extend GLI::App
|
|
64
|
-
|
|
65
|
-
opts = Opts.new
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
program_desc 'punk (or cryptopunk) command line tool'
|
|
69
|
-
|
|
70
|
-
version Pixelart::Module::Cryptopunks::VERSION
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
desc "Zoom factor x2, x4, x8, etc."
|
|
74
|
-
arg_name 'ZOOM'
|
|
75
|
-
default_value opts.zoom
|
|
76
|
-
flag [:z, :zoom], type: Integer
|
|
77
|
-
|
|
78
|
-
desc "Start counting at offset"
|
|
79
|
-
arg_name 'NUM'
|
|
80
|
-
default_value opts.offset
|
|
81
|
-
flag [:offset], type: Integer
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
desc "Seed for random number generation / shuffle"
|
|
85
|
-
arg_name 'NUM'
|
|
86
|
-
default_value opts.seed
|
|
87
|
-
flag [:seed], type: Integer
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
desc "Output directory"
|
|
92
|
-
arg_name 'DIR'
|
|
93
|
-
default_value opts.outdir
|
|
94
|
-
flag [:d, :dir,
|
|
95
|
-
:o, :out, :outdir], type: String
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
### todo/check: move option to -t/--tile command only - why? why not?
|
|
99
|
-
# desc "True Official Genuine CryptoPunks™ all-in-one composite image"
|
|
100
|
-
desc "All-in-one composite image"
|
|
101
|
-
arg_name 'FILE'
|
|
102
|
-
default_value opts.file
|
|
103
|
-
flag [:f, :file], type: String
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
### global option (required)
|
|
108
|
-
## todo: add check that path is valid?? possible?
|
|
109
|
-
desc '(Debug) Show debug messages'
|
|
110
|
-
switch [:verbose], negatable: false ## todo: use -w for short form? check ruby interpreter if in use too?
|
|
111
5
|
|
|
6
|
+
class Opts ## use nested Opts class (inside Tool) - why? why not?
|
|
7
|
+
def verbose=(boolean) # add: alias for debug ??
|
|
8
|
+
@verbose = boolean
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def verbose?
|
|
12
|
+
return false if @verbose.nil? # default verbose/debug flag is false
|
|
13
|
+
@verbose == true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def file() @file || './punks.png'; end
|
|
17
|
+
def file?() @file; end ## note: let's you check if file is set (or "untouched")
|
|
18
|
+
def file=(file) @file = file; end
|
|
19
|
+
|
|
20
|
+
def zoom() @zoom || 1; end
|
|
21
|
+
def zoom?() @zoom; end
|
|
22
|
+
def zoom=(num) @zoom = num; end
|
|
23
|
+
|
|
24
|
+
def offset() @offset || 0; end
|
|
25
|
+
def offset?() @offset; end
|
|
26
|
+
def offset=(num) @offset = num; end
|
|
27
|
+
|
|
28
|
+
def outdir() @outdir || '.'; end
|
|
29
|
+
def outdir?() @outdir; end
|
|
30
|
+
def outdir=(dir) @outdir = dir; end
|
|
31
|
+
|
|
32
|
+
### use a standard (default) seed - why? why not?
|
|
33
|
+
def seed() @seed || 4142; end
|
|
34
|
+
def seed?() @seed; end
|
|
35
|
+
def seed=(num) @seed = num; end
|
|
36
|
+
end # class Opts
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
## use def self.run instead of run e.g.
|
|
40
|
+
## Tool.run( ARGV ) vs Tool.new.run( ARGV )
|
|
41
|
+
def run( args )
|
|
42
|
+
opts = Opts.new
|
|
43
|
+
|
|
44
|
+
parser = CmdParse::CommandParser.new(handle_exceptions: :no_help)
|
|
45
|
+
parser.main_options.program_name = 'punk'
|
|
46
|
+
parser.main_options.banner = 'punk (or cryptopunk) command line tool'
|
|
47
|
+
parser.main_options.version = Pixelart::Module::Cryptopunks::VERSION
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
parser.global_options do |opt|
|
|
52
|
+
opt.on( '-z', '--zoom=NUM', Integer,
|
|
53
|
+
"Zoom factor x2, x4, x8, etc. (default: #{opts.zoom})"
|
|
54
|
+
) do |num|
|
|
55
|
+
opts.zoom = num
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
opt.on( '--offset=NUM', Integer,
|
|
59
|
+
"Start counting at offset (default: #{opts.offset})"
|
|
60
|
+
) do |num|
|
|
61
|
+
opts.offset = num
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
## todo - move to shuffle (only used by shuffle) - why? why not?
|
|
65
|
+
opt.on( '--seed=NUM', Integer,
|
|
66
|
+
"Seed for random number generation / shuffle (default: #{opts.seed})"
|
|
67
|
+
) do |num|
|
|
68
|
+
opts.seed = num
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# note: remove -d alias (and --dir=DIR) why? why not?
|
|
72
|
+
opt.on( '-o', '--out=DIR', '--dir=DIR', '--outdir=DIR',
|
|
73
|
+
"Output directory (default: #{opts.outdir})"
|
|
74
|
+
) do |dir|
|
|
75
|
+
opts.outdir = dir
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
### todo/check: move option to -t/--tile command only - why? why not?
|
|
79
|
+
# desc "True Official Genuine CryptoPunks™ all-in-one composite image"
|
|
80
|
+
## todo: add check that path is valid?? possible?
|
|
81
|
+
opt.on( '-f', '--file=FILE',
|
|
82
|
+
"All-in-one composite image (default: #{opts.file})"
|
|
83
|
+
) do |file|
|
|
84
|
+
opts.file = file
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# note - not used for now - always on
|
|
88
|
+
## todo: use -w for short form? check ruby interpreter if in use too?
|
|
89
|
+
# opt.on( '--verbose',
|
|
90
|
+
# "(Debug) Show debug messages"
|
|
91
|
+
# ) do
|
|
92
|
+
# opts.verbose = true
|
|
93
|
+
# # ## LogUtils::Logger.root.level = :debug
|
|
94
|
+
# end
|
|
95
|
+
end
|
|
112
96
|
|
|
113
97
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
98
|
+
# command - f, flip
|
|
99
|
+
flip = CmdParse::Command.new('flip', takes_commands: false)
|
|
100
|
+
flip.short_desc( "Flip (vertically) all punk characters in all-in-one punk series composite (#{opts.file})" )
|
|
101
|
+
flip.action do
|
|
117
102
|
puts "==> reading >#{opts.file}<..."
|
|
118
103
|
punks = ImageComposite.read( opts.file )
|
|
119
104
|
|
|
120
105
|
## note: for now always assume 24x24
|
|
121
|
-
cols = punks.width / 24
|
|
122
|
-
rows = punks.height / 24
|
|
123
106
|
tile_width = 24
|
|
124
107
|
tile_height = 24
|
|
108
|
+
cols = punks.width / tile_width
|
|
109
|
+
rows = punks.height / tile_height
|
|
125
110
|
|
|
126
111
|
phunks = ImageComposite.new( cols, rows,
|
|
127
112
|
width: tile_width,
|
|
@@ -134,28 +119,28 @@ command [:f, :flip] do |c|
|
|
|
134
119
|
## make sure outdir exits (default is current working dir e.g. .)
|
|
135
120
|
FileUtils.mkdir_p( opts.outdir ) unless Dir.exist?( opts.outdir )
|
|
136
121
|
|
|
137
|
-
## note:
|
|
122
|
+
## note: always assume .png extension for now
|
|
138
123
|
basename = File.basename( opts.file, File.extname( opts.file ) )
|
|
139
124
|
path = "#{opts.outdir}/#{basename}-flipped.png"
|
|
140
125
|
puts "==> saving phunks flipped one-by-one by hand to >#{path}<..."
|
|
141
126
|
|
|
142
127
|
phunks.save( path )
|
|
143
128
|
puts 'Done.'
|
|
144
|
-
|
|
145
|
-
end # command flip
|
|
129
|
+
end # action
|
|
146
130
|
|
|
147
131
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
132
|
+
# command - s, shuffle
|
|
133
|
+
shuffle = CmdParse::Command.new('shuffle', takes_commands: false)
|
|
134
|
+
shuffle.short_desc( "Shuffle all punk characters (randomly) in all-in-one punk series composite (#{opts.file})" )
|
|
135
|
+
shuffle.action do
|
|
151
136
|
puts "==> reading >#{opts.file}<..."
|
|
152
137
|
punks = ImageComposite.read( opts.file )
|
|
153
138
|
|
|
154
139
|
## note: for now always assume 24x24
|
|
155
|
-
cols = punks.width / 24
|
|
156
|
-
rows = punks.height / 24
|
|
157
140
|
tile_width = 24
|
|
158
141
|
tile_height = 24
|
|
142
|
+
cols = punks.width / tile_width
|
|
143
|
+
rows = punks.height / tile_height
|
|
159
144
|
|
|
160
145
|
phunks = ImageComposite.new( cols, rows,
|
|
161
146
|
width: tile_width,
|
|
@@ -171,7 +156,6 @@ command [:s, :shuffle] do |c|
|
|
|
171
156
|
# seed 4142 ends in [..., 7566, 828, 8987, 9777]
|
|
172
157
|
# 333 ends in [..., 6067, 9635, 973, 8172]
|
|
173
158
|
|
|
174
|
-
|
|
175
159
|
indexes.each_with_index do |old_index,new_index|
|
|
176
160
|
puts " ##{old_index} now ##{new_index}"
|
|
177
161
|
phunks << punks[old_index]
|
|
@@ -190,26 +174,16 @@ command [:s, :shuffle] do |c|
|
|
|
190
174
|
|
|
191
175
|
phunks.save( path )
|
|
192
176
|
puts 'Done.'
|
|
193
|
-
|
|
194
|
-
end # command shuffle
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
177
|
+
end # action
|
|
199
178
|
|
|
200
179
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
# puts "opts:"
|
|
207
|
-
# puts opts.inspect
|
|
208
|
-
|
|
180
|
+
# command - t, tile
|
|
181
|
+
tile = CmdParse::Command.new('tile', takes_commands: false)
|
|
182
|
+
tile.short_desc( "Get punk characters via image tiles from all-in-one punk series composite (#{opts.file}) - for IDs use 0 to 9999" )
|
|
183
|
+
tile.action do |*args|
|
|
209
184
|
puts "==> reading >#{opts.file}<..."
|
|
210
185
|
punks = ImageComposite.read( opts.file )
|
|
211
186
|
|
|
212
|
-
|
|
213
187
|
puts " setting zoom to #{opts.zoom}x" if opts.zoom != 1
|
|
214
188
|
|
|
215
189
|
## make sure outdir exits (default is current working dir e.g. .)
|
|
@@ -234,17 +208,16 @@ command [:t, :tile] do |c|
|
|
|
234
208
|
punk.save( path )
|
|
235
209
|
end
|
|
236
210
|
puts 'Done.'
|
|
237
|
-
|
|
238
|
-
end # command tile
|
|
211
|
+
end # action
|
|
239
212
|
|
|
240
213
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
214
|
+
# command - g, gen, generate
|
|
215
|
+
# note: shorten to gen
|
|
216
|
+
generate = CmdParse::Command.new('gen', takes_commands: false)
|
|
217
|
+
generate.short_desc( "Generate punk characters from text attributes (from scratch / zero) via builtin punk spritesheet" )
|
|
218
|
+
generate.action do |*args|
|
|
246
219
|
puts "==> generating >#{args.join( ' + ' )}<..."
|
|
247
|
-
punk = Image.generate( *args )
|
|
220
|
+
punk = Punk::Image.generate( *args )
|
|
248
221
|
|
|
249
222
|
puts " setting zoom to #{opts.zoom}x" if opts.zoom != 1
|
|
250
223
|
|
|
@@ -265,17 +238,14 @@ command [:g, :gen, :generate] do |c|
|
|
|
265
238
|
|
|
266
239
|
punk.save( path )
|
|
267
240
|
puts 'Done.'
|
|
268
|
-
|
|
269
|
-
end # command generate
|
|
270
|
-
|
|
241
|
+
end # action
|
|
271
242
|
|
|
272
|
-
desc 'Query (builtin off-chain) punk contract for punk text attributes by IDs - use 0 to 9999'
|
|
273
|
-
command [:q, :query] do |c|
|
|
274
|
-
c.action do |g,o,args|
|
|
275
243
|
|
|
276
|
-
# puts "opts:"
|
|
277
|
-
# puts opts.inspect
|
|
278
244
|
|
|
245
|
+
# command - q, query
|
|
246
|
+
query = CmdParse::Command.new('query', takes_commands: false)
|
|
247
|
+
query.short_desc( "Query (builtin off-chain) punk contract for punk text attributes by IDs - use 0 to 9999" )
|
|
248
|
+
query.action do |*args|
|
|
279
249
|
args.each_with_index do |arg,index|
|
|
280
250
|
punk_index = arg.to_i( 10 ) ## assume base 10 decimal
|
|
281
251
|
|
|
@@ -292,19 +262,20 @@ command [:q, :query] do |c|
|
|
|
292
262
|
print "\n"
|
|
293
263
|
end
|
|
294
264
|
puts 'Done.'
|
|
295
|
-
end
|
|
296
265
|
end
|
|
297
266
|
|
|
298
267
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
268
|
+
# command - l, ls # (NOT) list
|
|
269
|
+
## note: ls (alias) is NOT possible with cmdparse gem!!!!! - ask if workaround?
|
|
270
|
+
## note: as a workaround use ls for now (not list)!!!
|
|
271
|
+
list = CmdParse::Command.new('ls', takes_commands: false)
|
|
272
|
+
list.short_desc( "List all punk archetype and attribute names from builtin punk spritesheet" )
|
|
273
|
+
list.action do
|
|
274
|
+
# was: generator = Punk::Image.generator
|
|
275
|
+
sheet = Punk::Spritesheet.builtin
|
|
305
276
|
|
|
306
277
|
puts "==> Archetypes"
|
|
307
|
-
|
|
278
|
+
sheet.meta.each do |rec|
|
|
308
279
|
next unless rec.archetype?
|
|
309
280
|
|
|
310
281
|
print " "
|
|
@@ -315,7 +286,7 @@ command [:l, :ls, :list] do |c|
|
|
|
315
286
|
|
|
316
287
|
puts ""
|
|
317
288
|
puts "==> Attributes"
|
|
318
|
-
|
|
289
|
+
sheet.meta.each do |rec|
|
|
319
290
|
next unless rec.attribute?
|
|
320
291
|
|
|
321
292
|
print " "
|
|
@@ -325,58 +296,27 @@ command [:l, :ls, :list] do |c|
|
|
|
325
296
|
end
|
|
326
297
|
|
|
327
298
|
puts ""
|
|
328
|
-
puts " See github.com/
|
|
299
|
+
puts " See github.com/openpunkart/punkart.spritesheet for more."
|
|
329
300
|
puts ""
|
|
330
301
|
|
|
331
302
|
puts 'Done.'
|
|
332
|
-
|
|
333
|
-
end # command list
|
|
303
|
+
end # action
|
|
334
304
|
|
|
335
305
|
|
|
306
|
+
parser.add_command(CmdParse::HelpCommand.new, default: true)
|
|
307
|
+
parser.add_command(CmdParse::VersionCommand.new)
|
|
308
|
+
parser.add_command( flip )
|
|
309
|
+
parser.add_command( shuffle )
|
|
310
|
+
parser.add_command( tile )
|
|
311
|
+
parser.add_command( generate )
|
|
312
|
+
parser.add_command( query )
|
|
313
|
+
parser.add_command( list )
|
|
336
314
|
|
|
337
|
-
pre do |g,c,o,args|
|
|
338
|
-
opts.merge_gli_options!( g )
|
|
339
|
-
opts.merge_gli_options!( o )
|
|
340
|
-
|
|
341
|
-
if opts.verbose?
|
|
342
|
-
## LogUtils::Logger.root.level = :debug
|
|
343
|
-
end
|
|
344
|
-
|
|
345
|
-
## logger.debug "Executing #{c.name}"
|
|
346
|
-
true
|
|
347
|
-
end
|
|
348
|
-
|
|
349
|
-
post do |global,c,o,args|
|
|
350
|
-
## logger.debug "Executed #{c.name}"
|
|
351
|
-
true
|
|
352
|
-
end
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
on_error do |e|
|
|
356
|
-
|
|
357
|
-
if opts.verbose?
|
|
358
|
-
puts e.backtrace
|
|
359
|
-
end
|
|
360
|
-
|
|
361
|
-
if e.is_a?( SystemExit )
|
|
362
|
-
puts
|
|
363
|
-
puts "*** error: system exit with status code ( #{e.status} )"
|
|
364
|
-
exit( e.status ) ## try exit again to make sure error code gets passed along!!!
|
|
365
|
-
else
|
|
366
|
-
puts
|
|
367
|
-
puts "*** error: #{e.message}"
|
|
368
|
-
end
|
|
369
|
-
|
|
370
|
-
## note: was false # skip default error handling
|
|
371
|
-
|
|
372
|
-
## note: try true - false WILL SWALLOW exit codes and such
|
|
373
|
-
## - looks like it's still returning 0 (e.g. on unknown option or such)!!!!
|
|
374
|
-
true
|
|
375
|
-
end
|
|
376
315
|
|
|
316
|
+
parser.parse( args )
|
|
317
|
+
end # method run
|
|
318
|
+
end # class Tool
|
|
319
|
+
end # moduule Punk
|
|
377
320
|
|
|
378
|
-
### exit run(ARGV) ## note: use Toolii.run( ARGV ) outside of class
|
|
379
|
-
end # class Toolii
|
|
380
|
-
end # module Punk
|
|
381
321
|
|
|
382
322
|
|
data/lib/cryptopunks/version.rb
CHANGED
data/lib/cryptopunks.rb
CHANGED
|
@@ -6,7 +6,7 @@ require 'punks'
|
|
|
6
6
|
## extra stdlibs
|
|
7
7
|
require 'digest' ## move/add to pixelart upstream - why? why not?
|
|
8
8
|
require 'optparse'
|
|
9
|
-
require '
|
|
9
|
+
require 'cmdparse' ## used for command line tool
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
@@ -15,23 +15,7 @@ require 'cryptopunks/version' # note: let version always go first
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
require 'cryptopunks/attributes'
|
|
18
|
-
require 'cryptopunks/structs'
|
|
19
|
-
require 'cryptopunks/composite'
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
## add old backwards compatible alias
|
|
23
|
-
module Punk
|
|
24
|
-
class Image
|
|
25
|
-
Composite = ImageComposite
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
require 'cryptopunks/dataset'
|
|
32
|
-
|
|
33
18
|
require 'cryptopunks/colors'
|
|
34
|
-
require 'cryptopunks/image'
|
|
35
19
|
|
|
36
20
|
|
|
37
21
|
####
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cryptopunks
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 2024.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gerald Bauer
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2024-03-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: pixelart
|
|
@@ -30,16 +30,16 @@ dependencies:
|
|
|
30
30
|
requirements:
|
|
31
31
|
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
33
|
+
version: 2024.2.29
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
40
|
+
version: 2024.2.29
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
42
|
+
name: cmdparse
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - ">="
|
|
@@ -78,17 +78,18 @@ dependencies:
|
|
|
78
78
|
requirements:
|
|
79
79
|
- - "~>"
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: '
|
|
81
|
+
version: '4.1'
|
|
82
82
|
type: :development
|
|
83
83
|
prerelease: false
|
|
84
84
|
version_requirements: !ruby/object:Gem::Requirement
|
|
85
85
|
requirements:
|
|
86
86
|
- - "~>"
|
|
87
87
|
- !ruby/object:Gem::Version
|
|
88
|
-
version: '
|
|
89
|
-
description: cryptopunks - generate your own 24×24 pixel punk images
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
version: '4.1'
|
|
89
|
+
description: cryptopunks - generate your own 24×24 pixel punk images from text prompts
|
|
90
|
+
incl. 2x/4x/8x zoom for bigger sizes (or crop 'n' save tiles from all-in-one composites
|
|
91
|
+
incl. the True Official Matt & John's® Punks sha256-verified original 10 000 unique
|
|
92
|
+
character collection)
|
|
92
93
|
email: wwwmake@googlegroups.com
|
|
93
94
|
executables:
|
|
94
95
|
- cryptopunk
|
|
@@ -108,13 +109,9 @@ files:
|
|
|
108
109
|
- lib/cryptopunks.rb
|
|
109
110
|
- lib/cryptopunks/attributes.rb
|
|
110
111
|
- lib/cryptopunks/colors.rb
|
|
111
|
-
- lib/cryptopunks/composite.rb
|
|
112
112
|
- lib/cryptopunks/contract/punksdata-assets.rb
|
|
113
113
|
- lib/cryptopunks/contract/punksdata-contract.rb
|
|
114
114
|
- lib/cryptopunks/contract/punksdata-meta.rb
|
|
115
|
-
- lib/cryptopunks/dataset.rb
|
|
116
|
-
- lib/cryptopunks/image.rb
|
|
117
|
-
- lib/cryptopunks/structs.rb
|
|
118
115
|
- lib/cryptopunks/tool.rb
|
|
119
116
|
- lib/cryptopunks/version.rb
|
|
120
117
|
homepage: https://github.com/cryptopunksnotdead/cryptopunks
|
|
@@ -138,10 +135,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
138
135
|
- !ruby/object:Gem::Version
|
|
139
136
|
version: '0'
|
|
140
137
|
requirements: []
|
|
141
|
-
rubygems_version: 3.
|
|
138
|
+
rubygems_version: 3.4.10
|
|
142
139
|
signing_key:
|
|
143
140
|
specification_version: 4
|
|
144
|
-
summary: cryptopunks - generate your own 24×24 pixel punk images
|
|
145
|
-
|
|
146
|
-
|
|
141
|
+
summary: cryptopunks - generate your own 24×24 pixel punk images from text prompts
|
|
142
|
+
incl. 2x/4x/8x zoom for bigger sizes (or crop 'n' save tiles from all-in-one composites
|
|
143
|
+
incl. the True Official Matt & John's® Punks sha256-verified original 10 000 unique
|
|
144
|
+
character collection)
|
|
147
145
|
test_files: []
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
module Punk
|
|
2
|
-
## note: was Image::Composite
|
|
3
|
-
class ImageComposite < Pixelart::ImageComposite
|
|
4
|
-
|
|
5
|
-
PUNK_HASH = 'ac39af4793119ee46bbff351d8cb6b5f23da60222126add4268e261199a2921b'
|
|
6
|
-
|
|
7
|
-
def self.sha256( data )
|
|
8
|
-
## todo/check: or just use Digest::SHA256.hexdigest - why? why not?
|
|
9
|
-
Digest::SHA256.digest( data ).unpack( 'H*' )[0]
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
PUNK_HEIGHT = 24
|
|
14
|
-
PUNK_WIDTH = 24
|
|
15
|
-
|
|
16
|
-
def self.read( path='./punks.png', width: PUNK_WIDTH, height: PUNK_HEIGHT )
|
|
17
|
-
data = File.open( path, 'rb' ) { |f| f.read }
|
|
18
|
-
|
|
19
|
-
hexdigest = sha256( data ) ## check sha256 checksum
|
|
20
|
-
if hexdigest == PUNK_HASH
|
|
21
|
-
puts " >#{hexdigest}< SHA256 hash matching"
|
|
22
|
-
puts " ✓ True Official Genuine Matt & John's® Punks verified"
|
|
23
|
-
else
|
|
24
|
-
puts " ✓ True Official Genuine Yes, You Can! Punk's Not Dead® verified"
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
img = ChunkyPNG::Image.from_blob( data )
|
|
28
|
-
new( img, width: width, height: height )
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def initialize( *args, width: PUNK_WIDTH,
|
|
33
|
-
height: PUNK_HEIGHT )
|
|
34
|
-
super
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
end ## class ImageComposite
|
|
38
|
-
end ## module Punk
|
data/lib/cryptopunks/dataset.rb
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
module Punk
|
|
4
|
-
module Dataset
|
|
5
|
-
|
|
6
|
-
def self.read( path='./datasets/punks/*.csv' )
|
|
7
|
-
|
|
8
|
-
datasets = Dir.glob( path )
|
|
9
|
-
#=> ["./datasets/punks/0-999.csv",
|
|
10
|
-
# "./datasets/punks/1000-1999.csv",
|
|
11
|
-
# "./datasets/punks/2000-2999.csv",
|
|
12
|
-
# "./datasets/punks/3000-3999.csv",
|
|
13
|
-
# "./datasets/punks/4000-4999.csv",
|
|
14
|
-
# "./datasets/punks/5000-5999.csv",
|
|
15
|
-
# "./datasets/punks/6000-6999.csv",
|
|
16
|
-
# "./datasets/punks/7000-7999.csv",
|
|
17
|
-
# "./datasets/punks/8000-8999.csv",
|
|
18
|
-
# "./datasets/punks/9000-9999.csv"]
|
|
19
|
-
|
|
20
|
-
rows = []
|
|
21
|
-
datasets.each do |dataset|
|
|
22
|
-
rows += CsvHash.read( dataset )
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# puts " #{rows.size} rows(s)"
|
|
26
|
-
#=> 10000 rows(s)
|
|
27
|
-
|
|
28
|
-
### wrap in punk struct for easier access
|
|
29
|
-
punks = []
|
|
30
|
-
rows.each do |row|
|
|
31
|
-
id = row['id'].to_i
|
|
32
|
-
type_q = row['type']
|
|
33
|
-
count = row['count'].to_i
|
|
34
|
-
accessories_q = row['accessories'].split( %r{[ ]*/[ ]*} )
|
|
35
|
-
|
|
36
|
-
if count != accessories_q.size
|
|
37
|
-
puts "!! ERROR - punk data assertion failed - expected accessories count #{count}; got #{accessories_q.size}"
|
|
38
|
-
pp row
|
|
39
|
-
exit 1
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
type = Metadata::Type.find( type_q )
|
|
43
|
-
if type.nil?
|
|
44
|
-
puts "!! ERROR - punk data assertion failed - unknown punk type >#{type_q}<"
|
|
45
|
-
pp row
|
|
46
|
-
exit 1
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
accessories = []
|
|
50
|
-
accessories_q.each do |acc_q|
|
|
51
|
-
acc = Metadata::Accessory.find( acc_q )
|
|
52
|
-
if acc.nil?
|
|
53
|
-
puts "!! ERROR - punk data assertion failed - unknown punk accessory type >#{acc_q}<"
|
|
54
|
-
pp row
|
|
55
|
-
exit 1
|
|
56
|
-
end
|
|
57
|
-
accessories << acc
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
punks << Metadata.new( id, type, accessories )
|
|
61
|
-
end
|
|
62
|
-
punks
|
|
63
|
-
end
|
|
64
|
-
end # module Dataset
|
|
65
|
-
end # module Punk
|
|
66
|
-
|
|
67
|
-
|
data/lib/cryptopunks/image.rb
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
module Punk
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class Image
|
|
6
|
-
|
|
7
|
-
def self.read( path ) ## convenience helper
|
|
8
|
-
img = ChunkyPNG::Image.from_file( path )
|
|
9
|
-
new( img )
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
=begin
|
|
15
|
-
|
|
16
|
-
### keep design & colors keyword args in c'tor here
|
|
17
|
-
## or use parse() like in pixelart - why? why not?
|
|
18
|
-
|
|
19
|
-
def initialize( initial=nil, design: nil,
|
|
20
|
-
colors: nil )
|
|
21
|
-
if initial
|
|
22
|
-
## pass image through as-is
|
|
23
|
-
img = initial
|
|
24
|
-
else
|
|
25
|
-
## note: unwrap inner image before passing on to super c'tor
|
|
26
|
-
img = Pixelart::Image.parse( design, colors: colors ).image
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
super( img.width, img.height, img )
|
|
30
|
-
end
|
|
31
|
-
=end
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
end # class Image
|
|
35
|
-
end # module Punk
|
data/lib/cryptopunks/structs.rb
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
module Punk
|
|
3
|
-
### wrap metadata (e.g. punk types, accessories, etc.
|
|
4
|
-
## in structs for easy/easier access)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class Metadata
|
|
9
|
-
|
|
10
|
-
## nested class
|
|
11
|
-
class Type ## todo/check: use alias family or such?
|
|
12
|
-
attr_reader :name,
|
|
13
|
-
:limit
|
|
14
|
-
def initialize( name, limit )
|
|
15
|
-
@name = name
|
|
16
|
-
@limit = limit
|
|
17
|
-
end
|
|
18
|
-
## def to_s() @name; end
|
|
19
|
-
|
|
20
|
-
def inspect
|
|
21
|
-
%Q{<Type "#{@name}", limit: #{@limit}>}
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def self.build
|
|
27
|
-
TYPES.reduce( {} ) do |h, rec|
|
|
28
|
-
type = Type.new( rec[:name], rec[:limit ] )
|
|
29
|
-
h[ rec[:name].downcase ] = type
|
|
30
|
-
h
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def self.registry
|
|
35
|
-
## auto-build registry (hash table) lookup (by name)
|
|
36
|
-
@@types ||= build
|
|
37
|
-
@@types
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def self.all() registry.values; end
|
|
41
|
-
|
|
42
|
-
def self.find( q ) registry[ q.to_s.downcase ]; end
|
|
43
|
-
end ## (nested) class Type
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
## nested class
|
|
48
|
-
class AccessoryType
|
|
49
|
-
attr_reader :name,
|
|
50
|
-
:accessories
|
|
51
|
-
def initialize( name, accessories=[] )
|
|
52
|
-
@name = name
|
|
53
|
-
@accessories = accessories
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def self.build
|
|
59
|
-
ACCESSORY_TYPES.reduce( {} ) do |h, rec|
|
|
60
|
-
type = AccessoryType.new( rec[:name] )
|
|
61
|
-
## add all accessories
|
|
62
|
-
rec[:accessories].each do |rec_acc|
|
|
63
|
-
type.accessories << Accessory.new( rec_acc[:name],
|
|
64
|
-
type,
|
|
65
|
-
rec_acc[:limit].to_i )
|
|
66
|
-
end
|
|
67
|
-
h[ rec[:name].downcase ] = type
|
|
68
|
-
h
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
def self.registry
|
|
73
|
-
## auto-build registry (hash table) lookup (by name)
|
|
74
|
-
@@types ||= build
|
|
75
|
-
@@types
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def self.all() registry.values; end
|
|
79
|
-
|
|
80
|
-
def self.find( q ) registry[ q.to_s.downcase ]; end
|
|
81
|
-
end ## (nested) class AccessoryType
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
## nested class
|
|
85
|
-
class Accessory
|
|
86
|
-
|
|
87
|
-
attr_reader :name,
|
|
88
|
-
:type,
|
|
89
|
-
:limit
|
|
90
|
-
def initialize( name, type, limit )
|
|
91
|
-
@name = name
|
|
92
|
-
@type = type
|
|
93
|
-
@limit = limit
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def inspect
|
|
98
|
-
%Q{<Accessory "#{@name}", type: "#{@type.name}", limit: #{@limit}>}
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def self.build
|
|
104
|
-
AccessoryType.all.reduce( {} ) do |h, type|
|
|
105
|
-
type.accessories.each do |acc|
|
|
106
|
-
h[ acc.name.downcase ] = acc
|
|
107
|
-
end
|
|
108
|
-
h
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def self.registry
|
|
113
|
-
## auto-build registry (hash table) lookup (by name)
|
|
114
|
-
@@types ||= build
|
|
115
|
-
@@types
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
def self.all() registry.values; end
|
|
119
|
-
|
|
120
|
-
def self.find( q ) registry[ q.to_s.downcase ]; end
|
|
121
|
-
end ## (nested) class Accessory
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
attr_reader :id,
|
|
129
|
-
:type,
|
|
130
|
-
:accessories,
|
|
131
|
-
:birthday ## todo/check: use minted or such?
|
|
132
|
-
|
|
133
|
-
def initialize( id, type, accessories )
|
|
134
|
-
@id = id
|
|
135
|
-
@type = type
|
|
136
|
-
@accessories = accessories
|
|
137
|
-
@birthday = Date.new( 2017, 6, 23) ## all 10,000 minted on June 23, 2017
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def is_type?( name ) @type.name == name; end
|
|
141
|
-
alias_method :is?, :is_type?
|
|
142
|
-
|
|
143
|
-
## convenience helpers for "classic" (5) types
|
|
144
|
-
def alien?() is_type?( 'Alien'); end
|
|
145
|
-
def ape?() is_type?( 'Ape' ); end
|
|
146
|
-
def zombie?() is_type?( 'Zombie' ); end
|
|
147
|
-
def female?() is_type?( 'Female' ); end
|
|
148
|
-
def male?() is_type?( 'Male' ); end
|
|
149
|
-
|
|
150
|
-
## convenience helpers to lookup attributes
|
|
151
|
-
def has_attribute?( name )
|
|
152
|
-
accessories.each do |acc|
|
|
153
|
-
return true if acc.name == name
|
|
154
|
-
end
|
|
155
|
-
false
|
|
156
|
-
end
|
|
157
|
-
alias_method :has?, :has_attribute?
|
|
158
|
-
alias_method :include?, :has_attribute?
|
|
159
|
-
end # class Metadata
|
|
160
|
-
|
|
161
|
-
end # module Punk
|