In class I went over a new example Duo Slango. Its a program where you randomly generate questions to help students learn a language. This example uses a wide variety of the ADTs we learned about in class.

Duoslango which happily implements some of the great ideas in duolingo.


Data

In duoslango, you don't just learn a language... you learn the words that are most relevant to you. I ran a program that chose a few words from the CS106B website that common on the website (and less popular in the general internet).

translation.txt

good times:buenos tiempos
program:la programa
map:la mapa
neighbor:el vecino
ladder:la escalera
word:la palabra
style:el estilo
collection:la coleccion
example:el ejemplo
life:la vida
set:el conjunto
queue:la cola
stack:el monton

ADTs

Duoslango is a tour de force of a lot of the ADTs we study in CS106B. It uses Sets, Vectors, Maps. It even uses an ADT that we normally don't tell CS106B students about (but I guess I think its super neat and super useful aka worth your time) called a PriorityQueue.

A PriorityQueue is very similar in functionality to a regular Queue. The two main ways you interact with this new ADT are to enqueue and dequeue values. Its templatized just like a Queue, so for example you could declare a PriorityQueue<string> myQueue. It is different from a regular Queue in that, when you enqueue a value you give the PriorityQueue your value and a corresponding priority. Continuing with the same example you could write myQueue.enqueue("Chris", 5);. Now when you dequeue, the first element to come out will be the one with the smallest corresponding value. Check out the Priority Queue documentation. Thats all. PriorityQueues are really useful.

Solution

Here is the code in all of its glory.

/*
 * CS 106B, Chris Piech
 * This program uses several ADTs to help generate random questions that
 * will help you learn a language.
 */

#include <fstream>
#include <iostream>
#include <iomanip>
#include "console.h"
#include "hashmap.h"
#include "map.h"
#include "set.h"
#include "simpio.h"
#include "filelib.h"
#include "gwindow.h"
#include "gobjects.h"
#include "pqueue.h"
#include "ginteractors.h"
#include "gevents.h"

using namespace std;

// some constants
const int N_ANSWERS = 4;
const int N_DISTRACTORS = N_ANSWERS - 1;
const int SCREEN_WIDTH = 700;
const int SCREEN_HEIGHT = 400;

Map<string, string> loadTranslations(string fileName);
void askQuestion(GWindow & gw, string word, Vector<string> answers, int correctIndex);

int main() {
    GWindow gw(SCREEN_WIDTH, SCREEN_HEIGHT);
    gw.setTitle("Duo Slango");

    // store the translations into a map
    Map<string, string> englishToSpanish = loadTranslations("translations.txt");
    // this gets all the values in the map. In this case that is a vector of all 
    // the spanish words.
    Vector<string> allSpanish = englishToSpanish.values();

    // loops over the keys in englishToSpanish dictionary
    for(string question : englishToSpanish) {
        // 0. get answer
        string answer = englishToSpanish.get(question);

        // 1. make distractors
        Set<string> distractors;
        while(distractors.size() < N_DISTRACTORS) {
            int index = randomInteger(0, allSpanish.size() - 1);
            string dis = allSpanish[index];
            if(dis != answer) {
                distractors.add(dis);
            }
        }

        // 2. get the answers in random order
        PriorityQueue<string> answerQueue;
        answerQueue.enqueue(answer, random());
        for(string dis : distractors) {
            answerQueue.enqueue(dis, random());
        }
        int correctIndex = 0;
        Vector<string> answers;
        for(int i = 0; i < N_ANSWERS; i++) {
            string ans = answerQueue.dequeue();
            if(ans == answer) correctIndex = i;
            answers.add(ans);
        }

        // 3. does the graphics display of the question and answer
        askQuestion(gw, question, answers, correctIndex);

    }

    gw.clear();
    return 0;
}

/* Load Translations
 * This method does the file reading that we have come to learn
 * live and love. I saved the translations one per line with a
 * colon separating the spanish and the english parts. This
 * function breaks apart each line, and happily adds the two
 * to a Map from english to spanish.
 */
Map<string, string> loadTranslations(string fileName) {
    ifstream fileStream;
    openFile(fileStream, fileName);

    Map<string, string> englishToSpanish;
    string line;
    while(getline(fileStream, line)) {
        int splitIndex = line.find(":");
        string english = line.substr(0, splitIndex);
        string spanish = line.substr(splitIndex + 1);
        // this is the best line in the function
        englishToSpanish[english] = spanish;
    }

    return englishToSpanish;
}

Graphics

The main point of this demo was to use a lot of different ADTs. But I also wanted it to be pretty. Here is some graphics code that creates the nicely displayed questions. The style is rough and I didn't intent to show it to students. I included it just in case someone was interested.