'Solving a Chain Link Python Puzzle:
I am not sure where to start with the following python puzzle.
"You are holding a link of a chain. Implement a method longerSide
to find which side of the chain has more links, relative to the link you are holding. If the left side has more links return Side.left
. If the right side has more links return Side.right
, and if both sides have an equal number of links, or if the chain is a closed loop, return Side.none
.
For example, the code below should output True
:
left = ChainLink()
middle = ChainLink()
right = ChainLink()
left.append(middle)
middle.append(right)
print(left.longerSide() == Side.right)
I don't really have any idea on how to approach this. I would like to show something that I've done so far but I haven't created anything of any substance. So far I have only defined the below enumerations
from enum import Enum
class Side(Enum):
NONE = 0
LEFT = 1
RIGHT = 2
If anyone has any suggestions or resources that would help me I would very much appreciate it.
Thanks
Solution 1:[1]
So here is a solution for this puzzle with comments in code.
from enum import Enum
class Side(Enum):
none = 0
left = 1
right = 2
class ChainLink:
def __init__(self):
self._left = None
self._right = None
def append(self, link):
if self._right is not None: raise Exception('Link already connected!')
self._right = link
link._left = self
def longer_side(self):
# Initialize right side and left side counters
right = 0
left = 0
# Create an empty list that will be used to check if the link
# has been used already which indicates it's a loop
seen_links = []
# Set the link to be the first one on the right side
link = self._right
# Loop through all the links while the next one on the right is of type "ChainLink"
while isinstance(link , ChainLink):
# If the link on the right appears in the seen_links array, this means
# it's a loop.
if link in seen_links:
print("Loop")
return Side.none
# Add +1 to the right side counter for each link
right += 1
# Add the link to the seen_links array
seen_links.append(link)
# Set the link to the next one on the right.
link = link._right
# At this moment we know the count of links on the right side, and we know
# if the chain is a loop or not. Now we just need to count the left side.
# Set link to the first link on the left.
link = self._left
# Loop through all the links while the next one on the left is of type "ChainLink"
while isinstance(link , ChainLink):
# Add +1 to left side counter
left += 1
# set link to next on the left.
link = link._left
# Return needed value depending on which side is longer
if left > right:
return Side.left
elif left < right:
return Side.right
# Return Side.none if both sides are equal.
return Side.none
if __name__ == "__main__":
left = ChainLink()
middle = ChainLink()`
right = ChainLink()
left.append(middle)
middle.append(right)
print(left.longer_side() == Side.right)
Solution 2:[2]
My take of the answer, using some help with the answer of Luka Kunej :)
from enum import Enum
class Side(Enum):
none = 0
left = 1
right = 2
class ChainLink:
def __init__(self):
self._left = None
self._right = None
def append(self, link):
if self._right is not None: raise Exception('Link already connected!')
self._right = link
link._left = self
def longer_side(self):
#check if you even have a chain!?
if (self._left == None) and (self._right == None):
return Side.none
#check your on the left end
if (self._left == None):
return Side.right
#check your on the right end
if (self._right == None):
return Side.left
links_to_the_right = 0
links_to_the_left = 0
links_checked = []
#checking right hand side of chain from our current link.
current_link = self._right
while isinstance(current_link, ChainLink):
#lets first check if the chain is in a loop
if current_link in links_checked:
return Side.none
#record that we've checked the current link
links_checked.append(current_link)
#move onto the next possible link in the chain
current_link = current_link._right
links_to_the_right += 1
#checking left hand side of chain from our current link.
current_link = self._left
while isinstance(current_link, ChainLink):
#no need to check if the chain is a loop again since the previous isinstance loop takes care of that
#move onto the next possible link in the chain
current_link = current_link._left
links_to_the_left += 1
#checking which side of the chain is longer
if links_to_the_left > links_to_the_right:
return Side.left
elif links_to_the_left < links_to_the_right:
return Side.right
# the sides are equal if this else is reached
else:
return Side.none
#check if the chain is a loop. The chains are appended always to the right, and the left link is the whole chain.
# if (self._right._left == self._left._right):
# return Side.none
return self.longer_side()
left = ChainLink()
middle = ChainLink()
right = ChainLink()
left.append(middle)
middle.append(right)
print(left.longer_side() == Side.right)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Luka Kunej |
Solution 2 | David Rhode |