├── bitcat
├── HISTORY.md
├── bitcat.png
├── lib
│ ├── bitcat
│ │ ├── public
│ │ │ └── style.css
│ │ ├── views
│ │ │ ├── layout.erb
│ │ │ ├── index.erb
│ │ │ └── kitty.erb
│ │ ├── version.rb
│ │ └── app.rb
│ └── bitcat.rb
├── Manifest.txt
├── bin
│ └── bitcat
├── .gitignore
├── Rakefile
└── README.md
├── copycats
├── CHANGELOG.md
├── test
│ ├── helper.rb
│ ├── test_version.rb
│ ├── test_models.rb
│ ├── test_traits.rb
│ ├── test_mixgenes.rb
│ └── test_genome.rb
├── bin
│ └── kitty
├── script
│ ├── kitty.rb
│ └── convert.rb
├── lib
│ ├── copycats
│ │ ├── version.rb
│ │ ├── traits.rb
│ │ ├── reports
│ │ │ ├── kitty.rb
│ │ │ ├── mix.rb
│ │ │ └── traits.rb
│ │ ├── models
│ │ │ └── kitty.rb
│ │ ├── import
│ │ │ ├── setup.rb
│ │ │ └── read.rb
│ │ ├── schema.rb
│ │ ├── tool.rb
│ │ ├── gene.rb
│ │ └── genome.rb
│ └── copycats.rb
├── Manifest.txt
├── Rakefile
├── .gitignore
├── KITTY-100000.md
├── KITTY-99895.md
├── NOTES.md
└── README.md
├── copycats-tables.png
├── LICENSE.md
└── README.md
/bitcat/HISTORY.md:
--------------------------------------------------------------------------------
1 | ### 0.0.1 / 2018-03-24
2 |
3 | * Everything is new. First release
4 |
--------------------------------------------------------------------------------
/bitcat/bitcat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cryptocopycats/copycats/HEAD/bitcat/bitcat.png
--------------------------------------------------------------------------------
/copycats/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### 0.0.1 / 2018-01-10
2 |
3 | * Everything is new. First release
4 |
--------------------------------------------------------------------------------
/copycats-tables.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cryptocopycats/copycats/HEAD/copycats-tables.png
--------------------------------------------------------------------------------
/bitcat/lib/bitcat/public/style.css:
--------------------------------------------------------------------------------
1 |
2 | body {
3 | font-family: arial,sans-serif;
4 | color: #222;
5 | }
6 |
--------------------------------------------------------------------------------
/copycats/test/helper.rb:
--------------------------------------------------------------------------------
1 | ## $:.unshift(File.dirname(__FILE__))
2 |
3 | ## minitest setup
4 |
5 | require 'minitest/autorun'
6 |
7 |
8 | ## our own code
9 |
10 | require 'copycats'
11 |
--------------------------------------------------------------------------------
/bitcat/lib/bitcat/views/layout.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Bitcat - Bit Catalog Kitty Browser
5 |
6 |
7 |
8 |
9 | <%= yield %>
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/bitcat/Manifest.txt:
--------------------------------------------------------------------------------
1 | HISTORY.md
2 | LICENSE.md
3 | Manifest.txt
4 | README.md
5 | Rakefile
6 | bin/bitcat
7 | lib/bitcat.rb
8 | lib/bitcat/app.rb
9 | lib/bitcat/public/style.css
10 | lib/bitcat/version.rb
11 | lib/bitcat/views/index.erb
12 | lib/bitcat/views/kitty.erb
13 | lib/bitcat/views/layout.erb
14 |
--------------------------------------------------------------------------------
/bitcat/bin/bitcat:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | ###################
4 | # DEV TIPS:
5 | #
6 | # For local testing run like:
7 | #
8 | # ruby -I./lib bin/bitcat
9 | #
10 | # Set the executable bit in Linux. Example:
11 | #
12 | # % chmod a+x bin/bitcat
13 | #
14 |
15 | require 'bitcat'
16 |
17 | Bitcat.main
18 |
--------------------------------------------------------------------------------
/copycats/bin/kitty:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | ###################
4 | # DEV TIPS:
5 | #
6 | # For local testing run like:
7 | #
8 | # ruby -I./lib bin/kitty
9 | #
10 | # Set the executable bit in Linux. Example:
11 | #
12 | # % chmod a+x bin/kitty
13 | #
14 |
15 | require 'copycats'
16 |
17 | Copycats.main
18 |
--------------------------------------------------------------------------------
/copycats/test/test_version.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | ###
4 | # to run use
5 | # ruby -I ./lib -I ./test test/test_version.rb
6 |
7 |
8 | require 'helper'
9 |
10 |
11 | class TestVersion < MiniTest::Test
12 |
13 | def test_version
14 | pp Copycats.version
15 | pp Copycats.banner
16 | pp Copycats.root
17 |
18 | assert true ## (for now) everything ok if we get here
19 | end
20 |
21 | end # class TestVersion
22 |
--------------------------------------------------------------------------------
/bitcat/lib/bitcat/views/index.erb:
--------------------------------------------------------------------------------
1 | Bitcat - Bit Catalog Kitty Browser
2 |
3 |
4 |
8 |
9 |
10 |
11 |
12 | Try
13 | <% Copycats::Model::Kitty.limit(10).each do |kitty| %>
14 | #<%= kitty.id %>
15 | <% end %>
16 |
17 |
--------------------------------------------------------------------------------
/copycats/script/kitty.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | ####
4 | # use:
5 | # $ ruby -I ./lib script/kitty.rb
6 |
7 |
8 | require 'copycats'
9 |
10 |
11 | KittyReport.new( id: 100_000,
12 | genes: "dadc 557j 4aaa gb9g 1161 383k 7dbe 774b 6667 8438 dd9a cbbd"
13 | ).save( "./KITTY-100000.md" )
14 |
15 | KittyReport.new( id: 99_895,
16 | genes: "cdad 55r6 7f2f g9bg 1111 3757 d99d 272h 8k78 k884 9da9 fdee"
17 | ).save( "./KITTY-99895.md" )
18 |
--------------------------------------------------------------------------------
/bitcat/lib/bitcat/version.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 |
4 | module Bitcat
5 |
6 | MAJOR = 0
7 | MINOR = 1
8 | PATCH = 0
9 | VERSION = [MAJOR,MINOR,PATCH].join('.')
10 |
11 | def self.version
12 | VERSION
13 | end
14 |
15 | def self.banner
16 | "bitcat/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
17 | end
18 |
19 | def self.root
20 | "#{File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )}"
21 | end
22 |
23 | end # module Bitcat
24 |
--------------------------------------------------------------------------------
/copycats/lib/copycats/version.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 |
4 | module Copycats
5 |
6 | MAJOR = 0
7 | MINOR = 8
8 | PATCH = 1
9 | VERSION = [MAJOR,MINOR,PATCH].join('.')
10 |
11 | def self.version
12 | VERSION
13 | end
14 |
15 | def self.banner
16 | "copycats/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
17 | end
18 |
19 | def self.root
20 | "#{File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )}"
21 | end
22 |
23 | end # module Copycats
24 |
--------------------------------------------------------------------------------
/copycats/Manifest.txt:
--------------------------------------------------------------------------------
1 | CHANGELOG.md
2 | LICENSE.md
3 | Manifest.txt
4 | README.md
5 | Rakefile
6 | bin/kitty
7 | lib/copycats.rb
8 | lib/copycats/fancies.rb
9 | lib/copycats/gene.rb
10 | lib/copycats/genome.rb
11 | lib/copycats/import/read.rb
12 | lib/copycats/import/setup.rb
13 | lib/copycats/models/kitty.rb
14 | lib/copycats/reports/genes.rb
15 | lib/copycats/reports/kitty.rb
16 | lib/copycats/reports/mix.rb
17 | lib/copycats/reports/traits.rb
18 | lib/copycats/schema.rb
19 | lib/copycats/tool.rb
20 | lib/copycats/traits.rb
21 | lib/copycats/traits_timeline.rb
22 | lib/copycats/version.rb
23 | test/helper.rb
24 | test/test_genome.rb
25 | test/test_mixgenes.rb
26 | test/test_models.rb
27 | test/test_traits.rb
28 | test/test_version.rb
29 |
--------------------------------------------------------------------------------
/bitcat/lib/bitcat/app.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | module Bitcat
4 |
5 | class App < Sinatra::Base
6 |
7 | set :root, "#{Bitcat.root}/lib/bitcat"
8 |
9 | get '/' do
10 | erb :index
11 | end
12 |
13 | post '/' do
14 | puts "post '/'"
15 | pp params
16 |
17 | id = params['kitty']['id']
18 | if id.blank?
19 | ## id required - todo: add flash message
20 | redirect "/"
21 | else
22 | redirect "/kitty/#{id}"
23 | end
24 | end
25 |
26 |
27 | get '/kitty/:id' do
28 | puts "get '/kitty/:id'"
29 | pp params
30 |
31 | kitty = Copycats::Model::Kitty.find( params['id'] )
32 | pp kitty
33 |
34 | erb :kitty, :locals => { kitty: kitty }
35 | end
36 |
37 |
38 | ## helpers
39 | def h(text)
40 | Rack::Utils.escape_html(text)
41 | end
42 |
43 | end # class App
44 | end # module Bitcat
45 |
--------------------------------------------------------------------------------
/bitcat/.gitignore:
--------------------------------------------------------------------------------
1 | ####################
2 | # copycats specific ignores
3 |
4 | kitties.db
5 | dl/
6 | data/
7 | data2/
8 | data3/
9 | debug/
10 |
11 |
12 |
13 | *.gem
14 | *.rbc
15 | /.config
16 | /coverage/
17 | /InstalledFiles
18 | /pkg/
19 | /spec/reports/
20 | /test/tmp/
21 | /test/version_tmp/
22 | /tmp/
23 |
24 | ## Specific to RubyMotion:
25 | .dat*
26 | .repl_history
27 | build/
28 |
29 | ## Documentation cache and generated files:
30 | /.yardoc/
31 | /_yardoc/
32 | /doc/
33 | /rdoc/
34 |
35 | ## Environment normalisation:
36 | /.bundle/
37 | /vendor/bundle
38 | /lib/bundler/man/
39 |
40 | # for a library or gem, you might want to ignore these files since the code is
41 | # intended to run in multiple environments; otherwise, check them in:
42 | # Gemfile.lock
43 | # .ruby-version
44 | # .ruby-gemset
45 |
46 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
47 | .rvmrc
48 |
--------------------------------------------------------------------------------
/bitcat/Rakefile:
--------------------------------------------------------------------------------
1 | require 'hoe'
2 | require './lib/bitcat/version.rb'
3 |
4 | Hoe.spec 'bitcat' do
5 |
6 | self.version = Bitcat::VERSION
7 |
8 | self.summary = "bitcat - bit cat(alog) browser - browse your (digital) bit(s) collections; browse your (crypto) kitties and more"
9 | self.description = summary
10 |
11 | self.urls = ['https://github.com/openblockchains/bitcat']
12 |
13 | self.author = 'Gerald Bauer'
14 | self.email = 'wwwmake@googlegroups.com'
15 |
16 | # switch extension to .markdown for gihub formatting
17 | self.readme_file = 'README.md'
18 | self.history_file = 'HISTORY.md'
19 |
20 | self.extra_deps = [
21 | ['sinatra', '>=2.0'],
22 | ['sass'], ## used for css style preprocessing (scss)
23 | ['copycats', '>=0.6.1'],
24 | ]
25 |
26 | self.licenses = ['Public Domain']
27 |
28 | self.spec_extras = {
29 | required_ruby_version: '>= 2.3'
30 | }
31 |
32 | end
33 |
--------------------------------------------------------------------------------
/copycats/test/test_models.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | ###
4 | # to run use
5 | # ruby -I ./lib -I ./test test/test_models.rb
6 |
7 |
8 | require 'helper'
9 |
10 |
11 | class TestModels < MiniTest::Test
12 |
13 |
14 | def test_create
15 | ## connect to local kitties.db database
16 | connect( adapter: 'sqlite3',
17 | database: ':memory:' )
18 |
19 | setup_db
20 | setup_traits # note: also builds TRAIT_IDS_CACHE for read_datafiles for now
21 |
22 | ## print some (record) stats
23 | kitty_count = Copycats::Model::Kitty.count
24 | gene_count = Copycats::Model::Gene.count
25 | trait_count = Copycats::Model::Trait.count
26 |
27 | puts "kitties: #{kitty_count}"
28 | puts "genes: #{gene_count}"
29 | puts "traits: #{trait_count}"
30 |
31 | assert_equal 0, kitty_count
32 | assert_equal 0, gene_count
33 | assert_equal 384, trait_count
34 | end
35 |
36 | end # class TestModels
37 |
--------------------------------------------------------------------------------
/copycats/lib/copycats/traits.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 |
4 | ### build "reverse" lookup tables
5 |
6 | TRAITS_BY_NAME = {} # e.g. savannah, selkirk, chantilly, ...
7 | TRAITS_BY_CODE = {} # e.g. FU00, FU01, FU02, ...
8 |
9 | TRAITS.each do |key,h|
10 | h[:kai].each do |kai, name|
11 |
12 | num = Kai::NUMBER[kai]
13 | code = "#{h[:code]}#{'%02d' % num}" ## e.g. FU00, FU01, etc.
14 |
15 | rec = {}
16 | rec[:name] = name
17 | rec[:kai] = kai
18 | rec[:code] = code
19 | rec[:type] = key ## todo - use trait instead of type (use string not symbol?) - why? why not?
20 |
21 | if TRAITS_BY_NAME[name]
22 | puts "warn: duplicate trait name!! overwritting old #{name}:"
23 | pp TRAITS_BY_NAME[name]
24 | ## add count - why? why not?
25 | ## note: totebasic used three (3) times!!!
26 | ## how to make name "unique" ? - add kai e.g. totebase_g etc. - why? why not?
27 | end
28 |
29 |
30 | TRAITS_BY_NAME[name] = rec unless name.empty? || name == '?'
31 | TRAITS_BY_CODE[code] = rec
32 | end
33 | end
34 |
--------------------------------------------------------------------------------
/copycats/Rakefile:
--------------------------------------------------------------------------------
1 | require 'hoe'
2 | require './lib/copycats/version.rb'
3 |
4 | Hoe.spec 'copycats' do
5 |
6 | self.version = Copycats::VERSION
7 |
8 | self.summary = "copycats - command line tool (and core library) crypto cats / kitties collectibles unchained - buy! sell! hodl! sire! - play for free - runs off the blockchain w/ ledger lite - no ether / gas required; run your own peer-to-peer (P2P) network node over HTTP"
9 | self.description = summary
10 |
11 | self.urls = ['https://github.com/cryptocopycats/copycats']
12 |
13 | self.author = 'Gerald Bauer'
14 | self.email = 'wwwmake@googlegroups.com'
15 |
16 | # switch extension to .markdown for gihub formatting
17 | self.readme_file = 'README.md'
18 | self.history_file = 'CHANGELOG.md'
19 |
20 | self.extra_deps = [
21 | ['base32-alphabets', '>= 1.0.0'],
22 | ['csvreader', '>= 1.2.3'],
23 | ['activerecord'],
24 | ['sqlite3'],
25 | ]
26 |
27 | self.licenses = ['Public Domain']
28 |
29 | self.spec_extras = {
30 | required_ruby_version: '>= 2.3'
31 | }
32 |
33 | end
34 |
--------------------------------------------------------------------------------
/copycats/lib/copycats/reports/kitty.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | class KittyReport
4 |
5 | def initialize( *args, **kwargs )
6 | if args.empty? # try keyword args
7 | @id = kwargs[:id]
8 | @kai = kwargs[:genes] ## todo/check: also incl. check for kai key - why? why not?
9 | else
10 | # try positional args
11 | ## for now alsways assume ActiveRecord - Kitty::Model
12 | kitty = args[0]
13 | @id = kitty.id
14 | @kai = fmt_kai( kitty.genes_kai ) ## pretty print in groups of four (4)
15 | end
16 | end
17 |
18 | def build
19 | buf = "# Kitty \##{@id}\n\n"
20 | buf << "genes (kai): #{@kai}\n\n"
21 | buf << Genome.new( @kai ).build_tables
22 |
23 | ## puts buf
24 |
25 | buf
26 | end
27 |
28 | def save( path )
29 | File.open( path, "w" ) do |f|
30 | f.write build
31 | end
32 | end
33 |
34 |
35 | #####
36 | # helpers
37 | def fmt_kai( kai )
38 | ## format in groups of four (4) separated by space
39 | ## e.g. ccac7787fa7fafaa16467755f9ee444467667366cccceede
40 | ## : ccac 7787 fa7f afaa 1646 7755 f9ee 4444 6766 7366 cccc eede
41 | kai.reverse.gsub( /(.{4})/, '\1 ').reverse.strip
42 | end
43 |
44 |
45 | end # class KittyReport
46 |
--------------------------------------------------------------------------------
/copycats/lib/copycats/reports/mix.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | class MixReport
4 |
5 | def initialize( matron, sire )
6 | @matron_id = matron.id
7 | @sire_id = sire.id
8 | @matron_kai = fmt_kai( matron.genes_kai ) ## pretty print in groups of four (4)
9 | @sire_kai = fmt_kai( sire.genes_kai )
10 | end
11 |
12 |
13 | def build
14 | buf = "# Kitty \##{@matron_id} + \##{@sire_id}\n\n"
15 | buf << "genes (kai) 1: #{@matron_kai}\n"
16 | buf << "genes (kai) 2: #{@sire_kai}\n\n"
17 |
18 | buf << Genome.new( @matron_kai ).build_mix_tables( Genome.new( @sire_kai ))
19 |
20 | ## puts buf
21 | buf
22 | end
23 |
24 |
25 | ## fix/todo: use "generic" report class (inherits save)!!!!!
26 | def save( path )
27 | File.open( path, "w" ) do |f|
28 | f.write build
29 | end
30 | end
31 |
32 |
33 |
34 | #####
35 | # helpers
36 | # todo: move to helpers module for (re)use
37 | def fmt_kai( kai )
38 | ## format in groups of four (4) separated by space
39 | ## e.g. ccac7787fa7fafaa16467755f9ee444467667366cccceede
40 | ## : ccac 7787 fa7f afaa 1646 7755 f9ee 4444 6766 7366 cccc eede
41 | kai.reverse.gsub( /(.{4})/, '\1 ').reverse.strip
42 | end
43 |
44 |
45 | end # class KittyReport
46 |
--------------------------------------------------------------------------------
/bitcat/lib/bitcat/views/kitty.erb:
--------------------------------------------------------------------------------
1 |
2 | « Index
3 |
4 | Kitty #<%= kitty.id %>
5 |
6 | Generation: <%= kitty.gen %>
7 |
8 | Birthdate: <%= kitty.birthdate %> (<%= Date.today.jd - kitty.birthdate.to_date.jd %> days ago)
9 |
10 | Day count: <%= kitty.day_count %>
11 |
12 | Genes (Kai): <%= kitty.genes_kai %>
13 |
14 |
15 |
16 | <% kitty.genes.each do |gene|
17 | trait = Copycats::Model::Trait.find( gene.trait_id )
18 | trait_type = Copycats::Model::TraitType.find( trait.trait_type_id )
19 | %>
20 | -
21 | <%= gene.n %> --
22 | <%= gene.gene %> -
23 | <%= trait.name %>
24 | (<%= trait.kai %>) -
25 | <%= trait_type.name %>
26 |
27 | <% end %>
28 |
29 |
30 |
31 |
32 | More Profile Pages:
33 |
34 |
35 |
45 |
46 |
47 |
54 |
--------------------------------------------------------------------------------
/copycats/.gitignore:
--------------------------------------------------------------------------------
1 | ####################
2 | # copycats specific ignores
3 |
4 | kitties.db
5 | dl/
6 | data/
7 | data2/
8 | data3/
9 | debug/
10 |
11 |
12 | ##########
13 | # regular ignores
14 |
15 | *.gem
16 | *.rbc
17 | /.config
18 | /coverage/
19 | /InstalledFiles
20 | /pkg/
21 | /spec/reports/
22 | /spec/examples.txt
23 | /test/tmp/
24 | /test/version_tmp/
25 | /tmp/
26 |
27 | # Used by dotenv library to load environment variables.
28 | # .env
29 |
30 | ## Specific to RubyMotion:
31 | .dat*
32 | .repl_history
33 | build/
34 | *.bridgesupport
35 | build-iPhoneOS/
36 | build-iPhoneSimulator/
37 |
38 | ## Specific to RubyMotion (use of CocoaPods):
39 | #
40 | # We recommend against adding the Pods directory to your .gitignore. However
41 | # you should judge for yourself, the pros and cons are mentioned at:
42 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
43 | #
44 | # vendor/Pods/
45 |
46 | ## Documentation cache and generated files:
47 | /.yardoc/
48 | /_yardoc/
49 | /doc/
50 | /rdoc/
51 |
52 | ## Environment normalization:
53 | /.bundle/
54 | /vendor/bundle
55 | /lib/bundler/man/
56 |
57 | # for a library or gem, you might want to ignore these files since the code is
58 | # intended to run in multiple environments; otherwise, check them in:
59 | # Gemfile.lock
60 | # .ruby-version
61 | # .ruby-gemset
62 |
63 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
64 | .rvmrc
65 |
--------------------------------------------------------------------------------
/bitcat/lib/bitcat.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | require 'pp'
4 |
5 | ## 3rd party
6 | require 'copycats'
7 | require 'sinatra/base' ## note: use "modular" class sinatra style
8 |
9 |
10 |
11 | ## our own code
12 | require 'bitcat/version' # note: let version always go first
13 | require 'bitcat/app'
14 |
15 |
16 |
17 | module Bitcat
18 |
19 | ## convenience method
20 | def self.run!
21 | app = App
22 | port = 4567
23 | Rack::Handler::WEBrick.run( app, Port:port ) do |server|
24 | ## todo: add traps here - why, why not??
25 | end
26 | end
27 |
28 | def self.main
29 | p banner
30 | ## p root #=> e.g. "C:/Sites/openblockchains/bitcat"
31 |
32 | database = './kitties.db'
33 |
34 | unless File.exist?( database )
35 | puts "*** error - no SQLite database found - expected >#{database}<"
36 | puts
37 | puts " note: for how to setup a database,"
38 | puts " see "
39 | puts
40 | exit 1
41 | end
42 |
43 |
44 | ## connect to local kitties.db database
45 | connect( adapter: 'sqlite3',
46 | database: database )
47 |
48 | ## print some (record) stats
49 | puts "kitties: #{Copycats::Model::Kitty.count}"
50 | puts "genes: #{Copycats::Model::Gene.count}"
51 | puts "traits: #{Copycats::Model::Trait.count}"
52 |
53 | run!
54 | end
55 | end # module Bitcat
56 |
--------------------------------------------------------------------------------
/bitcat/README.md:
--------------------------------------------------------------------------------
1 | # bitcat - Bit Catalog Kitty Browser
2 |
3 | browse your (digital) bit(s) collections -
4 | browse your (crypto) kitties and more
5 |
6 |
7 | * home :: [github.com/openblockchains/bitcat](https://github.com/openblockchains/bitcat)
8 | * bugs :: [github.com/openblockchains/bitcat/issues](https://github.com/openblockchains/bitcat/issues)
9 | * gem :: [rubygems.org/gems/bitcat](https://rubygems.org/gems/bitcat)
10 | * rdoc :: [rubydoc.info/gems/bitcat](http://rubydoc.info/gems/bitcat)
11 |
12 |
13 | ## Usage
14 |
15 |
16 | ### Step 0 - Database Setup
17 |
18 | Note: The bitcat server machinery requires a (local) single-file SQLite database,
19 | that is, `kitties.db`, in your working folder.
20 |
21 | See the [Copycats page on how to setup a (local) single-file SQLite database »](https://github.com/openblockchains/copycats#database-setup)
22 |
23 |
24 |
25 | ### Step 1 - Start the Bitcat Server
26 |
27 | Start up the bitcat server on the command line:
28 |
29 | $ bitcat
30 |
31 |
32 | ### Step 3 - Open Bitcat Page in Browser
33 |
34 | Open up the browser at `localhost:4567`.
35 |
36 | 
37 |
38 | That's it. Enjoy.
39 |
40 |
41 |
42 |
43 | ## Installation - I Can Has Bitcat?
44 |
45 | Use:
46 |
47 | ```
48 | $ gem install bitcat
49 | ```
50 |
51 |
52 | ## Questions? Comments?
53 |
54 | Post them on the [cryptokitties reddit](https://www.reddit.com/r/cryptokitties). Thanks.
55 |
56 |
57 |
58 | ## License
59 |
60 | 
61 |
62 | The `bitcat` scripts are dedicated to the public domain.
63 | Use it as you please with no restrictions whatsoever.
64 |
--------------------------------------------------------------------------------
/copycats/test/test_traits.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | ###
4 | # to run use
5 | # ruby -I ./lib -I ./test test/test_traits.rb
6 |
7 |
8 | require 'helper'
9 |
10 |
11 | class TestTraits < MiniTest::Test
12 |
13 | def test_traits
14 | pp TRAITS
15 | assert true ## (for now) everything ok if we get here
16 |
17 | ## todo: assert number of traits use traits.keys.size !!!
18 | end
19 |
20 | def test_fancies
21 | pp FANCIES
22 | assert true ## (for now) everything ok if we get here
23 |
24 | ## todo: assert number of fancies use fancies.keys.size !!!
25 | end
26 |
27 |
28 | def test_kai
29 |
30 | ## Kitty #1001
31 | ## see https://cryptokittydex.com/kitties/1001
32 |
33 | kai = "aaaa 7885 22f2 agff 1661 7755 e979 2441 6667 7664 a9aa cfff".gsub( ' ', '' )
34 |
35 | puts "kai.length: #{kai.length}" ## 48
36 | puts " first: #{kai[0]}"
37 | puts " last: #{kai[-1]}"
38 | puts " last: #{kai[47]}"
39 |
40 | puts kai.reverse
41 | puts kai.reverse[0,4]
42 | puts kai.reverse[4,4]
43 | puts kai.reverse[8,4]
44 | eyes = kai.reverse[12,4]
45 | puts "eyes:"
46 | puts eyes
47 |
48 | puts TRAITS[:eyes]
49 | pp eyes[0]
50 | puts TRAITS[:eyes][eyes[0]]
51 | puts TRAITS[:eyes][eyes[1]]
52 | puts TRAITS[:eyes][eyes[2]]
53 | puts TRAITS[:eyes][eyes[3]]
54 |
55 | color1 = kai.reverse[16,4]
56 | puts "color1:"
57 | puts color1
58 | pp color1[0]
59 | puts TRAITS[:color1][color1[0]]
60 | puts TRAITS[:color1][color1[1]]
61 | puts TRAITS[:color1][color1[2]]
62 | puts TRAITS[:color1][color1[3]]
63 |
64 | assert true
65 | end
66 |
67 | end # class TestTraits
68 |
--------------------------------------------------------------------------------
/copycats/test/test_mixgenes.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | ###
4 | # to run use
5 | # ruby -I ./lib -I ./test test/test_mixgenes.rb
6 |
7 | ## note:
8 | ## rand(100) - random number between 0 and 100 inclusively
9 | ## todo/check: use rand(99) - why? why not? e.g. 0 to 99 inclusive (100 values)
10 |
11 |
12 | require 'helper'
13 |
14 |
15 |
16 | class TestMixGenes < MiniTest::Test
17 |
18 | def setup
19 | Lottery.random = Random.new( 1234 ) ## seed == 1234
20 | end
21 |
22 | def mixgenes( matron, sire )
23 | matron.mix( sire )
24 | end
25 |
26 | def test_random
27 | assert_equal 47, Lottery.rand(100)
28 | assert_equal 83, Lottery.rand(100)
29 | assert_equal 38, Lottery.rand(100)
30 | assert_equal 53, Lottery.rand(100)
31 | end
32 |
33 |
34 | def test_baby
35 |
36 | kai1 = "dadc 557j 4aaa gb9g 1161 383k 7dbe 774b 6667 8438 dd9a cbbd" # kitty 100000
37 | kai2 = "cdad 55r6 7f2f g9bg 1111 3757 d99d 272h 8k78 k884 9da9 fdee" # kitty 99895
38 |
39 | matron = Genome.new( kai1 )
40 | sire = Genome.new( kai2 )
41 | baby = mixgenes( matron, sire )
42 | pp baby
43 |
44 | puts "body: #{baby.body}"
45 | puts "coloreyes: #{baby.coloreyes}"
46 | puts "eyes: #{baby.eyes}"
47 | puts "pattern: #{baby.pattern}"
48 | puts "mouth: #{baby.mouth}"
49 | puts "color1: #{baby.color1}"
50 | puts "color2: #{baby.color2}"
51 | puts "color3: #{baby.color3}"
52 |
53 | assert_equal "laperm", baby.body
54 | assert_equal "strawberry", baby.coloreyes
55 | assert_equal "simple", baby.eyes
56 | assert_equal "calicool", baby.pattern
57 | assert_equal "soserious", baby.mouth
58 | assert_equal "salmon", baby.color1
59 | assert_equal "coffee", baby.color2
60 | assert_equal "bloodred", baby.color3
61 | end
62 |
63 | end # class TestMixGenes
64 |
--------------------------------------------------------------------------------
/copycats/lib/copycats/models/kitty.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | ##
4 | # todo: rename file from kitty.rb to models.rb - why? why not?
5 | # keep all models together in a single file? - why? why not?
6 |
7 |
8 | module Copycats
9 | module Model
10 |
11 | class Kitty < ActiveRecord::Base
12 | ## self.table_name = 'kitties'
13 |
14 | has_many :genes
15 |
16 | belongs_to :sire, class_name: 'Kitty', foreign_key: 'sire_id'
17 | belongs_to :matron, class_name: 'Kitty', foreign_key: 'matron_id'
18 |
19 | ## convenience shortcuts for gene (d) traits
20 | belongs_to :body, class_name: 'Trait', foreign_key: 'body_id'
21 | belongs_to :pattern, class_name: 'Trait', foreign_key: 'pattern_id'
22 | belongs_to :coloreyes, class_name: 'Trait', foreign_key: 'coloreyes_id'
23 | belongs_to :eyes, class_name: 'Trait', foreign_key: 'eyes_id'
24 | belongs_to :color1, class_name: 'Trait', foreign_key: 'color1_id'
25 | belongs_to :color2, class_name: 'Trait', foreign_key: 'color2_id'
26 | belongs_to :color3, class_name: 'Trait', foreign_key: 'color3_id'
27 | belongs_to :wild, class_name: 'Trait', foreign_key: 'wild_id'
28 | belongs_to :mouth, class_name: 'Trait', foreign_key: 'mouth_id'
29 |
30 | ## todo: add more genes convenience shortcuts
31 | ## has_many :genes_body
32 | ## has_many :genes_pattern
33 | end # class Kitty
34 |
35 |
36 | class TraitType < ActiveRecord::Base
37 | ## self.table_name = 'trait_types'
38 |
39 | has_many :traits
40 | end # class TraitType
41 |
42 |
43 | class Trait < ActiveRecord::Base
44 | ## self.table_name = 'traits'
45 |
46 | belongs_to :trait_types
47 | end # class Trait
48 |
49 |
50 | class Gene < ActiveRecord::Base
51 | ## self.table_name = 'genes'
52 |
53 | belongs_to :kitty
54 | end # class Gene
55 |
56 |
57 |
58 | end # module Model
59 | end # module Copycats
60 |
--------------------------------------------------------------------------------
/copycats/lib/copycats.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | require 'pp' # for pp => pretty printer
4 |
5 | require 'date'
6 | require 'time'
7 | require 'uri'
8 | require 'json'
9 | require 'enumerator' ## needed for each_slice
10 | require 'optparse' # note: used for command line tool (see Tool in tool.rb)
11 |
12 | require 'logger' # note: use for ActiveRecord::Base.logger -- remove/replace later w/ LogUtils::Logger ???
13 |
14 | ## 3rd party gems
15 | require 'active_record' ## todo: add sqlite3? etc.
16 |
17 | require 'base32-alphabets' ## base32 / kai encoding / decoding for genes
18 | require 'csvreader'
19 |
20 |
21 |
22 | ## our own code
23 | require 'copycats/version' # note: let version always go first
24 | require 'copycats/traits'
25 | require 'copycats/traits_timeline'
26 |
27 | require 'copycats/fancies'
28 | require 'copycats/gene'
29 | require 'copycats/genome'
30 |
31 | require 'copycats/schema'
32 |
33 | require 'copycats/models/kitty'
34 |
35 | require 'copycats/links'
36 |
37 | require 'copycats/reports/kitty'
38 | require 'copycats/reports/mix'
39 | require 'copycats/reports/genes'
40 | require 'copycats/reports/traits'
41 |
42 | require 'copycats/import/setup'
43 | require 'copycats/import/read'
44 |
45 | require 'copycats/tool'
46 |
47 |
48 | ## add wrapper for allowing configuration of random number generator
49 | module Lottery
50 |
51 | def self.random
52 | @random ||= Random.new
53 | end
54 |
55 | def self.random=(value)
56 | @random = value
57 | end
58 |
59 | def self.rand( arg=nil )
60 | if arg.is_a? Integer
61 | random.rand( arg ) ## max (number) = arg
62 | else
63 | random.rand ## between 0.0 and 1.0 (as floating point number)
64 | end
65 | end
66 | end ## module Lottery
67 |
68 |
69 | module Copycats
70 | ## add command line binary (tool) e.g. $ try kitty -h
71 | def self.main
72 | Tool.new.run( ARGV )
73 | end
74 | end
75 |
76 |
77 |
78 | # say hello
79 | puts Copycats.banner if defined?($RUBYLIBS_DEBUG) && $RUBYLIBS_DEBUG
80 |
--------------------------------------------------------------------------------
/copycats/KITTY-100000.md:
--------------------------------------------------------------------------------
1 | # Kitty #100000
2 |
3 | genes (kai): dadc 557j 4aaa gb9g 1161 383k 7dbe 774b 6667 8438 dd9a cbbd
4 |
5 | Fur (Genes 0-3)
6 |
7 | |Gene |Binary |Kai |Trait | |
8 | |------|---------|-----|---------|---|
9 | | 0 | 01100 | d | **munchkin** | d |
10 | | 1 | 01010 | b | chartreux | r1 |
11 | | 2 | 01010 | b | chartreux | r2 |
12 | | 3 | 01011 | c | himalayan | r3 |
13 |
14 | d = dominant, r1 = 1st order recessive, r2 = 2nd order recessive, r3 = 3rd order recessive
15 |
16 | Pattern (Genes 4-7)
17 |
18 | |Gene |Binary |Kai |Trait | |
19 | |------|---------|-----|---------|---|
20 | | 4 | 01001 | a | **luckystripe** | d |
21 | | 5 | 01000 | 9 | calicool | r1 |
22 | | 6 | 01100 | d | spock | r2 |
23 | | 7 | 01100 | d | spock | r3 |
24 |
25 | Eye Color (Genes 8-11)
26 |
27 | |Gene |Binary |Kai |Trait | |
28 | |------|---------|-----|---------|---|
29 | | 8 | 00111 | 8 | **strawberry** | d |
30 | | 9 | 00010 | 3 | topaz | r1 |
31 | | 10 | 00011 | 4 | mintgreen | r2 |
32 | | 11 | 00111 | 8 | strawberry | r3 |
33 |
34 | Eye Shape (Genes 12-15)
35 |
36 | |Gene |Binary |Kai |Trait | |
37 | |------|---------|-----|---------|---|
38 | | 12 | 00110 | 7 | **crazy** | d |
39 | | 13 | 00101 | 6 | simple | r1 |
40 | | 14 | 00101 | 6 | simple | r2 |
41 | | 15 | 00101 | 6 | simple | r3 |
42 |
43 | Base Color (Genes 16-19)
44 |
45 | |Gene |Binary |Kai |Trait | |
46 | |------|---------|-----|---------|---|
47 | | 16 | 01010 | b | **greymatter** | d |
48 | | 17 | 00011 | 4 | orangesoda | r1 |
49 | | 18 | 00110 | 7 | aquamarine | r2 |
50 | | 19 | 00110 | 7 | aquamarine | r3 |
51 |
52 | Highlight Color (Genes 20-23)
53 |
54 | |Gene |Binary |Kai |Trait | |
55 | |------|---------|-----|---------|---|
56 | | 20 | 01101 | e | **lemonade** | d |
57 | | 21 | 01010 | b | scarlet | r1 |
58 | | 22 | 01100 | d | coffee | r2 |
59 | | 23 | 00110 | 7 | royalpurple | r3 |
60 |
61 | Accent Color (Genes 24-27)
62 |
63 | |Gene |Binary |Kai |Trait | |
64 | |------|---------|-----|---------|---|
65 | | 24 | 10011 | k | **bloodred** | d |
66 | | 25 | 00010 | 3 | peach | r1 |
67 | | 26 | 00111 | 8 | emeraldgreen | r2 |
68 | | 27 | 00010 | 3 | peach | r3 |
69 |
70 | Wild (Genes 28-31)
71 |
72 | |Gene |Binary |Kai |Trait | |
73 | |------|---------|-----|---------|---|
74 | | 28 | 00000 | 1 | **?** | d |
75 | | 29 | 00101 | 6 | ? | r1 |
76 | | 30 | 00000 | 1 | ? | r2 |
77 | | 31 | 00000 | 1 | ? | r3 |
78 |
79 | Mouth (Genes 32-35)
80 |
81 | |Gene |Binary |Kai |Trait | |
82 | |------|---------|-----|---------|---|
83 | | 32 | 01111 | g | **soserious** | d |
84 | | 33 | 01000 | 9 | beard | r1 |
85 | | 34 | 01010 | b | saycheese | r2 |
86 | | 35 | 01111 | g | soserious | r3 |
87 |
88 |
--------------------------------------------------------------------------------
/copycats/KITTY-99895.md:
--------------------------------------------------------------------------------
1 | # Kitty #99895
2 |
3 | genes (kai): cdad 55r6 7f2f g9bg 1111 3757 d99d 272h 8k78 k884 9da9 fdee
4 |
5 | Fur (Genes 0-3)
6 |
7 | |Gene |Binary |Kai |Trait | |
8 | |------|---------|-----|---------|---|
9 | | 0 | 01101 | e | **sphynx** | d |
10 | | 1 | 01101 | e | sphynx | r1 |
11 | | 2 | 01100 | d | munchkin | r2 |
12 | | 3 | 01110 | f | ragamuffin | r3 |
13 |
14 | d = dominant, r1 = 1st order recessive, r2 = 2nd order recessive, r3 = 3rd order recessive
15 |
16 | Pattern (Genes 4-7)
17 |
18 | |Gene |Binary |Kai |Trait | |
19 | |------|---------|-----|---------|---|
20 | | 4 | 01000 | 9 | **calicool** | d |
21 | | 5 | 01001 | a | luckystripe | r1 |
22 | | 6 | 01100 | d | spock | r2 |
23 | | 7 | 01000 | 9 | calicool | r3 |
24 |
25 | Eye Color (Genes 8-11)
26 |
27 | |Gene |Binary |Kai |Trait | |
28 | |------|---------|-----|---------|---|
29 | | 8 | 00011 | 4 | **mintgreen** | d |
30 | | 9 | 00111 | 8 | strawberry | r1 |
31 | | 10 | 00111 | 8 | strawberry | r2 |
32 | | 11 | 10011 | k | bubblegum | r3 |
33 |
34 | Eye Shape (Genes 12-15)
35 |
36 | |Gene |Binary |Kai |Trait | |
37 | |------|---------|-----|---------|---|
38 | | 12 | 00111 | 8 | **thicccbrowz** | d |
39 | | 13 | 00110 | 7 | crazy | r1 |
40 | | 14 | 10011 | k | raisedbrow | r2 |
41 | | 15 | 00111 | 8 | thicccbrowz | r3 |
42 |
43 | Base Color (Genes 16-19)
44 |
45 | |Gene |Binary |Kai |Trait | |
46 | |------|---------|-----|---------|---|
47 | | 16 | 10000 | h | **cloudwhite** | d |
48 | | 17 | 00001 | 2 | salmon | r1 |
49 | | 18 | 00110 | 7 | aquamarine | r2 |
50 | | 19 | 00001 | 2 | salmon | r3 |
51 |
52 | Highlight Color (Genes 20-23)
53 |
54 | |Gene |Binary |Kai |Trait | |
55 | |------|---------|-----|---------|---|
56 | | 20 | 01100 | d | **coffee** | d |
57 | | 21 | 01000 | 9 | swampgreen | r1 |
58 | | 22 | 01000 | 9 | swampgreen | r2 |
59 | | 23 | 01100 | d | coffee | r3 |
60 |
61 | Accent Color (Genes 24-27)
62 |
63 | |Gene |Binary |Kai |Trait | |
64 | |------|---------|-----|---------|---|
65 | | 24 | 00110 | 7 | **kittencream** | d |
66 | | 25 | 00100 | 5 | granitegrey | r1 |
67 | | 26 | 00110 | 7 | kittencream | r2 |
68 | | 27 | 00010 | 3 | peach | r3 |
69 |
70 | Wild (Genes 28-31)
71 |
72 | |Gene |Binary |Kai |Trait | |
73 | |------|---------|-----|---------|---|
74 | | 28 | 00000 | 1 | **?** | d |
75 | | 29 | 00000 | 1 | ? | r1 |
76 | | 30 | 00000 | 1 | ? | r2 |
77 | | 31 | 00000 | 1 | ? | r3 |
78 |
79 | Mouth (Genes 32-35)
80 |
81 | |Gene |Binary |Kai |Trait | |
82 | |------|---------|-----|---------|---|
83 | | 32 | 01111 | g | **soserious** | d |
84 | | 33 | 01010 | b | saycheese | r1 |
85 | | 34 | 01000 | 9 | beard | r2 |
86 | | 35 | 01111 | g | soserious | r3 |
87 |
88 |
--------------------------------------------------------------------------------
/copycats/lib/copycats/import/setup.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 |
4 | def connect( config={} )
5 | if config.empty?
6 | puts "ENV['DATBASE_URL'] - >#{ENV['DATABASE_URL']}<"
7 |
8 | ### change default to ./copycats.db ?? why? why not?
9 | db = URI.parse( ENV['DATABASE_URL'] || 'sqlite3:///kitties.db' )
10 |
11 | if db.scheme == 'postgres'
12 | config = {
13 | adapter: 'postgresql',
14 | host: db.host,
15 | port: db.port,
16 | username: db.user,
17 | password: db.password,
18 | database: db.path[1..-1],
19 | encoding: 'utf8'
20 | }
21 | else # assume sqlite3
22 | config = {
23 | adapter: db.scheme, # sqlite3
24 | database: db.path[1..-1] # world.db (NB: cut off leading /, thus 1..-1)
25 | }
26 | end
27 | end
28 |
29 |
30 | puts "Connecting to db using settings: "
31 | pp config
32 | ActiveRecord::Base.establish_connection( config )
33 | ActiveRecord::Base.logger = Logger.new( STDOUT )
34 | ## ActiveRecord::Base.colorize_logging = false - no longer exists - check new api/config setting?
35 |
36 | ## if sqlite3 add (use) some pragmas for speedups
37 | if config[:adapter] == 'sqlite3'
38 | ## check/todo: if in memory e.g. ':memory:' no pragma needed!!
39 | con = ActiveRecord::Base.connection
40 | con.execute( 'PRAGMA synchronous=OFF;' )
41 | con.execute( 'PRAGMA journal_mode=OFF;' )
42 | con.execute( 'PRAGMA temp_store=MEMORY;' )
43 | end
44 | end ## method connect
45 |
46 |
47 | def setup_db
48 | ## build schema
49 | CreateDb.new.up
50 | end
51 |
52 |
53 |
54 | ### todo/fix:
55 | ## make trait_ids_cache more (re)usable - fix global!!!!
56 | TRAIT_IDS_CACHE = {}
57 |
58 |
59 | def setup_traits
60 | ## for speed - turn off logging for info/debug/etc. levels
61 | ActiveRecord::Base.logger.level = :warn
62 |
63 | ### add traits
64 | TRAITS.each do |trait_key, trait_hash|
65 |
66 | trait_t = Copycats::Model::TraitType.new
67 | trait_t.name = trait_hash[:name]
68 | trait_t.key = trait_key.to_s
69 | trait_t.save!
70 |
71 | cache = {}
72 |
73 | Kai::ALPHABET.each_with_index do |kai,n|
74 | name = trait_hash[:kai][kai]
75 | name = '?' if name.nil? || name.empty?
76 |
77 | tier = Gene::TIER[kai]
78 |
79 | puts "Kai: #{kai} (#{n}) /#{tier}, Cattribute: #{name}"
80 | trait = Copycats::Model::Trait.new
81 | trait.name = name
82 | trait.kai = kai
83 | trait.n = n
84 | trait.tier = tier
85 | trait.trait_type_id = trait_t.id
86 | trait.save!
87 |
88 | cache[ kai ] = trait.id
89 | end
90 |
91 | TRAIT_IDS_CACHE[ trait_key ] = { id: trait_t.id,
92 | kai: cache }
93 | end
94 | end
95 |
--------------------------------------------------------------------------------
/copycats/test/test_genome.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | ###
4 | # to run use
5 | # ruby -I ./lib -I ./test test/test_genome.rb
6 |
7 |
8 | require 'helper'
9 |
10 |
11 | class TestGenome < MiniTest::Test
12 |
13 |
14 | def test_kitty_100000
15 | ## see https://cryptokittydex.com/kitties/100000
16 | ## https://www.cryptokitties.co/kitty/100000
17 |
18 | kai = "dadc 557j 4aaa gb9g 1161 383k 7dbe 774b 6667 8438 dd9a cbbd"
19 |
20 | genome = Genome.new( kai )
21 | pp genome
22 |
23 | puts "body: #{genome.body}"
24 | puts "coloreyes: #{genome.coloreyes}"
25 | puts "eyes: #{genome.eyes}"
26 | puts "pattern: #{genome.pattern}"
27 | puts "mouth: #{genome.mouth}"
28 | puts "color1: #{genome.color1}"
29 | puts "color2: #{genome.color2}"
30 | puts "color3: #{genome.color3}"
31 |
32 | assert_equal "munchkin", genome.body
33 | assert_equal "strawberry", genome.coloreyes
34 | assert_equal "crazy", genome.eyes
35 | assert_equal "luckystripe", genome.pattern
36 | assert_equal "soserious", genome.mouth
37 | assert_equal "greymatter", genome.color1
38 | assert_equal "lemonade", genome.color2
39 | assert_equal "bloodred", genome.color3
40 |
41 |
42 | puts genome.genes[:color1].p
43 | puts genome.genes[:color1].h1
44 | puts genome.genes[:color1].h2
45 | puts genome.genes[:color1].h3
46 |
47 | assert_equal genome.genes[:color1].p, genome.genes[:color1].d
48 | assert_equal genome.genes[:color1].h1, genome.genes[:color1].r1
49 | assert_equal genome.genes[:color1].h2, genome.genes[:color1].r2
50 | assert_equal genome.genes[:color1].h3, genome.genes[:color1].r3
51 |
52 |
53 | puts genome.genes[:eyes].p
54 | puts genome.genes[:eyes].h1
55 | puts genome.genes[:eyes].h2
56 | puts genome.genes[:eyes].h3
57 |
58 | puts TRAITS[:eyes][ genome.genes[:eyes].p ]
59 | puts TRAITS[:eyes][ genome.genes[:eyes].h1 ]
60 | puts TRAITS[:eyes][ genome.genes[:eyes].h2 ]
61 | puts TRAITS[:eyes][ genome.genes[:eyes].h3 ]
62 | end
63 |
64 |
65 | def test_kitty_99895
66 | ## see https://cryptokittydex.com/kitties/99895
67 | ## https://www.cryptokitties.co/kitty/99895
68 |
69 | kai = "cdad 55r6 7f2f g9bg 1111 3757 d99d 272h 8k78 k884 9da9 fdee"
70 |
71 | genome = Genome.new( kai )
72 | pp genome
73 |
74 | puts "body: #{genome.body}"
75 | puts "coloreyes: #{genome.coloreyes}"
76 | puts "eyes: #{genome.eyes}"
77 | puts "pattern: #{genome.pattern}"
78 | puts "mouth: #{genome.mouth}"
79 | puts "color1: #{genome.color1}"
80 | puts "color2: #{genome.color2}"
81 | puts "color3: #{genome.color3}"
82 |
83 | assert_equal "sphynx", genome.body
84 | assert_equal "mintgreen", genome.coloreyes
85 | assert_equal "thicccbrowz", genome.eyes
86 | assert_equal "calicool", genome.pattern
87 | assert_equal "soserious", genome.mouth
88 | assert_equal "cloudwhite", genome.color1
89 | assert_equal "coffee", genome.color2
90 | assert_equal "kittencream", genome.color3
91 | end
92 |
93 | end # class TestGenome
94 |
--------------------------------------------------------------------------------
/copycats/lib/copycats/schema.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | #######################
4 | ## yuml.me diagram:
5 |
6 | =begin
7 | [Kitties|id;gen;birthdate;day_count;genes_kai;name]1-<>48 (12x4)[Genes|n;gene;gene_n],
8 | [Genes]0..*<>-1[Traits|n;kai;tier;name],
9 | [Traits]32<>-1[Trait Types|name;key],
10 | [Kitties]<-parents (matron x sire) [Kitties],
11 | =end
12 |
13 |
14 |
15 |
16 | class CreateDb
17 |
18 | def up
19 |
20 | ActiveRecord::Schema.define do
21 |
22 | create_table :kitties do |t|
23 | ### t.integer :ref, null: false ## reference id - todo - find a better name e.g. uid (for unique id?) or gid?
24 | ## note: use built-in id for id!!!!
25 |
26 | t.string :name ## optional name e.g. Genesis, Galaxy Cat, etc.
27 | t.string :genes_kai, null: false ## genes in kai format
28 | t.integer :gen, null: false ## generation e.g. 0,1,2,etc.
29 | t.datetime :birthdate, null: false
30 | t.integer :day_count, null: false ## day 1, day 2, running day counter since 2017-11-23
31 |
32 | t.references :matron ## optional references kitty (with matron id)
33 | t.references :sire ## optional references kitty (with sire id)
34 |
35 |
36 | t.boolean :is_fancy, null: false, default: false
37 | t.boolean :is_exclusive, null: false, default: false
38 | t.boolean :is_founder, null: false, default: false # ids 1 to 100 (in cryptokitties)
39 |
40 |
41 | ## for easy queries add convenience gene-d for all traits
42 | t.references :body, null: false ## gene 0 (d)
43 | t.references :pattern, null: false ## gene 4 (d)
44 | t.references :coloreyes, null: false ## gene 8 (d)
45 | t.references :eyes, null: false ## gene 12 (d)
46 | t.references :color1, null: false ## gene 16 (d)
47 | t.references :color2, null: false ## gene 20 (d)
48 | t.references :color3, null: false ## gene 24 (d)
49 | t.references :wild, null: false ## gene 28 (d)
50 | t.references :mouth, null: false ## gene 32 (d)
51 | end
52 |
53 |
54 | create_table :genes do |t|
55 | t.references :kitty, null: false
56 | t.integer :n, null: false # gene number/pos 0-47 (start w/ 1 why? why not?)
57 |
58 | t.string :gene, null: false # d, r1, r2, r3
59 | t.integer :gene_n, null: false # 0-3 (0=d,1=r1,2=r2,3=r3 - start w/ 1 why? why not?)
60 |
61 | t.references :trait, null: false
62 | end
63 |
64 |
65 | create_table :traits do |t|
66 | t.references :trait_type, null: false
67 | t.string :name, null: false
68 | t.integer :n, null: false # 0-31 (decimal/base10)
69 | t.string :kai, null: false # 1-x (kai/base32)
70 | t.integer :tier # 1,2,3,4 - note: is nil (for x/31) for now (thus, optinal)
71 | end
72 |
73 | create_table :trait_types do |t|
74 | t.string :name, null: false # use "pretty" name e.g. fur, highlight color, etc.
75 | t.string :key, null: false # use key/ lowercase name from "official json api"
76 | end
77 |
78 |
79 | end # block Schema.define
80 |
81 | end # method up
82 |
83 | end # class CreateDb
84 |
--------------------------------------------------------------------------------
/copycats/lib/copycats/tool.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | module Copycats
4 |
5 | class Tool
6 |
7 | def run( args )
8 | opts = {}
9 |
10 | parser = OptionParser.new do |cmd|
11 | cmd.banner = "Usage: kitty [options]"
12 |
13 | cmd.separator ""
14 | cmd.separator " Database options:"
15 |
16 | cmd.on("-n", "--dbname=NAME", "Database name (default: kitties.db)") do |name|
17 | opts[:db_name] = name
18 | end
19 |
20 | cmd.on("-d", "--dbpath=PATH", "Database path (default: .)") do |path|
21 | opts[:db_path] = path
22 | end
23 |
24 | cmd.separator ""
25 | cmd.separator " Data options:"
26 |
27 | cmd.on("-i", "--include=DIR", "Data directory (default: ./data for in-memory queries and . for setup)") do |name|
28 | opts[:data_dir] = name
29 | end
30 |
31 | cmd.separator ""
32 | cmd.separator " General options:"
33 |
34 | cmd.on("-h", "--help", "Prints this help") do
35 | puts cmd
36 | exit
37 | end
38 | end
39 |
40 | parser.parse!( args )
41 | pp opts
42 | pp args
43 |
44 |
45 | db_path = opts[:db_path] || '.'
46 | db_name = opts[:db_name] || 'kitties.db'
47 | database = "#{db_path}/#{db_name}"
48 |
49 |
50 | if args.size == 1 && args[0] == 'setup' ## setup database
51 | connect( adapter: 'sqlite3',
52 | database: database )
53 |
54 | setup_db
55 | setup_traits # note: also builds TRAIT_IDS_CACHE for read_datafiles for now
56 |
57 | data_dir = opts[:data_dir] || '.' ## for setup assume local dir for data
58 | read_datafiles( data_dir: data_dir )
59 | else
60 | ## check if (local) database exists?
61 | if File.exist?( database ) ## if yes, use "cached" local database
62 | connect( adapter: 'sqlite3',
63 | database: database )
64 | else ## otherwise use (new) on-demand in-memory database
65 | puts "note: database >#{database}<; setting up in-memory database"
66 | connect( adapter: 'sqlite3',
67 | database: ':memory:' )
68 |
69 | setup_db
70 | setup_traits # note: also builds TRAIT_IDS_CACHE for read_datafiles for now
71 |
72 | data_dir = opts[:data_dir] || './data'
73 | read_datafiles( data_dir: data_dir )
74 | end
75 |
76 |
77 |
78 | if args.size == 1
79 | id = args[0].to_i
80 | kitty = Copycats::Model::Kitty.find( id )
81 |
82 | ## pp kitty
83 | ## pp kitty.genes
84 | ## pp kitty.body
85 | ## pp kitty.pattern
86 | ## pp kitty.genes.to_a
87 |
88 | buf = KittyReport.new( kitty ).build
89 |
90 | puts buf
91 | elsif args.size == 2
92 | matron_id = args[0].to_i
93 | sire_id = args[1].to_i
94 |
95 | matron = Copycats::Model::Kitty.find( matron_id )
96 | sire = Copycats::Model::Kitty.find( sire_id )
97 | ## pp matron
98 |
99 | buf = MixReport.new( matron, sire ).build
100 |
101 | puts buf
102 | else
103 | puts "error: too many arguments (expected setup or one or two kitty ids / names / genes)"
104 | end
105 | end
106 | end ## method run
107 |
108 |
109 | end ## class Tool
110 |
111 | end ## module Copycats
112 |
--------------------------------------------------------------------------------
/copycats/lib/copycats/gene.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 |
4 | class Gene
5 |
6 |
7 |
8 |
9 | ### todo/check:
10 | ## find a better name for Slice(incl.4 genes)
11 | ## e.g. GeneFour, Gene4, GeneGroup, GeneSlice,TraitGenes,... - why? why not?
12 |
13 | class Slice ## Gene::Slice (nested class)
14 |
15 | attr_reader :p, :h1, :h2, :h3 # p(rimary), h(idden) 1, h(idden) 2, h(idden) 3
16 |
17 | ## compat: add alias for ("old/classic") d, r1, r2, r3
18 | # d (dominant gene) -- todo/check: rename to just d instead of d0 - why? why not?
19 | # r1 (1st order recessive gene)
20 | # r2 (2nd order recessive gene)
21 | # r3 (3rd order recessive gene)
22 | def d() p; end # todo: use alias - why? why not?
23 | def r1() h1; end
24 | def r2() h2; end
25 | def r3() h3; end
26 |
27 |
28 | def initialize( arg )
29 | ## (always) assume String in base32/kai for now
30 | kai = arg
31 | ## puts "Gene.initialize #{kai}"
32 | kai = kai.reverse
33 | @p = kai[0]
34 | @h1 = kai[1]
35 | @h2 = kai[2]
36 | @h3 = kai[3]
37 | end
38 |
39 | def to_kai() @h3 + @h2 + @h1 + @p; end ## return a string in kai/base32 notation
40 |
41 |
42 | def swap
43 | puts "Gene#swap"
44 | kai = to_kai.reverse # note: use reverse kai string (kai[0] is first char/digit/letter)
45 |
46 | 3.downto(1) do |i|
47 | if Lottery.rand(100) < 25
48 | puts " bingo! swap #{i}<>#{i-1}"
49 | kai[i-1], kai[i] = kai[i], kai[i-1]
50 | end
51 | end
52 | Gene.new( kai.reverse ) ## note: do NOT forget to pass in kai (unreversed)
53 | end
54 |
55 |
56 | def mutate( other )
57 | puts "Gene#mutate"
58 |
59 | gene1 = Kai::NUMBER[p] ## primary/dominant gene1
60 | gene2 = Kai::NUMBER[other.p] ## primary/dominant gene2
61 | if gene1 > gene2
62 | gene1, gene2 = gene2, gene1 ## make sure gene2 is always bigger
63 | end
64 | if (gene2 - gene1) == 1 && gene1.even?
65 | probability = 25
66 | probability /= 2 if gene1 > 23
67 | if Lottery.rand(100) < probability
68 | genex = (gene1 / 2) + 16 ## 16=2^4
69 | puts " bingo! mutation #{gene2}+#{gene1} => #{genex}"
70 | puts " #{Kai::ALPHABET[gene2]}+#{Kai::ALPHABET[gene1]} => #{Kai::ALPHABET[genex]}"
71 | return Kai::ALPHABET[genex]
72 | end
73 | end
74 | nil # no mutation
75 | end
76 |
77 | def mix_inner( other )
78 | puts "Gene#mix_inner"
79 |
80 | new_p = mutate( other )
81 | if new_p.nil? ## no mutation of gene.p - use "regular" formula
82 | new_p = Lottery.rand(100) < 50 ? p : other.p
83 | end
84 |
85 | new_h1 = Lottery.rand(100) < 50 ? h1 : other.h1
86 | new_h2 = Lottery.rand(100) < 50 ? h2 : other.h2
87 | new_h3 = Lottery.rand(100) < 50 ? h3 : other.h3
88 |
89 | gene = Gene.new( new_h3 + new_h2 + new_h1 + new_p )
90 | pp gene
91 | gene
92 | end
93 |
94 |
95 | def mix( other )
96 | puts "Gene#mix"
97 | self_swapped = swap
98 | other_swapped = other.swap
99 |
100 | gene = self_swapped.mix_inner( other_swapped )
101 | pp gene
102 | gene
103 | end
104 |
105 | end # class Slice
106 | end # class Gene
107 |
--------------------------------------------------------------------------------
/copycats/lib/copycats/reports/traits.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 | class TraitsReport
4 |
5 | ROMAN = {
6 | 1 => 'I',
7 | 2 => 'II',
8 | 3 => 'III',
9 | 4 => 'IIII',
10 | 5 => 'V'
11 | }
12 |
13 |
14 | def build
15 | buf = ""
16 | buf << "# Traits\n\n"
17 |
18 | buf << "| Tier | Kai |"
19 | TRAITS.values[0,6].each do |trait|
20 | buf << " #{trait[:name]} |"
21 | end
22 | buf << "\n"
23 | buf << "|----|----|----|----|----|----|----|----|\n"
24 |
25 | buf << "| | |"
26 | TRAITS.values[0,6].each do |trait|
27 | buf << " #{trait[:genes]} |"
28 | end
29 | buf << "\n"
30 |
31 | Kai::ALPHABET.each_char do |kai|
32 | tier = ROMAN[ Gene::TIER[kai] ]
33 | tier = '?' if tier.nil?
34 | buf << "| #{tier} | #{kai} |"
35 | TRAITS.values[0,6].each do |trait|
36 | value = trait[:kai][kai]
37 | value = '?' if value.nil? || value.empty?
38 | buf << " #{value} |"
39 | end
40 | buf << "\n"
41 | end
42 | buf << "\n\n"
43 |
44 | ## part ii (split into two tables)
45 | buf << "| Tier | Kai |"
46 | TRAITS.values[6,6].each do |trait|
47 | buf << " #{trait[:name]} |"
48 | end
49 | buf << "\n"
50 | buf << "|----|----|----|----|----|----|----|----|\n"
51 |
52 | buf << "| | |"
53 | TRAITS.values[6,6].each do |trait|
54 | buf << " #{trait[:genes]} |"
55 | end
56 | buf << "\n"
57 |
58 | Kai::ALPHABET.each_char do |kai|
59 | tier = ROMAN[ Gene::TIER[kai] ]
60 | tier = '?' if tier.nil?
61 | buf << "| #{tier} | #{kai} |"
62 | TRAITS.values[6,6].each do |trait|
63 | value = trait[:kai][kai]
64 | value = '?' if value.nil? || value.empty?
65 | buf << " #{value} |"
66 | end
67 | buf << "\n"
68 | end
69 | buf << "\n\n"
70 |
71 |
72 | buf += < '1-99_999',
40 | 1 => '100_000-199_999',
41 | 2 => '200_000_299_999',
42 | 3 => '300_000-399_999',
43 | 4 => '400_000-499_999',
44 | 5 => '500_000-599_999',
45 | 6 => '600_000-699_999',
46 | 7 => '700_000-799_999',
47 | 8 => '800_000-899_999',
48 | 9 => '900_000-999_999',
49 | }
50 |
51 |
52 | def id_to_nos( id )
53 | dir_no = id / 100_000 ## e.g. 0-9 ++ 1 => 100_000-199_999 ...
54 | file_no = id / 1000 ## e.g. 0-999 ++ 1 => 001 ...
55 |
56 | ## puts "id: #{id} => #{dir_no} / #{file_no}"
57 |
58 | [dir_no, file_no]
59 | end
60 |
61 |
62 |
63 | HEADERS = ['id',
64 | 'gen',
65 | 'matron_id',
66 | 'sire_id',
67 | 'birthdate',
68 | 'genes',
69 | 'name']
70 |
71 |
72 |
73 | def initialize
74 | @last_no = [-1,-1]
75 | @last_out = nil
76 | end
77 |
78 |
79 |
80 | def out_for( id, out_dir: )
81 | no = id_to_nos( id )
82 | print no.inspect
83 |
84 | ## check for new section / batch
85 | ## if yes, close old file and open new file
86 | if @last_no[1] != no[1]
87 | @last_out.close if @last_out
88 |
89 | root = "#{out_dir}/#{DIR[no[0]]}"
90 | num = '%03d' % no[1] ## use 000, 001, 002, 099,
91 | ## 100, 101, 102, ... etc.
92 | filepath = "#{root}/#{num}.csv"
93 | puts "\n** >#{filepath}<:"
94 |
95 | FileUtils.mkdir_p( root ) unless Dir.exist?( root )
96 |
97 | out = CSV.open( filepath, 'w' )
98 | out << HEADERS
99 | @last_out = out
100 | end
101 |
102 | @last_no = no
103 | @last_out
104 | end
105 |
106 |
107 | def convert( path, out_dir: './o' )
108 | i = 0
109 | last_id = 0
110 | out = nil
111 |
112 | CSV.foreach( path, headers: true ) do |row|
113 | if i==0
114 | pp row
115 | pp row.headers
116 | end
117 |
118 | id = row['id'].to_i
119 | print id
120 | print "."
121 |
122 | if id < last_id
123 | puts "!!! kitty id must be greater than last id"
124 | exit 1
125 | end
126 |
127 | last_id = id
128 |
129 | rec = []
130 | rec << row['id']
131 | rec << row['gen']
132 | rec << (row['matron_id'] == '0' ? nil : row['matron_id'])
133 | rec << (row['sire_id'] == '0' ? nil : row['sire_id'])
134 | rec << row['birth_date']
135 | rec << fmt_kai(row['genes_kai'])
136 | rec << nil ## name
137 |
138 | out = out_for( id, out_dir: out_dir )
139 | out << rec
140 |
141 | i+=1
142 | ## break if i>=2002
143 | end
144 |
145 | print "\n"
146 | out.close ## close last out(put) file/stream
147 | end
148 |
149 |
150 | #########################
151 | ### format helpers
152 |
153 | def fmt_kai( kai )
154 | ## format in groups of four (4) separated by space
155 | ## e.g. ccac7787fa7fafaa16467755f9ee444467667366cccceede
156 | ## : ccac 7787 fa7f afaa 1646 7755 f9ee 4444 6766 7366 cccc eede
157 | kai.reverse.gsub( /(.{4})/, '\1 ').reverse.strip
158 | end
159 |
160 | end # class KittyConverter
161 |
162 |
163 |
164 | conv = KittyConverter.new
165 | conv.convert( 'dl/kittydex-20180320.csv', out_dir: '../kitties' )
166 |
--------------------------------------------------------------------------------
/copycats/NOTES.md:
--------------------------------------------------------------------------------
1 | # Notes
2 |
3 | ## Todos
4 |
5 | - [ ] change formula / recipe to traits in traits.rb
6 |
7 | ### How to name the group of four genes?
8 |
9 | use
10 | - Gene
11 | - Genes / G4 / Gene4x / ?
12 | - Gene Slice / Slice / Gene::Slice / Genome::Slice
13 | - Gene Family / Family
14 | - Gene Cluster / Cluster
15 | - Gene Group / Group
16 | - Gene Region / Region
17 | - Gene Seq / Sequence / ?
18 | - Gene Set / Set / ?
19 | - Multigene (?)
20 | - Zone / Unit / ?
21 |
22 | https://en.wikipedia.org/wiki/Gene
23 |
24 | > The term gene was introduced by Danish botanist, plant physiologist and geneticist Wilhelm Johannsen in 1905.
25 | > It is inspired by the ancient Greek: γόνος, gonos, that means offspring and procreation.
26 |
27 | https://en.wikipedia.org/wiki/Gene_family
28 |
29 |
30 |
31 |
32 |
33 | ### print traits with database id - why? why not?
34 |
35 | TRAIT_IDS.md - use / build a new page (report) - why? why not?
36 |
37 |
38 | ### Ruby SQL intersect with ActiveRecord
39 |
40 |
41 | ```
42 | genes = Gene.where( trait: Trait.find_by( name: 'savannah' )).intersect(
43 | Gene.where( trait: Trait.find_by( name: 'pattern' )))
44 | genes.map { |gene| gene.kitty } # get kitties (from gene)
45 | ```
46 |
47 | check if the same as:
48 |
49 | ```
50 | genes = Gene.find_by( trait: Trait.find_by( name: 'savannah' )) &
51 | Gene.find_by( trait: Trait.find_by( name: 'pattern' ))
52 | genes.map { |gene| gene.kitty } # get kitties (from gene)
53 | ```
54 |
55 | use to_sql for see generated sql!
56 |
57 |
58 | check if project on kitty_id required!!
59 | otherwise all records are different (has its own id!!!)
60 |
61 |
62 |
63 | ### SQL
64 |
65 | ``` sql
66 | SELECT kitty_id FROM genes WHERE trait_id = 0
67 | INTERSECT
68 | SELECT kitty_id FROM genes WHERE trait_id = 33
69 | ```
70 |
71 |
72 | check query samples
73 | with article and tags (find article by two tags - more than one - for example)
74 |
75 |
76 | does it work with inner join?
77 |
78 | ``` sql
79 | SELECT id -- ??? to be done (not working)
80 | FROM kitties
81 | INNER JOIN genes
82 | where genes.trait_id in [0,3]
83 | ```
84 |
85 | or use subselect in where?
86 |
87 | ``` sql
88 | SELECT id -- ??? to be done (not working)
89 | FROM kitties
90 | where select kitty_id from genes where trait_id in [0,3]
91 | ```
92 |
93 |
94 |
95 |
96 |
97 |
98 | ---
99 |
100 | ## Mutations / Mewtations
101 |
102 | 5-bit Gene = 2^5 = 32 Values / Attributes
103 |
104 | 16 Mutation Pairs (16 x 2 = 32)
105 |
106 | | Tier | Count | Total |
107 | |------------------------|-------|-------|
108 | | Tier 1 (Basic Traits) | 16 | 16 |
109 | | Tier 2 (Mutations) | 8 | 24 |
110 | | Tier 3 (Mutations) | 4 | 28 |
111 | | Tier 4 (Mutations) | 2 | 30 |
112 | | Tier 5 (Mutations) | 1 | 31 |
113 |
114 |
115 | ```
116 | Tier 1 Tier 2 Tier 3 Tier 4 Tier 5
117 | (0-15) (16-23) (24-27) (28,29) (30)
118 | 0+1 = 16 16+17 = 24 24+25 = 28 28+29 = 30
119 | 2+3 = 17 18+19 = 25 26+27 = 29
120 | 4+5 = 18 20+21 = 26
121 | 6+7 = 19 22+23 = 27
122 | 8+9 = 20
123 | 10+11 = 21
124 | 12+13 = 22
125 | 14+15 = 23
126 | ```
127 |
128 | Note: It's impossible for a mutation to reach `31` e.g.`30+31 = 31`.
129 |
130 |
131 | in Kai (base32) notation:
132 |
133 | ```
134 | Tier 1 Tier 2 Tier 3 Tier 4 Tier 5
135 | (1-g) (h-p) (q-t) (u,v) (w)
136 | 1+2 = h h+i = q q+r = u u+v = w
137 | 3+4 = i j+k = r s+t = v
138 | 5+6 = j m+n = s
139 | 7+8 = k o+p = t
140 | 9+a = m
141 | b+c = n
142 | d+e = o
143 | f+g = p
144 | ```
145 |
146 | Note: It's impossible for a mutation to reach `x` e.g. `w+x = x`.
147 |
148 |
149 |
150 | The formula is `n+(n+1) = n/2+16` if n is an even number (0,2,4,6,...).
151 | Running:
152 |
153 | ``` ruby
154 | (0..31).each do |n|
155 | if n.even?
156 | puts "#{n}+#{n+1} = #{n/2+16}"
157 | end
158 | end
159 | ```
160 |
161 | results in:
162 |
163 | ```
164 | 0+1 = 16
165 | 2+3 = 17
166 | 4+5 = 18
167 | 6+7 = 19
168 | 8+9 = 20
169 | 10+11 = 21
170 | 12+13 = 22
171 | 14+15 = 23
172 | 16+17 = 24
173 | 18+19 = 25
174 | 20+21 = 26
175 | 22+23 = 27
176 | 24+25 = 28
177 | 26+27 = 29
178 | 28+29 = 30
179 | 30+31 = 31
180 | ```
181 |
182 | and in kai (base32) notation.
183 |
184 | ``` ruby
185 | ALPHABET = "123456789abcdefghijkmnopqrstuvwx"
186 |
187 | (0..31).each do |n|
188 | if n.even?
189 | puts "#{ALPHABET[n]}+#{ALPHABET[n+1]} = #{ALPHABET[n/2+16]}"
190 | end
191 | end
192 | ```
193 |
194 | results in:
195 |
196 | ```
197 | 1+2 = h
198 | 3+4 = i
199 | 5+6 = j
200 | 7+8 = k
201 | 9+a = m
202 | b+c = n
203 | d+e = o
204 | f+g = p
205 | h+i = q
206 | j+k = r
207 | m+n = s
208 | o+p = t
209 | q+r = u
210 | s+t = v
211 | u+v = w
212 | w+x = x
213 | ```
214 |
215 |
216 | ## Fancies
217 |
218 | Stephen Curry Kitties
219 |
220 | Three kitties created in the likeness of Stephen Curry, an NBA player.
221 | These three kittis were ChefFurry, StephFurThree, and #30Furry (Kitty ids: 130, 230, and 330 respectively). However, shortly after releasing these kitties, their pages were removed. Currently the CryptoKitties team states:
222 |
223 | We have reason to believe Steph wasn't as involved in the CurryKitties as we thought.
224 | Until we're sure he's an active participant, we're suspending the campaign.
225 |
226 | ---
227 |
228 | - 帝龙喵 (GoldenDragonCat) 888
229 | - 旺财汪 (GoldDogCat) 1802, 1803, 1805, 1806, 1808, 1809, 1812, 1816, 1826, 1827, 1828
230 |
231 | Fancies:
232 | - 汪星爷/DogCat 88 tigerpunk, sweetlemoncakes, barkbrown, periwinkle, yokel
233 | - 咚咚锵/LionDanceCat 888 manx, googly, royalblue, starstruck
234 | - 红包喵/FortuneCat 888
235 |
236 | http://www.cryptokittieswiki.com/Fancies/
237 |
238 |
239 | http://www.cryptokittieswiki.com/contracts/
240 |
241 | Trait Releases
242 |
243 | In early April, 2018, trait releases were changed in gen0 kitties.
244 | Specifically, after the Family Jewels update when new traits were released, it was relatively easy to snipe the diamond. This lead to automation that would quickly purchase the kitty. Therefore traits were changed so they would be introduced at H3 and then after some time go up to H2, till they are at the highest level they will achieve. While this did not eliminated the automation, it made the process require more investment and breeding to get the diamond.1
245 |
246 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | CC0 1.0 Universal
2 |
3 | Statement of Purpose
4 |
5 | The laws of most jurisdictions throughout the world automatically confer
6 | exclusive Copyright and Related Rights (defined below) upon the creator and
7 | subsequent owner(s) (each and all, an "owner") of an original work of
8 | authorship and/or a database (each, a "Work").
9 |
10 | Certain owners wish to permanently relinquish those rights to a Work for the
11 | purpose of contributing to a commons of creative, cultural and scientific
12 | works ("Commons") that the public can reliably and without fear of later
13 | claims of infringement build upon, modify, incorporate in other works, reuse
14 | and redistribute as freely as possible in any form whatsoever and for any
15 | purposes, including without limitation commercial purposes. These owners may
16 | contribute to the Commons to promote the ideal of a free culture and the
17 | further production of creative, cultural and scientific works, or to gain
18 | reputation or greater distribution for their Work in part through the use and
19 | efforts of others.
20 |
21 | For these and/or other purposes and motivations, and without any expectation
22 | of additional consideration or compensation, the person associating CC0 with a
23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
25 | and publicly distribute the Work under its terms, with knowledge of his or her
26 | Copyright and Related Rights in the Work and the meaning and intended legal
27 | effect of CC0 on those rights.
28 |
29 | 1. Copyright and Related Rights. A Work made available under CC0 may be
30 | protected by copyright and related or neighboring rights ("Copyright and
31 | Related Rights"). Copyright and Related Rights include, but are not limited
32 | to, the following:
33 |
34 | i. the right to reproduce, adapt, distribute, perform, display, communicate,
35 | and translate a Work;
36 |
37 | ii. moral rights retained by the original author(s) and/or performer(s);
38 |
39 | iii. publicity and privacy rights pertaining to a person's image or likeness
40 | depicted in a Work;
41 |
42 | iv. rights protecting against unfair competition in regards to a Work,
43 | subject to the limitations in paragraph 4(a), below;
44 |
45 | v. rights protecting the extraction, dissemination, use and reuse of data in
46 | a Work;
47 |
48 | vi. database rights (such as those arising under Directive 96/9/EC of the
49 | European Parliament and of the Council of 11 March 1996 on the legal
50 | protection of databases, and under any national implementation thereof,
51 | including any amended or successor version of such directive); and
52 |
53 | vii. other similar, equivalent or corresponding rights throughout the world
54 | based on applicable law or treaty, and any national implementations thereof.
55 |
56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of,
57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
59 | and Related Rights and associated claims and causes of action, whether now
60 | known or unknown (including existing as well as future claims and causes of
61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum
62 | duration provided by applicable law or treaty (including future time
63 | extensions), (iii) in any current or future medium and for any number of
64 | copies, and (iv) for any purpose whatsoever, including without limitation
65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
66 | the Waiver for the benefit of each member of the public at large and to the
67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver
68 | shall not be subject to revocation, rescission, cancellation, termination, or
69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work
70 | by the public as contemplated by Affirmer's express Statement of Purpose.
71 |
72 | 3. Public License Fallback. Should any part of the Waiver for any reason be
73 | judged legally invalid or ineffective under applicable law, then the Waiver
74 | shall be preserved to the maximum extent permitted taking into account
75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
76 | is so judged Affirmer hereby grants to each affected person a royalty-free,
77 | non transferable, non sublicensable, non exclusive, irrevocable and
78 | unconditional license to exercise Affirmer's Copyright and Related Rights in
79 | the Work (i) in all territories worldwide, (ii) for the maximum duration
80 | provided by applicable law or treaty (including future time extensions), (iii)
81 | in any current or future medium and for any number of copies, and (iv) for any
82 | purpose whatsoever, including without limitation commercial, advertising or
83 | promotional purposes (the "License"). The License shall be deemed effective as
84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the
85 | License for any reason be judged legally invalid or ineffective under
86 | applicable law, such partial invalidity or ineffectiveness shall not
87 | invalidate the remainder of the License, and in such case Affirmer hereby
88 | affirms that he or she will not (i) exercise any of his or her remaining
89 | Copyright and Related Rights in the Work or (ii) assert any associated claims
90 | and causes of action with respect to the Work, in either case contrary to
91 | Affirmer's express Statement of Purpose.
92 |
93 | 4. Limitations and Disclaimers.
94 |
95 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
96 | surrendered, licensed or otherwise affected by this document.
97 |
98 | b. Affirmer offers the Work as-is and makes no representations or warranties
99 | of any kind concerning the Work, express, implied, statutory or otherwise,
100 | including without limitation warranties of title, merchantability, fitness
101 | for a particular purpose, non infringement, or the absence of latent or
102 | other defects, accuracy, or the present or absence of errors, whether or not
103 | discoverable, all to the greatest extent permissible under applicable law.
104 |
105 | c. Affirmer disclaims responsibility for clearing rights of other persons
106 | that may apply to the Work or any use thereof, including without limitation
107 | any person's Copyright and Related Rights in the Work. Further, Affirmer
108 | disclaims responsibility for obtaining any necessary consents, permissions
109 | or other rights required for any use of the Work.
110 |
111 | d. Affirmer understands and acknowledges that Creative Commons is not a
112 | party to this document and has no duty or obligation with respect to this
113 | CC0 or use of the Work.
114 |
115 | For more information, please see
116 |
117 |
--------------------------------------------------------------------------------
/copycats/lib/copycats/genome.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 |
4 | class Genome
5 | attr_reader :genes ## hash of (sliced) genes (key is gene trait type)
6 |
7 | def initialize( arg )
8 | if arg.is_a? Hash
9 | hash = arg ## assumes (pre-built) hash with genes
10 | @genes = hash
11 | else
12 | if arg.is_a? Integer ## use Integer (Fixnum+Bignum??) - why? why not?
13 | num = arg
14 | kai = Kai.encode( num )
15 | else # else assume string in kai/base32 format
16 | kai = arg.dup # just in case; make a clean (fresh) copy
17 | kai = kai.gsub( ' ', '' ) ## allow spaces (strip/remove)
18 | end
19 | ## puts "Genome.initialize #{kai}"
20 | build_genes( kai )
21 | end
22 | end
23 |
24 |
25 | def build_genes( kai )
26 | kai = kai.reverse ## note: reserve for easy left-to-right access
27 | @genes = {} ## hash of genes (key is gene type)
28 | ## fix/todo: use as_json for "official" api order
29 | ## note: use insert order from "official" api
30 | @genes[:body] = Gene::Slice.new( kai[0,4].reverse )
31 | @genes[:pattern] = Gene::Slice.new( kai[4,4].reverse )
32 | @genes[:coloreyes] = Gene::Slice.new( kai[8,4].reverse )
33 | @genes[:eyes] = Gene::Slice.new( kai[12,4].reverse )
34 | @genes[:color1] = Gene::Slice.new( kai[16,4].reverse ) ## colorprimary / body color / base color
35 | @genes[:color2] = Gene::Slice.new( kai[20,4].reverse ) ## colorsecondary / sec color / pattern color / hi(light) color
36 | @genes[:color3] = Gene::Slice.new( kai[24,4].reverse ) ## colortertiary / acc(ent) color
37 | @genes[:wild] = Gene::Slice.new( kai[28,4].reverse )
38 | @genes[:mouth] = Gene::Slice.new( kai[32,4].reverse )
39 | @genes[:environment] = Gene::Slice.new( kai[36,4].reverse )
40 | @genes[:secret] = Gene::Slice.new( kai[40,4].reverse )
41 | @genes[:prestige] = Gene::Slice.new( kai[44,4].reverse )
42 | end
43 |
44 | def body() TRAITS[:body][:kai][ @genes[:body].p ]; end
45 | def coloreyes() TRAITS[:coloreyes][:kai][ @genes[:coloreyes].p ]; end
46 | def eyes() TRAITS[:eyes][:kai][ @genes[:eyes].p ]; end
47 | def pattern() TRAITS[:pattern][:kai][ @genes[:pattern].p ]; end
48 | def mouth() TRAITS[:mouth][:kai][ @genes[:mouth].p ]; end
49 | def color1() TRAITS[:color1][:kai][ @genes[:color1].p ]; end
50 | def color2() TRAITS[:color2][:kai][ @genes[:color2].p ]; end
51 | def color3() TRAITS[:color3][:kai][ @genes[:color3].p ]; end
52 |
53 | def wild() TRAITS[:wild][:kai][ @genes[:wild].p ]; end
54 | def environment() TRAITS[:environment][:kai][ @genes[:environment].p ]; end
55 |
56 |
57 |
58 | def genes_color1() @genes[:color1]; end ## rename to color1_genes instead - why? why not?
59 | def genes_eyes() @genes[:eyes]; end
60 | ## ....
61 |
62 | ## add cattributes ?? why? why not?
63 |
64 |
65 | def mix( other )
66 | mgenes = genes ## matron genes
67 | sgenes = other.genes ## sire genes
68 | new_genes = {}
69 |
70 | [:body, ### todo/fix: use TRAITS.keys or something - why? why not?
71 | :pattern,
72 | :coloreyes,
73 | :eyes,
74 | :color1,
75 | :color2,
76 | :color3,
77 | :wild,
78 | :mouth,
79 | :environment,
80 | :secret,
81 | :prestige].each do |key|
82 | mgene = mgenes[key]
83 | sgene = sgenes[key]
84 |
85 | new_gene = mgene.mix( sgene )
86 | new_genes[key] = new_gene
87 | end
88 |
89 | Genome.new( new_genes ) ## return new genome from (pre-built) hash (with genes)
90 | end
91 |
92 |
93 | def build_tables() GenomeTables.new( self ).build; end
94 |
95 | def build_mix_tables( other ) GenomeMixTables.new( self, other ).build; end
96 |
97 | end # class Genome
98 |
99 |
100 |
101 | class GenomeTables
102 | def initialize( genome )
103 | @genome = genome
104 | end
105 |
106 | def build
107 | pos = 0
108 | buf = ""
109 |
110 | genes = @genome.genes
111 |
112 | TRAITS.each do |key, trait|
113 | gene = genes[key]
114 | next if gene.nil? ## skip future_1, future_2, etc.
115 |
116 | buf << "#{trait[:name]} (Genes #{trait[:genes]})\n\n"
117 |
118 | ###
119 | ## fix/todo: add stars for purity?
120 | ## **** - all traits the same
121 | ## *** - two same pairs of traits
122 | ## ** - one pair of same traits
123 |
124 | buf << "|Gene |Binary |Kai |Trait | |\n"
125 | buf << "|------|---------|-----|---------|---|\n"
126 | buf << "| #{pos} | #{Kai::BINARY[gene.d]} | #{gene.d} | **#{fmt_trait(trait[:kai][gene.d])}** | d |\n"; pos+=1
127 | buf << "| #{pos} | #{Kai::BINARY[gene.r1]} | #{gene.r1} | #{fmt_trait(trait[:kai][gene.r1])} | r1 |\n"; pos+=1
128 | buf << "| #{pos} | #{Kai::BINARY[gene.r2]} | #{gene.r2} | #{fmt_trait(trait[:kai][gene.r2])} | r2 |\n"; pos+=1
129 | buf << "| #{pos} | #{Kai::BINARY[gene.r3]} | #{gene.r3} | #{fmt_trait(trait[:kai][gene.r3])} | r3 |\n"; pos+=1
130 | buf << "\n"
131 |
132 | if key == :body ## add legend for first entry
133 | buf << "d = dominant, r1 = 1st order recessive, r2 = 2nd order recessive, r3 = 3rd order recessive\n\n"
134 | end
135 | end
136 |
137 | buf
138 | end
139 |
140 | ####################
141 | ## helpers
142 |
143 | def fmt_trait( trait )
144 | (trait.nil? || trait.empty?) ? '?' : trait
145 | end
146 | end # class GenomeTables
147 |
148 |
149 |
150 |
151 | class GenomeMixTables
152 | def initialize( matron, sire )
153 | @matron = matron
154 | @sire = sire
155 | end
156 |
157 | def build
158 | pos = 0
159 | buf = ""
160 |
161 | mgenes = @matron.genes
162 | sgenes = @sire.genes
163 |
164 | TRAITS.each do |key, trait|
165 | mgene = mgenes[key]
166 | sgene = sgenes[key]
167 | next if mgene.nil? ## skip future_1, future_2, etc.
168 |
169 | buf << "#{trait[:name]} (Genes #{trait[:genes]})\n\n"
170 |
171 | buf << "|Gene |Kai |Trait (Matron)|Kai|Trait (Sire)| |\n"
172 | buf << "|------|-----|---------|-----|---------|---|\n"
173 | buf << "| #{pos} | #{mgene.d} | **#{fmt_trait(trait[:kai][mgene.d])}** | #{sgene.d} | **#{fmt_trait(trait[:kai][sgene.d])}** | d |\n"; pos+=1
174 | buf << "| #{pos} | #{mgene.r1} | #{fmt_trait(trait[:kai][mgene.r1])} | #{sgene.r1} | #{fmt_trait(trait[:kai][sgene.r1])} | r1 |\n"; pos+=1
175 | buf << "| #{pos} | #{mgene.r2} | #{fmt_trait(trait[:kai][mgene.r2])} | #{sgene.r2} | #{fmt_trait(trait[:kai][sgene.r2])} | r2 |\n"; pos+=1
176 | buf << "| #{pos} | #{mgene.r3} | #{fmt_trait(trait[:kai][mgene.r3])} | #{sgene.r3} | #{fmt_trait(trait[:kai][sgene.r3])} | r3 |\n"; pos+=1
177 | buf << "\n"
178 |
179 | if key == :body ## add legend for first entry
180 | buf << "d = dominant, r1 = 1st order recessive, r2 = 2nd order recessive, r3 = 3rd order recessive\n\n"
181 | end
182 | end
183 |
184 | buf
185 | end
186 |
187 | ####################
188 | ## helpers
189 |
190 | def fmt_trait( trait )
191 | (trait.nil? || trait.empty?) ? '?' : trait
192 | end
193 | end # class GenomeMixTables
194 |
--------------------------------------------------------------------------------
/copycats/lib/copycats/import/read.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 |
3 |
4 | ## load all *.file in data folder
5 |
6 | def find_datafiles( root='.' )
7 | files = []
8 | ## todo/check: include all subfolders - why? why not?
9 | Dir.glob( root + '/**/*.csv' ).each do |file|
10 | files << file
11 | end
12 | files
13 | end
14 |
15 |
16 | def read_datafiles( data_dir: './data' )
17 | files = find_datafiles( data_dir )
18 | pp files
19 |
20 | ## todo: check if files found
21 |
22 |
23 | ## for speed - turn off logging for info/debug/etc. levels
24 | ActiveRecord::Base.logger.level = :warn
25 |
26 |
27 | ## pp TRAIT_IDS_CACHE
28 |
29 | ## add / read / load all datafiles
30 | files.each_with_index do |file,i|
31 |
32 | puts "== #{i+1}/#{files.size} reading datafile '#{file}'..."
33 |
34 |
35 | kitties_headers = CsvReader.header( file )
36 | pp kitties_headers
37 |
38 | ## todo: fix - use field index not name!!!! - why? why not?
39 | ## check format
40 | if kitties_headers.include?( 'id' ) &&
41 | kitties_headers.include?( 'gen' ) &&
42 | kitties_headers.include?( 'matron_id' ) &&
43 | kitties_headers.include?( 'sire_id' ) &&
44 | kitties_headers.include?( 'birthdate' ) &&
45 | kitties_headers.include?( 'genes' ) &&
46 | kitties_headers.include?( 'name' )
47 | ## "standard" format
48 | ## required headers include: id, gen, matron_id, sire_id, birthdate, genes, name
49 |
50 | ## todo: fix - use field index not name!!!! - why? why not?
51 | headers = {
52 | 'id' => 'id',
53 | 'gen' => 'gen',
54 | 'matron_id' => 'matron_id',
55 | 'sire_id' => 'sire_id',
56 | 'birthdate' => 'birthdate',
57 | 'genes' => 'genes',
58 | 'name' => 'name'
59 | }
60 | elsif kitties_headers.include?( 'id' ) &&
61 | kitties_headers.include?( 'matron_id' ) &&
62 | kitties_headers.include?( 'sire_id' ) &&
63 | kitties_headers.include?( 'gen' ) &&
64 | kitties_headers.include?( 'birth_date' ) &&
65 | kitties_headers.include?( 'genes_kai' )
66 | ## "kittydex" format
67 | ## see https://cryptokittydex.com/resources
68 | ## required headers include: id, matron_id, sire_id, gen, birth_date, genes_kai
69 | headers = {
70 | 'id' => 'id',
71 | 'matron_id' => 'matron_id',
72 | 'sire_id' => 'sire_id',
73 | 'gen' => 'gen',
74 | 'birthdate' => 'birth_date',
75 | 'genes' => 'genes_kai',
76 | 'name' => 'name' ## note: will always be nil (is missing in kittydex)
77 | }
78 | else
79 | ## unknown format
80 | puts "!!! unknown datafile format; matching headers NOT found / missing"
81 | exit 1
82 | end
83 |
84 |
85 | ## start of kitties blockchain / genesis
86 | genesisdate = Date.new( 2017, 11, 23) ## 2017-11-23
87 |
88 | ## note: for now use first 5 rows for testing
89 | ## kitties[0..4].each do |row|
90 |
91 | kitties = CsvHash.read( file )
92 | kitties.each do |row|
93 | ## puts row['id'] + '|' + row['gen'] + '|' + row['genes_kai']
94 | k = Copycats::Model::Kitty.new
95 | k.id = row[headers['id']].to_i
96 | k.gen = row[headers['gen']].to_i
97 | k.matron_id = row[headers['matron_id']].to_i unless row[headers['matron_id']].blank? || row[headers['matron_id']] == '0'
98 | k.sire_id = row[headers['sire_id']].to_i unless row[headers['sire_id']].blank? || row[headers['sire_id']] == '0'
99 | k.name = row[headers['name']] unless row[headers['name']].blank?
100 |
101 | ## founder cats - first one hundret (1 to 100 - note: includes genesis (1))
102 | k.is_founder = true if k.id >= 1 && k.id <= 100
103 |
104 |
105 | ## todo: pretty print (format genes !!!!)
106 | k.genes_kai = row[headers['genes']] ### .gsub( ' ', '' ) ## remove all spaces - why? why not?
107 |
108 | ## pp row['birthdate']
109 | birthdate = DateTime.strptime( row[headers['birthdate']], '%Y-%m-%d %H:%M:%S' )
110 | k.birthdate = birthdate
111 | k.day_count = (birthdate.to_date.jd - genesisdate.jd)+1
112 |
113 |
114 | genome = Genome.new( k.genes_kai )
115 | genes = genome.genes
116 |
117 | k.body_id = TRAIT_IDS_CACHE[:body][:kai][genes[:body].d]
118 | k.pattern_id = TRAIT_IDS_CACHE[:pattern][:kai][genes[:pattern].d]
119 | k.coloreyes_id = TRAIT_IDS_CACHE[:coloreyes][:kai][genes[:coloreyes].d]
120 | k.eyes_id = TRAIT_IDS_CACHE[:eyes][:kai][genes[:eyes].d]
121 | k.color1_id = TRAIT_IDS_CACHE[:color1][:kai][genes[:color1].d]
122 | k.color2_id = TRAIT_IDS_CACHE[:color2][:kai][genes[:color2].d]
123 | k.color3_id = TRAIT_IDS_CACHE[:color3][:kai][genes[:color3].d]
124 | k.wild_id = TRAIT_IDS_CACHE[:wild][:kai][genes[:wild].d]
125 | k.mouth_id = TRAIT_IDS_CACHE[:mouth][:kai][genes[:mouth].d]
126 |
127 | ## pp k
128 |
129 | ## print ids for progress report - why? why not?
130 | print "#{k.id}."
131 | k.save!
132 |
133 | ## add genes
134 | TRAITS.each_with_index do |(trait_key, trait_hash),i|
135 | gene = genes[trait_key]
136 | next if gene.nil? ## skip future_1, future_2, etc. for now - add - why? why not?
137 |
138 | ## puts "#{trait_hash[:name]} (Genes #{trait_hash[:genes]})\n\n"
139 |
140 | ## note: start counting for d.n with 1 (NOT 0)
141 | ## use idx for zero-based counting - why? why not?
142 |
143 | d = Copycats::Model::Gene.new
144 | d.kitty_id = k.id
145 | d.n = (i*4) # gene number/pos 0-47 (start w/ 1 why? why not?)
146 | d.gene = 'd' # d (0), r1 (1), r2 (2), r3 (3)
147 | d.gene_n = 0 # 0-3 (0=d,1=r1,2=r2,3=r3)
148 | d.trait_id = TRAIT_IDS_CACHE[trait_key][:kai][gene.d]
149 | d.save!
150 |
151 | r1 = Copycats::Model::Gene.new
152 | r1.kitty_id = k.id
153 | r1.n = (i*4)+1 # gene number/pos 0-47 (start w/ 1 why? why not?)
154 | r1.gene = 'r1' # d (0), r1 (1), r2 (2), r3 (3)
155 | r1.gene_n = 1 # 0-3 (0=d,1=r1,2=r2,3=r3)
156 | r1.trait_id = TRAIT_IDS_CACHE[trait_key][:kai][gene.r1]
157 | r1.save!
158 |
159 | r2 = Copycats::Model::Gene.new
160 | r2.kitty_id = k.id
161 | r2.n = (i*4)+2 # gene number/pos 0-47 (start w/ 1 why? why not?)
162 | r2.gene = 'r2' # d (0), r1 (1), r2 (2), r3 (3)
163 | r2.gene_n = 2 # 0-3 (0=d,1=r1,2=r2,3=r3)
164 | r2.trait_id = TRAIT_IDS_CACHE[trait_key][:kai][gene.r2]
165 | r2.save!
166 |
167 | r3 = Copycats::Model::Gene.new
168 | r3.kitty_id = k.id
169 | r3.n = (i*4)+3 # gene number/pos 0-47 (start w/ 1 why? why not?)
170 | r3.gene = 'r3' # d (0), r1 (1), r2 (2), r3 (3)
171 | r3.gene_n = 3 # 0-3 (0=d,1=r1,2=r2,3=r3)
172 | r3.trait_id = TRAIT_IDS_CACHE[trait_key][:kai][gene.r3]
173 | r3.save!
174 | end
175 |
176 | end
177 | print "\n"
178 | end
179 | end
180 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Crypto Copycats Collectibles - Buy! Sell! Hodl! Sire!
2 |
3 |
4 | ## Copycats Database Tools
5 |
6 | - [**copycats**](copycats) - incl. `kitty` command line tool to (auto-)read kitty data records (in comma-separated values (CSV)) into an in-memory SQLite database
7 | and print reports
8 | - [**bitcat**](bitcat) - bit catalog kitty browser; browse your (digital) bit(s) collections
9 |
10 |
11 |
12 |
13 | ## Database Tables
14 |
15 | Table Diagram
16 |
17 | 
18 |
19 |
20 | SQL Tables (in SQLite Dialect)
21 |
22 | ``` sql
23 | CREATE TABLE kitties (
24 | id INTEGER PRIMARY KEY AUTOINCREMENT
25 | NOT NULL,
26 | name VARCHAR,
27 | genes_kai VARCHAR NOT NULL,
28 | gen INTEGER NOT NULL,
29 | birthdate DATETIME NOT NULL,
30 | day_count INTEGER NOT NULL,
31 | matron_id INTEGER,
32 | sire_id INTEGER,
33 | body_id INTEGER NOT NULL,
34 | pattern_id INTEGER NOT NULL,
35 | coloreyes_id INTEGER NOT NULL,
36 | eyes_id INTEGER NOT NULL,
37 | color1_id INTEGER NOT NULL,
38 | color2_id INTEGER NOT NULL,
39 | color3_id INTEGER NOT NULL,
40 | wild_id INTEGER NOT NULL,
41 | mouth_id INTEGER NOT NULL
42 | );
43 |
44 |
45 | CREATE TABLE genes (
46 | id INTEGER PRIMARY KEY AUTOINCREMENT
47 | NOT NULL,
48 | kitty_id INTEGER NOT NULL,
49 | n INTEGER NOT NULL,
50 | gene VARCHAR NOT NULL,
51 | gene_n INTEGER NOT NULL,
52 | trait_id INTEGER NOT NULL
53 | );
54 |
55 |
56 | CREATE TABLE traits (
57 | id INTEGER PRIMARY KEY AUTOINCREMENT
58 | NOT NULL,
59 | trait_type_id INTEGER NOT NULL,
60 | name VARCHAR NOT NULL,
61 | n INTEGER NOT NULL,
62 | kai VARCHAR NOT NULL,
63 | tier INTEGER
64 | );
65 |
66 | CREATE TABLE trait_types (
67 | id INTEGER PRIMARY KEY AUTOINCREMENT
68 | NOT NULL,
69 | name VARCHAR NOT NULL,
70 | [key] VARCHAR NOT NULL
71 | );
72 |
73 | ```
74 |
75 | ## Database Setup
76 |
77 | Use the kitty setup command to setup an SQLite database and (auto-)read
78 | all datafiles. Example:
79 |
80 | ```
81 | $ kitty setup
82 | ```
83 |
84 | This will create:
85 |
86 | - a single-file SQLite database `kitties.db`
87 | - setup all tables
88 | - add all known traits and trait types (body, pattern, eyes, ...) and
89 | - (auto-)read all datafiles (`**/*.csv`) in the `.` and all subdirectories
90 |
91 |
92 | Note: Use the `-i/--include` option to change the default data directory (that is, `.`)
93 | and use the `-n/--dbname` option to change the default SQLite database name (that is, `kitties.db`)
94 | and use the `-d/--dbpath` option to change the default SQLite database path (that is, `.`).
95 |
96 |
97 | Showtime! Use the sqlite3 command line tool
98 | and try some queries. Example:
99 |
100 | ```
101 | $ sqlite3 kitties.db
102 |
103 | sqlite> SELECT * FROM kitties WHERE id = 1;
104 |
105 | 1||ccac 7787 fa7f afaa 1646 7755 f9ee 4444 6766 7366 cccc eede|0|2017-11-23 06:19:59|...
106 |
107 | sqlite> SELECT * FROM genes WHERE trait_id = 14; -- sphynx (14)
108 |
109 | 1|1|0|d|0|14
110 | 3|1|2|r2|2|14
111 | 4|1|3|r3|3|14
112 | 38|2|1|r1|1|14
113 | 146|5|1|r1|1|14
114 | 181|6|0|d|0|14
115 | 183|6|2|r2|2|14
116 | ...
117 | ```
118 |
119 |
120 |
121 | ## Database Queries
122 |
123 | ### SQL
124 |
125 | #### Find all kitties with a trait
126 |
127 | Let's use the trait savannah (fur) with the id 0:
128 |
129 | ``` sql
130 | SELECT id FROM kitties WHERE body_id = 0
131 | ```
132 |
133 | #### Find all kitties with two traits
134 |
135 | Let's use the trait savannah (fur) with the id 0
136 | and the trait tiger (pattern) with the id 33:
137 |
138 | ``` sql
139 | SELECT id FROM kitties
140 | WHERE body_id = 0 AND pattern_id = 33
141 | ```
142 |
143 |
144 | #### Find all kitties with a trait (in any gene d/r1/r2/r3)
145 |
146 | Note: All traits (12 x 32 = 384) are numbered with ids from 0 to 383 in the traits database table.
147 | Let's use the trait savannah (fur) with the id 0:
148 |
149 | ``` sql
150 | SELECT kitty_id FROM genes WHERE trait_id = 0
151 | ```
152 |
153 |
154 | #### Find all kitties with a dominant (visible) trait
155 |
156 | Note: Use `gene` column (`d`/`r1`/`r2`/`r3`) or the numeric `gene_n`
157 | column (0/1/2/3): Let's use the trait savannah (fur) with the id 0
158 | and a dominant (d) gene:
159 |
160 |
161 | ``` sql
162 | SELECT kitty_id FROM genes
163 | WHERE trait_id = 0 AND gene='d'
164 | ```
165 |
166 |
167 | #### Find all kitties with two traits (in any gene d/r1/r2/r3)
168 |
169 | Use two query with "intersect" the result. Let's
170 | use the trait savannah (fur) with the id 0
171 | and the trait tiger (pattern) with the id 33:
172 |
173 | ``` sql
174 | SELECT kitty_id FROM genes WHERE trait_id = 0
175 | INTERSECT
176 | SELECT kitty_id FROM genes WHERE trait_id = 33
177 | ```
178 |
179 |
180 | ### Using Models w/ ActiveRecord in Ruby
181 |
182 |
183 | #### Find all kitties with a trait
184 |
185 | Let's use the trait savannah (fur) with the id 0:
186 |
187 | ``` ruby
188 | Kitty.find_by( body: Trait.find_by( name: 'savannah' ))
189 | # -or -
190 | Kitty.find_by( body_id: 0)
191 | ```
192 |
193 | #### Find all kitties with two traits
194 |
195 | Let's use the trait savannah (fur) with the id 0
196 | and the trait tiger (pattern) with the id 33:
197 |
198 | ``` ruby
199 | Kitty.find_by( body: Trait.find_by( name: 'savannah' ),
200 | pattern: Trait.find_by( name: 'tiger' ))
201 | # -or -
202 | Kitty.find_by( body_id: 0, pattern_id: 33 )
203 | ```
204 |
205 |
206 | #### Find all kitties with a trait (in any gene d/r1/r2/r3)
207 |
208 | Let's use the trait savannah (fur) with the id 0:
209 |
210 | ``` ruby
211 | genes = Gene.find_by( trait: Trait.find_by( name: 'savannah' )) # query
212 | #-or-
213 | genes = Gene.find_by( trait_id: 0 )
214 | genes.map { |gene| gene.kitty } # get kitties (from gene)
215 | ```
216 |
217 |
218 | #### Find all kitties with a dominant (visible) trait
219 |
220 | Let's use the trait savannah (fur) with the id 0 and a dominant (d) gene:
221 |
222 |
223 | ``` ruby
224 | genes = Gene.find_by( trait: Trait.find_by( name: 'savannah' ),
225 | d: 'd' ) #query
226 | #-or-
227 | genes = Gene.find_by( trait_id: 0, d: 'd' )
228 | genes.map { |gene| gene.kitty } # get kitties (from gene)
229 | ```
230 |
231 |
232 | #### Find all kitties with two traits
233 |
234 | Use two query with "intersect" the result. Let's
235 | use the trait savannah (fur)
236 | and the trait tiger (pattern):
237 |
238 | ``` ruby
239 | genes = Gene.select('kitty_id').where( trait: Trait.find_by( name: 'savannah' )).intersect(
240 | Gene.select('kitty_id').where( trait: Trait.find_by( name: 'pattern' )))
241 | genes.map { |gene| gene.kitty } # get kitties (from gene)
242 | ```
243 |
244 |
245 | ## Datasets
246 |
247 | [(Crypto) Kitties on the Blockchain](https://github.com/cryptocopycats/kitties) -
248 | public dataset in comma-separated values (CSV) format in blocks of a thousand kitties each (e.g.
249 | [`000.csv`](https://github.com/cryptocopycats/kitties/blob/master/1-99_999/000.csv) incl. 1-999,
250 | [`001.csv`](https://github.com/cryptocopycats/kitties/blob/master/1-99_999/001.csv) incl. 1000-1999,
251 | [`002.csv`](https://github.com/cryptocopycats/kitties/blob/master/1-99_999/002.csv) incl. 2000-2999,
252 | and so on). The data records for kitties incl. id, gen(eration), matron+sire ids, birthdate, 48 (12x4) genes in kai (base32) notation, and more.
253 |
254 |
258 |
259 |
260 | Add your dataset here!
261 |
262 |
263 |
--------------------------------------------------------------------------------
/copycats/README.md:
--------------------------------------------------------------------------------
1 | # Crypto Copycats Collectibles - Buy! Sell! Hodl! Sire!
2 |
3 | copycats command line tool (and core library) - crypto cats / kitties collectibles unchained - buy! sell! hodl! sire! - play for free - runs off the blockchain w/ ledger lite - no ether / gas required; run your own peer-to-peer (P2P) network node over HTTP
4 |
5 |
6 |
7 | * home :: [github.com/cryptocopycats/copycats](https://github.com/cryptocopycats/copycats)
8 | * bugs :: [github.com/cryptocopycats/copycats/issues](https://github.com/cryptocopycats/copycats/issues)
9 | * gem :: [rubygems.org/gems/copycats](https://rubygems.org/gems/copycats)
10 | * rdoc :: [rubydoc.info/gems/copycats](http://rubydoc.info/gems/copycats)
11 |
12 |
13 |
14 |
61 |
62 |
63 |
64 |
65 | ## kitty Command Line Tool
66 |
67 | Use the `kitty` command line tool to (auto-)read kitty data records
68 | (in comma-separated values (CSV)) into an in-memory SQLite database
69 | and print reports. Example - [`kitties/1-99_999/000.csv`](https://github.com/cryptocopycats/kitties/blob/master/1-99_999/000.csv):
70 |
71 | ```
72 | id,gen,matron_id,sire_id,birthdate,genes,name
73 | 1,0,,,2017-11-23 06:19:59,ccac 7787 fa7f afaa 1646 7755 f9ee 4444 6766 7366 cccc eede,
74 | 2,0,,,2017-11-23 06:19:59,ca9c 7575 f442 af9g 6664 5557 7777 4444 6686 8667 cccc ffec,
75 | 3,0,,,2017-11-23 06:19:59,ac9a 6686 ff7f 99aa 6666 5575 779f 4444 6786 7748 cccc dcfc,
76 | 4,0,,,2017-11-23 06:19:59,ccac 5686 22ff f99g 1616 7555 ffed 4444 8668 4687 cccc dcff,
77 | 5,0,,,2017-11-23 06:19:59,ca9c 8777 747f g99g 4411 7775 f77d 4444 7788 6377 cccc ffef,
78 | ...
79 | ```
80 |
81 | Note: By default all datafiles (`**/*.csv`) in the `./data` and all subdirectories
82 | get (auto-)read. Use the `-i/--include` option to change the data directory.
83 |
84 |
85 |
86 | ### Kitty Genes Reader / Report
87 |
88 | Pass in the id (e.g. `1`, `43`, etc.) of the kitty to print a genes report.
89 | Example:
90 |
91 | ```
92 | $ kitty 1
93 | ```
94 |
95 | prints:
96 |
97 | ```
98 | # Kitty #1
99 |
100 | genes (kai): ccac 7787 fa7f afaa 1646 7755 f9ee 4444 6766 7366 cccc eede
101 |
102 | Fur (Genes 0-3)
103 |
104 | |Gene| Binary |Kai (Tier)| Trait | |
105 | |----|--------|----------|------------|----|
106 | | 0 | 01101 | e (I) | **sphynx** | d |
107 | | 1 | 01100 | d (I) | munchkin ) | r1 |
108 | | 2 | 01101 | e (I) | sphynx | r2 |
109 | | 3 | 01101 | e (I) | sphynx | r3 |
110 |
111 | d = dominant, r1 = 1st order recessive, r2 = 2nd order recessive, r3 = 3rd order recessive
112 |
113 | Pattern (Genes 4-7)
114 |
115 | |Gene| Binary |Kai (Tier)| Trait | |
116 | |----|--------|----------|------------|----|
117 | | 4 | 01011 | c (I) | **jaguar** | d |
118 | | 5 | 01011 | c (I) | jaguar | r1 |
119 | | 6 | 01011 | c (I) | jaguar | r2 |
120 | | 7 | 01011 | c (I) | jaguar | r3 |
121 |
122 | Eye Color (Genes 8-11)
123 |
124 | |Gene| Binary |Kai (Tier)| Trait | |
125 | |----|--------|----------|-------------|----|
126 | | 8 | 00101 | 6 (I) | **sizzurp** | d |
127 | | 9 | 00101 | 6 (I) | sizzurp | r1 |
128 | | 10 | 00010 | 3 (I) | topaz | r2 |
129 | | 11 | 00110 | 7 (I) | chestnut | r3 |
130 |
131 | Eye Shape (Genes 12-15)
132 |
133 | |Gene| Binary |Kai (Tier)| Trait | |
134 | |----|---------|----------|------------|----|
135 | | 12 | 00101 | 6 (I) | **simple** | d |
136 | | 13 | 00101 | 6 (I) | simple | r1 |
137 | | 14 | 00110 | 7 (I) | crazy | r2 |
138 | | 15 | 00101 | 6 (I) | simple | r3 |
139 |
140 | Base Color (Genes 16-19)
141 |
142 | |Gene| Binary |Kai (Tier)| Trait | |
143 | |----|--------|----------|----------------|----|
144 | | 16 | 00011 | 4 (I) | **orangesoda** | d |
145 | | 17 | 00011 | 4 (I) | orangesoda | r1 |
146 | | 18 | 00011 | 4 (I) | orangesoda | r2 |
147 | | 19 | 00011 | 4 (I) | orangesoda | r3 |
148 |
149 | Highlight Color (Genes 20-23)
150 |
151 | |Gene| Binary |Kai (Tier)| Trait | |
152 | |----|--------|----------|--------------|----|
153 | | 20 | 01101 | e (I) | **lemonade** | d |
154 | | 21 | 01101 | e (I) | lemonade | r1 |
155 | | 22 | 01000 | 9 (I) | swampgreen | r2 |
156 | | 23 | 01110 | f (I) | chocolate | r3 |
157 |
158 | Accent Color (Genes 24-27)
159 |
160 | |Gene| Binary |Kai (Tier)| Trait | |
161 | |----|--------|----------|-----------------|----|
162 | | 24 | 00100 | 5 (I) | **granitegrey** | d |
163 | | 25 | 00100 | 5 (I) | granitegrey | r1 |
164 | | 26 | 00110 | 7 (I) | kittencream | r2 |
165 | | 27 | 00110 | 7 (I) | kittencream | r3 |
166 |
167 | Wild (Genes 28-31)
168 |
169 | |Gene| Binary |Kai (Tier)| Trait | |
170 | |----|--------|----------|---------|----|
171 | | 28 | 00101 | 6 (I) | **?** | d |
172 | | 29 | 00011 | 4 (I) | ? | r1 |
173 | | 30 | 00101 | 6 (I) | ? | r2 |
174 | | 31 | 00000 | 1 (I) | ? | r3 |
175 |
176 | Mouth (Genes 32-35)
177 |
178 | |Gene| Binary |Kai (Tier)| Trait | |
179 | |----|--------|----------|--------------|---|
180 | | 32 | 01001 | a (I) | **pouty** | d |
181 | | 33 | 01001 | a (I) | pouty | r1 |
182 | | 34 | 01110 | f (I) | happygokitty | r2 |
183 | | 35 | 01001 | a (I) | pouty | r3 |
184 | ```
185 |
186 |
187 | ### Kitty Mix Genes (Matron + Sire) Report
188 |
189 | Pass in two ids for the matron and sire kitties to print a mix genes report.
190 | Example:
191 |
192 |
193 | ```
194 | $ kitty 2 43
195 | ```
196 |
197 | prints:
198 |
199 | ```
200 | # Kitty #2 + #43
201 |
202 | genes (kai) 1: ca9c 7575 f442 af9g 6664 5557 7777 4444 6686 8667 cccc ffec
203 | genes (kai) 2: ca9a 7588 72a7 fa9f 4111 5555 dedf 4444 5888 4666 cccc fded
204 |
205 | Fur (Genes 0-3)
206 |
207 | |Gene|Kai|Trait (Matron) |Kai|Trait (Sire) | |
208 | |----|---|---------------|---|--------------|----|
209 | | 0 | c | **himalayan** | d | **munchkin** | d |
210 | | 1 | e | sphynx | e | sphynx | r1 |
211 | | 2 | f | ragamuffin | d | munchkin | r2 |
212 | | 3 | f | ragamuffin | f | ragamuffin | r3 |
213 |
214 | d = dominant, r1 = 1st order recessive, r2 = 2nd order recessive, r3 = 3rd order recessive
215 |
216 | Pattern (Genes 4-7)
217 |
218 | |Gene|Kai|Trait (Matron)|Kai|Trait (Sire)| |
219 | |----|---|--------------|---|------------|----|
220 | | 4 | c | **jaguar** | c | **jaguar** | d |
221 | | 5 | c | jaguar | c | jaguar | r1 |
222 | | 6 | c | jaguar | c | jaguar | r2 |
223 | | 7 | c | jaguar | c | jaguar | r3 |
224 |
225 | Eye Color (Genes 8-11)
226 |
227 | |Gene|Kai|Trait (Matron)|Kai|Trait (Sire) | |
228 | |----|---|--------------|---|-------------|----|
229 | | 8 | 7 | **chestnut** | 6 | **sizzurp** | d |
230 | | 9 | 6 | sizzurp | 6 | sizzurp | r1 |
231 | | 10 | 6 | sizzurp | 6 | sizzurp | r2 |
232 | | 11 | 8 | strawberry | 4 | mintgreen | r3 |
233 |
234 | Eye Shape (Genes 12-15)
235 |
236 | |Gene|Kai|Trait (Matron)|Kai|Trait (Sire) | |
237 | |----|---|--------------|---|-----------------|----|
238 | | 12 | 6 | **simple** | 8 | **thicccbrowz** | d |
239 | | 13 | 8 | thicccbrowz | 8 | thicccbrowz | r1 |
240 | | 14 | 6 | simple | 8 | thicccbrowz | r2 |
241 | | 15 | 6 | simple | 5 | otaku | r3 |
242 |
243 | Base Color (Genes 16-19)
244 |
245 | |Gene|Kai|Trait (Matron) |Kai|Trait (Sire) | |
246 | |----|---|----------------|---|----------------|----|
247 | | 16 | 4 | **orangesoda** | 4 | **orangesoda** | d |
248 | | 17 | 4 | orangesoda | 4 | orangesoda | r1 |
249 | | 18 | 4 | orangesoda | 4 | orangesoda | r2 |
250 | | 19 | 4 | orangesoda | 4 | orangesoda | r3 |
251 |
252 | Highlight Color (Genes 20-23)
253 |
254 | |Gene|Kai|Trait (Matron) |Kai|Trait (Sire) | |
255 | |----|---|-----------------|---|---------------|----|
256 | | 20 | 7 | **royalpurple** | f | **chocolate** | d |
257 | | 21 | 7 | royalpurple | d | coffee | r1 |
258 | | 22 | 7 | royalpurple | e | lemonade | r2 |
259 | | 23 | 7 | royalpurple | d | coffee | r3 |
260 |
261 | Accent Color (Genes 24-27)
262 |
263 | |Gene|Kai|Trait (Matron) |Kai|Trait (Sire) | |
264 | |----|---|-----------------|---|-----------------|----|
265 | | 24 | 7 | **kittencream** | 5 | **granitegrey** | d |
266 | | 25 | 5 | granitegrey | 5 | granitegrey | r1 |
267 | | 26 | 5 | granitegrey | 5 | granitegrey | r2 |
268 | | 27 | 5 | granitegrey | 5 | granitegrey | r3 |
269 |
270 | Wild (Genes 28-31)
271 |
272 | |Gene|Kai|Trait (Matron)|Kai|Trait (Sire)| |
273 | |----|---|--------------|---|------------|----|
274 | | 28 | 4 | **?** | 1 | **?** | d |
275 | | 29 | 6 | ? | 1 | ? | r1 |
276 | | 30 | 6 | ? | 1 | ? | r2 |
277 | | 31 | 6 | ? | 4 | ? | r3 |
278 |
279 | Mouth (Genes 32-35)
280 |
281 | |Gene|Kai|Trait (Matron) |Kai|Trait (Sire) | |
282 | |----|---|---------------|---|------------------|----|
283 | | 32 | g | **soserious** | f | **happygokitty** | d |
284 | | 33 | 9 | beard | 9 | beard | r1 |
285 | | 34 | f | happygokitty | a | pouty | r2 |
286 | | 35 | a | pouty | f | happygokitty | r3 |
287 | ```
288 |
289 |
290 |
291 | ## Installation - I Can Has Copycats?
292 |
293 | Use:
294 |
295 | ```
296 | $ gem install copycats
297 | ```
298 |
299 |
300 | ## License
301 |
302 | 
303 |
304 | The `copycats` scripts are dedicated to the public domain.
305 | Use it as you please with no restrictions whatsoever.
306 |
307 |
308 | ## Questions? Comments?
309 |
310 | Post them on the [cryptokitties reddit](https://www.reddit.com/r/cryptokitties). Thanks.
311 |
--------------------------------------------------------------------------------