Skip to content

Instantly share code, notes, and snippets.

@HarvsG
Last active April 21, 2020 17:50
Show Gist options
  • Save HarvsG/cb1020671ec9258baa94dd0f85d6d82f to your computer and use it in GitHub Desktop.
Save HarvsG/cb1020671ec9258baa94dd0f85d6d82f to your computer and use it in GitHub Desktop.
My solution to Matt Parker's 4 CARD PUZZLE (MPMP PUZZLE 4) https://www.youtube.com/watch?v=oCMVUROty0g
import itertools
import sys
if sys.version_info[0] < 3:
raise Exception("Python 3 or a more recent version is required.")
class Deck:
# a class that takes an array of True/False of any length. True equals face down
def __init__(self,cards):
# make sure a list is passed, if not, convert it to one
if not isinstance(cards, list):
try:
cards = list(cards)
print('non-list object given, converted to list:')
print(cards)
except TypeError:
print('argument is not a list and cannot be converted to one:')
print(cards)
# check it is a list of bools
if not all(isinstance(x, bool) for x in cards):
raise Exception("The list provided contains non boolean values")
self.cards = cards
self.moves = []
self.start = self._card_view(cards)
def check(self):
# A functions that checks to see if all cards are face down, if so returns the number of moves to get there
if all(self.cards) == True:
return len(self.moves)
else:
return False
def flip(self, index):
# Flip a card but if we have all cards face down then we have won, so don't make any further moves
if self.check() is False:
self.cards[index] = not self.cards[index]
self.moves.append(index)
def _card_view(self, cards):
# Prints the cards in a pretty emoji
array = []
for x in cards:
if x == True:
# playing card face down emoji
array.append("\U0001F3B4")
else:
# playing card face up emoji
array.append("\U0001F0CF")
return array
def __repr__(self):
return str(self._card_view(self.cards))
def __str__(self):
return ''.join(self._card_view(self.cards))
def __len__(self):
return len(self.cards)
def make_decks(l):
# make all possible iterations of a deck of length l. return this as a list of decks
permutations = itertools.product([True,False],repeat=l)
permutations = list(permutations) # creates a list of tuples
for i,val in enumerate(permutations):
# for every permutation, create a Deck from the list(tuple)
permutations[i] = Deck(list(val))
return permutations
def construct_gray_code(b):
# A reccursive function to construct gray code of bit length 'b'. Returns a list of strings
if b == 1:
# the simplest 1 bit gray code
return ['0','1']
else:
li = construct_gray_code(b-1) # recursively get the gray code of length b - 1
il = li[::-1] # creates a mirror of the list
for i, val in enumerate(li):
# prepend 0 to all the first list
li[i] = '0'+val
for i, val in enumerate(il):
# prepend 1 to the mirror image
il[i] = '1'+val
# concatenate and return to two lists
return li + il
def construct_moves(bits):
# from the generated Gray code this will generate the moves that need to be made to 'count' up through the Gray code
gc = construct_gray_code(bits)
for i, val in enumerate(gc):
#convert the Gray code strings to ints
gc[i] = int(val,base=2)
moves = []
for i in range(len(gc)-1):
# since by defintion Gray code only flips one bit each time, we can find the flipped bit by subtracting between each count
diff = gc[i+1] - gc[i]
# we only care which bit is flipped, not the direction
diff = abs(diff)
# converts the difference back into a binary string that is padded
binary = format(diff, '#0'+str(bits+2)+'b')[2:]
# getting the index of the flipped bit will give us which card needs to be flipped
move = list(binary).index('1')
moves.append(move)
return moves
# construct the deck of the chosen length, and construct the moves of the corresponding length
num_of_cards = 4
decks = make_decks(num_of_cards)
moves_to_make = construct_moves(num_of_cards)
dic = {}
for deck in decks:
# iterate through the decks
print(deck)
for move in moves_to_make:
# Make each move on the deck
deck.flip(move)
print(deck)
# show the moves made for said deck
print(deck.moves)
# fill out a dictionary of the start position of each deck and the number of moves required
dic[''.join(deck.start)] = len(deck.moves)
# print the final dictionary
print(dic)
print('The final ans is: ')
print(max(dic.values()))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment