'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