diff --git a/angry.py b/angry.py new file mode 100644 index 0000000..ad8a426 --- /dev/null +++ b/angry.py @@ -0,0 +1,53 @@ +from smiley import Smiley +import time + + + +class Angry(Smiley): + def __init__(self): + super().__init__(complexion = self.RED) + + Y = self.complexion() + O = self.BLANK + self.pixels = [ + O, Y, Y, Y, Y, Y, Y, O, + Y, Y, Y, Y, Y, Y, Y, Y, + Y, Y, Y, Y, Y, Y, Y, Y, + Y, Y, Y, Y, Y, Y, Y, Y, + Y, Y, Y, Y, Y, Y, Y, Y, + Y, Y, Y, Y, Y, Y, Y, Y, + Y, Y, Y, Y, Y, Y, Y, Y, + O, Y, Y, Y, Y, Y, Y, O, + ] + + self.draw_mouth() + self.draw_eyes() + + def draw_mouth(self): + """ + Draws the mouth feature on a smiley + """ + mouth = [50, 42, 43, 44, 45, 53] + for pixel in mouth: + self.pixels[pixel] = self.BLANK + + def draw_eyes(self, wide_open=True): + """ + Draws open or closed eyes on a smiley + :param wide_open: Render eyes wide open or shut + """ + eyes = [9, 10, 13, 14, 18, 21] + for pixel in eyes: + if wide_open: + eyes = self.BLANK + else: + eyes = self.complexion() + self.pixels[pixel] = eyes + + def blink(self, delay=0.25): + + self.draw_eyes(wide_open=False) + self.show() + time.sleep(delay) + self.draw_eyes(wide_open=True) + self.show() diff --git a/civ-ipriot-smiley_screenshots/Blue sad.png b/civ-ipriot-smiley_screenshots/Blue sad.png new file mode 100644 index 0000000..8b2b7ee Binary files /dev/null and b/civ-ipriot-smiley_screenshots/Blue sad.png differ diff --git a/civ-ipriot-smiley_screenshots/Complexion implemented.png b/civ-ipriot-smiley_screenshots/Complexion implemented.png new file mode 100644 index 0000000..c892641 Binary files /dev/null and b/civ-ipriot-smiley_screenshots/Complexion implemented.png differ diff --git a/civ-ipriot-smiley_screenshots/Complexion used in happy.png b/civ-ipriot-smiley_screenshots/Complexion used in happy.png new file mode 100644 index 0000000..c5b69bd Binary files /dev/null and b/civ-ipriot-smiley_screenshots/Complexion used in happy.png differ diff --git a/civ-ipriot-smiley_screenshots/Complexion used in sad.png b/civ-ipriot-smiley_screenshots/Complexion used in sad.png new file mode 100644 index 0000000..8ecaa57 Binary files /dev/null and b/civ-ipriot-smiley_screenshots/Complexion used in sad.png differ diff --git a/civ-ipriot-smiley_screenshots/Found_refactoring_and_renamed_Y_to_X.png b/civ-ipriot-smiley_screenshots/Found_refactoring_and_renamed_Y_to_X.png new file mode 100644 index 0000000..35ae02b Binary files /dev/null and b/civ-ipriot-smiley_screenshots/Found_refactoring_and_renamed_Y_to_X.png differ diff --git a/civ-ipriot-smiley_screenshots/Smiley, blue implemented.png b/civ-ipriot-smiley_screenshots/Smiley, blue implemented.png new file mode 100644 index 0000000..2863203 Binary files /dev/null and b/civ-ipriot-smiley_screenshots/Smiley, blue implemented.png differ diff --git a/happy.py b/happy.py index c3b0ba5..79825a1 100644 --- a/happy.py +++ b/happy.py @@ -28,12 +28,12 @@ def draw_eyes(self, wide_open=True): """ eyes = [10, 13, 18, 21] for pixel in eyes: - self.pixels[pixel] = self.BLANK if wide_open else self.YELLOW + self.pixels[pixel] = self.BLANK if wide_open else self.complexion() def blink(self, delay=0.25): """ Blinks the smiley's eyes once - + :param delay: Delay between blinks (in seconds) """ self.draw_eyes(wide_open=False) diff --git a/knowledge_and_evidence.md b/knowledge_and_evidence.md index db45098..38d260a 100644 --- a/knowledge_and_evidence.md +++ b/knowledge_and_evidence.md @@ -108,68 +108,81 @@ python3 main.py 1. Examine the code for the `smiley.py` file and provide an example of a variable of each of the following types and their corresponding values (`_` should be replaced with the appropriate values): - | Type | name | value | - | ---------- | ---------- | -------------- | - | built-in primitive type | _ | _ | - | built-in composite type | _ | _ | - | user-defined type | _ | _ | + | Type | name | value | + | ---------- |--------|------------------| + | built-in primitive type | int | 255 | + | built-in composite type | WHITE | (255, 255, 255) | + | user-defined type | Smiley | Class | 2. Fill in (`_`) the following table based on the code in `smiley.py`: - | Object | Type | - | ------------ | ----------------------- | - | self.pixels | _ | - | A member of self.pixels | _ | - | self | _ | + | Object | Type | + | ------------ |-------| + | self.pixels | array | + | A member of self.pixels | int | + | self | class | -3. Examine the code for `smiley.py`, `sad.py`, and `happy.py`. Give an example of each of the following control structures using an example from **each** of these files. Include the first line and the line range: + Examine the code for `smiley.py`, `sad.py`, and `happy.py`. Give an example of each of the following control structures using an example from **each** of these files. Include the first line and the line range: + + | Control Flow | File | First line | Line range | + |--------------|-----------|--------------------------------------|------------| + | sequence | sad.py | self.draw_mouth() | 8-9 | + | | smiley.py | Y = self.YELLOW | 15-26 | + | | happy.py | self.draw_eyes(wide_open=False | 39-43 | + | selection | smiley.py | def dim_display(self, dimmed=True): | 28-33 | + | | sad.py | def draw_eyes(self, wide_open=True): | 19-30 | + | | happy.py | def draw_eyes(self, wide_open=True): | 24-31 | + | iteration | smiley.py | _ | _ | + | | sad.py | for pixel in eyes: | 25-30 | + | | happy.py | for pixel in eyes: | 30-31 | - | Control Flow | File | First line | Line range | - | ------------ | ---------- | ----------- | ----------- | - | sequence | _ | _ | _ | - | selection | _ | _ | _ | - | iteration | _ | _ | _ | 4. Though everything in Python is an object, it is sometimes said to have four "primitive" types. Examining the three files `smiley.py`, `sad.py`, and `happy.py`, identify which of the following types are used in any of these files, and give an example of each (use an example from the code, if applicable, otherwise provide an example of your own): - | Type | Used? | Example | - | ----------------------- | ----- | --------| - | int | _ | _ | - | float | _ | _ | - | str | _ | _ | - | bool | _ | _ | + | Type | Used? | Example | + | ----------------------- |-------|------------------------------| + | int | No | _ | + | float | Yes | delay = 0.25 (happy.py) | + | str | No | _ | + | bool | Yes | wide_open = False (happy.py) | 5. Examining `smiley.py`, provide an example of a class variable and an instance variable (attribute). Explain **why** one is defined as a class variable and the other as an instance variable. -> Your answer here -> +> An example of a class variable would be WHITE and an instance variable would be Y. The +> reason for the difference is that, WHITE would stay the same throughout the class but Y +> could go through changes depending on which function it is part of. 6. Examine `happy.py`, and identify the constructor (initializer) for the `Happy` class: 1. What is the purpose of a constructor (in general) and this one (in particular)? - > Your answer here + > In general, the constructor is used to initialize the object and set default values for + > attributes. In this case, however, the constructor was used to call upon a function + > rather than initializing. > 2. What statement(s) does it execute (consider the `super` call), and what is the result? - > Your answer here + > It executes the draw_mouth and draw_eyes statements. The results draw the eyes and the + > mouth of the happy face. > ### Code style 1. What code style is used in the code? Is it likely to be the same as the code style used in the SenseHat? Give to reasons as to why/why not: -> Your answer here +> PEP 8. Yes because PEP 8 is the standard coding convention for Python code writing. > 2. List three aspects of this convention you see applied in the code. -> Your answer here +> Indentations are being used correctly. Maximum character being used per line is 79 +> characters. Using lowercase with underscores to name the functions and variables. > 3. Give two examples of organizational documentation in the code. -> Your answer here +> happy.py line 17-19, and smiley.py line 29-33. Both of these helped me to understand the +code better. > ### Identifying and understanding classes @@ -180,19 +193,27 @@ python3 main.py Use the following table for your answers: -| Class Name | Super or Sub? | Direct parent(s) | -| ---------- | ------------- | ---------------- | -| NotReal | Sub | NotRealParent | -| ... | ... | ... | +| Class Name | Super or Sub? | Direct parent(s) | +|--------------|---------------|-------------------| +| blinkable.py | Super | N/A | +| smiley.py | Super | N/A | +| sad.py | Sub | smiley | +| happy.py | Sub | smiley, blinkable | +| | | | 2. Explain the concept of abstraction, giving an example from the project (note "implementing an ABC" is **not** in itself an example of abstraction). (Max 150 words) -> Your answer here +> The concept of abstraction is to show the objects in how they are used and not how they +> are implemented or work. With this particular program, to know how the code outputs smiley, +> I only need to look at smiley.py to understand how it's getting displayed. I don't need to +> look at or understand the deeper and more complex code in sense_hat.py > 3. What is the name of the process of deriving from base classes? What is its purpose in this project? (Max 150 words) -> Your answer here +> The process is called inheritance. Its purpose in this project is to call upon other +> classes and change their pixels instead of closing the current class and making a new +> emoji with the new class. > ### Compare and contrast classes @@ -200,54 +221,67 @@ python3 main.py Compare and contrast the classes Happy and Sad. 1. What is the key difference between the two classes? - > Your answer here + > happy has an additional method which uses the module time to delay and show an + > animation of blinking. Which is something that sad doesn't have. > 2. What are the key similarities? - > Your answer here + > Happy and Sad both use arrays to save values within the methods > 3. What difference stands out the most to you and why? - > Your answer here + > The usage of delay and Time in happy stands out the most for me because I haven't seen + > such usage for libraries before. > 4. How does this difference affect the functionality of these classes - > Your answer here + > The functionality of happy offers much more than sad within the application, the + > blinking of the emoji gives the happy class much more personality and makes the user + > feel more certain about the effort put into the application > ### Where is the Sense(Hat) in the code? 1. Which class(es) utilize the functionality of the SenseHat? - > Your answer here + > Smiley, Happy and Sad utilize SenseHat's functionality. > 2. Which of these classes directly interact with the SenseHat functionalities? - > Your answer here + > Only smiley interacts directly with the functionalities of SenseHat > 3. Discuss the hiding of the SenseHAT in terms of encapsulation (100-200 Words) - > Your answer here + > The encapsulation of SenseHat was done through the use of Smiley class within the program, + > there was a single instance of usage of SenseHat, and it was done in Smiley. Within + > Smiley, the SenseHat was initialized. From then and onwards, other classes referenced and + > used Smiley not SenseHat. With this, everyone only needs to refer to the smiley + > class to understand what's happening within sad and happy. And within smiley class, the + > user can see how the emoji and its pixels were implemented, how the colours were added + > to the program without needing to understand what made these implementations possible. > ### Sad Smileys Can’t Blink (Or Can They?) -Unlike the `Happy` smiley, the current implementation of the `Sad` smiley does not possess the ability to blink. Let's first explore how blinking has been implemented in the Happy Smiley by examining the blink() method, which takes one argument that determines the duration of the blink. +Unlike the `Happy` smiley, the current implementation of the `Sad` smiley does not possess the +ability to blink. Let's first explore how blinking has been implemented in the Happy Smiley by +examining the blink() method, which takes one argument that determines the duration of the blink. **Understanding Blink Mechanism:** 1. Does the code's author believe that every `Smiley` should be able to blink? Explain. -> Your answer here -> +> No, because the child-class of 'blinkable' is only the 'happy' class + 2. For those smileys that blink, does the author expect them to blink in the same way? Explain. -> Your answer here -> +> No, because there could be different delays based on different smileys + 3. Referring to the implementation of blink in the Happy and Sad Smiley classes, give a brief explanation of what polymorphism is. -> Your answer here -> +>If blink were to be implemented in Sad class, the delay could be of different values. The +> structure of the blink function would be same but throughout different classes, there +> would be different ways to implement them. 4. How is inheritance used in the blink method, and why is it important for polymorphism? -> Your answer here +> Inheritance is used in the blink method to build the framework to be used by other classes. > 1. **Implement Blink in Sad Class:** @@ -270,31 +304,40 @@ Include a screenshot of the sad smiley or the modified `main.py`: - Observe and document the Sad smiley as it blinks its eyes. Describe any adjustments or issues encountered during implementation. - > Your answer here + > I had to import Blinkable method from blinkable module to sad class and had to import it + > to main from sad afterwards. ### If It Walks Like a Duck… - Previously, you implemented the blink functionality for the Sad smiley without utilizing the class `Blinkable`. Assuming you did not use `Blinkable` (even if you actually did), consider how the Sad smiley could blink similarly to the Happy smiley without this specific class. + Previously, you implemented the blink functionality for the Sad smiley without utilizing the +- class `Blinkable`. Assuming you did not use `Blinkable` (even if you actually did), consider +- how the Sad smiley could blink similarly to the Happy smiley without this specific class. 1. **Class Type Analysis:** What kind of class is `Blinkable`? Inspect its superclass for clues about its classification. - > Your answer here + >The superclass of `Blinkable` is ABC which stands for abstract base class, it is used to standardize +> the way of testing whether the object adheres to a given specification. +> (Abstract Base Class (abc) in Python. (2020, August 20). GeeksforGeeks. https://www.geeksforgeeks.org/abstract-base-class-abc-in-python/) - 2. **Class Implementation:** `Blinkable` is a class intended to be implemented by other classes. What generic term describes this kind of class, which is designed for implementation by others? **Clue**: Notice the lack of any concrete implementation and the naming convention. + 2. **Class Implementation:** `Blinkable` is a class intended to be implemented by other classes. + What generic term describes this kind of class, which is designed for implementation by others? **Clue**: Notice the lack of any concrete implementation and the naming convention. - > Your answer here + > The class `Blinkable` falls under the abstract class 3. **OO Principle Identification:** Regarding your answer to question (2), which Object-Oriented (OO) principle does this represent? Choose from the following and justify your answer in 1-2 sentences: Abstraction, Polymorphism, Inheritance, Encapsulation. - > Your answer here + > The principle Abstraction is used in the class `Blinkable`, Blinkable is there to show the user what the Blink function is supposed to do. +> Due to this, the user wouldn't need to look through other classes to see how happy or sad blinks. 4. **Implementation Flexibility:** Explain why you could grant the Sad Smiley a blinking feature similar to the Happy Smiley's implementation, even without directly using `Blinkable`. - > Your answer here + > Blinkable is only there to show how the method `Blink` is supposed to operate. Because I added the method `Blink` to the `sad` class, +> I didn't need to inherit the `Blinkable` class. 5. **Concept and Language Specificity:** In relation to your response to question (4), what is this capability known as, and why is it feasible in Python and many other dynamically typed languages but not in most statically typed programming languages like C#? **Clue** This concept is hinted at in the title of this section. - > Your answer here + > In python, everything is an object, so composition is easy to implement in Python. In languages like C#, you have to +> create the object yourself. Thus making it feasible for dynamically typed languages. *** @@ -307,19 +350,23 @@ Include a screenshot of the sad smiley or the modified `main.py`: 1. **Defined Colors and Their Location:** 1. Which colors are defined and in which class(s)? - > Your answer here + > WHITE, GREEN, RED, YELLOW, BLANK are defined in the `smiley` class. + 2. What type of variables hold these colors? Are the values expected to change during the program's execution? Explain your answer. - > Your answer here + > In smiley, the variable `YELLOW` holds the yellow colour. + > Yes during execution, some of the yellow colour in `smiley` class is expected to change to BLANK to show the + > eyes and mouth. And the eyes are expected to change to yellow if `blink` is implemented. 3. Add the color blue to the appropriate class using the appropriate format and values. + > "Done" 2. **Usage of Color Variables:** 1. In which classes are the color variables used? - > Your answer here + > The color variables are used in sad, happy and smiley. 3. **Simple Method to Change Colors:** 4. What is the easiest way you can think to change the smileys to green? Easiest, not necessarily the best! - > Your answer here + > Change Y = self.YELLOW to Y = self.GREEN Here's a revised version of the "Flexible Colors – Step 1" section for the smiley project, incorporating your specifications for formatting and content updates: @@ -328,12 +375,17 @@ Include a screenshot of the sad smiley or the modified `main.py`: Changing the color of the smileys once is straightforward, but it isn't very flexible. To facilitate various colors for smileys, it is advisable not to hardcode values in any class. This approach was identified earlier as a necessary change. Let's start by removing the built-in assumptions about color in our classes. 1. **Add a method called `complexion` to the `Smiley` class:** Implement this instance method to return `self.YELLOW`. Using the term "complexion" instead of "color" provides a more abstract terminology that focuses on the meaning rather than implementation. + >Done 2. **Refactor subclasses to use the `complexion` method:** Modify any subclass that directly accesses the color variable to instead utilize the new `complexion` method. This ensures that color handling is centralized and can be easily modified in the future. - + >Done + 3. **Determine the applicable Object-Oriented principle:** Consider whether Abstraction, Polymorphism, Inheritance, or Encapsulation best applies to the modifications made in this step. + > Abstraction fits modifications that has been done by Q3. Because the user would only need to look at complexion +> understand that it is showing the emoji's colour, they do not need to go to smiley. 4. **Verify the implementation:** Ensure that the modifications function as expected. The smileys should still display in yellow, confirming that the new method correctly replaces the direct color references. + >Verified This step is crucial for setting up a more flexible system for color management in the smiley display logic, allowing for easy adjustments and extensions in the future. @@ -342,19 +394,19 @@ Include a screenshot of the sad smiley or the modified `main.py`: Having removed the hardcoded color values, we now enhance the base class to support dynamic color assignments more effectively. 1. **Modify the `__init__()` method in the `Smiley` class:** Introduce a default argument named `complexion` and assign `YELLOW` as its default value. This allows the instantiation of smileys with customizable colors. - + >Done 2. **Introduce a new instance variable:** Create a variable called `my_complexion` and assign the `complexion` parameter to it. This step ensures that each smiley instance can maintain its own color state. - + >Done 3. **Rationale for `my_complexion`:** Using a distinct instance variable like `my_complexion` avoids potential conflicts with the method parameter names and clarifies that it is an attribute specific to the object. - + >Done 4. **Bulk rename:** We want to update our grid to use the value of complexion, but we have so many `Y`'s in the grid. Use your IDE's refactoring tool to rename all instances of the **symbol** `Y` to `X`. Where `X` is the value of the `complexion` variable. Include a screenshot evidencing you have found the correct refactor tool and the changes made. - + >Done ![Bulk Rename](screenshots/bulk_rename.png) 5. **Update the `complexion` method:** Adjust this method to return `self.my_complexion`, ensuring that whatever color is assigned during instantiation is what the smiley displays. - + >Done 6. **Verification:** Run the updated code to confirm that Smileys still defaults to yellow unless specified otherwise. - + >Done ### Flexible Colors – Step 3 With the foundational changes in place, it's now possible to implement varied smiley colors for different emotional expressions. @@ -364,11 +416,11 @@ Include a screenshot of the sad smiley or the modified `main.py`: ```python super().__init__(complexion=self.BLUE) ``` - + >Done 2. **Test color functionality for the Sad smiley:** Execute the program to verify that the Sad smiley now appears blue. - + >Done 3. **Ensure the Happy smiley remains yellow:** Confirm that changes to the Sad smiley do not affect the default color of the Happy smiley, which should still display in yellow. - + >Done 4. **Design and Implement An Angry Smiley:** Create an Angry smiley class that inherits from the `Smiley` class. Set the color of the Angry smiley to red by passing `self.RED` as the `complexion` argument in the superclass call. - + >Done *** diff --git a/main.py b/main.py index ab15a99..e74aa4e 100644 --- a/main.py +++ b/main.py @@ -5,9 +5,11 @@ import time from happy import Happy +from sad import Sad +from angry import Angry def main(): - smiley = Happy() + smiley = Angry() smiley.show() diff --git a/sad.py b/sad.py index fe14277..1ea3647 100644 --- a/sad.py +++ b/sad.py @@ -1,9 +1,24 @@ from smiley import Smiley +import time + class Sad(Smiley): def __init__(self): - super().__init__() + super().__init__(complexion=self.BLUE) + + Y = self.complexion() + O = self.BLANK + self.pixels = [ + O, Y, Y, Y, Y, Y, Y, O, + Y, Y, Y, Y, Y, Y, Y, Y, + Y, Y, Y, Y, Y, Y, Y, Y, + Y, Y, Y, Y, Y, Y, Y, Y, + Y, Y, Y, Y, Y, Y, Y, Y, + Y, Y, Y, Y, Y, Y, Y, Y, + Y, Y, Y, Y, Y, Y, Y, Y, + O, Y, Y, Y, Y, Y, Y, O, + ] self.draw_mouth() self.draw_eyes() @@ -26,5 +41,13 @@ def draw_eyes(self, wide_open=True): if wide_open: eyes = self.BLANK else: - eyes = self.YELLOW + eyes = self.complexion() self.pixels[pixel] = eyes + + def blink(self, delay=0.25): + + self.draw_eyes(wide_open=False) + self.show() + time.sleep(delay) + self.draw_eyes(wide_open=True) + self.show() diff --git a/smiley.py b/smiley.py index f942a66..9d410a5 100644 --- a/smiley.py +++ b/smiley.py @@ -1,28 +1,32 @@ from sense_hat import SenseHat - class Smiley: WHITE = (255, 255, 255) GREEN = (0, 255, 0) RED = (255, 0, 0) YELLOW = (255, 255, 0) BLANK = (0, 0, 0) + BLUE = (0, 0, 255) + - def __init__(self): + def __init__(self, complexion = YELLOW): # We have encapsulated the SenseHat object self.sense_hat = SenseHat() + self.my_complexion = complexion + Y = self.YELLOW O = self.BLANK + X = self.my_complexion self.pixels = [ - O, Y, Y, Y, Y, Y, Y, O, - Y, Y, Y, Y, Y, Y, Y, Y, - Y, Y, Y, Y, Y, Y, Y, Y, - Y, Y, Y, Y, Y, Y, Y, Y, - Y, Y, Y, Y, Y, Y, Y, Y, - Y, Y, Y, Y, Y, Y, Y, Y, - Y, Y, Y, Y, Y, Y, Y, Y, - O, Y, Y, Y, Y, Y, Y, O, + O, X, X, X, X, X, X, O, + X, X, X, X, X, X, X, X, + X, X, X, X, X, X, X, X, + X, X, X, X, X, X, X, X, + X, X, X, X, X, X, X, X, + X, X, X, X, X, X, X, X, + X, X, X, X, X, X, X, X, + O, X, X, X, X, X, X, O, ] def dim_display(self, dimmed=True): @@ -37,3 +41,6 @@ def show(self): Show the smiley on the screen. """ self.sense_hat.set_pixels(self.pixels) + + def complexion(self): + return self.my_complexion