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](Medium)
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.[-- Base58 @ Wikipedia](https://en.wikipedia.org/wiki/Base58\)
Let's get coding, for an example:
# 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] quiz/008 at master · planetruby/quiz · GitHub
[2] quiz/008/test.rb at master · planetruby/quiz · GitHub