CS 70

Phase 1: Words That Don't Exist

  • Dog speaking

    I need a name for my startup. Something that sounds like a real word, but isn't one, so nobody else has it already!

  • Goat speaking

    Meh. Just mash the keyboard. Let's see… X-q-z-v-b-k and you're done.

  • Hedgehog speaking

    How would you pronounce that?

  • Cat speaking

    How could you expect anyone to spell that!

  • Duck speaking

    Huh. So it has to sound like English without having to be English. How would you even write a program for that?

  • LHS Cow speaking

    By counting. And by the end of this homework, your hash table will be doing the counting for you.

Companies really do make up names for things this way. George Eastman wanted a name for his camera that was short, hard to mispronounce, and like no existing word, so he made one up: Kodak.

In this homework, you'll build a program that makes up words like that, thousands of them, each one sounding like it belongs to whatever list of words you trained it on.

The Idea, by Hand

Imagine that you're writing something. Look back at the last few letters you wrote, and ask yourself: In real words, which letters came next after those letters, and how often did each option appear? Then choose the next letter based on those odds.

The number of letters you look back at is called \( k \), the context length. Here's how this approach works with \( k = 2 \) and five words to learn from,

lemon, melon, lemur, mellow, yellow

To ensure that every letter has two “letters” before it (even the first one), we put two ^ characters at the start of each word, and a $ at the end to show where the word stops. So melon becomes ^^melon$, lemur ^^lemur$, and so on.

Now slide a window that's three characters wide (i.e., the two letters of context and the letter that followed them) along every padded word, and count the three-character sequences you see. Sequences like these are called n-grams; here we have 3-grams (or trigrams).

In general, a model that looks back \( k \) letters counts n-grams of \( n = k + 1 \) characters.

Here are some of the counts:

Context What Came Next (And How Often)
^^ l (2), m (2), y (1)
el l (2: mellow, yellow), o (1: melon)
lo w (2: mellow, yellow), n (1: melon)
ow $ (2)
on $ (2: lemon, melon)

To invent a word, start with the context ^^ and roll some dice. Say you get y (a 1-in-5 chance). The context is now ^y, and the only thing that ever followed ^y was e; then ye was followed only by l. From el, roll a three-sided die: two sides say l and one says o. Say it comes up o. From lo, the die says w two times out of three and n one time out of three. Say n, and from on the only thing next is $, so we stop.

We've made yelon, which isn't any of the five words, but it sounds like it could be. Starting with m, you might make melow the same way. (Try it! What other new words could these five words make? Are there any they can never make?)

  • Hedgehog speaking

    Is this machine learning? I thought that was way beyond me.

  • LHS Cow speaking

    It's one of the oldest ideas in it! In 1913, Andrey Markov counted, by hand, which kinds of letters followed which in Pushkin's poem Eugene Onegin, and in 1948 Claude Shannon made “English-like” text this way, choosing each letter by opening a book at a random page. This kind of model is still called a Markov chain.

  • Cat speaking

    And each count is just “how many times did I see this n-gram?” That's a multiset!

  • LHS Cow speaking

    Exactly. The key is the context plus the letter that followed it (like elo), and its count is how many times that n-gram turned up. You'll be implementing HashMultiset<T> in Phases 2–7, and putting it to work in Phase 8.

A multiset is like a set, except that inserting the same key again adds one to that key's count (instead of being discarded). (Python calls this type a Counter.) With a few hundred thousand n-grams to count and look up from, we'll want our multiset code to be fast, which is where hash tables come in.

Building the Code

After cloning the homework repository on the CS 70 server, run make (or cs70-make -H) to build the provided code. It should build without any warnings.

Running wordgen

The wordgen program you just built learns from a list of words (one per line) and invents new ones. The CS 70 server has a list of about 35,000 English words in /cs70/data/ispell.words you can use for your word list; try running wordgen with

./wordgen -s 127 /cs70/data/ispell.words

You'll get ten “words”, followed by some information about what was learned. With the seed -s 127, the first few are

s
xh
dnwosjhojaain
i
cxbrxsgcwidutkk
  • Horse speaking

    Hay! Those aren't words! That's just Goat's keyboard mashing!

  • LHS Cow speaking

    That's true. You haven't built your hash table yet, so for now wordgen uses a placeholder model that doesn't count anything: it just picks letters uniformly at random. In Phase 8, you'll write the real model, and then wordgen will invent more word-like words like “irreclusted” and “befrongs”.

wordgen has a few options:

  • -k K sets the context length (the default is 3, so wordgen counts 4-grams);
  • -n N says how many words to invent (the default is 10);
  • -s SEED gives the random-number generator a seed, so using the same seed will cause wordgen to make the same words again (without the -s parameter, you'll get different words each time);
  • -d DIR says where to look for filenames without a full path (the default location to search is the directory /cs70/data/wordlists; see below).

You can also give wordgen more than one list to work on, and it will learn from all of them.

Lists to Learn From

The CS 70 server has a number of lists you can try out, stored in /cs70/data/wordlists. Each list file contains a set of words, one word per line, all lowercased. You can use one of the provided lists without specifying the full path; for example,

./wordgen adverbs

reads /cs70/data/wordlists/adverbs.txt.

Provided Word Lists

nouns, verbs, adjectives, adverbs
Common English words, sorted by part of speech.
places-hawaii, places-wales, places-maori, places-gaelic, places-us
Place names for the named locations.
companies
Names of companies listed on stock exchanges.
names-girls, names-boys, names-androgynous
U.S. first names given mostly to girls, mostly to boys, or to both.
names-surnames:
U.S. surnames.
names-fr-girls, names-fr-boys, names-fr-androgynous
French first names for girls, boys, and both.
pokemon and software
Just for fun.

You're welcome to make your own lists, too: any file with one (lowercased) word or name per line works. If you'd like to keep your lists, put them in a lists folder in your repository and run, say, ./wordgen lists/mylist.txt. (Working somewhere other than the CS 70 server? Copy /cs70/data/wordlists and point -d at your copy.)

  • Dog speaking

    So I could train it on company names and get a name for my startup!

  • Goat speaking

    Meh. Still gotta check that nobody else is using it.

Where the Lists Come From

The part-of-speech lists are derived from WordNet 3.1, © 2011 Princeton University, used under the WordNet License (/cs70/data/wordlists/LICENSE-WordNet.txt). Hawaiian place names are from the U.S. Geological Survey's Geographic Names Information System, and U.S. place names from the U.S. Census Bureau's 2024 Gazetteer Files. Welsh and Gaelic place names are from OS Open Names under the Open Government Licence v3.0: contains OS data © Crown copyright and database right 2026; contains Royal Mail data © Royal Mail copyright and database right 2026; contains National Statistics data © Crown copyright and database right 2026. Māori place names are from the New Zealand Gazetteer, Land Information New Zealand (Toitū Te Whenua), under CC BY 4.0 (changed: single words only, macrons removed). Company names are from Wikidata (CC0). First names are from the U.S. Social Security Administration's baby-name data (births from 1960 to 2022), and surnames from the 1990 U.S. Census. French first names are from Insee's Fichier des prénoms (births from 1960 to 2025), under the Licence Ouverte 2.0 (changed: accents removed, hyphenated names left out, names grouped by sex). The Pokémon and software names come from the data set Jonathan Chang built for his Spring 2026 version of this homework; Pokémon names are trademarks of Nintendo, Creatures Inc. and GAME FREAK Inc. Every list was converted to plain ASCII: accents removed, lowercased, and multiword names left out (/cs70/data/wordlists/SOURCES.txt has the details).

To Complete This Part of the Assignment…

You'll know you're done with this part of the assignment when you've done all of the following:

(When logged in, completion status appears here.)