diff --git a/_internal/targets.json b/_internal/targets.json index 2106734b5..872065524 100644 --- a/_internal/targets.json +++ b/_internal/targets.json @@ -1 +1 @@ -[{"due": "10/18/24", "link": "lab/lab07/", "name": "Lab 07: Object-Oriented Programming", "piazza_name": "Lab 07", "release": "10/14/24"}, {"due": "10/23/24", "link": "hw/hw07/", "name": "HW 07: Object-Oriented Programming", "piazza_name": "HW 07", "release": "10/16/24"}, {"due": "11/20/24", "link": "proj/ants/", "name": "Ants", "piazza_name": "Ants", "release": "10/16/24"}] +[{"due": "10/23/24", "link": "hw/hw07/", "name": "HW 07: Object-Oriented Programming", "piazza_name": "HW 07", "release": "10/16/24"}, {"due": "10/25/24", "link": "lab/lab08/", "name": "Lab 08: Inheritance, Linked Lists", "piazza_name": "Lab 08", "release": "10/21/24"}, {"due": "11/20/24", "link": "proj/ants/", "name": "Ants", "piazza_name": "Ants", "release": "10/16/24"}] diff --git a/disc/disc08/index.html b/disc/disc08/index.html new file mode 100644 index 000000000..a5235e408 --- /dev/null +++ b/disc/disc08/index.html @@ -0,0 +1,513 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Discussion 8 | Data C88C Fall 2024 + + + + + + +
+ +
+
+
+

+ +Discussion 8: Linked Lists + + + + + + +

+
+ + + + + + +

If there are fewer than 3 people in your group, feel free to merge your group with another group in the room.

+ +

Now switch to Pensieve:

+ +
    +
  • Everyone: Go to pensieve.co, log in with your @berkeley.edu email, and enter your group number (which was in the email that assigned you to this lab).
  • +
+ +

Once you're on Pensieve, you don't need to return to this page; Pensieve has all the same content (but more features). If for some reason Penseive doesn't work, return to this page and continue with the discussion.

+ + +

Getting Started

+ + +

Everybody say your name and your birthday and then tell the group about your +favorite birthday party you've attended (either for your birthday or someone +else's).

+ +

Pro tip: Groups tend not to ask for help unless they've been stuck for a +looooooong time. Try asking for help sooner. We're pretty helpful! You might +learn something.

+ + +

Linked Lists

+ + +

A linked list is a Link object or Link.empty.

+ +

You can mutate a Link object s in two ways:

+ +
    +
  • Change the first element with s.first = ...
  • +
  • Change the rest of the elements with s.rest = ...
  • +
+ +

You can make a new Link object by calling Link:

+ +
    +
  • Link(4) makes a linked list of length 1 containing 4.
  • +
  • Link(4, s) makes a linked list that starts with 4 followed by the elements of linked list s.
  • +
+ + + +
+ +
class Link:
+    """A linked list is either a Link object or Link.empty
+
+    >>> s = Link(3, Link(4, Link(5)))
+    >>> s.rest
+    Link(4, Link(5))
+    >>> s.rest.rest.rest is Link.empty
+    True
+    >>> s.rest.first * 2
+    8
+    >>> print(s)
+    <3 4 5>
+    """
+    empty = ()
+
+    def __init__(self, first, rest=empty):
+        assert rest is Link.empty or isinstance(rest, Link)
+        self.first = first
+        self.rest = rest
+
+    def __repr__(self):
+        if self.rest:
+            rest_repr = ', ' + repr(self.rest)
+        else:
+            rest_repr = ''
+        return 'Link(' + repr(self.first) + rest_repr + ')'
+
+    def __str__(self):
+        string = '<'
+        while self.rest is not Link.empty:
+            string += str(self.first) + ' '
+            self = self.rest
+        return string + str(self.first) + '>'
+ + +
+ +

Drawing Time. Pick a way for your group to draw diagrams. Paper, a +whiteboard, or a tablet, are all fine. If you don't have anything like that, ask +another group in the room if they have extra paper.

+ + +

Q1: Sum Two Ways

+ + +

Implement both sum_rec and sum_iter. Each one takes a linked list of numbers +s and a non-negative integer k and returns the sum of the first k elements +of s. If there are fewer than k elements in s, all of them are summed. If +k is 0 or s is empty, the sum is 0.

+ +

Use recursion to implement sum_rec. Don't use recursion to implement +sum_iter; use a while loop instead.

+ + +
+ Run in 61A Code + +
+ + + + + +
+Add s.first to the sum of the first k-1 elements in s.rest. Your base case +condition should include s is Link.empty so that you're checking whether s +is empty before ever evaluating s.first or s.rest. +
+ + + +
+Introduce a new name, such as total, then repeatedly (in a while loop) add +s.first to total, set s = s.rest to advance through the linked list, and reduce k by one. +
+ +

Discussion time: When adding up numbers, the intermediate sums depend on the +order. (1 + 3) + 5 and 1 + (3 + 5) both equal 9, but the first one makes 4 +along the way while the second makes 8 along the way. For the same linked list +s and length k, will sum_rec and sum_iter both make the same +intermediate sums along the way?

+ +
+ + +

Q2: Overlap

+ + +

Implement overlap, which takes two linked lists of numbers called s and t +that are sorted in increasing order and have no repeated elements within each +list. It returns the count of how many numbers appear in both lists.

+ +

This can be done in linear time in the combined length of s and t by +always advancing forward in the linked list whose first element is smallest +until both first elements are equal (add one to the count and advance both) or +one list is empty (time to return). Here's a +lecture video clip +about this (but the video uses Python lists instead of linked lists).

+ +

Take a vote to decide whether to use recursion or iteration. +Either way works (and the solutions are about the same complexity/difficulty).

+ + + + +
+ Run in 61A Code + +
+ + + + + +
+ +
    if s is Link.empty or t is Link.empty:
+        return 0
+    if s.first == t.first:
+        return __________________
+    elif s.first < t.first:
+        return __________________
+    elif s.first > t.first:
+        return __________________
+ + +
+ + + +
+ +
    k = 0
+    while s is not Link.empty and t is not Link.empty:
+        if s.first == t.first:
+            __________________
+        elif s.first < t.first:
+            __________________
+        elif s.first > t.first:
+            __________________
+    return k
+ + +
+ +
+ + +

Document the Occasion

+ + +

Please all fill out the attendance form (one submission per person per week).

+ + +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hw/sol-hw06/hw06.ok b/hw/sol-hw06/hw06.ok new file mode 100644 index 000000000..31ca83279 --- /dev/null +++ b/hw/sol-hw06/hw06.ok @@ -0,0 +1,24 @@ +{ + "name": "Homework 6", + "endpoint": "cal/c88c/fa24/hw06", + "src": [ + "hw06.py" + ], + "tests": { + "hw*.py": "doctest", + "tests/*.py": "ok_test" + }, + "default_tests": [ + "shuffle", + "deep_map" + ], + "protocols": [ + "restore", + "file_contents", + "analytics", + "help", + "unlock", + "grading", + "backup" + ] +} \ No newline at end of file diff --git a/hw/sol-hw06/hw06.py b/hw/sol-hw06/hw06.py new file mode 100644 index 000000000..91f10cacf --- /dev/null +++ b/hw/sol-hw06/hw06.py @@ -0,0 +1,50 @@ +def shuffle(s): + """Return a shuffled list that interleaves the two halves of s. + + >>> shuffle(range(6)) + [0, 3, 1, 4, 2, 5] + >>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] + >>> shuffle(letters) + ['a', 'e', 'b', 'f', 'c', 'g', 'd', 'h'] + >>> shuffle(shuffle(letters)) + ['a', 'c', 'e', 'g', 'b', 'd', 'f', 'h'] + >>> letters # Original list should not be modified + ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] + """ + assert len(s) % 2 == 0, 'len(seq) must be even' + half = len(s) // 2 + shuffled = [] + for i in range(half): + shuffled.append(s[i]) + shuffled.append(s[half + i]) + return shuffled + + +def deep_map(f, s): + """Replace all non-list elements x with f(x) in the nested list s. + + >>> six = [1, 2, [3, [4], 5], 6] + >>> deep_map(lambda x: x * x, six) + >>> six + [1, 4, [9, [16], 25], 36] + >>> # Check that you're not making new lists + >>> s = [3, [1, [4, [1]]]] + >>> s1 = s[1] + >>> s2 = s1[1] + >>> s3 = s2[1] + >>> deep_map(lambda x: x + 1, s) + >>> s + [4, [2, [5, [2]]]] + >>> s1 is s[1] + True + >>> s2 is s1[1] + True + >>> s3 is s2[1] + True + """ + for i in range(len(s)): + if type(s[i]) == list: + deep_map(f, s[i]) + else: + s[i] = f(s[i]) + diff --git a/hw/sol-hw06/hw06.zip b/hw/sol-hw06/hw06.zip new file mode 100644 index 000000000..4de0a2187 Binary files /dev/null and b/hw/sol-hw06/hw06.zip differ diff --git a/hw/sol-hw06/index.html b/hw/sol-hw06/index.html new file mode 100644 index 000000000..ccac83c9c --- /dev/null +++ b/hw/sol-hw06/index.html @@ -0,0 +1,414 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Homework 6 Solutions | Data C88C Fall 2024 + + + + + + +
+ +
+
+
+

+ +Homework 6 Solutions + + + + + + +

+
+ +

Solution Files

+

You can find the solutions in hw06.py.

+ + +

Required Questions

+ + +
+ + +
+ +

Getting Started Videos

+ + +

These videos may provide some helpful direction for tackling the coding +problems on this assignment.

+ +

To see these videos, you should be logged into your berkeley.edu email.

+ + +

YouTube link

+
+ +
+ + +

Q1: Shuffle

+ + +

Implement shuffle, which takes a sequence s (such as a list or range) with +an even number of elements. It returns a new list that interleaves the +elements of the first half of s with the elements of the second half. It does +not modify s.

+ +

To interleave two sequences s0 and s1 is to create a new list containing +the first element of s0, the first element of s1, the second element of +s0, the second element of s1, and so on. For example, if s0 = [1, 2, 3] +and s1 = [4, 5, 6], then interleaving s0 and s1 would result in +[1, 4, 2, 5, 3, 6].

+ + + +
def shuffle(s):
+    """Return a shuffled list that interleaves the two halves of s.
+
+    >>> shuffle(range(6))
+    [0, 3, 1, 4, 2, 5]
+    >>> letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
+    >>> shuffle(letters)
+    ['a', 'e', 'b', 'f', 'c', 'g', 'd', 'h']
+    >>> shuffle(shuffle(letters))
+    ['a', 'c', 'e', 'g', 'b', 'd', 'f', 'h']
+    >>> letters  # Original list should not be modified
+    ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
+    """
+    assert len(s) % 2 == 0, 'len(seq) must be even'
+
half = len(s) // 2 + shuffled = [] + for i in range(half): + shuffled.append(s[i]) + shuffled.append(s[half + i]) + return shuffled
+ +
+ +

Use Ok to test your code:

python3 ok -q shuffle
+ +
+ + +

Q2: Deep Map

+ + +

Definition: A nested list of numbers is a list that contains numbers and +lists. It may contain only numbers, only lists, or a mixture of both. The lists +must also be nested lists of numbers. For example: [1, [2, [3]], 4], [1, 2, +3], and [[1, 2], [3, 4]] are all nested lists of numbers.

+ +

Write a function deep_map that takes two arguments: a nested list of numbers +s and a one-argument function f. It modifies s in place by applying +f to each number within s and replacing the number with the result of +calling f on that number.

+ +

deep_map returns None and should not create any new lists.

+ +

Hint: type(a) == list will evaluate to True if a is a list.

+ + + +
def deep_map(f, s):
+    """Replace all non-list elements x with f(x) in the nested list s.
+
+    >>> six = [1, 2, [3, [4], 5], 6]
+    >>> deep_map(lambda x: x * x, six)
+    >>> six
+    [1, 4, [9, [16], 25], 36]
+    >>> # Check that you're not making new lists
+    >>> s = [3, [1, [4, [1]]]]
+    >>> s1 = s[1]
+    >>> s2 = s1[1]
+    >>> s3 = s2[1]
+    >>> deep_map(lambda x: x + 1, s)
+    >>> s
+    [4, [2, [5, [2]]]]
+    >>> s1 is s[1]
+    True
+    >>> s2 is s1[1]
+    True
+    >>> s3 is s2[1]
+    True
+    """
+
for i in range(len(s)): + if type(s[i]) == list: + deep_map(f, s[i]) + else: + s[i] = f(s[i])
+ +
+ +

Use Ok to test your code:

python3 ok -q deep_map
+ +
+ + +

Check Your Score Locally

+ +

You can locally check your score on each question of this assignment by running

+ +
python3 ok --score
+ +

This does NOT submit the assignment! When you are satisfied with your score, submit the assignment to Gradescope to receive credit for it.

+ + +

Submit Assignment

+ + +

Submit this assignment by uploading any files you've edited to the appropriate Gradescope assignment. Lab 00 has detailed instructions.

+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hw/sol-hw06/ok b/hw/sol-hw06/ok new file mode 100644 index 000000000..b84a800fe Binary files /dev/null and b/hw/sol-hw06/ok differ diff --git a/index.html b/index.html index 0aa493ced..1666a8a9e 100644 --- a/index.html +++ b/index.html @@ -148,6 +148,31 @@

Data C88C: Computational Structures in Data Science

+ + +

Announcements: Monday, October 21

+ + + +
+ + +

Announcements: Wednesday, October 16

@@ -169,7 +194,7 @@

Announcements: Wednesday, October 16

-
+

Announcements: Monday, October 14

@@ -186,7 +211,7 @@

Announcements: Monday, October 14

-
+

Announcements: Wednesday, October 9

@@ -206,7 +231,7 @@

Announcements: Wednesday, October 9

-
+

Announcements: Monday, October 7

@@ -227,7 +252,7 @@

Announcements: Monday, October 7

-
+

Announcements: Wednesday, October 2

@@ -257,7 +282,7 @@

Announcements: Wednesday, October 2

-
+

Announcements: Monday, September 30

@@ -278,7 +303,7 @@

Announcements: Monday, September 30

-
+

Announcements: Wednesday, September 25

@@ -301,7 +326,7 @@

Announcements: Wednesday, September 25

-
+

Announcements: Monday, September 23

@@ -313,7 +338,7 @@

Announcements: Monday, September 23

-
+

Announcements: Wednesday, September 18

@@ -332,7 +357,7 @@

Announcements: Wednesday, September 18

-
+

Announcements: Monday, September 16

@@ -350,7 +375,7 @@

Announcements: Monday, September 16

-
+

Announcements: Wednesday, September 11

@@ -363,7 +388,7 @@

Announcements: Wednesday, September 11

-
+

Announcements: Monday, September 9

@@ -376,7 +401,7 @@

Announcements: Monday, September 9

-
+

Announcements: Wednesday, September 4

@@ -402,7 +427,7 @@

Announcements: Wednesday, September 4

-
+

Announcements: Monday, August 26

@@ -978,13 +1003,17 @@

Calendar

-HW 06: Mutability +HW 06: Mutability
Due Wed 10/16
+ +
@@ -1123,7 +1152,7 @@

Calendar


-Lab 08: Linked Lists +Lab 08: Inheritance, Linked Lists
Due Fri 10/25 @@ -1494,7 +1523,7 @@

Policies

+ + + + + + + + + + + + + + + + + + +Lab 8: Inheritance, Linked Lists | Data C88C Fall 2024 + + + + + + +
+ +
+
+
+

+ +Lab 8: Inheritance, Linked Lists + + + + + + +

+
+ + +

Due by 11:59pm on Friday, October 25.

+ + + + + + +

Starter Files

+ +

Download lab08.zip.

+ + + + + + + + + +

Required Questions

+ + +
+ + +
+ + +

Getting Started Videos

+ + +

These videos may provide some helpful direction for tackling the coding +problems on this assignment.

+ +

To see these videos, you should be logged into your berkeley.edu email.

+ + +

YouTube link

+
+ + +

Inheritance

+ + +

Consult the drop-down if you need a refresher on Inheritance. It's +okay to skip directly to the questions and refer back +here should you get stuck. + + +

+ + + +

To avoid redefining attributes and methods for similar classes, we can write a +single base class from which more specialized classes inherit. For +example, we can write a class called Pet and define Dog as a subclass of +Pet:

+ +
class Pet:
+
+    def __init__(self, name, owner):
+        self.is_alive = True    # It's alive!!!
+        self.name = name
+        self.owner = owner
+
+    def eat(self, thing):
+        print(self.name + " ate a " + str(thing) + "!")
+
+    def talk(self):
+        print(self.name)
+
+class Dog(Pet):
+
+    def talk(self):
+        super().talk()
+        print('This Dog says woof!')
+ + + +

Inheritance represents a hierarchical relationship between two or more +classes where one class is a more specific version of the other: +a dog is a pet +(We use is a to describe this sort of relationship in OOP languages, +and not to refer to the Python is operator).

+ +

Since Dog inherits from Pet, the Dog class will also inherit the +Pet class's methods, so we don't have to redefine __init__ or eat. +We do want each Dog to talk in a Dog-specific way, +so we can override the talk method.

+ +

We can use super() to refer to the superclass of self, +and access any superclass methods as if we were an instance of the superclass. +For example, super().talk() in the Dog class will call the talk +method from the Pet class, but passing the Dog instance as the self.

+ +
+ + +

Class Practice

+ + +

Let's improve the Account class from lecture, which models a bank account +that can process deposits and withdrawals.

+ +
class Account:
+    """An account has a balance and a holder.
+
+    >>> a = Account('John')
+    >>> a.deposit(10)
+    10
+    >>> a.balance
+    10
+    >>> a.interest
+    0.02
+    >>> a.time_to_retire(10.25)  # 10 -> 10.2 -> 10.404
+    2
+    >>> a.balance                # Calling time_to_retire method should not change the balance
+    10
+    >>> a.time_to_retire(11)     # 10 -> 10.2 -> ... -> 11.040808032
+    5
+    >>> a.time_to_retire(100)
+    117
+    """
+    max_withdrawal = 10
+    interest = 0.02
+
+    def __init__(self, account_holder):
+        self.balance = 0
+        self.holder = account_holder
+
+    def deposit(self, amount):
+        self.balance = self.balance + amount
+        return self.balance
+
+    def withdraw(self, amount):
+        if amount > self.balance:
+            return "Insufficient funds"
+        if amount > self.max_withdrawal:
+            return "Can't withdraw that amount"
+        self.balance = self.balance - amount
+        return self.balance
+ + +

Q1: Retirement

+ + +

Add a time_to_retire method to the Account class. This method takes in an +amount and returns the number of years until the current balance grows to at +least amount, assuming that the bank adds the interest (calculated as the +current balance multiplied by the interest rate) to the balance at the end +of each year. Make sure you're not modifying the account's balance!

+ +

Important: Calling the time_to_retire method should not change the account balance.

+ + + +
    def time_to_retire(self, amount):
+        """Return the number of years until balance would grow to amount."""
+        assert self.balance > 0 and amount > 0 and self.interest > 0
+        "*** YOUR CODE HERE ***"
+
+ +
+ +

Use Ok to test your code:

python3 ok -q Account
+ +
+ + + + +

Q2: FreeChecking

+ + +

Implement the FreeChecking class, which is like the Account class +except that it charges a withdraw fee withdraw_fee after +withdrawing free_withdrawals number of times. +If a withdrawal is unsuccessful, no withdrawal fee will be charged, but it still counts towards the number of free +withdrawals remaining.

+ + + +
class FreeChecking(Account):
+    """A bank account that charges for withdrawals, but the first two are free!
+
+    >>> ch = FreeChecking('Jack')
+    >>> ch.balance = 20
+    >>> ch.withdraw(100)  # First one's free. Still counts as a free withdrawal even though it was unsuccessful
+    'Insufficient funds'
+    >>> ch.withdraw(3)    # Second withdrawal is also free
+    17
+    >>> ch.balance
+    17
+    >>> ch.withdraw(3)    # Now there is a fee because free_withdrawals is only 2
+    13
+    >>> ch.withdraw(3)
+    9
+    >>> ch2 = FreeChecking('John')
+    >>> ch2.balance = 10
+    >>> ch2.withdraw(3) # No fee
+    7
+    >>> ch.withdraw(3)  # ch still charges a fee
+    5
+    >>> ch.withdraw(5)  # Not enough to cover fee + withdraw
+    'Insufficient funds'
+    """
+    withdraw_fee = 1
+    free_withdrawals = 2
+
+    "*** YOUR CODE HERE ***"
+
+ +
+ +

Use Ok to test your code:

python3 ok -q FreeChecking
+ +
+ + + + +

Linked Lists

+ + +

Consult the drop-down if you need a refresher on Linked Lists. It's +okay to skip directly to the questions and refer back +here should you get stuck.

+ + + +
+ +

A linked list is a data structure for storing a sequence of values. It is more +efficient than a regular built-in list for certain operations, such as inserting +a value in the middle of a long list. Linked lists are not built in, and so we +define a class called Link to represent them. +A linked list is either a Link instance or Link.empty +(which represents an empty linked list).

+ +

A instance of Link has two instance attributes, first and rest.

+ +

The rest attribute of a Link instance should always be a linked list: either +another Link instance or Link.empty. It SHOULD NEVER be None.

+ +

To check if a linked list is empty, compare it to Link.empty. Since there is only +ever one empty list, we can use is to compare, but == would work too.

+ +
def is_empty(s):
+    """Return whether linked list s is empty."""
+    return s is Link.empty:
+ +

You can mutate a Link object s in two ways:

+ +
    +
  • Change the first element with s.first = ...
  • +
  • Change the rest of the elements with s.rest = ...
  • +
+ +

You can make a new Link object by calling Link:

+ +
    +
  • Link(4) makes a linked list of length 1 containing 4.
  • +
  • Link(4, s) makes a linked list that starts with 4 followed by the elements of linked list s.
  • +
+ +
+ + +

Q3: Without One

+ + +

Implement without, which takes a linked list s and a non-negative integer i. It returns a new linked list with all of the elements of s except the one at index i. (Assume s.first is the element at index 0.) +The original linked list s should not be changed.

+ + + +
def without(s, i):
+    """Return a new linked list like s but without the element at index i.
+
+    >>> s = Link(3, Link(5, Link(7, Link(9))))
+    >>> without(s, 0)
+    Link(5, Link(7, Link(9)))
+    >>> without(s, 2)
+    Link(3, Link(5, Link(9)))
+    >>> without(s, 4)           # There is no index 4, so all of s is retained.
+    Link(3, Link(5, Link(7, Link(9))))
+    >>> without(s, 4) is not s  # Make sure a copy is created
+    True
+    """
+    "*** YOUR CODE HERE ***"
+
+ +
+ +

Use Ok to test your code:

python3 ok -q without
+ +
+ + + + + +

Write a function duplicate_link that takes in a linked list s and a value val. +It mutates s so that each element equal to val is followed by an additional val (a duplicate copy). +It returns None. Be careful not to get into an infinite loop where you keep duplicating the new copies!

+ +

Note: In order to insert a link into a linked list, reassign the rest attribute of the Link instances that have val as their first. Try drawing out a doctest to visualize!

+ + + +
def duplicate_link(s, val):
+    """Mutates s so that each element equal to val is followed by another val.
+
+    >>> x = Link(5, Link(4, Link(5)))
+    >>> duplicate_link(x, 5)
+    >>> x
+    Link(5, Link(5, Link(4, Link(5, Link(5)))))
+    >>> y = Link(2, Link(4, Link(6, Link(8))))
+    >>> duplicate_link(y, 10)
+    >>> y
+    Link(2, Link(4, Link(6, Link(8))))
+    >>> z = Link(1, Link(2, (Link(2, Link(3)))))
+    >>> duplicate_link(z, 2) # ensures that back to back links with val are both duplicated
+    >>> z
+    Link(1, Link(2, Link(2, Link(2, Link(2, Link(3))))))
+    """
+    "*** YOUR CODE HERE ***"
+
+ +
+ +

Use Ok to test your code:

python3 ok -q duplicate_link
+ +
+ + +

Check Your Score Locally

+ +

You can locally check your score on each question of this assignment by running

+ +
python3 ok --score
+ +

This does NOT submit the assignment! When you are satisfied with your score, submit the assignment to Gradescope to receive credit for it.

+ + +

Submit Assignment

+ + +

Submit this assignment by uploading any files you've edited to the appropriate Gradescope assignment. Lab 00 has detailed instructions.

+ + +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lab/lab08/lab08.ok b/lab/lab08/lab08.ok new file mode 100644 index 000000000..c5e287973 --- /dev/null +++ b/lab/lab08/lab08.ok @@ -0,0 +1,27 @@ +{ + "name": "Lab 8", + "endpoint": "cal/c88c/fa24/lab08", + "src": [ + "lab08.py", + "classes.py" + ], + "tests": { + "lab*.py": "doctest", + "tests/*.py": "ok_test", + "classes.py": "doctest" + }, + "default_tests": [ + "Account", + "FreeChecking", + "without", + "duplicate_link" + ], + "protocols": [ + "restore", + "file_contents", + "unlock", + "grading", + "analytics", + "backup" + ] +} \ No newline at end of file diff --git a/lab/lab08/lab08.py b/lab/lab08/lab08.py new file mode 100644 index 000000000..fe79f6e9e --- /dev/null +++ b/lab/lab08/lab08.py @@ -0,0 +1,150 @@ +class Account: + """An account has a balance and a holder. + + >>> a = Account('John') + >>> a.deposit(10) + 10 + >>> a.balance + 10 + >>> a.interest + 0.02 + >>> a.time_to_retire(10.25) # 10 -> 10.2 -> 10.404 + 2 + >>> a.balance # Calling time_to_retire method should not change the balance + 10 + >>> a.time_to_retire(11) # 10 -> 10.2 -> ... -> 11.040808032 + 5 + >>> a.time_to_retire(100) + 117 + """ + max_withdrawal = 10 + interest = 0.02 + + def __init__(self, account_holder): + self.balance = 0 + self.holder = account_holder + + def deposit(self, amount): + self.balance = self.balance + amount + return self.balance + + def withdraw(self, amount): + if amount > self.balance: + return "Insufficient funds" + if amount > self.max_withdrawal: + return "Can't withdraw that amount" + self.balance = self.balance - amount + return self.balance + + def time_to_retire(self, amount): + """Return the number of years until balance would grow to amount.""" + assert self.balance > 0 and amount > 0 and self.interest > 0 + "*** YOUR CODE HERE ***" + + +class FreeChecking(Account): + """A bank account that charges for withdrawals, but the first two are free! + + >>> ch = FreeChecking('Jack') + >>> ch.balance = 20 + >>> ch.withdraw(100) # First one's free. Still counts as a free withdrawal even though it was unsuccessful + 'Insufficient funds' + >>> ch.withdraw(3) # Second withdrawal is also free + 17 + >>> ch.balance + 17 + >>> ch.withdraw(3) # Now there is a fee because free_withdrawals is only 2 + 13 + >>> ch.withdraw(3) + 9 + >>> ch2 = FreeChecking('John') + >>> ch2.balance = 10 + >>> ch2.withdraw(3) # No fee + 7 + >>> ch.withdraw(3) # ch still charges a fee + 5 + >>> ch.withdraw(5) # Not enough to cover fee + withdraw + 'Insufficient funds' + """ + withdraw_fee = 1 + free_withdrawals = 2 + + "*** YOUR CODE HERE ***" + + +def without(s, i): + """Return a new linked list like s but without the element at index i. + + >>> s = Link(3, Link(5, Link(7, Link(9)))) + >>> without(s, 0) + Link(5, Link(7, Link(9))) + >>> without(s, 2) + Link(3, Link(5, Link(9))) + >>> without(s, 4) # There is no index 4, so all of s is retained. + Link(3, Link(5, Link(7, Link(9)))) + >>> without(s, 4) is not s # Make sure a copy is created + True + """ + "*** YOUR CODE HERE ***" + + +def duplicate_link(s, val): + """Mutates s so that each element equal to val is followed by another val. + + >>> x = Link(5, Link(4, Link(5))) + >>> duplicate_link(x, 5) + >>> x + Link(5, Link(5, Link(4, Link(5, Link(5))))) + >>> y = Link(2, Link(4, Link(6, Link(8)))) + >>> duplicate_link(y, 10) + >>> y + Link(2, Link(4, Link(6, Link(8)))) + >>> z = Link(1, Link(2, (Link(2, Link(3))))) + >>> duplicate_link(z, 2) # ensures that back to back links with val are both duplicated + >>> z + Link(1, Link(2, Link(2, Link(2, Link(2, Link(3)))))) + """ + "*** YOUR CODE HERE ***" + + +class Link: + """A linked list. + + >>> s = Link(1) + >>> s.first + 1 + >>> s.rest is Link.empty + True + >>> s = Link(2, Link(3, Link(4))) + >>> s.first = 5 + >>> s.rest.first = 6 + >>> s.rest.rest = Link.empty + >>> s # Displays the contents of repr(s) + Link(5, Link(6)) + >>> s.rest = Link(7, Link(Link(8, Link(9)))) + >>> s + Link(5, Link(7, Link(Link(8, Link(9))))) + >>> print(s) # Prints str(s) + <5 7 <8 9>> + """ + empty = () + + def __init__(self, first, rest=empty): + assert rest is Link.empty or isinstance(rest, Link) + self.first = first + self.rest = rest + + def __repr__(self): + if self.rest is not Link.empty: + rest_repr = ', ' + repr(self.rest) + else: + rest_repr = '' + return 'Link(' + repr(self.first) + rest_repr + ')' + + def __str__(self): + string = '<' + while self.rest is not Link.empty: + string += str(self.first) + ' ' + self = self.rest + return string + str(self.first) + '>' + diff --git a/lab/lab08/lab08.zip b/lab/lab08/lab08.zip new file mode 100644 index 000000000..30aa5647f Binary files /dev/null and b/lab/lab08/lab08.zip differ diff --git a/lab/lab08/ok b/lab/lab08/ok new file mode 100644 index 000000000..b84a800fe Binary files /dev/null and b/lab/lab08/ok differ