Gerald Bauer
2018-12-07 16:01:40 UTC
Hello,
It's Friday. Ruby Quiz time! Join us. Let's keep going with a new
Ruby Quiz [1] every Friday. Here we go:
Challenge #8 - Base32 Alphabet - Convert the Super "Sekretoooo"
240-Bit CryptoKitties Genome to Kai Notation - Annipurrsary!
Annipurrsary! Let's celebrate one year of CryptoKitties -
yes, more than one million cute little cartoon cats on the blockchain.
Let's convert the super "sekretoooo" kitty genome - that is, a 240-bit
integer number
where every 5-bit block is a gene - into the base32 (2^5=32) kai notation.
Q: What's base32 kai notation?
Kai notation (named to honor [Kai
Turner](https://medium.com/@kaigani/the-cryptokitties-genome-project-on-dominance-inheritance-and-mutation-b73059dcd0a4)
who deciphered the kitties genome)
is a base58 variant / subset for decoding the 240-bit integer into 5-bit blocks.
Each 5-bit block is a gene with 32 possible traits.
The 240-bit genome breaks down into 12 groups of 4 (x 5-bit) genes
(that is, 12 x 4 x 5-bit = 240 bits)
Example:
|Kai |Binary |Num|Kai |Binary |Num|Kai |Binary |Num|Kai
|Binary |Num|
|-------|-------|---|-------|-------|---|-------|-------|---|-------|-------|---|
| **1** | 00000 | 00 | **9** | 01000 | 08 | **h** | 10000 |16 | **q**
| 11000 |24 |
| **2** | 00001 | 01 | **a** | 01001 | 09 | **i** | 10001 |17 | **r**
| 11001 |25 |
| **3** | 00010 | 02 | **b** | 01010 | 10 | **j** | 10010 |18 | **s**
| 11010 |26 |
| **4** | 00011 | 03 | **c** | 01011 | 11 | **k** | 10011 |19 | **t**
| 11011 |27 |
| **5** | 00100 | 04 | **d** | 01100 | 12 | **m** | 10100 |20 | **u**
| 11100 |28 |
| **6** | 00101 | 05 | **e** | 01101 | 13 | **n** | 10101 |21 | **v**
| 11101 |29 |
| **7** | 00110 | 06 | **f** | 01110 | 14 | **o** | 10110 |22 | **w**
| 11110 |30 |
| **8** | 00111 | 07 | **g** | 01111 | 15 | **p** | 10111 |23 | **x**
| 11111 |31 |
Note: The digit-0 and the letter-l are NOT used in kai.
```
# A 240-bit super "sekretoooo" integer genome
# hexadecimal (base 16)
genome = 0x4a52931ce4085c14bdce014a0318846a0c808c60294a6314a34a1295b9ce
# decimal (base 10)
genome = 512955438081049600613224346938352058409509756310147795204209859701881294
# binary (base 2)
genome = 0b010010100101001010010011000111001110010000001000010111000001010010111101110011100000000101001010000000110001100010000100\
011010100000110010000000100011000110000000101001010010100110001100010100101000110100101000010010100101011011100111001110
```
Let's convert from decimal (base 10) to hexadecimal (base 16 - 2^4)
and binary (base 2 that is, 0 and 1):
```
p genome # printed as decimal (base 10) by default
# => 512955438081049600613224346938352058409509756310147795204209859701881294
p genome.to_s(16)
# => "4a52931ce4085c14bdce014a0318846a0c808c60294a6314a34a1295b9ce"
p genome.to_s(2)
# => "10010100101001010010011000111001110010000001000010111000001010010111101110011100000000101001010000000110001100010000100\
# 011010100000110010000000100011000110000000101001010010100110001100010100101000110100101000010010100101011011100111001110"
bin = '%0240b' % genome # note: adds leading zeros - to_s(2) does not
p bin.size
# => 240
p bin
# => "010010100101001010010011000111001110010000001000010111000001010010111101110011100000000101001010000000110001100010000100\
# 011010100000110010000000100011000110000000101001010010100110001100010100101000110100101000010010100101011011100111001110"
hex = '%060x' % genome # note: adds leading zeros - to_s(16) does not
p hex.size
# => 60
p hex
# => 60
# => "4a52931ce4085c14bdce014a0318846a0c808c60294a6314a34a1295b9ce"
```
And finally:
```
kai = kai_encode( genome ) ## number to base32 kai notation
p kai
# => "aaaa788522f2agff16617755e979244166677664a9aacfff"
```
The challenge: Code a `kai_encode` method that passes the RubyQuizTest :-) [2].
```
def kai_encode( num )
# ...
end
```
For the starter level 1 turn
super "sekretoooo" kitty genome 240-bit integer numbers
into base 32 (2^5) kai notation.
For the bonus level 2 pretty print and format
the base 32 (2^5) kai notation in groups of four e.g.
turn:
"aaaa788522f2agff16617755e979244166677664a9aacfff"
into
"aaaa 7885 22f2 agff 1661 7755 e979 2441 6667 7664 a9aa cfff"
```
def kai_fmt( kai )
# ...
end
```
Start from scratch or, yes, use any library / gem you can find.
To qualify for solving the code challenge / puzzle you must pass the test:
```
require 'minitest/autorun'
class RubyQuizTest < MiniTest::Test
################################
# test data
def genomes
[
[0x00004a52931ce4085c14bdce014a0318846a0c808c60294a6314a34a1295b9ce,
"aaaa 7885 22f2 agff 1661 7755 e979 2441 6667 7664 a9aa cfff"]
]
end
#############
# tests
def test_kai_encode
genomes.each do |pair|
num = pair[0]
exp_value = pair[1].gsub(' ','') # note: remove spaces
assert_equal exp_value, kai_encode( num )
end
end # method test_kai_encode
def test_kai_fmt
genomes.each do |pair|
kai = pair[1].gsub(' ','') # remove spaces
exp_value = pair[1]
assert_equal exp_value, kai_fmt( kai )
end
end # method test_kai_fmt
end # class RubyQuizTest
```
Post your code snippets on the "official" Ruby Quiz Channel,
that is, the ruby-talk mailing list right here.
Happy data wrangling and genome genetics bits & bytes slicing with Ruby.
[1] https://github.com/planetruby/quiz/tree/master/008
[2] https://github.com/planetruby/quiz/blob/master/008/test.rb
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>
It's Friday. Ruby Quiz time! Join us. Let's keep going with a new
Ruby Quiz [1] every Friday. Here we go:
Challenge #8 - Base32 Alphabet - Convert the Super "Sekretoooo"
240-Bit CryptoKitties Genome to Kai Notation - Annipurrsary!
Annipurrsary! Let's celebrate one year of CryptoKitties -
yes, more than one million cute little cartoon cats on the blockchain.
Let's convert the super "sekretoooo" kitty genome - that is, a 240-bit
integer number
where every 5-bit block is a gene - into the base32 (2^5=32) kai notation.
Q: What's base32 kai notation?
Kai notation (named to honor [Kai
Turner](https://medium.com/@kaigani/the-cryptokitties-genome-project-on-dominance-inheritance-and-mutation-b73059dcd0a4)
who deciphered the kitties genome)
is a base58 variant / subset for decoding the 240-bit integer into 5-bit blocks.
Each 5-bit block is a gene with 32 possible traits.
The 240-bit genome breaks down into 12 groups of 4 (x 5-bit) genes
(that is, 12 x 4 x 5-bit = 240 bits)
Example:
|Kai |Binary |Num|Kai |Binary |Num|Kai |Binary |Num|Kai
|Binary |Num|
|-------|-------|---|-------|-------|---|-------|-------|---|-------|-------|---|
| **1** | 00000 | 00 | **9** | 01000 | 08 | **h** | 10000 |16 | **q**
| 11000 |24 |
| **2** | 00001 | 01 | **a** | 01001 | 09 | **i** | 10001 |17 | **r**
| 11001 |25 |
| **3** | 00010 | 02 | **b** | 01010 | 10 | **j** | 10010 |18 | **s**
| 11010 |26 |
| **4** | 00011 | 03 | **c** | 01011 | 11 | **k** | 10011 |19 | **t**
| 11011 |27 |
| **5** | 00100 | 04 | **d** | 01100 | 12 | **m** | 10100 |20 | **u**
| 11100 |28 |
| **6** | 00101 | 05 | **e** | 01101 | 13 | **n** | 10101 |21 | **v**
| 11101 |29 |
| **7** | 00110 | 06 | **f** | 01110 | 14 | **o** | 10110 |22 | **w**
| 11110 |30 |
| **8** | 00111 | 07 | **g** | 01111 | 15 | **p** | 10111 |23 | **x**
| 11111 |31 |
Note: The digit-0 and the letter-l are NOT used in kai.
Base58 is a group of binary-to-text encoding schemes used to represent large integers as alphanumeric text.
It is similar to Base64 but has been modified to avoid both non-alphanumeric characters
and letters which might look ambiguous when printed [e.g. 1 and l, 0 and o].
It is therefore designed for human users who manually enter the data,
copying from some visual source, but also allows easy copy
and paste because a double-click will usually select the whole string.
Let's get coding, for an example:It is similar to Base64 but has been modified to avoid both non-alphanumeric characters
and letters which might look ambiguous when printed [e.g. 1 and l, 0 and o].
It is therefore designed for human users who manually enter the data,
copying from some visual source, but also allows easy copy
and paste because a double-click will usually select the whole string.
```
# A 240-bit super "sekretoooo" integer genome
# hexadecimal (base 16)
genome = 0x4a52931ce4085c14bdce014a0318846a0c808c60294a6314a34a1295b9ce
# decimal (base 10)
genome = 512955438081049600613224346938352058409509756310147795204209859701881294
# binary (base 2)
genome = 0b010010100101001010010011000111001110010000001000010111000001010010111101110011100000000101001010000000110001100010000100\
011010100000110010000000100011000110000000101001010010100110001100010100101000110100101000010010100101011011100111001110
```
Let's convert from decimal (base 10) to hexadecimal (base 16 - 2^4)
and binary (base 2 that is, 0 and 1):
```
p genome # printed as decimal (base 10) by default
# => 512955438081049600613224346938352058409509756310147795204209859701881294
p genome.to_s(16)
# => "4a52931ce4085c14bdce014a0318846a0c808c60294a6314a34a1295b9ce"
p genome.to_s(2)
# => "10010100101001010010011000111001110010000001000010111000001010010111101110011100000000101001010000000110001100010000100\
# 011010100000110010000000100011000110000000101001010010100110001100010100101000110100101000010010100101011011100111001110"
bin = '%0240b' % genome # note: adds leading zeros - to_s(2) does not
p bin.size
# => 240
p bin
# => "010010100101001010010011000111001110010000001000010111000001010010111101110011100000000101001010000000110001100010000100\
# 011010100000110010000000100011000110000000101001010010100110001100010100101000110100101000010010100101011011100111001110"
hex = '%060x' % genome # note: adds leading zeros - to_s(16) does not
p hex.size
# => 60
p hex
# => 60
# => "4a52931ce4085c14bdce014a0318846a0c808c60294a6314a34a1295b9ce"
```
And finally:
```
kai = kai_encode( genome ) ## number to base32 kai notation
p kai
# => "aaaa788522f2agff16617755e979244166677664a9aacfff"
```
The challenge: Code a `kai_encode` method that passes the RubyQuizTest :-) [2].
```
def kai_encode( num )
# ...
end
```
For the starter level 1 turn
super "sekretoooo" kitty genome 240-bit integer numbers
into base 32 (2^5) kai notation.
For the bonus level 2 pretty print and format
the base 32 (2^5) kai notation in groups of four e.g.
turn:
"aaaa788522f2agff16617755e979244166677664a9aacfff"
into
"aaaa 7885 22f2 agff 1661 7755 e979 2441 6667 7664 a9aa cfff"
```
def kai_fmt( kai )
# ...
end
```
Start from scratch or, yes, use any library / gem you can find.
To qualify for solving the code challenge / puzzle you must pass the test:
```
require 'minitest/autorun'
class RubyQuizTest < MiniTest::Test
################################
# test data
def genomes
[
[0x00004a52931ce4085c14bdce014a0318846a0c808c60294a6314a34a1295b9ce,
"aaaa 7885 22f2 agff 1661 7755 e979 2441 6667 7664 a9aa cfff"]
]
end
#############
# tests
def test_kai_encode
genomes.each do |pair|
num = pair[0]
exp_value = pair[1].gsub(' ','') # note: remove spaces
assert_equal exp_value, kai_encode( num )
end
end # method test_kai_encode
def test_kai_fmt
genomes.each do |pair|
kai = pair[1].gsub(' ','') # remove spaces
exp_value = pair[1]
assert_equal exp_value, kai_fmt( kai )
end
end # method test_kai_fmt
end # class RubyQuizTest
```
Post your code snippets on the "official" Ruby Quiz Channel,
that is, the ruby-talk mailing list right here.
Happy data wrangling and genome genetics bits & bytes slicing with Ruby.
[1] https://github.com/planetruby/quiz/tree/master/008
[2] https://github.com/planetruby/quiz/blob/master/008/test.rb
Unsubscribe: <mailto:ruby-talk-***@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-talk>