725 lines
26 KiB
Markdown
725 lines
26 KiB
Markdown
# Ghost Writing: Text, Arrays, Randomness
|
|
|
|
<p align="center">
|
|
<img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/love-letter.png" width="80%"/>
|
|
</p>
|
|
|
|
## Sketch: 2.0 Array + Index
|
|
|
|
```javascript
|
|
// Array + Index!
|
|
|
|
var NAMES = ["David", "Karin", "Sigrid", "Nanna", "Laura", "Maaike"];
|
|
var INDEX = 0;
|
|
|
|
function setup() {
|
|
createCanvas(400, 400);
|
|
}
|
|
|
|
function draw() {
|
|
background(220);
|
|
}
|
|
|
|
function keyTyped() {
|
|
if(key == 'x') {
|
|
print("Hi " + NAMES[0] + "!");
|
|
}
|
|
}
|
|
|
|
// Reference: https://p5js.org/reference/
|
|
```
|
|
|
|
### 🤔 What are indices?
|
|
|
|
```javascript
|
|
["David", "Karin", "Sigrid", "Nanna", "Laura", "Maaikke"] <--- Array (var NAMES)
|
|
| | | | | |
|
|
0 1 2 3 4 5 <--- indices (var INDEX)
|
|
```
|
|
|
|
### 📚 Exercise
|
|
|
|
1. Modify sketch 2.0 so that:
|
|
* When key ```'k'``` is typed then ```"Hi Karin!"``` is printed on the console
|
|
* When key ```'s'``` is typed then ```"Hi Sigrid!"``` is printed on the console
|
|
* When key ```'n'``` is typed then ```"Hi Nanna!"``` is printed on the console
|
|
* When key ```'m'``` is typed then ```"Hi Maaike!"``` is printed on the console
|
|
|
|
2. Modify sketch 2.0 so that:
|
|
* Every time key ```'x'``` is typed then print the name of the following person in the array (```"Hi David!"```, ```"Hi Karin!"```, ```"Hi Sigrid!"```, and so forth)
|
|
|
|
### 🤔 Who/what is "undefined"?
|
|
|
|
<p align="center">
|
|
<img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/undefined.png">
|
|
</p>
|
|
|
|
## Sketch: 2.1 Array + Index + Loop
|
|
|
|
```javascript
|
|
// Array + Index + Loop!
|
|
|
|
var NAMES = ["David", "Karin", "Sigrid", "Nanna", "Laura", "Maaike"];
|
|
var ACTIVITIES = ["piano", "tennis", "chess", "records"];
|
|
var INDEX = 0;
|
|
|
|
function setup() {
|
|
createCanvas(400, 400);
|
|
}
|
|
|
|
function draw() {
|
|
background(220);
|
|
}
|
|
|
|
function keyTyped() {
|
|
if(key == 'x') {
|
|
for(let i = 0; i < ACTIVITIES.length; i++) {
|
|
print(NAMES[INDEX] + " likes to play " + ACTIVITIES[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reference: https://p5js.org/reference/
|
|
```
|
|
|
|
### 🤔 How do for-loops work?
|
|
|
|
```javascript
|
|
for(let i = 0; i < X; i++) {
|
|
// do_somethings();
|
|
}
|
|
```
|
|
where
|
|
|
|
```javascript
|
|
let i = 0
|
|
// is the declaration and initialisation of the control variable (i)
|
|
|
|
i < X
|
|
//is the loop continuation condition: if the condition is true, the statement in the loop [do_something();] is executed, otherwise exit the loop when the condition is false
|
|
|
|
i++
|
|
//is the incremental (update) statement that is executed at the end of the loop (i.e. just after the loop statement [do_something();] as been executed)
|
|
```
|
|
|
|
### 📚 Exercise
|
|
|
|
1. Modify sketch 2.1 so that every name listed in the ```NAMES``` array have all activities listed in the ```ACTIVITIES``` array printed out on the console when key ```'x'``` is typed. The console output should look like this:
|
|
|
|
```
|
|
Karin likes to play piano
|
|
Karin likes to play tennis
|
|
Karin likes to play chess
|
|
Karin likes to play records
|
|
Sigrid likes to play piano
|
|
Sigrid likes to play tennis
|
|
Sigrid likes to play chess
|
|
Sigrid likes to play records
|
|
Nanna likes to play piano
|
|
Nanna likes to play tennis
|
|
Nanna likes to play chess
|
|
(etc.)
|
|
```
|
|
|
|
## Sketch: 2.2 Array + Index + Randomness
|
|
|
|
Randomness in p5js is based on generating a random number between 0 and a specified maximum.
|
|
|
|
Typically a random number is produced with the ```random``` function:
|
|
```javascript
|
|
random(X); // generates a random number between 0 and X
|
|
````
|
|
Here is an example of how to use the function with a variable:
|
|
```javascript
|
|
let random_number = random(10); // assign a random number between 0 and 10 to variable random_number
|
|
````
|
|
|
|
Rudimentary indeed, but there are many things we can build with this simple function!
|
|
|
|
### 🤔 How to select a random element in an array?
|
|
|
|
Since we access elements of an array with indices, we can generate a random index between 0 and the length of an array to select a random element in it.
|
|
|
|
The first problem we must solve though is that the ```random``` functions generates a "real" number (ex: 4.993319470244624, 1.9486631456631776, 7.1841821754535813, etc.) while the indices of an array are "integer" numbers (5, 2, 7, etc.). We thus need to round the "real" numbers produced by random to get an “integer” (4.993319470244624 -> 5, 1.9486631456631776 -> 2, 7.1841821754535813 -> 7).
|
|
|
|
We do this with the ```floor``` function that simply rounds a number down (4.993319470244624 -> 4) to the nearest integer. Here is an example:
|
|
|
|
```javascript
|
|
let random_number = floor(random(10)); // assign a random integer number between 0 and 10 to variable random_number
|
|
````
|
|
|
|
With this we can generate a random index (integer) between 0 and the length of a given array. Below is an example that picks a random name in the ```NAMES``` array.
|
|
|
|
```javascript
|
|
var NAMES = ["David", "Karin", "Sigrid", "Nanna", "Laura", "Maaike"];
|
|
|
|
let random_index_names = floor(random(NAMES.length));
|
|
|
|
print(NAMES[random_index_names]);
|
|
````
|
|
|
|
This snippet of code will indeed print a random name in the array ```NAMES``` each time it is executed.
|
|
|
|
But what if we would like to print a random activity from the ```ACTIVITIES``` array as well?
|
|
|
|
```javascript
|
|
var NAMES = ["David", "Karin", "Sigrid", "Nanna", "Laura", "Maaike"];
|
|
var ACTIVITIES = ["piano", "tennis", "chess", "records"];
|
|
|
|
let random_index_names = floor(random(NAMES.length));
|
|
let random_index_activities = floor(random(ACTIVITIES.length));
|
|
|
|
print(NAMES[random_index_names] + " likes to play " + ACTIVITIES[random_index_activities]);
|
|
````
|
|
|
|
This will work, but it is not "elegant"... Why?
|
|
|
|
Because we have here two variables (```random_index_names```, ```random_index_activities```) that are assigned a random value with the respective arrays' length (```NAMES.length```, ```ACTIVITIES.length```). What if we had many arrays? Then we would need as many variables as there are arrays to select from right? Consequently, the code would be very long!
|
|
|
|
To remediate this tedious need to write too much code, how about writing a custom function that selects a random element from an "generic" array? Writing custom functions is central in writing programs that are structured and “modular.”
|
|
|
|
Here is an example of a custom ```choice``` function taking a “generic” array as input ```array_to_choose_from``` and returns a randomly selected elements from this array:
|
|
|
|
```javascript
|
|
// function selecting a random element from an array
|
|
function choice(array_to_choose_from) {
|
|
let random_index = floor(random(array_to_choose_from.length));
|
|
return array_to_choose_from[random_index];
|
|
}
|
|
````
|
|
|
|
Now with this custom ```choice``` function it is rather simple to select random names or activities from the ```NAMES``` and ```ACTIVITIES``` arrays. In fact, we can start inventing sentences whose constituting phrases or words can be randomised.
|
|
|
|
Here is an example:
|
|
|
|
```javascript
|
|
// Array + Index + Randomness!
|
|
|
|
var NAMES = ["David", "Karin", "Sigrid", "Nanna", "Laura", "Maaike"];
|
|
var ACTIVITIES = ["piano", "tennis", "chess", "records"];
|
|
|
|
function setup() {
|
|
createCanvas(400, 400);
|
|
}
|
|
|
|
function draw() {
|
|
background(220);
|
|
}
|
|
|
|
// function selecting a random element from an array
|
|
function choice(array_to_choose_from) {
|
|
let random_index = floor(random(array_to_choose_from.length));
|
|
return array_to_choose_from[random_index];
|
|
}
|
|
|
|
function keyTyped() {
|
|
if(key == 'x') {
|
|
print(choice(NAMES) + " likes to play " + choice(ACTIVITIES) + " with " + choice(NAMES));
|
|
}
|
|
}
|
|
|
|
// Reference: https://p5js.org/reference/
|
|
````
|
|
|
|
### 📚 Exercise
|
|
|
|
1. Modify sketch 2.2 by adding a day of the week when an activity is taking place. For example, the output could look like this:
|
|
|
|
```
|
|
David likes to play records with Karin on Tuesday
|
|
```
|
|
|
|
2. Come up with your own random sentences! Remember you can add as many arrays to select from as you wish. Most languages are structured "systems" having nouns, verb, adjectives, adverbs, etc. Below is the output of a random sentence generator I came up with yesterday (can you guess what my code might look like?):
|
|
|
|
```
|
|
Laura wears a blue sweater when Sigrid plays tennis
|
|
Karin wears a black cap when Karin plays records
|
|
Laura wears a expensive scarf when Karin plays records
|
|
Karin wears a yellow jacket when Sigrid plays chess
|
|
David wears a ridiculous scarf when Sigrid plays records
|
|
Karin wears a black jacket when Maaike plays chess
|
|
```
|
|
|
|
## ✍️ Christopher Strachey's Love Letters
|
|
|
|
<p align="center">
|
|
<img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/Strachey-Mark1.png" width="100%"/>
|
|
</p>
|
|
|
|
So now that we have a better understanding of how arrays, indices, randomness, and functions work, let's write love letters!
|
|
|
|
One of the first non-scientific computer program that was ever written is Christopher Strachey's Love Letters program for the Manchester Mark I (so called [Baby](https://content.presspage.com/uploads/1369/1920_themanchestermk1computerbuiltbyextendingthebaby.jpg?10000)). In fact, this computer program (written in 1952 and making use of randomness) is arguably the first art-inspired program!
|
|
|
|
Christopher Strachey was/is a computer programming pioneer who worked along Alan Turing in the very early days of computing at the University of Manchester. Strachey's story is fascinating. There is a great article about [him and the love letters on Rhizome's Queer History of Computing written by Jacob Gaboury](https://rhizome.org/editorial/2013/apr/9/queer-history-computing-part-three/). For those who are interested in researching Strachey's work, please have a look at his [papers and correspondences at the Bodleain library's archive](https://archives.bodleian.ox.ac.uk/repositories/2/resources/2561).
|
|
|
|
Strachey's Love Letters have been studied before. [David Link](http://www.alpha60.de) did a colossal reconstitution of the Love Letter program on a simulator of the Manchester Mark computer. [The works was exhibited circa 2010](http://www.alpha60.de/art/love_letters/). The program does not look at all like the code we are writing now! The picture on the right side of the image above (☝️) is from Link's simulator. Early computers did not have the compilers and interpreters we have now (remember compilers and interpreters?) and thus the code was written in a rather cryptic way (believe me, way more cryptic than what we are writing now).
|
|
|
|
The program we are about to write in a "modern" computing language (i.e. javascript/p5js) is a modified version of [Nick Montfort](https://nickm.com)'s letter.py code written in python (another programming language). Montfort's letter.py was based on Noah Wardrip-Fruin's article ["Digital Media Archaeology."](https://www.degruyter.com/document/doi/10.1525/9780520948518-016/html)
|
|
|
|
|
|
### Analysing Love Letters' structure
|
|
|
|
First, let's have a look at love letters to see what they look like.
|
|
|
|
David Link has generated an [archive of simulated letters](http://www.alpha60.de/art/love_letters/archive/muc/).
|
|
|
|
Here are five examples:
|
|
|
|
```
|
|
HONEY MOPPET
|
|
YOU ARE MY AMOROUS RAPTURE.: MY KEEN LOVE. MY COVETOUS
|
|
INFATUATION THIRSTS FOR YOUR FERVENT LIKING. YOU ARE MY
|
|
CRAVING LIKING. MY CURIOUS RAPTURE FONDLY THIRSTS FOR YOUR
|
|
ANXIOUS ENCHANTMENT.
|
|
YOURS COVETOUSLY
|
|
MUC
|
|
```
|
|
|
|
```
|
|
DEAR DARLING
|
|
MY ADORABLE FELLOW FEELING WANTS YOUR SWEET INFATUATION
|
|
. MY ADORABLE ARDOUR LOVINGLY WISHES YOUR FERVOUR. MY
|
|
UNSATISFIED FELLOW FEELING EAGERLY HUNGERS FOR YOUR IMPATIENT
|
|
DESIRE. YOU ARE MY LOVING FERVOUR. MY WINNING WISH YEARNS FOR YOUR
|
|
KEEN HEART.
|
|
YOURS FERVENTLY
|
|
MUC
|
|
```
|
|
|
|
```
|
|
HONEY HONEY
|
|
MY BURNING FANCY EAGERLY TEMPTS YOUR INFATUATION.
|
|
YOU ARE MY FERVENT YEARNING. MY LIKING BEAUTIFULLY YEARNS FOR YOUR
|
|
LOVE. MY APPETITE TENDERLY CHERISHES YOUR BEAUTIFUL WISH.
|
|
YOU ARE MY EROTIC ADORATION.
|
|
YOURS SEDUCTIVELY
|
|
MUC
|
|
```
|
|
|
|
```
|
|
DARLING LOVE
|
|
YOU ARE MY AMOROUS ENCHANTMENT.: MY KEEN EAGERNESS.
|
|
YOU ARE MY DEVOTED ENCHANTMENT. MY YEARNING FERVENTLY LIKES
|
|
YOUR AMOROUS PASSION. MY EAGERNESS TENDERLY YEARNS FOR YOUR
|
|
PASSION.
|
|
YOURS ARDENTLY
|
|
MUC
|
|
```
|
|
|
|
```
|
|
HONEY LOVE
|
|
MY AVID CHARM EAGERLY LOVES YOUR LOVING ENTHUSIASM. MY
|
|
AMBITION LUSTS AFTER YOUR LOVE. MY HUNGER THIRSTS FOR YOUR
|
|
ENTHUSIASM. MY ADORABLE LONGING AFFECTIONATELY PINES FOR YOUR
|
|
DEVOTION. MY FONDNESS PASSIONATELYFTER YOUR IMPATIENT
|
|
FERVOUR.
|
|
YOURS KEENLY
|
|
MUC
|
|
```
|
|
|
|
Can you decipher certain writing patterns in the above formulations? If so, what are they?
|
|
|
|
Consider the following sentences:
|
|
|
|
```
|
|
MY YEARNING FERVENTLY LIKES YOUR AMOROUS PASSION.
|
|
MY APPETITE TENDERLY CHERISHES YOUR BEAUTIFUL WISH.
|
|
```
|
|
|
|
Are there common words here? Yes, the "MY" and "YOUR".
|
|
|
|
What about the other words, do they have something in common? Yes. They are nouns, adverbs, verbs, and adjectives. And these have indeed a particular position in each sentence.
|
|
|
|
We can thus devise a "code" of the sentences as follow:
|
|
|
|
MY + ```noun``` + ```adverb``` + ```verb``` + YOUR + ```adjective``` + ```noun``` + .
|
|
|
|
We could even add an ```adjective``` before the first ```noun``` as to make it even more "wordy" yet still valid linguistically speaking:
|
|
|
|
MY + ```adjective``` + ```noun``` + ```adverb``` + ```verb``` + YOUR + ```adjective``` + ```noun``` + .
|
|
|
|
Are there other types of sentences in the letter above?
|
|
|
|
Consider this sentence, whose structure seems to come up often:
|
|
|
|
```
|
|
YOU ARE MY AMOROUS RAPTURE.
|
|
```
|
|
|
|
Let's "code" this like:
|
|
|
|
YOU ARE MY + ```adjective``` + ```noun``` + .
|
|
|
|
There is also this small phrase:
|
|
|
|
```
|
|
MY KEEN EAGERNESS.
|
|
```
|
|
|
|
Which can be "coded" as:
|
|
|
|
MY + ```adjective``` + ```noun``` + .
|
|
|
|
|
|
So overall we have two types of sentences:
|
|
* 1x long form: MY + ```noun``` + ```adverb``` + ```verb``` + YOUR + ```adjective``` + ```noun``` + .
|
|
* 2x short forms: YOU ARE MY + ```adjective``` + ```noun``` + . / MY + ```adjective``` + ```noun``` + .
|
|
|
|
Also, in terms of composition or sentences sequencing we can notice that:
|
|
1. A letter always starts with a certain opening {HONEY or DEAR or DARLING} + {MOPPET or DARLING or HONEY or LOVE}
|
|
2. the short form MY + ```adjective``` + ```noun``` + . always follows the other short form YOU ARE MY + ```adjective``` + ```noun``` + . This short form never follows the long form.
|
|
3. short form YOU ARE MY + ```adjective``` + ```noun``` + . is never followed by the same short form YOU ARE MY + ```adjective``` + ```noun``` + .
|
|
4. A letter comprises between 4 and 5 sentences (long or short form)
|
|
5. A letter is always closed with YOURS + ```adverb```
|
|
6. A letter is always signed by MUC (which means Manchester University Computer Department)
|
|
|
|
|
|
|
|
### Reconstituting Love Letters' algorithm
|
|
|
|
Now that we have an idea of the structure of Strachey's letters, let's get to work in formalising it's algorithmic generation.
|
|
|
|
Luckily, in terms of vocabulary, we can start with Monfort's work that gives the following arrays:
|
|
|
|
```javascript
|
|
// vocabulary
|
|
const first = ['DARLING', 'DEAR', 'HONEY', 'JEWEL'];
|
|
const second = ['DUCK', 'LOVE', 'MOPPET', 'SWEETHEART'];
|
|
const adjectives = ['ADORABLE', 'AFFECTIONATE', 'AMOROUS', 'ANXIOUS', 'ARDENT', 'AVID', 'BREATHLESS', 'BURNING', 'COVETOUS', 'CRAVING', 'CURIOUS', 'DARLING', 'DEAR', 'DEVOTED', 'EAGER', 'EROTIC', 'FERVENT', 'FOND', 'IMPATIENT', 'KEEN', 'LITTLE', 'LOVEABLE', 'LOVESICK', 'LOVING', 'PASSIONATE', 'PRECIOUS', 'SWEET', 'SYMPATHETIC', 'TENDER', 'UNSATISFIED', 'WISTFUL'];
|
|
const nouns = ['ADORATION', 'AFFECTION', 'AMBITION', 'APPETITE', 'ARDOUR', 'CHARM', 'DESIRE', 'DEVOTION', 'EAGERNESS', 'ENCHANTMENT', 'ENTHUSIASM', 'FANCY', 'FELLOW FEELING', 'FERVOUR', 'FONDNESS', 'HEART', 'HUNGER', 'INFATUATION', 'LIKING', 'LONGING', 'LOVE', 'LUST', 'PASSION', 'RAPTURE', 'SYMPATHY', 'TENDERNESS', 'THIRST', 'WISH', 'YEARNING'];
|
|
const adverbs = ['AFFECTIONATELY', 'ANXIOUSLY', 'ARDENTLY', 'AVIDLY', 'BEAUTIFULLY', 'BREATHLESSLY', 'BURNINGLY', 'COVETOUSLY', 'CURIOUSLY', 'DEVOTEDLY', 'EAGERLY', 'FERVENTLY', 'FONDLY', 'IMPATIENTLY', 'KEENLY', 'LOVINGLY', 'PASSIONATELY', 'SEDUCTIVELY', 'TENDERLY', 'WINNINGLY', 'WISTFULLY'];
|
|
const verbs = ['KICKS', 'ADORES', 'ATTRACTS', 'CARES FOR', 'CHERISHES', 'CLINGS TO', 'DESIRES','HOLDS DEAR', 'HOPES FOR', 'HUNGERS FOR', 'IS WEDDED TO', 'LIKES', 'LONGS FOR', 'LOVES', 'LUSTS AFTER', 'PANTS FOR', 'PINES FOR', 'PRIZES', 'SIGHS FOR', 'TEMPTS', 'THIRSTS FOR', 'TREASURES', 'WANTS', 'WISHES', 'WOOS', 'YEARNS FOR'];
|
|
|
|
```
|
|
|
|
We can randomly select from these arrays with our ```choice``` function we devised earlier:
|
|
|
|
```javascript
|
|
// function selecting a random element from an array
|
|
function choice(array_to_choose_from) {
|
|
let random_index = floor(random(array_to_choose_from.length));
|
|
return array_to_choose_from[random_index];
|
|
}
|
|
```
|
|
|
|
With both these elements (arrays and ```choice```) we can start devising the code of the long form we identified above.
|
|
|
|
MY + ```noun``` + ```adverb``` + ```verb``` + YOUR + ```adjective``` + ```noun``` + .
|
|
|
|
Let's do this coding by devising a custom function again. Let's name it ```long```:
|
|
|
|
```javascript
|
|
// function that randomly generates a long form sentence
|
|
function long() {
|
|
return "MY " + choice(nouns) + " " + choice(adverbs) + " " + choice(verbs) + " YOUR " + choice(adjectives) + " " + choice(nouns) + ".";
|
|
}
|
|
````
|
|
|
|
This will certainly work. Yet I would like to have more variation with the sentences the function returns. As it stands it will always follow the long form structure. Is there a way we can achieve this with injecting some randomness in the structure?
|
|
|
|
How about we make ```adjective``` and ```adverb``` non mandatory, meaning they maybe there or not. What I have in mind is something like:
|
|
|
|
```javascript
|
|
// function that randomly generates a long form sentence
|
|
function long() {
|
|
return "MY " + maybe(adjectives) + " " + choice(nouns) + " " + maybe(adverbs) + " " + choice(verbs) + " YOUR " + maybe(adjectives) + " " + choice(nouns) + ".";
|
|
}
|
|
````
|
|
|
|
Notice the ```maybe``` that replaces ```choice```?
|
|
|
|
Let's write this ```maybe``` function that randomly chooses true or false if an element should be chosen from a given array, which in our case will be adjectives or adverbs.
|
|
|
|
```javascript
|
|
// function that randomly decides if an element from an array should be selected or not
|
|
function maybe(array_to_choose_from) {
|
|
// choose between true or false
|
|
if(choice([true, false])) {
|
|
// if true then return an element from the array
|
|
return choice(array_to_choose_from);
|
|
} else {
|
|
// otherwise return and empty sentence (i.e. nothing)
|
|
return "";
|
|
}
|
|
}
|
|
````
|
|
|
|
With this ```maybe``` function we now have a way to diversify the letter's sentences and thus create more variation on our generated long forms.
|
|
|
|
How about the short forms?
|
|
|
|
YOU ARE MY + ```adjective``` + ```noun``` + .
|
|
MY + ```adjective``` + ```noun``` + .
|
|
|
|
We can simply write a ```short``` function like this:
|
|
|
|
```javascript
|
|
// function that randomly generates a short form sentence
|
|
function short() {
|
|
return choice(adjectives) + ' ' + choice(nouns) + '. ';
|
|
}
|
|
```
|
|
|
|
And prefix it with YOU ARE MY or MY when we are in the midst of writing the sequence of sentences. This might become clearer below.
|
|
|
|
How about the opening? Notice the ```first``` and ```second``` arrays in the vocabulary. These are exactly what we need:
|
|
|
|
```javascript
|
|
// function that randomly an opening
|
|
function opening() {
|
|
return choice(first) + ' ' + choice(second);
|
|
}
|
|
```
|
|
|
|
And the closing?
|
|
|
|
YOURS + ```adverb```
|
|
|
|
Simple:
|
|
|
|
```javascript
|
|
// function that randomly a closing
|
|
function closing() {
|
|
return "YOURS " + choice(adverbs);
|
|
}
|
|
```
|
|
|
|
Great. Now we have most of the ingredients in place with the functions ```choice```, ```maybe```, ```long```, ```short```, ```opening```, ```closing``` right?
|
|
|
|
How about sequencing ```long``` and ```short``` forms? Remember what we observed above (i.e. a letter is 4 to 5 sentences long, short form MY + ```adjective``` + ```noun``` + . always follows the other short form, etc.)?
|
|
|
|
Following these observation here is a skeleton of an algorithm doing just that:
|
|
|
|
```javascript
|
|
// start with an empty text
|
|
var text = "";
|
|
|
|
// did we just wrote the short form with "YOU ARE MY"
|
|
let YOU_ARE = false;
|
|
|
|
// loop 5 times to generate 5 sentences
|
|
for(let i = 0; i < 5; i++) {
|
|
|
|
// choose if the next sentence is a short or long
|
|
let sentence_form = choice(['short', 'long']);
|
|
|
|
if(sentence_form == 'short') {
|
|
// there's two types of short to switch from
|
|
|
|
// the short form MY + ```adjective``` + ```noun``` + .
|
|
// always follows the YOU ARE MY + ```adjective``` + ```noun``` + . one
|
|
// and
|
|
// the short form YOU ARE MY + ```adjective``` + ```noun``` + . one
|
|
// can never follow itself
|
|
|
|
// this means we need keep track of when "YOU ARE MY" is generated
|
|
// and switch to the other form next time. This is what the variable
|
|
// YOU_ARE is doing
|
|
|
|
if(YOU_ARE) {
|
|
// the ": MY" can only follow a "YOU ARE MY"
|
|
text += ": MY " + short();
|
|
YOU_ARE = false;
|
|
} else {
|
|
text += "YOUR ARE MY " + short();
|
|
// the ": MY" can only follow a "YOU ARE MY"
|
|
YOU_ARE = true;
|
|
}
|
|
}
|
|
else if(sentence_form == 'long') {
|
|
text += long();
|
|
// make sure the next sentence is not ": MY"
|
|
YOU_ARE = false
|
|
}
|
|
}
|
|
````
|
|
|
|
|
|
|
|
### Putting it all together
|
|
|
|
Ok, let's formalise what we have sketched above and write a custom ```write_letter``` function that returns and full fleshed love letter.
|
|
|
|
```javascript
|
|
// function returning a love letter
|
|
function write_letter(){
|
|
|
|
// the letter's text we will fill in
|
|
var text = "";
|
|
|
|
// write the letter's opening
|
|
text += opening();
|
|
text += "\n"; // this is a new line!
|
|
|
|
// did we just wrote the short form with "YOU ARE MY"
|
|
let YOU_ARE = false;
|
|
|
|
// write 5 sentences
|
|
for(let i = 0; i < 5; i++) {
|
|
|
|
// choose if the next sentence is a short or long
|
|
let sentence_form = choice(['short', 'long']);
|
|
|
|
if(sentence_form == 'short') {
|
|
// there's two types of short to switch from
|
|
if(YOU_ARE) {
|
|
// the ": MY" can only follow a "YOU ARE MY"
|
|
text += ": MY " + short();
|
|
YOU_ARE = false;
|
|
} else {
|
|
text += "YOUR ARE MY " + short();
|
|
// the ": MY" can only follow a "YOU ARE MY"
|
|
YOU_ARE = true;
|
|
}
|
|
} else if(sentence_form == 'long') {
|
|
text += long();
|
|
// make sure the next sentence is not ": MY"
|
|
YOU_ARE = false;
|
|
}
|
|
}
|
|
|
|
text += "\n"; // this is a new line!
|
|
|
|
// write the letter's closing
|
|
text += " " + closing();
|
|
|
|
text += "\n"; // this is a new line!
|
|
|
|
// sign
|
|
text += "MUC";
|
|
|
|
// return the letter's text
|
|
return text;
|
|
}
|
|
```
|
|
|
|
This function follows the algorithm we wrote above and adds the opening and closing sequence.
|
|
|
|
If you followed me during the session, you should have a sketch looking more or less like the one below comprising all the functions we wrote.
|
|
|
|
Here the letter is printed when ```x```is typed.
|
|
|
|
```javascript
|
|
// Strachey's Love Letter generator!
|
|
|
|
// vocabulary
|
|
const first = ['DARLING', 'DEAR', 'HONEY', 'JEWEL'];
|
|
const second = ['DUCK', 'LOVE', 'MOPPET', 'SWEETHEART'];
|
|
const adjectives = ['ADORABLE', 'AFFECTIONATE', 'AMOROUS', 'ANXIOUS', 'ARDENT', 'AVID', 'BREATHLESS', 'BURNING', 'COVETOUS', 'CRAVING', 'CURIOUS', 'DARLING', 'DEAR', 'DEVOTED', 'EAGER', 'EROTIC', 'FERVENT', 'FOND', 'IMPATIENT', 'KEEN', 'LITTLE', 'LOVEABLE', 'LOVESICK', 'LOVING', 'PASSIONATE', 'PRECIOUS', 'SWEET', 'SYMPATHETIC', 'TENDER', 'UNSATISFIED', 'WISTFUL'];
|
|
const nouns = ['ADORATION', 'AFFECTION', 'AMBITION', 'APPETITE', 'ARDOUR', 'CHARM', 'DESIRE', 'DEVOTION', 'EAGERNESS', 'ENCHANTMENT', 'ENTHUSIASM', 'FANCY', 'FELLOW FEELING', 'FERVOUR', 'FONDNESS', 'HEART', 'HUNGER', 'INFATUATION', 'LIKING', 'LONGING', 'LOVE', 'LUST', 'PASSION', 'RAPTURE', 'SYMPATHY', 'TENDERNESS', 'THIRST', 'WISH', 'YEARNING'];
|
|
const adverbs = ['AFFECTIONATELY', 'ANXIOUSLY', 'ARDENTLY', 'AVIDLY', 'BEAUTIFULLY', 'BREATHLESSLY', 'BURNINGLY', 'COVETOUSLY', 'CURIOUSLY', 'DEVOTEDLY', 'EAGERLY', 'FERVENTLY', 'FONDLY', 'IMPATIENTLY', 'KEENLY', 'LOVINGLY', 'PASSIONATELY', 'SEDUCTIVELY', 'TENDERLY', 'WINNINGLY', 'WISTFULLY'];
|
|
const verbs = ['KICKS', 'ADORES', 'ATTRACTS', 'CARES FOR', 'CHERISHES', 'CLINGS TO', 'DESIRES','HOLDS DEAR', 'HOPES FOR', 'HUNGERS FOR', 'IS WEDDED TO', 'LIKES', 'LONGS FOR', 'LOVES', 'LUSTS AFTER', 'PANTS FOR', 'PINES FOR', 'PRIZES', 'SIGHS FOR', 'TEMPTS', 'THIRSTS FOR', 'TREASURES', 'WANTS', 'WISHES', 'WOOS', 'YEARNS FOR'];
|
|
|
|
|
|
function setup() {
|
|
createCanvas(400, 400);
|
|
}
|
|
|
|
function draw() {
|
|
background(220);
|
|
}
|
|
|
|
// function selecting a random element from an array
|
|
function choice(array_to_choose_from) {
|
|
let random_index = floor(random(array_to_choose_from.length));
|
|
return array_to_choose_from[random_index];
|
|
}
|
|
|
|
// function that randomly decides if an element from an array should be selected or not
|
|
function maybe(array_to_choose_from) {
|
|
// choose between true or false
|
|
if(choice([true, false])) {
|
|
// if true then return an element from the array
|
|
return choice(array_to_choose_from);
|
|
} else {
|
|
// otherwise return and empty sentence (i.e. nothing)
|
|
return "";
|
|
}
|
|
}
|
|
|
|
// function that randomly generates a long form sentence
|
|
function long() {
|
|
return "MY " + maybe(adjectives) + " " + choice(nouns) + " " + maybe(adverbs) + " " + choice(verbs) + " YOUR " + maybe(adjectives) + " " + choice(nouns) + ".";
|
|
}
|
|
|
|
// function that randomly generates a short form sentence
|
|
function short() {
|
|
return choice(adjectives) + ' ' + choice(nouns) + '. ';
|
|
}
|
|
|
|
// function that randomly an opening
|
|
function opening() {
|
|
return choice(first) + ' ' + choice(second);
|
|
}
|
|
|
|
// function that randomly a closing
|
|
function closing() {
|
|
return "YOURS " + choice(adverbs);
|
|
}
|
|
|
|
// function returning a love letter
|
|
function write_letter(){
|
|
var text = "";
|
|
|
|
// write opening
|
|
text += opening();
|
|
text += "\n"; // this is a new line!
|
|
|
|
let YOU_ARE = false;
|
|
// write 5 sentences
|
|
for(let i = 0; i < 5; i++) {
|
|
|
|
// choose if the next sentence is a short or long
|
|
let sentence_form = choice(['short', 'long']);
|
|
|
|
if(sentence_form == 'short') {
|
|
// there's two types of short to switch from
|
|
if(YOU_ARE) {
|
|
// the ": MY" can only follow a "YOU ARE MY"
|
|
text += ": MY " + short();
|
|
YOU_ARE = false;
|
|
} else {
|
|
text += "YOUR ARE MY " + short();
|
|
// the ": MY" can only follow a "YOU ARE MY"
|
|
YOU_ARE = true;
|
|
}
|
|
} else if(sentence_form == 'long') {
|
|
text += long();
|
|
// make sure the next sentence is not ": MY"
|
|
YOU_ARE = false;
|
|
}
|
|
}
|
|
|
|
text += "\n"; // this is a new line!
|
|
|
|
// write closing
|
|
text += " " + closing();
|
|
|
|
text += "\n"; // this is a new line!
|
|
|
|
// sign
|
|
text += "MUC";
|
|
|
|
// return the letter
|
|
return text;
|
|
}
|
|
|
|
function keyTyped() {
|
|
if(key == 'x') {
|
|
let letter = write_letter();
|
|
print(letter);
|
|
}
|
|
}
|
|
|
|
// Reference: https://p5js.org/reference/
|
|
```
|
|
|
|
The output of our program looks like this:
|
|
|
|
<p align="center">
|
|
<img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/letter-output.png"/>
|
|
</p>
|
|
|
|
|
|
There might be minor formatting issues with the code above. I'll let you fix them as you inspect what the code does when it prints to the console.
|