Skip to content

Instantly share code, notes, and snippets.

@RickyCook
Created August 25, 2019 04:33
Show Gist options
  • Save RickyCook/dcdaec6683ae54a960c7731d9a2ccaf5 to your computer and use it in GitHub Desktop.
Save RickyCook/dcdaec6683ae54a960c7731d9a2ccaf5 to your computer and use it in GitHub Desktop.
Decode a messy binary sequence whose value is ASCII/UTF-8 and that's all you know
#!/usr/bin/env python3
import sys
from copy import deepcopy
from pprint import pprint
class Decoder(object):
def __init__(
self,
seq,
orange_val,
silver_val,
char_width=8,
reverse=False,
start_at=0,
):
self.raw_seq = seq
self.orange_val = orange_val
self.silver_val = silver_val
self.char_width = char_width
self.reverse = reverse
self.start_at = start_at
@property
def seq_1(self):
""" Slice the start of seq as necessary
Examples:
>>> Decoder('obsob', 1, 0).seq_1
'obsob'
>>> Decoder('obsob', 1, 0, start_at=2).seq_1
'sob'
"""
return self.raw_seq[self.start_at:]
@property
def seq(self):
""" Get the sequence that we are processing (maybe without silver)
Examples:
>>> Decoder('obsob', 1, 0).seq
'obsob'
>>> Decoder('obsob', 1, 1).seq
'obsob'
>>> Decoder('obsob', 1, None).seq
'obob'
"""
if self.silver_val is None:
return ''.join(
ring for ring in self.seq_1 if ring != 's'
)
return self.seq_1
@property
def black_val(self):
""" Get the value of the black ring (inverse of orange)
Examples:
>>> Decoder('', 1, 0).black_val
0
>>> Decoder('', 0, 0).black_val
1
"""
if self.orange_val == 1:
return 0
else:
return 1
def bit_value(self, ring):
""" Get the bit value of a ring
>>> d = Decoder('', 0, 0)
>>> d.bit_value('o')
0
>>> d.bit_value('b')
1
>>> d.bit_value('s')
0
>>> d = Decoder('', 1, 0)
>>> d.bit_value('o')
1
>>> d.bit_value('b')
0
>>> d.bit_value('s')
0
>>> Decoder('', 0, 1).bit_value('s')
1
>>> Decoder('', 0, None).bit_value('s')
"""
if ring == 'o':
return self.orange_val
if ring == 'b':
return self.black_val
if ring == 's':
return self.silver_val
raise ValueError('Invalid ring bit: %r', ring)
@property
def bit_list(self):
""" Convert the sequence into a bit list
Examples:
>>> Decoder('obsobs', 0, 0).bit_list
[0, 1, 0, 0, 1, 0]
>>> Decoder('obsobs', 1, 0).bit_list
[1, 0, 0, 1, 0, 0]
>>> Decoder('obsobs', 0, 1).bit_list
[0, 1, 1, 0, 1, 1]
>>> Decoder('obsobs', 0, None).bit_list
[0, 1, 0, 1]
"""
return [self.bit_value(ring) for ring in self.seq]
@property
def bit_str(self):
""" Convert the bit list into a bit string
Examples:
>>> Decoder('obsobs', 0, 0).bit_str
'010010'
>>> Decoder('obsobs', 1, 0).bit_str
'100100'
>>> Decoder('obsobs', 0, 1).bit_str
'011011'
>>> Decoder('obsobs', 0, None).bit_str
'0101'
"""
return ''.join(
str(bit) for bit in self.bit_list
)
@property
def bit_str_ords_1(self):
""" Chunk the bit string into chars
Examples:
>>> t_val = 'ooobobb'
>>> e_val = 'oobbobo'
>>> Decoder(t_val + e_val, 1, None, char_width=7).bit_str_ords_1
['1110100', '1100101']
>>> t_val = 'booobobb'
>>> e_val = 'boobbobo'
>>> Decoder(t_val + e_val, 1, None, char_width=8).bit_str_ords_1
['01110100', '01100101']
"""
bit_str = self.bit_str
return [bit_str[i:i+self.char_width] for i in range(0, len(bit_str), self.char_width)]
@property
def bit_str_ords(self):
""" Reverse the ords as necessary
Examples:
>>> t_val = 'ooobobb'
>>> e_val = 'oobbobo'
>>> Decoder(t_val + e_val, 1, None, char_width=7, reverse=True).bit_str_ords
['0010111', '1010011']
>>> t_val = 'booobobb'
>>> e_val = 'boobbobo'
>>> Decoder(t_val + e_val, 1, None, char_width=8, reverse=True).bit_str_ords
['00101110', '10100110']
"""
if self.reverse:
return [i[::-1] for i in self.bit_str_ords_1]
return self.bit_str_ords_1
@property
def bit_str_chrs(self):
""" Convert the bit string ords to chars
Examples:
>>> t_val = 'ooobobb'
>>> e_val = 'oobbobo'
>>> Decoder(t_val + e_val, 1, None, char_width=7).bit_str_chrs
['t', 'e']
"""
return [chr(int(i, base=2)) for i in self.bit_str_ords]
rings = 'obobobbobbobbbobbobboobobboobobbbbbobbobboobobboobobbbbbobbbbooobbooooobobbobobobbobobbboboobbbbooobobobb'
# import doctest
# doctest.testmod(verbose=True)
# sys.exit(0)
# parts = 'osboobboobboobboobbobbobboob'
# parts_a = 'obobbooobboobb'
# parts_b = 'sobobbooobboo'
# parts_a = 'obobobobobboboobbobb'
# parts_b = 'sobobobobobboboobbob'
opts = dict(
orange_val = [1, 0],
silver_val = [1, 0, None],
char_width = [7, 8],
reverse = [True, False],
start_at = [0, 2],
)
# PRODUCT OF OPTS
# not part of the workout; just test all combinations of opts
all_opts = []
for k, vals in opts.items():
if len(all_opts) == 0:
for val in vals:
all_opts.append({k: val})
else:
all_opts_orig = all_opts
all_opts = []
for val in vals:
for o in all_opts_orig:
oo = deepcopy(o)
oo[k] = val
all_opts.append(oo)
col_fs = '{:<10}'
headers = list(opts.keys()) + ['string']
print(' | '.join(col_fs.format(h) for h in headers))
col_fs = {
h: '{!r:<10}' for h in headers
}
col_fs['string'] = '{:<10}'
for opts in all_opts:
d = Decoder(rings, **opts)
try:
opts['string'] = '%r' % d.bit_str_chrs
except Exception:
opts['string'] = 'ERROR'
print(' | '.join(col_fs[h].format(opts[h]) for h in headers))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment