
# grays.py
'''
  binary reflected Gray code

>>> grayDecode(0b00100)
7
>>> print(f"{grayDecode(0b00100):05b}")
00111
>>> grayEncode(7)
4
>>> print(f"{grayEncode(7):05b}")
00100
>>> grays(3)
[0, 1, 3, 2, 6, 7, 5, 4]
>>> print([bin(v) for v in grays(3)])
['0b0', '0b1', '0b11', '0b10', '0b110', '0b111', '0b101', '0b100']
>>> print([f"{v:05b}" for v in grays(3)])
['00000', '00001', '00011', '00010', '00110', '00111', '00101', '00100']
>>>
int('11111111', 2) -> 255
bin(255) -> '0b11111111'
list('1011') -> [ '1', '0', '1', '1']
'''

import math


def int2Binary(num, nbits):
  return bin(num)[2:].zfill(nbits)


def int2bits(num):
  if num <= 0:
    return [0]*8
  nbits = int(max(8, math.log(num, 2)+1))
  return [1 if num & (1 << (nbits-1-n)) else 0 for n in range(nbits)]

def bits2Gray(bits):
  n = len(bits)
  for i in range(n-1, 0, -1): 
    if bits[i-1] == 1:
      bits[i] = 1 - bits[i]
  return bits

def bits2BCD(bits):
  n = len(bits)
  for i in range(n-1, 0, -1): 
    if sum( bits[:i])%2 == 1:   # odd
      bits[i] = 1 - bits[i]
  return bits

def bits2int(bits):
  return int(''.join(map(str, bits)), 2)


def grayCodes(n):
  # return a list of the first 2**n gray codes;
  # n is no. of bits
  if n <= 0:
    return ['0']
  elif n == 1:
    return ['0', '1']

  half1 = grayCodes(n-1)
  revhalf2 = reversed(half1.copy())
 
  return ['0'+bs for bs in half1] + \
         ['1'+bs for bs in revhalf2]


def grayEncode(n):
  return n ^ (n >> 1) # xor 

def grayDecode(n):
  mask = n >> 1
  while mask:
    n ^= mask  # overwrite n
    mask >>= 1
  return n

def grays(n):
  # all grays from 0 to 2^n-1
  return [i ^ (i >> 1) for i in range(1 << n)]
   

def grayTransY(n):
  # generate gray code transitions from 0 to 2^n -1
  stk = [i for i in range(n, 0, -1)]
  while stk != []:
    t = stk.pop()
    for i in range(t-1, 0, -1):
      stk.append(i)
    yield t


if __name__ == '__main__':
  print("dec    bin => gray  dec")
  for i in range(32):
    gray = grayEncode(i)
    dec = grayDecode(gray)
    print(f" {i:>2d}, {i:>05b} => {gray:>05b}, {dec:>2d}")
