Saturday, 4 April 2015

Week 12: All's well that ends well

So, this is it: the final straw. Twelve intense weeks of CSC148 have now come to a close.

Twelve weeks of endless nights finishing up assignments.

Twelve weeks of learning newer concepts in lectures.

Twelve weeks of struggling to understand those concepts.

Twelve weeks of wishing I was a better programmer.

Twelve weeks of numerous Piazza questions and answers. (And more to come before exam time.)

Overall, these twelve weeks were filled with lots of learning, despite a few bumps in the road.

Almost there! Just one final push! We can do it!

These twelve weeks have impacted me in some way. In CSC108, we were taught the basics of Python. We went on to do more cool stuff in CSC148, as seen in our assignments. We got to do some sort of interaction between the user and computer. In other words, we had the opportunity to create games and apply our learning to these assignments. Sure, they weren't super easy, but with the right amount of help and support, we were capable of finishing them to the best of our abilities.

Although I did fall behind a few times, I still think I am capable enough of doing a computer science major or specialist. Hence, I'll be applying to both subject POSTs. I really enjoyed such concepts like tracing recursion on lists, raising errors, and inheritance. What I need to work on is understanding binary search trees and linked lists a lot more. I can draw both of those, but I really need to understand the implementations in BTNode and LLNode. It doesn't help as much to memorize everything without understanding. That's what my MAT137 instructor told me when it was time to prepare for tests: avoid memorization and understand the concepts thoroughly. Everything will come to your long-term memory once it is encoded in your short-term memory. I've learned that in PSY100. In fact, things I learned while taking PSY100 may help me do well on the CSC148 final, too, since there's no aid sheet this time, unfortunately. I'll reconsider the memory model (see below). Prof. Heap did allow one for the CSC165 final, though. Nevertheless, I'll try and go to office hours and perhaps organize a study group with a few peers.

Memory model, as seen in PSY100. Useful for CSC148 and other stuff.

In addition, we did miss labs for the whole month of March, and I had a very hard time understanding the labs without TA help.  The labs were very helpful for me because my TA was around to help everyone in my lab group. I was sad that we didn't have them because I owed it all to my TA to help me get why the code works the way it does.

The whole minimax thing startled me in Assignment 2, but I believe that Assignment 3 will be a success since we created a few helper functions and got our code to work. Minimax is an insightful concept to explore in CSC148. Putting it into code is another story. Failure to get minimax to work in A2 inspired me to do better on A3.


I'd like to say thank you to the profs and TAs for their consistent support and assistance with any challenging concepts. It's really hard to say goodbye to people like them. I've learned a lot from this course. Last, but not least, thanks to my fellow students for helping everyone out, in person and on Piazza. Now it's time to turn my dream into a reality.

Take care, everyone! I hope our paths will cross again soon!


Sunday, 29 March 2015

Week 11: That was then, and this is now

Before I do a CSC148 rewind, I have a quick and happy announcement to make. The strike is finally over! Phew! Everything can get marked now!


Aside from the strike (and missing a month's worth of quizzes), it's been a crazy ten weeks. All that's left is to (hopefully) bring up my mark in Assignment 3 and the final exam. 

What I loved about A3 was that there were two options for students to choose from: the harder (minimax) option or the easier option. My group opted for the latter option. I found it extremely generous, given that my partner and I did not work our minimax the way it should be last time. 

I've been re-reading my previous SLOG posts numerous times. Here, I try to explain concepts from the previous week for myself and for other people. That way, I can increase my understanding a bit, but it doesn't imply that my head hasn't stopped spinning completely. I understand recursion a bit better now that I've seen it numerous times, but there's still room for improvement. I want to take my understanding to the next level. In other words, I want to try and become a recursion master!

I am, however, pleased to say that my writing keeps getting better each time I write a SLOG entry. As I said before, a SLOG is a good way to practice writing. There is a justification that writing is an essential skill that geeks must have; writing is a form of expression. Also, there's a good reason CS students need to take CSC165. A significant part of the course deals with mathematical expression, which includes Big-O. We do tons of writing in that course, except not completely with Python. We practice things such as proof writing and logical notation. It may be hard at first, but with repetition and proper guidance, it will all be better. 

As well, when I was working on assignments and labs, I wrote comments to help me further understand how the code works. This person speaks about adding comments in Python. They can definitely be helpful when it's time to review.

The course setup somewhat reminds me of CSC108 such that we receive weekly worksheets as in-class exercises for mastery of the upcoming concept. We take these worksheets up after a couple of seconds or minutes, depending on how much time Prof. Heap allots to us. They are used to train us in the art of reading and writing code on paper, which I struggled with greatly in the CSC108 midterm and exam. Nevertheless, help is there when I need it. 

Comparing my experience to Saima's, I, too, understand things at a conceptual level rather than at a practical level (implementing code). Before the exam, I'll keep doing what I'm doing, which is reaching out for help whenever possible and not having too much anxiety. 

I do try to ask questions and practice the concepts, but I need to catch up on the labs because I haven't worked on them due to assignments from other courses. 

Well, we're almost there. I swear we started CSC148 yesterday. My group will complete A3 and I will begin reviewing for my exams. 

Best of luck in the final moments of CSC148, everyone! We can do this!

Last, but not least, here's a positive photo.

Sunday, 22 March 2015

Week 10: I will find you, but I won't kill you

The strike has been going on for three weeks. Thus, we have not had labs or quizzes for the past three weeks. They are worth 10% of everyone's final CSC148 grade. My TA was quite helpful with the lab exercises because I could not do the labs on my own. I still can't do them on my own. While the strike has been going on, I started turning to Piazza or office hours to ask questions. Nevertheless, Professors Heap and Horton have been doing a great job with managing the course, office hours, and Piazza discussions while the TAs are gone, so hats off to them!



In this post, I am going to talk about mutating binary search trees using recursive functions insert() and delete() in class BTNode.

All of the following conditions must be present for a tree to be classified as a binary search tree:
  1. All data are comparable.
  2. Data in the left subtree are less than root.data.
  3. Data in the right subtree are greater than root.data.
Here is a visual representation of a binary search tree.



I found the lecture on mutating BSTs straightforward to follow. In the additional exercises for Lab 6, the insert function can be found, and the code implementation is based off the general formula for recursion: base case, then general case.

To implement insert, we need an accumulator variable as our return value. Next, we start with the base case: if the node is a root, we create a leaf using a variable. Then we look at conditions 2 and 3 from above. If the data in the left subtree are less than root.data, recursively insert new data in the left subtree. On the contrary, if the data in the right subtree are greater than root.data, recursively insert new data in the right subtree. Finally, return the accumulator variable.

As for the delete function, we looked at an algorithm to help us implement it together in lecture. It is very similar to the algorithm for insert, except we recursively remove data in either the left or right subtrees in this case. However, there are a few extra steps. 

"I'm overwhelmed already," I think to myself as I attempt to understand how it works.
If a node with data has less than two children, acknowledging that one of the children is None, return the other child. Finally, if a node with data has two children that are not None, then replace that data with the largest child in the left subtree. Delete the original data that was swapped with the new data, and then return the new data.

I'm definitely going to practice with these two functions in Lab #8 while balancing work from my other courses.

This is the code that Prof. Heap showed us and had us work with.

I wish everyone the best of luck in A3 and the rest of the course! It's not easy, but it's not impossible! I'll leave you all with some motivation because positivity is key.


Saturday, 14 March 2015

Week 9: A conga line, but with nodes

This is a conga line. It gave me the inspiration for the title of this post.

Except nodes don't dance.

Oh, great. Now this song is stuck in my head:



In all seriousness, though, how did we just finish Week 9? Didn't the semester start yesterday?

Exactly.

Anyway, we only had one lecture on mutating binary search trees. Prof. Heap suggested that I add things such as definitions and important lines of code onto my aid sheet. In addition to these, I drew an example of a binary tree and a linked list. I was able to finish in fifty minutes, though more time would be helpful for students to look over their answers for errors, big or small, before submitting their tests.

What I have learned not to do in test situations is aim for a specific mark, say, 100. (I'm not a robot.) This would lead to mental stress, which I have endured a lot when I was around sixteen in grade eleven because of my heightened fear of failure. In spite of U of T, my fear of failure has been reduced slightly from grade eleven. So, Wednesday's test was fair. I was able to stay calm while writing my test.

We've covered linked lists in the past week. (The conga line above may give you a little hint.) A linked list can be defined in two ways:

  1. Lists comprised of an item and a sub-list
  2. Objects, or nodes, that contain a value and refer to the next node in a sequence
According to Prof. Horton, in CSC148, we will look at the second definition of linked lists. I find her slides useful to help me build on my understanding of concepts. They can also be useful for students in all lecture sections. 

Here is how one would visually represent a linked list. (Yay, visuals!)


15 is at the front of the list, and 4 is at the back. We use an "X" to indicate that we've reached the end of the list. In the case of the conga line, arrows point to the next node in the sequence, much like how people link arms with whoever is next in line.

With linked lists, we worked with two classes instead of one: LLNode and LinkedList. Hence, we were taught that a wrapper class represents a linked list in its entirety. So, LinkedList is our wrapper class. (LLNode refers to one node.)

I was extremely confused about this concept, but after looking at lecture slides from both profs and a post on Piazza, I understood how wrapper classes worked.

Speaking of which, Prof. Heap gave my class a gentle reminder not to confuse "wrapper" with "rapper."

404: "rapper class" not found

We also looked at a code generalization when it comes to traversing a linked list. It goes something like this. I've also added comments to help understand what the code does.

cur_node = self.front # start at front of list
while <some condition here>:
     <do something here>
     cur_node = cur_node.nxt # move on to next list
     # end of list: while loop condition becomes False
     # loop exits

For more on linked lists, go here for the Python representation of linked lists.

Also, we did not have labs for the past two weeks due to the TA strike; the profs left us to do the labs ourselves and ask for help when needed. I'll work on Lab #8 soon.

Happy Pi Day, everyone! In celebration of this day, have a picture of a pi(e).


I'll be back for more CSC148 ramblings next week. Stay tuned, and all the best on the last few weeks of school!

Saturday, 7 March 2015

Week 8: I'm a tree hugger

To start this blog post off, I must say that the past two weeks have been really hard. In particular, I devoted most of my time to Assignment #2 with my partner this past week, which means that I now need to catch up on this week's lab and review previous labs and lecture notes to prepare for the test. Go here if you need some help with the additional exercises.

We did our best on that assignment. The second test is on Wednesday, and I hope it's better than the first. I didn't do well on the recursion part of the first test, which cost me marks. (It's March now. Where are my time management skills?) Otherwise, I would have gotten at least a B+, which was the class average. Nevertheless, that class average was fantastic, especially for a first year computer science course like CSC148! Kudos to everyone! (Note to self: I CAN and WILL do well on the second test!)

Here's a good calm-down routine for the test. This is surely what I will be using, too:



Like everyone else, I have work from other courses to do. (Saima, I am in the same boat as you. Let's work hard.) As Saima put it in her post, time management is key, and I mean very key. It's short, sweet, and to the point. Not to mention, it's motivational! I recommend reading her blog, too, because she reflects on her experience in CSC148 very well.

Another fellow CSC148er gave me some advice recently. They told me to be curious as well as not be satisfied with not understanding anything. I need to be able to understand why my code works the way it does. One thing to think about when I'm in my Thursday morning lab is to find out why the method that I implemented works the way it does, with support from my TA. My problem solving skills will improve if I engage with the material as thoroughly as I can. The nicest part about this course and CSC165 is that an aid sheet is allowed.

Anyway, here's the latest from the CSC148 world. We've been looking at binary trees. (And I've been struggling with CSC148 as usual.)

"Binary trees? You mean these?"
As a bit of review from recursion, a tree is a data structure that consists of nodes. Some of these nodes have edges, which connect one node with another. So, it looks something like this:

Now, a binary tree is a type of tree that consists of a "parent" node with two "children," named left and right. Prof. Heap showed us a class, BTNode, that represented a binary tree. The above diagram is an example of a binary tree with 2 as the parent and 7 and 5 as the children. Then it goes on.. and on... and on.

I'm going to familiarize myself a bit more with binary trees in time for the test. The advice that someone gave me can be really helpful for me and anyone else who is struggling with grasping CSC148 material.

Best of luck on the test, everyone! I'll see you next time!

Saturday, 28 February 2015

Week 7: Getting back into the SLOG game

(Alternate title: Recursion is Recursion is Recursion II)

Note to TA: I would like this summary to be marked.

Reading Week went by extremely fast. Well, at least I was able to enjoy the comfort of my bed more often because I normally would have to be up at around 8am to get ready for school. With the due date of Assignment 2 (and assignments from other courses) looming, it's business as usual. We'll finish this assignment in due time, though.

How I feel at the moment
More concepts are being thrown at us week after week in CSC148. It's not at the same difficulty level as CSC108. That doesn't mean I can't look back at concepts from CSC108 (e.g. classes, Function Design Recipe) to help me understand what in the world is going on in CSC148 and, in particular, this assignment. Worksheets are being distributed each week for us to practice writing code on paper, much like CSC108. (Here's a personal action plan: I'm going to organize all my CSC148 worksheets in one place so I can look at them later. I have a bad habit of misplacing papers.)

Moving on then. In this post, I would like to summarize recursion with more detail this time.

To start this summary off, here's a dictionary definition of recursion:

It's used in linguistics too? Whoa!
In computer science, we solve complicated problems by creating methods to break down these problems into smaller problems. These methods are defined in terms of themselves. In other words, a recursive method is literally a "method within a method within a method..."

Circle of Life: Computer Science Edition

There are two easy steps to write recursive methods:


  1. Identify the base case. This can be solved without recursion
  2. Identify the general case. This is where the recursion takes place.


These steps somewhat remind me of proving by induction in MAT137. There, I would start with the base case, then move on to the induction step. In Python, this would take on the form of an if statement. Here's an example of a recursive function from one of the labs (with examples provided in the docstring) that contains an if statement:

def nested_concat(L):
    """ (list or str) -> str

    Return L if it's a str. Otherwise, if L is a possibly nested             list of str, return the concatenation of str elements of L. 
    
    >>> nested_concat('two')
    'two'
    >>> nested_concat(['one', 'two', 'three'])
    'onetwothree'
    """

    if isinstance(L, str): # base case; no recursion required
       return L
    else: # L is a possibly nested list of str
       return ''.join([nested_concat(x) for x in L])

In the Python shell, we would get the exact same results that we expected.

There's also a way to trace recursion on paper.

The first example involving a string, 'two', is very simple and will look like this:

nested_concat('two') --> 'two' # 'two' is a str

The second example requires some more steps:

nested_concat(['one', 'two', 'three']) --> ''.join([nested_concat(x) for x in ['one', 'two', 'three'])
--> ''.join(['one', 'two', 'three']) # traced nested_concat(str) before
--> 'onetwothree' # 'one' + 'two' + 'three'

This page, which was previously assigned as supplementary reading, can help others understand recursion and provides numerous examples, some of which involve graphics.

Jesse's post on recursion is a funny read, and he gets the point across. (That post also made me hungry.) Also, I really enjoyed reading Chris's insights on recursion. I liked his examples of recursion, and that has inspired me to create my own examples of recursive functions and other stuff to practice and get better at Python (because I'm still not very good at programming yet *cries*)!

I would like to wish the best of luck on A2! Also, feedback is greatly appreciated.

Thank you so much for reading! Cheers!

Sunday, 15 February 2015

Week 6: OOPs, I did it again

Here's another glimpse of my not-so-fascinating programmer life: object-oriented programming and my familiarity with the whole shebang.


The term "object-oriented programming," or OOP for the acronym-inclined, is something that I have been familiar with since learning Java in my grade 11 computer science class. It's a key concept in computer science, with the main focus being objects, of course!

I revisited this concept last semester in CSC108 as well as at the beginning of CSC148 while reviewing classes. Prof. Heap asked us to do a complementary exercise that involved object-oriented programming.

With that, we all took out a sheet of paper and designed a class using the following approach:
  1. Find the most important noun. This will be the class name.
  2. Find the most important attributes of that noun (or less important nouns).
  3. Find the operations for the noun to carry out (or verbs).
This approach can be considered linguistic, as we're dealing with nouns and verbs from a natural language (English) and putting it all together into a programming language (in our case, Python).

Here's a diagram for those who love looking at visuals (like me):



We had a few seconds to do it. I organized a sort of outline for this approach on my paper but was unable to identify the three parts in time. Eventually we took it up. (I would have liked a bit more time, personally, because I'm still not a proficient programmer yet and I'm a slowpoke.)

I'm familiar with Prof. Heap's teaching approach of having us complete exercises in a short period of time, but at the moment, it still would take me a while to solve these types of problems. When we take it up, however, I realize, "Of course. That's what is supposed to happen. Why didn't I think of that before?" To solve these types of problems within his given time frames (e.g. a minute), I'll do some review at home before coming to lecture. That's something I should have done in CSC165, but my course load was a bit too much for me to handle with five courses. Well, it's not too late, right? Then again, I have office hours to look forward to if I still don't get something. I will continue that approach so I can at least match my success in CSC165. (CS major, I'll see you soon.)

Anyway, I'll wrap this entry up by summarizing what I know about object-oriented programming.

We start with a class. A class is the most important object of any program. Using the approach that Prof. Heap provided, we start with #1, which is essentially the first line of our program. Here's a generalization:

class YourClassHere:
      """Your docstring goes here."""
      # to be continued...

At this point, our program is at a clean slate. Now, we want to implement steps #2 and #3 from our approach. How do we go about this? We need methods. Methods are functions defined within a class. Some important methods are: __init__, __eq__, __repr__, and __str__. We can also add our own methods, too.

Let's add on to our little generalization above.

class YourClassHere:
      """Your docstring for your class goes here."""

      # always start with __init__ to initialize your class!
      
      def method1(self, ...)
          """ (YourClassHere, ...) --> ...
           
          Your docstring for method1 goes here.
          """ 
          # body of method1
          # initialize variables, add loops, etc.

      def method2(self, ...)
          """ (YourClassHere, ...) --> ...

          Your docstring for method2 goes here.
          """
          # again, add body here
     
      # you get the idea

Another idea in object-oriented programming is inheritance. 




Here's the answer: Inheritance is the act of creating a subclass as an extension of the original class. The methods from the original are inherited onto the subclass. 

Let's inherit our class from above, YourClassHere.

class YourSubclassHere(YourClassHere)
      """Inherited from class YourClassHere..."""
      # inherit methods

In Assignment 1, we applied inheritance to our game_view program. We had general classes where the user could access the games made available to them, and specific classes for our game, "Subtract Square." Generally, inheritance is greatly applied when there is a general class and specific classes are needed as extensions.

The following diagram can add to our generalization of inheritance, too. The vehicle is the general class and the bike is the specific class (specific means of transportation that we are looking at). "Pedal," "trike," and "motor" are all subclasses inherited from the "bike" class. It's similar to the "Gameview" and "Subtract Square" classes from Assignment 1.





I think that sums up object-oriented programming. As well, this post also sums up object-oriented programming nicely, so feel free to check it out!

As always, feel free to leave a comment. I would love to hear any feedback from you.

Happy Reading Week, everyone! See you on the flip side!