Solutions Protocol exercises

Ex 1: Deck of Cards

 1# deck_solution.py
 2
 3"""
 4implement the:
 5
 6 __len__         method
 7 __add__         method
 8 __repr__        method
 9 __str__         method
10 __setitem__     method
11 __delitem__     method
12"""
13
14class Deck:
15    def __init__(self):
16        self.cards = ['A', 'K', 4, 7]
17
18
19    def __getitem__(self, key):
20        return self.cards[key]
21
22    def __setitem__(self, key, val):
23        self.cards[key] = val
24
25
26    def __delitem__(self, key):
27        del(self.cards[key])
28
29    def __len__(self):
30        return len(self.cards)
31
32
33    def __add__(self, other):
34        return self.cards + other.cards
35
36    def __repr__(self):
37        return str(self.cards)
38
39    def __str__(self):
40        return str(self.cards)

Ex 2: Jelly Beans

 1
 2""" 
 3        Imagine a game where different sizes of jelly beans  are floating around. 
 4        When they bump into each other they melt together and one of them gain mass the other looses mass.
 5
 6        The old one does not dissapear but its mass becomes 0 (maybe a little gas like state or a ghost).
 7
 8        If your main Jelly Bean hits a ghost jelly bean, the ghost jelly bean should regain its original state, and the mass of that should be deducted from your main Jelly Bean (it will shrink in size).
 9        
10        Some Ghost Jellies are born ghosts. If you hit one of these, half of your mass will be stolen by that ghost.
11
12        The game is won when your jelly bean is the only one with a mass. 
13        The Game is lost if you do not have any more mass.
14
15        YOUR JOB IS NOT TO CREATE THIS GAME, but to create a class that can be used in this game by someone else.
16        Your job is also to write pythonic code, using python protocols, properties, overloading etc.
17
18        SO:
19       
20        Create a Jelly class.
21        When initialized you will create a jelly bean with a mass.         
22        You should be able to add 2 or more jelly beans together thus the mass of the one of them will increese. 
23        The mass of the other one will be 0, and should not remember its former state. 
24
25        The class should also be able to deduct 2 jelly beans. If a gas like jelly bean hit your jelly bean it should regain its former mass and yours should decrease.
26        
27        The object should be able to when asked tell its state.
28
29        X-tra assignemnets:
30        The "gas like Jelly Beans" will over time gain a little mass. Small jelly fragments are lying around and can be added with the plus operator to. the fragments are not objects of the Jelly Bean Class but of another more simple class called Jelly_fragment. This class has a fixed mass of 1, and it should not be changed. If the Jelly Bean "Ghost" at some poit regain they old mass they are only allowed to keep "over time gained mass" corosponding to 2% of the original mass. If it succeceds it is discarded. 
31        
32        Add the functionallity of being able to write this code in the client. 
33            val = j2 in me
34            Where me and j2 are jelly objects
35
36        You can already write j == j2 -> and get a return value of True or False. Create an implementation that when writing j == j2 checks if the mass of the 2 objects are alike.
37
38        
39"""
40
41
42class Jelly:
43
44    def __init__(self, mass):
45        self.mass = mass
46        self.__merge_history = {}  # For saving object id and the object of the merged jelly beans {'123300668' : 80}
47
48    def __add__(self, other):
49        
50        if other.mass != 0: 
51            self.mass += other.mass                         # add mass of other to self
52            self.__merge_history[ id(other)] = other.mass     # add merged object to history dictionary
53            other.mass = 0                                  # remove mass of other object
54        else:
55            raise Exception('The other object is a ghost and can not be added')
56
57
58    def __sub__(self, other):
59            
60        if id(other) in self.__merge_history:
61            other.mass = self.__merge_history[id(other)]
62            self.mass = self.mass - other.mass
63            self.__merge_history.pop(id(other))
64        else:
65            self.mass = self.mass // 2
66            other.mass = self.mass
67    
68    def __eq__(self, other):
69        if self.mass == other.mass:
70            return True
71        return False
72
73    def __contains__(self, other):
74        pass
75
76
77class Jelly_fragment:
78
79    def __init__(self):
80        Jelly_fragment.__mass = 1
81    
82    @property
83    def mass(self):
84        return Jelly_fragment.__mass 
85
86    def __del__(self):
87            pass
88

Ex 3: linked_list.py

  1# linked_list.py (solution))
  2
  3# Node class
  4class Node:
  5
  6    # Function to initialise the node object
  7    def __init__(self, data):
  8        self.data = data  # Assign data
  9        self.next = None  # Initialize next as null
 10
 11    def __repr__(self):
 12        return f'{self.__dict__}'
 13
 14
 15
 16# Linked List class contains Node objects
 17class LinkedList:
 18
 19    def __init__(self):
 20        self.head = None
 21   
 22    def __len__(self):
 23        temp = self.head
 24        count = 0
 25        while temp: 
 26            temp = temp.next
 27            count += 1 
 28        return count
 29
 30    def __getitem__(self, key):
 31        temp = self.head
 32        count = 0
 33       
 34        if type(key) == slice:
 35            for i in range(key[0], key[1]):
 36                raise NotImplementedError('To be implemented')
 37       
 38
 39        # if key/index is -x l[-1]
 40        if key < 0: 
 41            x = len(self) + key
 42            for i in range(x+1):
 43                if i == x:
 44                    return temp
 45                else:
 46                    temp = temp.next
 47                
 48        else: 
 49            while temp: 
 50                if count == key:
 51                    return temp
 52                temp = temp.next
 53                count += 1 
 54
 55        raise IndexError('index out of range')
 56
 57
 58    def __setitem__(self, key, val):
 59        if len(self) < key:
 60            raise IndexError('index out of range')
 61        else:    
 62            temp = "self.head" + ".next" * key + ".data = val"
 63            exec(temp)
 64       
 65
 66        """ another option is the more direct programming approach
 67        temp = self.head
 68        for i in range(key+1):
 69            if i == key:
 70                temp.data = val
 71            else:
 72                temp = temp.next
 73        """
 74    
 75# Code execution starts here
 76if __name__ == '__main__':
 77
 78    # Start with the empty list
 79    llist = LinkedList()
 80
 81    """
 82    llist.head = Node(1)
 83    second = Node(2)
 84    third = Node(3)
 85    """
 86    ''' 
 87        Three nodes have been created. 
 88        We have references to these three blocks as head, 
 89        second and third 
 90
 91        llist.head        second              third 
 92           |                |                  | 
 93           |                |                  | 
 94        +----+------+     +----+------+     +----+------+ 
 95        | 1  | None |     | 2  | None |     |  3 | None | 
 96        +----+------+     +----+------+     +----+------+ 
 97    '''
 98
 99
100    """
101
102    llist.head.next = second  # Link first node with second
103    second.next = third  # Link second node with the third node
104    """