CS61A Fall 2020 Project 2 Autocorrected Typing Software 我的思路

Project Description: https://inst.eecs.berkeley.edu/~cs61a/fa20/proj/cats/#introduction

Logistics:

The CATS GUI is an open source project on Github

You will turn in the following files: cats.py

You do not need to modify or turn in any other files to complete the project

🎉 庆祝一下写完了, 也跑过了!!!

=====================================================================
Assignment: Project 2: Cats
OK, version v1.18.1
=====================================================================

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Running tests

---------------------------------------------------------------------
Test summary
    1022 test cases passed! No cases failed.

Cannot backup when running ok with --local.

Phase 3: Multiplayer

Typing is more fun with friends! You'll now implement multiplayer functionality, so that when you run gui.py on your computer, it connects to the course server at cats.cs61a.org and looks for someone else to race against.

To race against a friend, 5 different programs will be running:

  • Your GUI, which is a program that handles all the text coloring and display in your web browser.
  • Your gui.py, which is a web server that communicates with your GUI using the code you wrote in cats.py.
  • Your opponent's gui.py.
  • Your opponent's GUI.
  • The CS 61A multiplayer server, which matches players together and passes messages around.

When you type, your GUI sends what you have typed to your gui.py server, which computes how much progress you have made and returns a progress update. It also sends a progress update to the multiplayer server, so that your opponent's GUI can display it.

Meanwhile, your GUI display is always trying to keep current by asking for progress updates from gui.py, which in turn requests that info from the multiplayer server.

Each player has an id number that is used by the server to track typing progress.

Problem 10 (2 pt)

Implement fastest_words, which returns which words each player typed fastest. This function is called once both players have finished typing. It takes in a game.

The game argument is a game data abstraction, like the one returned in Problem 9. You can access words in the game with selectors word_at, which takes in a game and the word_index (an integer). You can access the time it took any player to type any word using time.

The fastest_words function returns a list of lists of words, one list for each player, and within each list the words they typed the fastest (against all the other players). In the case of a tie, consider the earliest player in the list (the smallest player index) to be the one who typed it the fastest.

Be sure to use the accessor functions for the game data abstraction, rather than assuming a particular data format.

理解题目:

Problem 10 > Suite 1 > Case 1
(cases remaining: 102)

>>> from cats import game, fastest_words
>>> p0 = [2, 2, 3]
>>> p1 = [6, 1, 2]
>>> fastest_words(game(['What', 'great', 'luck'], [p0, p1]))
? [['What'], ['great', 'luck']]
-- OK! --

>>> p0 = [2, 2, 3]
>>> p1 = [6, 1, 3]
>>> fastest_words(game(['What', 'great', 'luck'], [p0, p1]))  # with a tie, choose the first player
? [['What', 'luck'], ['great']
-- Not quite. Try again! --

? [['What', 'luck'], ['great']]
-- OK! --

>>> p2 = [4, 3, 1]
>>> fastest_words(game(['What', 'great', 'luck'], [p0, p1, p2]))
? [['What'], ['great'], ['luck']]
-- OK! --

思路:

Accessors/selectors of game:

    • 与单词相关的:all_words(game), word_at(game, word_index)
    • 与时间相关的:all_times(game), time(game, player_num, word_index)
    • 与格式相关的:game_string(game)  # convert to string

Create a list of list as placeholder for each player: fastest_words_list = [[] for i in player_indices]

Find the fastest typer for each word

代码:

def fastest_words(game):
    """Return a list of lists of which words each player typed fastest.

    Arguments:
        game: a game data abstraction as returned by time_per_word.
    Returns:
        a list of lists containing which words each player typed fastest
    """
    player_indices = range(len(all_times(game)))  # contains an *index* for each player
    word_indices = range(len(all_words(game)))  # contains an *index* for each word
    # BEGIN PROBLEM 10
    "*** YOUR CODE HERE ***"
    fastest_words_list = [[] for i in player_indices]
    for word_index in word_indices:
        fastest_player_so_far, best_time_so_far = 0, time(game, 0, word_index)
        for player_index in player_indices:
            if time(game, player_index, word_index) < best_time_so_far:
                fastest_player_so_far, best_time_so_far = player_index, time(game, player_index, word_index)
        fastest_words_list[fastest_player_so_far].append(word_at(game, word_index))
    return fastest_words_list
    # END PROBLEM 10

Problem 9 (1 pt)

Implement time_per_word, which takes in times_per_player, a list of lists for each player with timestamps indicating when each player finished typing each word. It also takes in a list words. It returns a game with the given information.

game is a data abstraction that has a list of words and times. The times are stored as a list of lists of how long it took each player to type each word. times[i][j] indicates how long it took player i to type word j.

Timestamps are cumulative and always increasing, while the values in time are differences between consecutive timestamps. For example, if times_per_player = [[1, 3, 5], [2, 5, 6]], the corresponding time attribute of the game would be [[2, 2], [3, 1]] ((3-1)(5-3) and (5-2)(6-5)). Note that the first value of each list within times_per_player represents the initial starting time for each player.

Be sure to use the game constructor when returning a game, rather than assuming a particular data format. Read the definitions for the game constructor and selectors in cats.py to learn more about how the data abstraction is implemented.

理解题目:

Problem 9 > Suite 1 > Case 1
(cases remaining: 102)

>>> from cats import game, game_string, time_per_word, all_words, all_times, word_at, time
>>> p = [[1, 4, 6, 7], [0, 4, 6, 9]]
>>> words = ['This', 'is', 'fun']
>>> game = time_per_word(p, words)
>>> all_words(game)
? [3, 2, 1]
-- Not quite. Try again! --

? ['This', 'is', 'fun']
-- OK! --

>>> all_times(game)
? [[3, 2, 1], [4, 2, 3]]
-- OK! --

>>> p = [[0, 2, 3], [2, 4, 7]]
>>> game = time_per_word(p, ['hello', 'world'])
>>> word_at(game, 1)
? 'world'
-- OK! --

>>> all_times(game)
? [[2, 1], [2, 3]]
-- OK! --

>>> time(game, 0, 1)
? 1
-- OK! --

思路:

Data Abstraction of game (Using the above example):

constructor of game (being a [words, times] data abstraction) being time_per_word(times_per_player, words)

selector all_words(game) = game[0] = ['This', 'is', 'fun']

selector all_times(game) = game[1] = [[3, 2, 1], [4, 2, 3]]  # for both play 0 and 1

代码:

def time_per_word(times_per_player, words):
    """Given timing data, return a game data abstraction, which contains a list
    of words and the amount of time each player took to type each word.

    Arguments:
        times_per_player: A list of lists of timestamps including the time
                          the player started typing, followed by the time
                          the player finished typing each word.
        words: a list of words, in the order they are typed.
    """
    # BEGIN PROBLEM 9
    "*** YOUR CODE HERE ***"
    times = []
    for times_list in times_per_player:
        timestamps_per_player = [(times_list[i+1] - times_list[i]) for i in range(len(words))]
        times.append(timestamps_per_player)
    return game(words, times)
    # END PROBLEM 9

Problem 8 (2 pt)

Implement report_progress, which is called every time the user finishes typing a word. It takes a list of the words typed, a list of the words in the prompt, the user's user_id, and a send function that is used to send a progress report to the multiplayer server. Note that there will never be more words in typed than in prompt.

Your progress is a ratio of the words in the prompt that you have typed correctly, up to the first incorrect word, divided by the number of prompt words. For example, this example has a progress of 0.25:

report_progress(["Hello", "ths", "is"], ["Hello", "this", "is", "wrong"], ...)

Your report_progress function should return this number. Before that, it should send a message to the multiplayer server that is a two-element dictionary containing the keys 'id' and 'progress'. The user_id is passed into report_progress from the GUI. The progress is the fraction you compute. Call send on this dictionary to send it to the multiplayer server.

理解题目:

Problem 8 > Suite 1 > Case 1
(cases remaining: 101)

>>> from cats import report_progress
>>> print_progress = lambda d: print('ID:', d['id'], 'Progress:', d['progress'])
>>> typed = ['I', 'have', 'begun']
>>> prompt = ['I', 'have', 'begun', 'to', 'type']
>>> print_progress({'id': 1, 'progress': 0.6})
? ID: 1 Progress: 0.6
-- OK! --

>>> report_progress(typed, prompt, 1, print_progress) # print_progress is called on the report
(line 1)? ID: 1 Progress: 0.6
(line 2)? 0.6
-- OK! --

>>> report_progress(['I', 'begun'], prompt, 2, print_progress)
(line 1)? ID: 2 Progress: 0.25
-- Not quite. Try again! --

(line 1)? ID: 2 Progress: 0.2
(line 2)? 0.2
-- OK! --

>>> report_progress(['I', 'hve', 'begun', 'to', 'type'], prompt, 3, print_progress)
(line 1)? ID: 3 Progress: 0.2
(line 2)? 0.2
-- OK! --

代码:

def report_progress(typed, prompt, user_id, send):
    """Send a report of your id and progress so far to the multiplayer server."""
    # BEGIN PROBLEM 8
    "*** YOUR CODE HERE ***"
    # Calculate progress
    correct_words = 0.0
    for i in range(len(typed)):
        if typed[i] != prompt[i]:
            break
        else:
            correct_words += 1
    progress = correct_words / len(prompt)
    # Create our dict of the report with two keys: 'id' and 'progress
    progress_dict = {'id': user_id, 'progress': progress}
    # Send report with the 'send' function
    send(progress_dict)
    # Return progress
    return progress
    # END PROBLEM 8

Phase 2: Autocorrect

In the web-based GUI, there is an autocorrect button, but right now it doesn't do anything. Let's implement automatic correction of typos.

Whenever the user presses the space bar, if the last word they typed doesn't match a word in the dictionary but is close to one, then that similar word will be substituted for what they typed.

Problem 7 (3 pt)

Try turning on autocorrect in the GUI. Does it help you type faster? Are the corrections accurate?

You should notice that inserting a letter or leaving one out near the beginning of a word is not handled well by this diff function. Let's fix that!

Implement pawssible_patches, which is a diff function that returns the minimum number of edit operations needed to transform the start word into the goal word.

There are three kinds of edit operations:

  1. Add a letter to start,
  2. Remove a letter from start,
  3. Substitute a letter in start for another.

Each edit operation contributes 1 to the difference between two words.

>>> big_limit = 10
>>> pawssible_patches("cats", "scat", big_limit)       # cats -> scats -> scat
2
>>> pawssible_patches("purng", "purring", big_limit)   # purng -> purrng -> purring
2
>>> pawssible_patches("ckiteus", "kittens", big_limit) # ckiteus -> kiteus -> kitteus -> kittens
3

We have provided a template of an implementation in cats.py. This is a recursive function with three recursive calls. One of these recursive calls will be similar to the recursive call in shifty_shifts.

You may modify the template however you want or delete it entirely.

If the number of edits required is greater than limit, then pawssible_patches should return any number larger than limit and should minimize the amount of computation needed to do so.

These two calls to pawssible_patches should take about the same amount of time to evaluate:

>>> limit = 2
>>> pawssible_patches("ckiteus", "kittens", limit) > limit
True
>>> pawssible_patches("ckiteusabcdefghijklm", "kittensnopqrstuvwxyz", limit) > limit
True

There are no unlock cases for this problem. Make sure you understand the above test cases!

思路:

参考了https://github.com/half-dreamer/CS61A-20fa/blob/main/project/cats/cats.py的思路

才明白sample code里的add_diff, remove_diff, substitute_diff是指可以用tree recursion来解题的意思

这里的假设是一开始并不知道哪种路径是最优的,就先都求出来,再比较(again是一个升级版的HW2 Q4 count coins问题)

代码:

def pawssible_patches(start, goal, limit):
    """A diff function that computes the edit distance from START to GOAL.
    
    >>> big_limit = 10
    >>> pawssible_patches("cats", "scat", big_limit)
    2
    >>> pawssible_patches("purng", "purring", big_limit)
    2
    >>> pawssible_patches("ckiteus", "kittens", big_limit)
    3
    >>> small_limit = 3
    >>> pawssible_patches("ckiteus", "kittens", small_limit) > small_limit  # note evaluation time
    False
    >>> pawssible_patches("ckiteusabcdefghijklm", "kittensnopqrstuvwxyz", small_limit)
    4
    >>> pawssible_patches("ckiteusabcdefghijklm", "kittensnopqrstuvwxyz", small_limit)
    4
    >>> pawssible_patches("ckiteusabcdefghijklm", "kittensnopqrstuvwxyz", small_limit) > small_limit # note evaluation time
    True
    """
    # assert False, 'Remove this line'
    
    if limit < 0:  # Fill in the condition
        # BEGIN
        "*** YOUR CODE HERE ***"
        return 0  # The 1 has been reflected in the 'else' code
        # END

    elif len(start) == 0 or len(goal) == 0:  # Feel free to remove or add additional cases
        # BEGIN
        "*** YOUR CODE HERE ***"
        return len(start) + len(goal)  # One of them will be zero
        # END

    elif start[0] == goal[0]:  # No patch is needed
        return pawssible_patches(start[1:], goal[1:], limit)

    else:
        add_diff = 1 + pawssible_patches(start, goal[1:], limit - 1)  # Fill in these lines
        remove_diff = 1 + pawssible_patches(start[1:], goal, limit - 1)
        substitute_diff = 1 + pawssible_patches(start[1:], goal[1:], limit - 1)
        # BEGIN
        "*** YOUR CODE HERE ***"
        return min(add_diff, remove_diff, substitute_diff)
        # END

Problem 6 (2 pts)

Implement shifty_shifts, which is a diff function that takes two strings. It returns the minimum number of characters that must be changed in the start word in order to transform it into the goal word. If the strings are not of equal length, the difference in lengths is added to the total.

Important: You may not use while or for statements in your implementation. Use recursion.

Here are some examples:

>>> big_limit = 10
>>> shifty_shifts("nice", "rice", big_limit)    # Substitute: n -> r
1
>>> shifty_shifts("range", "rungs", big_limit)  # Substitute: a -> u, e -> s
2
>>> shifty_shifts("pill", "pillage", big_limit) # Don't substitute anything, length difference of 3.
3
>>> shifty_shifts("roses", "arose", big_limit)  # Substitute: r -> a, o -> r, s -> o, e -> s, s -> e
5
>>> shifty_shifts("rose", "hello", big_limit)   # Substitute: r->h, o->e, s->l, e->l, length difference of 1.
5

If the number of characters that must change is greater than limit, then shifty_shifts should return any number larger than limit and should minimize the amount of computation needed to do so.

These two calls to shifty_shifts should take about the same amount of time to evaluate:

>>> limit = 4
>>> shifty_shifts("roses", "arose", limit) > limit
True
>>> shifty_shifts("rosesabcdefghijklm", "arosenopqrstuvwxyz", limit) > limit
True

理解题目:

Problem 6 > Suite 1 > Case 1
(cases remaining: 104)

>>> from cats import shifty_shifts, autocorrect
>>> import tests.construct_check as test
>>> big_limit = 10
>>> shifty_shifts("car", "cad", big_limit)
? 1
-- OK! --

>>> shifty_shifts("this", "that", big_limit)
? 2
-- OK! --

>>> shifty_shifts("one", "two", big_limit)
? 3
-- OK! --

>>> shifty_shifts("from", "form", big_limit)
? 2
-- OK! --

>>> shifty_shifts("awe", "awesome", big_limit)
? 4
-- OK! --

>>> shifty_shifts("someawe", "awesome", big_limit)
? 7
-- Not quite. Try again! --

? 6
-- OK! --

>>> shifty_shifts("awful", "awesome", big_limit)
? 3
-- Not quite. Try again! --

? 5
-- OK! --

>>> shifty_shifts("awful", "awesome", 3) > 3
? True
-- OK! --

>>> shifty_shifts("awful", "awesome", 4) > 4
? True
-- OK! --

>>> shifty_shifts("awful", "awesome", 5) > 5
? False
-- OK! --

思路:

基本的递归规律: if start[0] != goal[0]: return 1 + shifty_shifts(start[1:], goal[1:], limit - 1)  # 可供交换的字母减少1

else: return 0 + shifty_shifts(start[1:], goal[1:], limit)

需要处理的特殊情况:

start比goal长,或者goal比start长:if len(start) > len(goal): return shifty_shifts(goal, start, limit) # 保证goal比start长

在此基础上,start没字符了:return len(goal)  #包含了len(goal) == 0的情况

跟踪可替换字符数(limit),如果需要替换的字符超出limit(limit < 0),就return 1,以此保证return的值比limit大(此处是大一)&尽早结束递归

注意按顺序处理这些特殊情况的话,shifty_shifts("awe", "awesome", 2)会返回4而不是3,考虑到这没增加额外的计划步骤,问题不大

代码:

def shifty_shifts(start, goal, limit):
    """A diff function for autocorrect that determines how many letters
    in START need to be substituted to create GOAL, then adds the difference in
    their lengths.
    """
    # BEGIN PROBLEM 6
    # assert False, 'Remove this line'
    if len(start) > len(goal):
        return shifty_shifts(goal, start, limit)
    if len(start) == 0:
        return len(goal)
    if start[0] != goal[0]:
        if limit == 0:
            return 1
        else:
            return 1 + shifty_shifts(start[1:], goal[1:], limit - 1)
    else:
        return 0 + shifty_shifts(start[1:], goal[1:], limit)
    # END PROBLEM 6

Problem 5 (2 pt)

Implement autocorrect, which takes a user_word, a list of all valid_words, a diff_function, and a limit.

If the user_word is contained inside the valid_words list, autocorrect returns that word. Otherwise, autocorrect returns the word from valid_words that has the lowest difference from the provided user_word based on the diff_function. However, if the lowest difference between user_word and any of the valid_words is greater than limit, then user_word is returned instead.

A diff function takes in three arguments. The first two arguments are the two strings to be compared (the user_word and a word from valid_words), and the third argument is the limit. The output of the diff function, which is a number, represents the amount of difference between the two strings.

Here is an example of a diff function that computes the minimum of 1 + limit and the difference in length between the two input strings:

>>> def length_diff(w1, w2, limit):
...     return min(limit + 1, abs(len(w2) - len(w1)))
>>> length_diff('mellow', 'cello', 10)
1
>>> length_diff('hippo', 'hippopotamus', 5)
6

Assume that user_word and all elements of valid_words are lowercase and have no punctuation.

Important: if multiple strings have the same lowest difference according to the diff_functionautocorrect should return the string that appears first in valid_words.

Hint: Try using max or min with the optional key argument.

题目理解:

Problem 5 > Suite 1 > Case 1
(cases remaining: 103)

>>> from cats import autocorrect, lines_from_file
>>> abs_diff = lambda w1, w2, limit: abs(len(w2) - len(w1))
>>> autocorrect("cul", ["culture", "cult", "cultivate"], abs_diff, 10)
? 'cult'
-- OK! --

>>> autocorrect("cul", ["culture", "cult", "cultivate"], abs_diff, 0)
? cul
-- Not quite. Try again! --

? 'cul'
-- OK! --

>>> autocorrect("wor", ["worry", "car", "part"], abs_diff, 10)
? 'worry'
-- Not quite. Try again! --

? 'wor'
-- Not quite. Try again! --

? 'car'
-- OK! --

>>> first_diff = lambda w1, w2, limit: 1 if w1[0] != w2[0] else 0
>>> autocorrect("wrod", ["word", "rod"], first_diff, 1)
? 0
-- Not quite. Try again! --

? 'word'
-- OK! --

>>> autocorrect("inside", ["idea", "inside"], first_diff, 0.5)
? 'idea'
-- Not quite. Try again! --

? 'inside'
-- OK! --

>>> autocorrect("inside", ["idea", "insider"], first_diff, 0.5)
? 'idea'
-- OK! --

>>> autocorrect("outside", ["idea", "insider"], first_diff, 0.5)
? 'outside'
-- OK! --

思路:

用老师的话说这是"the meat of the phase",也是最能体现data abstraction的地方

官方提示:min的用法:min([[1, 6], [2, 5], [3, 4]], key = lambda item: item[1]),返回[3, 4]

# Handle special case e.g. user_word already in valid words

# Find element of valid_words that has smallest difference

#    Build a list where each element is represented as [amt_of_list, valid_word], using list comprehension; call diff_function(user_word, valid_word, limit) here

#    Output 例子:[[2, 'ripe'], [2, 'spatuliform'], [2, 'serpent'], [2, 'truantship'], [1, 'epicrystalline'], [2, 'endosteitis'], [2, 'shark']]

#    Use min with key (which is essentially a lambda function) to find the smallest limit not exceeding limit

代码: 

def autocorrect(user_word, valid_words, diff_function, limit):
    """Returns the element of VALID_WORDS that has the smallest difference
    from USER_WORD. Instead returns USER_WORD if that difference is greater
    than LIMIT.
    """
    # BEGIN PROBLEM 5
    "*** YOUR CODE HERE ***"
    # Handle special case: No correction is needed
    if user_word in valid_words:
        return user_word
    # Build a list where each element is [amt_of_diff, vd]  # vd for a valid word
    diff_list = [[diff_function(user_word, vw, limit), vw] for vw in valid_words]
    if min(diff_list, key=lambda item: item[0])[0] <= limit:  # select 1st elemenet from [amt_of_diff, vd]
        return min(diff_list, key=lambda item: item[0])[1]
    else:
        return user_word  # No element meets the limit constraint
    # END PROBLEM 5

Phase 1: Typing

Problem 4 (1 pt)

Implement wpm, which computes the words per minute, a measure of typing speed, given a string typed and the amount of elapsed time in seconds. Despite its name, words per minute is not based on the number of words typed, but instead the number of characters, so that a typing test is not biased by the length of words. The formula for words per minute is the ratio of the number of characters (including spaces) typed divided by 5 (a typical word length) to the elapsed time in minutes.

For example, the string "I am glad!" contains three words and ten characters (not including the quotation marks). The words per minute calculation uses 2 as the number of words typed (because 10 / 5 = 2). If someone typed this string in 30 seconds (half a minute), their speed would be 4 words per minute.

理解题目:

Problem 4 > Suite 1 > Case 1
(cases remaining: 103)

>>> from cats import wpm
>>> wpm("12345", 3) # Note: wpm returns a float (with a decimal point)
? 20.0
-- OK! --

>>> wpm("a b c", 20)
? 3.0
-- OK! --

>>> wpm("", 10)
? 0.0
-- OK! --

代码:

def wpm(typed, elapsed):
    """Return the words-per-minute (WPM) of the TYPED string."""
    assert elapsed > 0, 'Elapsed time must be positive'
    # BEGIN PROBLEM 4
    "*** YOUR CODE HERE ***"
    # solve words / time where words = len(typed) / 5, time = elapsed / 60
    return round(len(typed) * 60 / 5 / elapsed, 2)
    # END PROBLEM 4

Problem 3 (1 pt)

Implement accuracy, which takes a typed paragraph and a reference paragraph. It returns the percentage of words in typed that exactly match the corresponding words in reference. Case and punctuation must match as well.

word in this context is any sequence of characters separated from other words by whitespace, so treat "dog;" as all one word.

If a typed word has no corresponding word in the reference because typed is longer than reference, then the extra words in typed are all incorrect.

If typed is empty, then the accuracy is zero.

理解题目:

Problem 3 > Suite 1 > Case 1
(cases remaining: 102)

>>> from cats import accuracy
>>> accuracy("12345", "12345") # Returns 100.0
? 100.0
-- OK! --

>>> accuracy("a b c", "a b c")
? 100.0
-- OK! --

>>> accuracy("a  b  c  d", "b  a  c  d")
? 50.0
-- OK! --

>>> accuracy("a b", "c d e")
? 0.0
-- OK! --

>>> accuracy("Cat", "cat") # the function is case-sensitive
? 0.0
-- OK! --

>>> accuracy("a b c d", " a d ")
? 25.0
-- OK! --

>>> accuracy("abc", " ")
? 0.0
-- OK! --

>>> accuracy(" a b \tc" , "a b c") # Tabs don't count as words
? 100.0
-- OK! --

>>> accuracy("abc", "")
? 0.0
-- OK! --

>>> accuracy("", "abc")
? 0.0
-- OK! --

>>> accuracy("cats.", "cats") # punctuation counts
? 0.0
-- OK! --

代码:

def accuracy(typed, reference):
    """Return the accuracy (percentage of words typed correctly) of TYPED
    when compared to the prefix of REFERENCE that was typed.

    >>> accuracy('Cute Dog!', 'Cute Dog.')
    50.0
    >>> accuracy('A Cute Dog!', 'Cute Dog.')
    0.0
    >>> accuracy('cute Dog.', 'Cute Dog.')
    50.0
    >>> accuracy('Cute Dog. I say!', 'Cute Dog.')
    50.0
    >>> accuracy('Cute', 'Cute Dog.')
    100.0
    >>> accuracy('', 'Cute Dog.')
    0.0
    """
    typed_words = split(typed)
    reference_words = split(reference)
    # BEGIN PROBLEM 3
    "*** YOUR CODE HERE ***"
    # check special conditions
    if len(typed_words) == 0:
        return 0.0
    counter = 0
    for i in range(min(len(typed_words), len(reference_words))):  # min to deal with the IndexError
        if typed_words[i] == reference_words[i]:
            counter += 1
    return round(counter * 100 / len(typed_words), 2)  # numerator is the number of typed_words
    # END PROBLEM 3

Problem 2 (2 pt)

Implement about, which takes a list of topic words. It returns a function which takes a paragraph and returns a boolean indicating whether that paragraph contains any of the words in topic. The returned function can be passed to choose as the select argument.

To make this comparison accurately, you will need to ignore case (that is, assume that uppercase and lowercase letters don't change what word it is) and punctuation in the paragraph.

Assume that all words in the topic list are already lowercased and do not contain punctuation.

Hint: You may use the string utility functions in utils.py.

理解题目:

Problem 2 > Suite 1 > Case 1
(cases remaining: 101)

>>> from cats import about
>>> dogs = about(['dogs', 'hounds'])
>>> dogs('A paragraph about cats.')
? False
-- OK! --

>>> dogs('A paragraph about dogs.')
? True
-- OK! --

>>> dogs('Release the Hounds!')
? True
-- OK! --

>>> dogs('"DOGS" stands for Department Of Geophysical Science.')
? True
-- OK! --

>>> dogs('Do gs and ho unds don\'t count')
? False
-- OK! --

思路:

arguments: topic, which is a list of lower-case strings such as ['dogs', 'hounds']

return: a select function, which will take a paragraph string, and return true if the paragraph contains one of the words in topic

难点:需要将paragraph转化为小写的、去掉标点符号的、用空格拆分的list

代码:

def about(topic):
    """Return a select function that returns whether a paragraph contains one
    of the words in TOPIC.

    >>> about_dogs = about(['dog', 'dogs', 'pup', 'puppy'])
    >>> choose(['Cute Dog!', 'That is a cat.', 'Nice pup!'], about_dogs, 0)
    'Cute Dog!'
    >>> choose(['Cute Dog!', 'That is a cat.', 'Nice pup.'], about_dogs, 1)
    'Nice pup.'
    """
    assert all([lower(x) == x for x in topic]), 'topics should be lowercase.'
    # BEGIN PROBLEM 2
    "*** YOUR CODE HERE ***"

    def select(s):
        s_list = split(remove_punctuation(lower(s)))
        for _ in s_list:
            if _ in topic:
                return True
        return False

    return select
    # END PROBLEM 2

Problem 1 (1 pt)

Implement choose, which selects which paragraph the user will type. It takes a list of paragraphs (strings), a select function that returns True for paragraphs that can be selected, and a non-negative index k. The choose function return's the kth paragraph for which select returns True. If no such paragraph exists (because k is too large), then choose returns the empty string.

理解题目:

Problem 1 > Suite 1 > Case 1
(cases remaining: 101)

>>> from cats import choose
>>> ps = ['short', 'really long', 'tiny']
>>> s = lambda p: len(p) <= 5
>>> choose(ps, s, 0)
? tiny
-- Not quite. Try again! --

? short
-- Not quite. Try again! --

? 'short'
-- OK! --

>>> choose(ps, s, 1)
? 'tiny'
-- OK! --

>>> choose(ps, s, 2)
? ''
-- OK! --

 思路:

paragraphs is a list of string

select is function to determine how the the valid_paragraphs are formed (select判断paragraphs里的每一个paragraph(para)是否符合规则,select返回boolean value)

kvalid_paragraphs里面的第k个元素,如果不存在,则返回empty string

 代码:

def choose(paragraphs, select, k):
    """Return the Kth paragraph from PARAGRAPHS for which SELECT called on the
    paragraph returns true. If there are fewer than K such paragraphs, return
    the empty string.
    """
    # BEGIN PROBLEM 1
    "*** YOUR CODE HERE ***"
    valid_paragraphs = []
    for para in paragraphs:
        if select(para):
            valid_paragraphs.append(para)
    return valid_paragraphs[k] if k < len(valid_paragraphs) else ""
    # END PROBLEM 1
posted @ 2023-03-21 04:53  牛油果煎蛋吐司  阅读(1174)  评论(0)    收藏  举报