'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 |
