I’ve been on siesta for about a month now, so today I’m starting a new series. This one is going to be an experiment in building language-learning scripts.
Picking up a second language is really friggin’ hard. There are apps, but those seem to be tailored for total beginners. I took Spanish in high school, so I remember a lot of the rules. I don’t want to build from the ground up. I want something closer to a crash course. An interactive one.
So I turned to Processing.
Target Grammar
I HATE Spanish verbs. With a fiery passion from the depths of Hell. They are the devil. Mainly because Spanish has three different verb types, differentiated by the end of the infinitive: -ar, -er, and -ir.
Conjugated Spanish verbs tell you more than English ones—not just when, they tell you who is doing the action (the subject of the sentence). This forces you to make a lot of decisions all at once, which can be a real bitch if you didn’t grow up speaking it.
You conjugate them by chopping the end of the verb off and adding specific endings. Those endings vary based on tense, person, and whether the verb is an -ar,-er, or -ir. Here’s an example with hablar, an -ar verb, in present tense:
Thankfully, this is somewhat programmable.
So here’s today’s challenge. How do we plug different -ar verbs into Processing to make it operate like flashcards to test verb vocabulary? And how do we do that with the verbs conjugated in 1st, 2nd, or 3rd person, both singular and plural?
Raw Materials
We’re going to need verbs. A lot of them.
We’ve talked about loading .csv tables into Processing before using loadTable. That’s how we’ll store the verbs and their translations. Since later we’ll want to automate some sentences, I want to start logically separating out types of verbs now.
Let’s start out with verbs that take a direct object. That means the verb is done to something. Like so:
Here’s a quick list of -AR verbs that take objects:
Stem,Translation
mir,see
llev,take
invit,invite
golpe,hit
busc,look for
dej,leave
necesit,need
olvid,forget
evit,avoid
ayud,help
am,love
You’ll want to grab those and stash them inside a .csv file, which will then need to be added to the folder with your .pde. You can also just click Sketch->Add File and select the .csv to get that ready to go.
The Script
Step 1: Pull the Data
First step in the script will be to push that CSV data into arrays for easy access.
Table table; void setup() { table = loadTable("ARVerb.csv", "header"); stem = new String[table.getRowCount()]; trans = new String[table.getRowCount()]; for(int i = 0; i<table.getRowCount(); i++) { stem[i] = table.getString(i, 0); trans[i] = table.getString(i, 1); } }
Outside of the setup brackets, you'll also want to include arrays for the verb endings. Today we will only be testing for present tense endings. Below that, I've included an array of object pronouns.
String[] ArEnd = {"o","as","a","a","amos","áis","an","I","You","He","She","We","You all","They"}; String[] DOPro = {"me", "te", "lo", "lo", "la", "nos", "os", "los", "las", "me", "you", "it", "him", "her", "us", "you all", "them (m)", "them (f)"};
That'll help us randomize things later.
Step 2: Format the Background and Text
Ok, now to display the text. A couple of quick reminders on syntax. Setting the fill immediately before the text() call will set the color. This is an RGB value with an optional alpha channel.
textSize(32); fill(R, G, B, Alpha); text("String", x, y);
If you don’t like the preset font, you can change it up with anything installed on your system. I prefer Agency text. To pick that font, go to Tools, Create Font, and then select it, as below.
You’ll need to declare yourself a PFont variable outside your Void brackets. In void setup(), you can assign the font using the Filename that was at the bottom of the “Create Font” window.
PFont Font; void setup() { Font = createFont("AgencyFB-Bold-48.vlw", 32) }
Then you can use textFont(Font); before your text to get a nice Agency Bold.
Step 3: Get Random Verbs and Pronouns
The Random function is allows you to pick a number in a range. Remember, our arrays start counting at 0, so we’ll use 1-11 to get a random verb from our CSV file (the header is in position 0).
int verb_index = int(random(1,11));
Our random verb ending will come from the ArEnd array. That has 7 options—the rest of the array is translations.
int stem_index = int(random(0,7));
The array for reference:
String[] ArEnd =
{“o”,”as”,”a”,”a”,”amos”,”áis”,”an”,”I”,”You”,”He”,”She”,”We”,”You all”,”They”}
Our random object will come from the DOPro array. This has a few more options because there are masculine and feminine alternates.
int obj_index = int(random(0,9));
The array for reference:
String[] DOPro = {“me”, “te”, “lo”, “lo”, “la”, “nos”, “os”, “los”, “las”, “me”, “you”, “it”, “him”, “her”, “us”, “you all”, “them (m)”, “them (f)”};
You may have spotted the problem here. If you randomize the verb ending and the object pronoun separately, you might end up with some really awkward sentences. Like “You all love you all” or “I invite me.” We need to exclude instances of verbs somehow referring back to the same person. There are reflexive constructions for that.
Step 4: Exclude Awkward Constructions
Awkward sentences are really only going to happen in first and second person (I/me and you/you all). You can have a third person as both your subject and object because you could be referring to different people.
To avoid those, you can plug in a Conditional Statement that says if both your object and subject is the same, change the randomized object to something different.
The || in Processing means OR and && means AND. This can be translated into “If the verb ends in -o OR -amos and the object is “me” OR “nos”, change the object to “lo.” The else if statement does the same thing, changing the object to “me” for 2nd person conflicts.
Step 5: Display the Randomized Verb + Object Pronoun
Concatenating strings in Processing can be done with plus signs. You can stitch together pieces from the object pronoun, verb, and verb ending arrays to get your randomized practice sentence. The final two numbers are the X and Y coordinates.
text(DOPro[obj_index] + " "+ stem[verb_index] + ArEnd[stem_index], 110, 90);
Then you can list the translation’s tense, subject, action, and object like so:
fill(0,0,0); textSize(20); text("Time", headerx, headery); text("Present", headerx, headery+30); text("Subject",headerx+100, headery); text(ArEnd[stem_index+7],headerx+100, headery+30); text("Action",headerx+200, headery); text(trans[verb_index],headerx+200,headery+30); text("Object",headerx+300, headery); text(DOPro[obj_index+9],headerx+300, headery+30);
Step 6: Add Some Graphics
To add a picture to your Processing sketch, start out by declaring a PImage variable. You can load the image in the setup brackets. Remember, you’ll need to add the graphic to your Processing folder in order to be able to use it. Here’s the syntax for your sketch:
PImage img; void setup() { img = loadImage("Ben.png"); image(img, x, y); }
If you look at the full sketch that I’ve posed below, you’ll see that I went a little nuts with the graphics. I’m not going to go through all of it because I’m likely going to change it later. One thing I did want to point out is that random ellipses over my eyes make it look like I’m paying attention while you click through the flash cards.



Big plans to expand on this one over the next few months.
The Complete Sketch
Table table; String[] stem; String[] trans; PFont Font; String[] ArEnd = {"o","as","a","a","amos","áis","an","I","You","He","She","We","You all","They"}; String[] ArEndPret = {"é","aste","ó","ó","amos","asteis","aron","I","You","He","She","We","You all","They"}; int headerx; int headery; PImage img; PImage mouth; PImage GG; //Verbs where it makes sense to have a person as a direct object (works with ARVerb.csv) String[] DOPro = {"me", "te", "lo", "lo", "la", "nos", "os", "los", "las", "me", "you", "it", "him", "her", "us", "you all", "them (m)", "them (f)"}; //Verbs where it only makes sense to have a thing as a direct object String[] DOProT = {"lo", "la", "los", "las"}; void setup() { img = loadImage("Ben.png"); mouth=loadImage("Mouth.png"); GG=loadImage("GifGuide.png"); size(500,500); background(0, 0, 0); fill(255,255,255); rect(10, 10, 480, 480); Font = createFont("FranklinGothic-Heavy-80.vlw", 60); table = loadTable("ARVerb.csv", "header"); stem = new String[table.getRowCount()]; trans = new String[table.getRowCount()]; for(int i = 0; i< table.getRowCount(); i++) { stem[i] = table.getString(i, 0); trans[i] = table.getString(i, 1); } textAlign(CENTER,TOP); textFont(Font); textSize(80); fill(0,0,0); text("Click to", 250, 150); text("Start", 250, 250); } void draw() { } void mouseClicked() { headerx = 90; headery = 130; fill(255,255,255); rect(10, 10, 480, 480); fill(0,0,0); rect(20, 30, 460, 80); image(GG,8,190); textFont(Font); fill(255,255,255); int stem_index = int(random(0,7)); int verb_index = int(random(1,11)); int obj_index = int(random(0,9)); //Need to script this so that it doesn't select same person for object pronoun if (((stem_index == 0)||(stem_index == 4)) && ((obj_index == 0)||(obj_index == 5))) { obj_index = 2; } else if (((stem_index == 1)||(stem_index == 5)) && ((obj_index == 1)||(obj_index == 6))) { obj_index = 0; } print(stem_index +" "); print(obj_index + " "); textAlign(CENTER,TOP); text(DOPro[obj_index] + " "+ stem[verb_index] + ArEnd[stem_index], 250, 30); fill(0,0,0); textSize(20); text("Time", headerx, headery); text("Present", headerx, headery+30); text("Subject",headerx+100, headery); text(ArEnd[stem_index+7],headerx+100, headery+30); text("Action",headerx+200, headery); text(trans[verb_index],headerx+200,headery+30); text("Object",headerx+300, headery); text(DOPro[obj_index+9],headerx+300, headery+30); //Graphics int benx = int(random(50,200)); int eyey = int(random(0,20)); int eyex = int(random(0,20)); int mouthy = int(random(0,10)); image(img,benx,200); stroke(255); fill(200,200,200); ellipse(benx+148+eyex,350+eyey,10,10); stroke(255); fill(200,200,200); ellipse(benx+83+eyex,350+eyey,10,10); stroke(20); fill(0,0,0); ellipse(benx+145+eyex,350+eyey,8,8); ellipse(benx+80+eyex,350+eyey,8,8); image(mouth,benx+95+mouthy,395); }
Interesting project.
I was contemplating a similar flashcard – based program for Urdu and Japanese languages.
I’ll certainly try out your script on these languages someday!
LikeLiked by 1 person
Thanks Visualizer! I would love to see something like this in Urdu or Japanese 🙂
LikeLiked by 1 person
Lovely bblog you have
LikeLike