Ludium
Sign In
Introduction to Computer Science using Python
Computation & Python Basics
01Algorithms as Recipes02The Six Operations Behind Every Program03Primitives, Syntax, and Semantics04Objects, Types, and Type Casting05Expressions, Operators, and Types06Assignment vs. EqualityProblem set0/10Practice∞
01Objects, Names, and Assignment02String Concatenation, Repetition, and len()03String Indexing and Slicing04String Immutability and the print() Function05User Input, Type Conversion, and f-strings06Comparisons, Booleans, and Logical Operators07Conditionals: if, elif, and elseProblem set0/10Practice∞
Control Flow & Iteration
01Conditional Branching: if, elif, and else02Iteration and the While Loop03While Loops, Counters, and Infinite Loops04While Loop Variables and Running Products05The for Loop and range()06The Accumulator Pattern and range()Problem set0/10MIT problem set0/2Practice∞
01The break Statement: Exiting a Loop Early02Looping Over Strings and the in Operator03Guess-and-Check: Exhaustive Enumeration04for Loops, Boolean Flags, and Cube Roots05Nested Loops and Brute-Force Search06Floats, Binary, and Floating-Point ErrorProblem set0/10Practice∞
Numbers & Algorithms
01Converting Integers to Binary (and Negatives)02Why 0.1 Can't Be Stored: Fractions in Binary03How Floats Are Stored, and Why You Never Use ==04Successive Approximation and the Loop That Never EndsProblem set0/10Practice∞
01Why Approximation Search Hits a Wall02Halving the Search Space at Every Step03Coding Bisection Search for Square Roots04Fixing Bisection Search for Numbers Below One05Newton-Raphson: Sliding Down the Tangent LineProblem set0/10MIT problem set0/1Practice∞
Functions & Abstraction
01Abstraction and Decomposition: Why Your Phone Is a Black Box02What a Function Really Is: The Specification and Its Four Parts03Writing Your First Function: From a Sentence to is_even04How a Function Call Becomes Its Value: Parameters vs. Arguments05Return vs. Print: The Mysterious None, and Functions in Real Code06Building sum_odds: Plan on Paper, Then Catch the Off-by-One BugProblem set0/10Practice∞
Scope & Higher-Order Functions
01return vs. print, and the Hidden None That Reveals a Bug02Turning Bisection Square Root Into a Reusable Function03Environments and Scope: The Rule Behind UnboundLocalError04A Function Is an Object: Naming, Passing, and Tracing Calls05Higher-Order Functions: Building apply(criteria, n)Problem set0/10Practice∞
Lambdas & Sequences
01Writing Anonymous Functions With Lambda02Tracing Nested Calls with the Environment Model03Tuples: An Ordered, Mixed-Type Sequence04Why Tuples Are Immutable: Nesting and Iteration05Tuple Unpacking: One-Line Swaps and Many Returns06The Star (*args), Lists, and Pythonic LoopsProblem set0/10MIT problem set0/3Practice∞
Mutating Lists
01Lists Mutate, Tuples Don't: The Name vs the Object02append: Growing a List and the None Trap03Dot Notation: Building and Filtering Lists04split and join: Converting Between Strings and Lists05sort vs. sorted: Mutate in Place or Return a New List06Writing Functions That Mutate a List In Place07Appending While Looping, and extend vs append08Reassignment vs Mutation, Proven with id()Problem set0/10MIT problem set0/1Practice∞
Aliases & Copies
01Cloning with L[:]: Mutating a List In Place02del, pop, and remove: Three Ways to Delete03The Loop That Skips: Removing While Iterating04Aliases vs Clones: Why L2 = L1 Is Not a Copy05Shallow vs Deep Copy: copy.copy and copy.deepcopyProblem set0/10Practice∞
Comprehensions, Testing & Debugging
01List Comprehensions: Your Build-a-List Loop in One Line02Reading Any Comprehension: Iterable, Expression, Condition03Default Parameters: Defaults Last, Keywords at the Call Site04Returning a Function Object: return g, Not return g()05Catching a Returned Function: Two Names, One Object06Unit, Regression, and Integration Testing07Black Box vs Glass Box: Where Test Cases Come From08Debugging by Bisection: Print Statements as EvidenceProblem set0/10Practice∞
Exceptions & Assertions
01try and except: Catching an Exception Instead of Crashing02Named Exception Handlers, else, finally, and raise03raise ValueError and assert: Enforcing Your Docstring04One Empty List, Four Designs: Crash, None, Default, AssertProblem set0/10Practice∞
Dictionaries
01Why Lists Fail at Lookup: Parallel Lists and Nested Search02Dictionaries: Custom Keys, Curly Braces, and KeyError03Mutating a Dictionary: Add, Overwrite, del, and in04keys(), values(), items(): Three Windows Into a Dictionary05Hashing and Immutable Keys: Why a List Can't Be a Key06Case Study: Building a Word Frequency Dictionary07Ranking Words by Deleting Them: The Cost of MutationProblem set0/10MIT problem set0/8Practice∞
Recursion
01Multiplying With Only Addition: From Loops to a Smaller Copy02Writing mult_recur: Base Case, Recursive Step, and the Call Stack03Divide and Conquer: The Regrade Chain and Writing power_recur04Recursive Factorial Acted Out: Environments and When to RecurseProblem set0/10Practice∞
01fib_recur: Two Recursive Calls and an Exploding Call Tree02Memoization: One Dictionary Cuts 11 Million Calls to 6503Counting Basketball Scores: Three Base Cases, Three Branches04Recursion on Lists: Peel One Element, Trust the Rest05Debugging a Recursive Search: Print, Fix, and Return Types06Nested Lists: Flatten, Search, and Why Loops Fall Short07Reversing a List Recursively: The Brackets That Make It Legal08deep_rev: One Type Test Reverses Every LayerProblem set0/10MIT problem set0/3Practice∞
Classes & Objects
01Class vs Instance: The Blueprint Behind Every Object02Choosing Data and Behavior: Elevators, Employees, and Stacks03class Coordinate(object): Implementing a Type vs Using It04The __init__ Constructor: Why Every Method Starts With self05Creating Instances: Coordinate(3, 4), Dot Notation, and Memory06Methods and the Dot Operator: distance, and How self Gets BoundProblem set0/10MIT problem set0/3Practice∞
Composition & Dunder Methods
01Data Attributes vs Parameter Names: What self Guarantees02Returning a Value vs Mutating the Object: Writing to_origin03Composition and ValueError: A Circle Made of Coordinate Objects04Before the Dot Becomes self: Writing a SimpleFraction Class05Every Operator Is a Method: Meet Python's Dunder Names06The __str__ Method: You Decide What print Shows07Overloading * and float() for a Fraction Class08Inside reduce: a Nested gcd and the Branch That Returns an intProblem set0/10Practice∞
Inheritance
01Data and Procedural Attributes: Building the Animal Class02Getters, Setters and __str__: Why the Method Outlives the Attribute03Attribute Abuse From Outside, and a Dictionary of Animal Objects04make_animals: Walking Two Lists in Step to Build a List of Objects05Hierarchies and Subclasses: The Three Moves a Subclass Can Make06class Cat(Animal): Inheriting __init__ and the Chain Python Climbs07Overriding __init__: Person Calls Animal.__init__ By Name08Student, a Subclass of a Subclass, and the Rabbit Class Variable09__add__ and __eq__ on Rabbits: Operator Overloading With Shared IDsProblem set0/10MIT problem set0/5Practice∞
An Object-Oriented Case Study
01Designing a Workout Class: __init__ Makes Five Attributes From Three02Two State Dictionaries: __dict__ on the Class and on the Object03A Getter That Estimates: Class Variables, None, and datetime04parser.parse and Where a Class Variable Actually Lives05class RunWorkout(Workout): Inheritance and super().__init__06One __str__ in the Parent, Three Kinds of Workout Printing07A Subclass Where Its Parent Goes, and Positional Argument Order08Overriding get_calories: How Python Picks Which Method Runs09__eq__ With super(), and the Last Word on Building ClassesProblem set0/10MIT problem set0/4Practice∞
Program Efficiency
01Correct Isn't Fast: time.time() and Three Functions Built to Be Measured02Timing Nine Input Sizes, and Four Reasons the Seconds Measure the Machine03One Unit per Operation: Costing Three Functions by Hand, Then in Code04Ten Times the Input, a Hundred Times the Work: Reading Operation CountsProblem set0/10Practice∞
01A Finer Clock: time.perf_counter and a Runtime That Never Moves02Which Parameter Costs Time? compound, sum_of, and One Linear Shape03Brute Force, Bisection, or in: Timing Three Searches to 100 Million04A Loop Inside a Loop: the diameter Function and Quadratic Growth05Counting Operations: Exact Formulas and a Program That Counts Itself06Order of Growth: What to Measure, Which Input, and the Worst Case07Big O: An Upper Bound That Only Has to Hold Past the Crossover08Big Theta: Bounded From Both Sides, Keep Only the Dominant Term09Reading Theta Off the Loops: Two Laws and Six Complexity ClassesProblem set0/10Practice∞

Coding challenges on mutating lists: append, sort, split/join, and object identity — MIT problem set

Problem 1append: Growing a List and the None Trap

Hangman: The Whole Game, with Help

MIT 6.100L Introduction to CS and Programming Using Python, Fall 2022 · Problem set 2, 2) The Game, with 2.4) The Game with Help — hangman · Dr. Ana Bell · CC BY-NC-SA 4.0 · MIT publishes no solution for this set; the worked solution is ours

Implement the function hangman(secret_word, with_help), which plays an interactive game of Hangman between the user and the computer: the computer has picked a secret word, and the player tries to guess its letters.

This is part 2 of MIT's Problem Set 2, Hangman. The three helper functions from part 1 — has_player_won, get_word_progress and get_available_letters, the ones you wrote in the earlier Hangman challenges — are given, complete, at the top of the starter. In designing your code, be sure you take advantage of them! You may write additional helper functions if you need them.

hangman takes two parameters: (1) secret_word, the secret word the user is to guess; and (2) with_help, a boolean representing whether or not the game is to be played with the 'help' functionality.

Important: Do NOT change the name, input parameters, or specifications of the given functions or of hangman.

The general behavior:

  1. The user is given a certain number of guesses at the beginning.
  2. The user inputs their guess, and the computer either:
    • reveals the letter if it exists in the secret word,
    • informs the user if their guess is invalid (i.e. longer than 1 character, not a letter, or has already been guessed) and does not penalize or reveal anything, or
    • penalizes the user and updates the number of guesses remaining if the guess is valid and does not exist in the secret word.
  3. The game ends when either the user guesses the secret word or the user runs out of guesses.

There is also a feature that makes the game easier: when the game is played with help, the user can input a special 'help' character, !, that reveals an unguessed letter at the expense of losing more guesses.

Game setup

  1. The secret_word along with the boolean with_help are passed into the hangman function as parameters.
  2. At the start of the game, display how many letters secret_word contains.
  3. Users start with 10 guesses.
Welcome to Hangman!
I am thinking of a word that is 4 letters long.

User-computer interaction

  1. Before each guess, you should display to the user:
    • At least three (3) dashes (e.g. --------------) to separate individual guesses from each other. Leaving out the row of dashes will cause the tests to fail.
    • How many guesses they have remaining
    • All the letters that have not yet been guessed
  2. Ask the user to supply one guess at a time, with input("Please guess a letter: ").
    • The user can type any number, symbol, or letter. Your code should only accept capital and lowercase single letters as valid guesses!
    • If the game is played with help, your code should also accept the help character (!).
  3. Immediately after each guess, you should display:
    • Whether or not the letter is in the secret word (see the example game)
    • The word with guessed letters revealed and unguessed letters as asterisks (*)

Example Game Implementation 1 (on each Please guess a letter: line, what follows the colon is the user's input):

Welcome to Hangman!
I am thinking of a word that is 4 letters long.
--------------
You have 10 guesses left.
Available letters: abcdefghijklmnopqrstuvwxyz
Please guess a letter: a
Good guess: *a**
--------------
You have 10 guesses left.
Available letters: bcdefghijklmnopqrstuvwxyz
Please guess a letter: b
Oops! That letter is not in my word: *a**
--------------
You have 9 guesses left.
Available letters: cdefghijklmnopqrstuvwxyz
Please guess a letter: 2
Oops! That is not a valid letter. Please input a letter from the alphabet: *a**
--------------
You have 9 guesses left.
Available letters: cdefghijklmnopqrstuvwxyz
Please guess a letter: foo
Oops! That is not a valid letter. Please input a letter from the alphabet: *a**
--------------
You have 9 guesses left.
Available letters: cdefghijklmnopqrstuvwxyz
Please guess a letter: +
Oops! That is not a valid letter. Please input a letter from the alphabet: *a**

Check that the user input is an alphabet letter (or the help character if the game is played with help); if it is not, tell the user they can only input a letter from the alphabet. The string methods str.isalpha() and str.lower() may help:

my_string = "HeLLoWoRlD"
print(my_string.isalpha())  # True
print(my_string.lower())  # helloworld

Guesses remaining

If the user inputs:

  1. Anything besides a letter in the alphabet (e.g. symbols or numbers), tell the user that they can only input an alphabet letter. The user loses no guesses. Note: when the game is being played with help, ! is also a valid input.
  2. A letter that has already been guessed, print a message telling the user the letter has already been guessed before. The user loses no guesses.
  3. Any letter that hasn't been guessed before and the letter is in the secret word, the user loses no guesses.
  4. Consonants: If the user inputs a consonant that hasn't been guessed and the consonant is not in the secret word, the user loses one guess.
  5. Vowels: If the user inputs a vowel that hasn't been guessed and the vowel is not in the secret word, the user loses two guesses. Vowels are a, e, i, o, and u. The letter y does not count as a vowel. Note: if a user inputs an incorrect vowel that hasn't been guessed and there is only one guess remaining, the user loses and the game is over.

Example Game Implementation 1 (continued):

You have 9 guesses left.
Available letters: bcdefghijklmnopqrtuvwxyz
Please guess a letter: t
Good guess: ta*t
--------------
You have 9 guesses left.
Available letters: bcdefghijklmnopqruvwxyz
Please guess a letter: e
Oops! That letter is not in my word: ta*t
--------------
You have 7 guesses left.
Available letters: bcdfghijklmnopqruvwxyz
Please guess a letter: e
Oops! You've already guessed that letter: ta*t

The game with help

It isn't always easy to beat the computer, especially when it selects an esoteric word. It might be nice if you could ask for some help. To do this you will create a feature of the game that works as follows:

  • If you type the special character !, the computer will provide you with one of the missing letters in the secret word at a cost of three guesses. This character should be the only non-letter input that your game accepts as a guess.
  • If you do not have at least three guesses remaining, the computer will warn you of this and let you try again. You lose no guesses.

Note: the user can play the game with this feature only when the with_help parameter is True.

As a starting point, we suggest writing a helper function that chooses a letter to reveal. It should take two arguments: the secret word and the string of available letters (from get_available_letters). This helper function should create a string choose_from containing the unique letters that are in both the secret word and the available letters. You can then use the following statements to pick a random character revealed_letter from that string:

new = random.randint(0, len(choose_from)-1)
revealed_letter = choose_from[new]

Your helper function should then return this revealed_letter. Back in your original game logic, you'll need to add a conditional statement to catch the case of the user inputting !. This case, if triggered, can add the letter returned by your helper function to letters_guessed, show the new word progress, decrement the remaining guesses by 3, and continue the gameplay.

Example Game Implementation 2:

Welcome to Hangman!
I am thinking of a word that is 7 letters long.
--------------
You currently have 10 guesses left.
Available letters: abcdefghijklmnopqrstuvwxyz
Please guess a letter: !
Letter revealed: r
r*****r
--------------
You currently have 7 guesses left.
Available letters: abcdefghijklmnopqstuvwxyz
Please guess a letter: !
Letter revealed: a
ra***ar
--------------
You currently have 4 guesses left.
Available letters: bcdefghijklmnopqstuvwxyz
Please guess a letter: !
Letter revealed: e
ra*e*ar
--------------
You currently have 1 guess left.
Available letters: bcdfghijklmnopqstuvwxyz
Please guess a letter: !
Oops! Not enough guesses left: ra*e*ar

Game termination

  1. The game ends when the user guesses all the letters in secret_word or has 0 guesses remaining.
  2. If the user wins, print a congratulatory message, and tell the user their score:
    • total_score = (guesses_remaining + 4 * number of unique letters in secret_word) + (3 * length of secret_word)
    • Example: for a game with secret word "asleep" with 6 guesses remaining, there are a total of 5 unique letters (a, s, l, e, and p). Thus, the final score is: (6 + 4 * 5) + (3 * 6) = 44.
  3. If the player runs out of guesses before completing the word, tell them they lost and reveal the word to the user when the game ends.

Example Implementation (win):

# ... snip ...
You have 5 guesses left.
Available letters: abcgnqrstuvwxyz
Please guess a letter: n
Good guess: dolphin
--------------
Congratulations, you won!
Your total score for this game is: 54

Example Implementation (lose):

# ... snip ...
You have 1 guess left.
Available Letters: ghijklmnopqrstuvwxyz
Please guess a letter: i
Oops! That letter is not in my word: e**e
--------------
Sorry, you ran out of guesses. The word was else.

# ... snip ... is not part of the output; it indicates that only part of the game is shown.

Two complete games

A winning game:

Welcome to Hangman!
I am thinking of a word that is 4 letters long.
--------------
You have 10 guesses left.
Available letters: abcdefghijklmnopqrstuvwxyz
Please guess a letter: a
Good guess: *a**
--------------
You have 10 guesses left.
Available letters: bcdefghijklmnopqrstuvwxyz
Please guess a letter: a
Oops! You've already guessed that letter: *a**
--------------
You have 10 guesses left.
Available letters: bcdefghijklmnopqrstuvwxyz
Please guess a letter: s
Oops! That letter is not in my word: *a**
--------------
You have 9 guesses left.
Available letters: bcdefghijklmnopqrtuvwxyz
Please guess a letter: +
Oops! That is not a valid letter. Please input a letter from the alphabet: *a**
--------------
You have 9 guesses left.
Available letters: bcdefghijklmnopqrtuvwxyz
Please guess a letter: t
Good guess: ta*t
--------------
You have 9 guesses left.
Available letters: bcdefghijklmnopqruvwxyz
Please guess a letter: e
Oops! That letter is not in my word: ta*t
--------------
You have 7 guesses left.
Available letters: bcdfghijklmnopqruvwxyz
Please guess a letter: c
Good guess: tact
--------------
Congratulations, you won!
Your total score for this game is: 31

A game with help:

Welcome to Hangman!
I am thinking of a word that is 7 letters long
--------------
You currently have 10 guesses left
Available letters: abcdefghijklmnopqrstuvwxyz
Please guess a letter: r
Good guess: r*****r
--------------
You currently have 10 guesses left
Available letters: abcdefghijklmnopqstuvwxyz
Please guess a letter: !
Letter revealed: c
r*c*c*r
--------------
You currently have 7 guesses left
Available letters: abdefghijklmnopqstuvwxyz
Please guess a letter: !
Letter revealed: a
rac*car
--------------
You currently have 4 guesses left
Available letters: bdefghijklmnopqstuvwxyz
Please guess a letter: e
Good guess: racecar
--------------
Congratulations, you won!
Your total score for this game is: 41

A few available-letters lines in MIT's handout have typos (a revealed or guessed letter still listed, or an unguessed one missing); they are corrected in these games.

How the tests play your game

In this editor nobody can type into input(), so the tests play the games for you. Don't call hangman yourself at the top level of your code. Each test calls hangman with a secret word and answers every input() call with the next guess from a script. It captures everything you print, splits it on each row of three or more dashes, and checks each turn for the essential content, as MIT's tester does:

  • the guesses left, written like 10 guesses (or 1 guess)
  • the available letters
  • the word progress after every guess
  • a line containing revealed after a ! that reveals a letter
  • at the end, the word score and the score when the player wins, or the secret word when they lose

The rest of the wording is up to you. A game that asks for another guess after it should have ended fails the test.

Adapted for the browser: MIT's hangman.py loads a 55,900-word list from words.txt and picks the secret word at random (load_words, choose_word). Here the tests pass the secret word in, so those helpers, the word list and the Loading word list from file... lines of MIT's example games are left out. Instead of a person typing, the tests feed input() scripted guesses. While they play a game with help, they swap random.randint for a predictable stand-in, so the game plays out the same way on every run; any missing letter your code reveals passes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import random
import string

# --- given: has_player_won, get_word_progress and get_available_letters, from part 1 of this problem set (do not edit) ---


def has_player_won(secret_word, letters_guessed):
    """
    secret_word: string, the lowercase word the user is guessing
    letters_guessed: list (of lowercase letters), the letters that have been
        guessed so far

    returns: boolean, True if all the letters of secret_word are in letters_guessed,
        False otherwise
    """
    for letter in secret_word:
        if letter not in letters_guessed:
            return False
    return True


def get_word_progress(secret_word, letters_guessed):
    """
    secret_word: string, the lowercase word the user is guessing
    letters_guessed: list (of lowercase letters), the letters that have been
        guessed so far

    returns: string, comprised of letters and asterisks (*) that represents
        which letters in secret_word have not been guessed so far
    """
    progress = ''
    for letter in secret_word:
        if letter in letters_guessed:
            progress += letter
        else:
            progress += '*'
    return progress


def get_available_letters(letters_guessed):
    """
    letters_guessed: list (of lowercase letters), the letters that have been
        guessed so far

    returns: string, comprised of letters that represents which
      letters have not yet been guessed. The letters should be returned in
      alphabetical order
    """
    available = ''
    for letter in string.ascii_lowercase:
        if letter not in letters_guessed:
            available += letter
    return available


# --- end of given code ---


def hangman(secret_word, with_help):
    """
    secret_word: string, the secret word to guess.
    with_help: boolean, this enables help functionality if true.

    Starts up an interactive game of Hangman.

    * At the start of the game, let the user know how many
      letters the secret_word contains and how many guesses they start with.

    * The user should start with 10 guesses.

    * Before each round, you should display to the user how many guesses
      they have left and the letters that the user has not yet guessed.

    * Ask the user to supply one guess per round. Remember to make
      sure that the user puts in a single letter (or help character '!'
      for with_help functionality)

    * If the user inputs an incorrect consonant, then the user loses ONE guess,
      while if the user inputs an incorrect vowel (a, e, i, o, u),
      then the user loses TWO guesses.

    * The user should receive feedback immediately after each guess
      about whether their guess appears in the computer's word.

    * After each guess, you should display to the user the
      partially guessed word so far.

    -----------------------------------
    with_help functionality
    -----------------------------------
    * If the guess is the symbol !, you should reveal to the user one of the
      letters missing from the word at the cost of 3 guesses. If the user does
      not have 3 guesses remaining, print a warning message. Otherwise, add
      this letter to their guessed word and continue playing normally.

    Follows the other limitations detailed in the problem write-up.
    """
    pass

Scratchpad— run any Python to test ideas
1
2
3
4
5
# Scratchpad — run any Python here to test ideas.
# Anything you write below stays separate from the problem's tests.

print("hello, world")

Python runtime ready in a moment
Python runtime ready in a moment
Visible tests · 4Examples — click to expand
?
MIT tester (test_play_game_short): 'hi' without help, guesses h, e, i
?
MIT tester (test_play_game_short_fail): 'hi' without help, lost after nine guesses
?
MIT tester (test_play_game_wildcard): 'wildcard' with help, two ! reveals
?
MIT's appendix winning game: 'tact' with a repeat, an invalid guess and a wrong vowel
Hidden tests · 6Bodies hidden — pass/fail only
?
Hidden test 1
?
Hidden test 2
?
Hidden test 3
?
Hidden test 4
?
Hidden test 5
?
Hidden test 6