ask:
The project should be a creative project that builds off or is inspired by the concepts we’ve covered this semester. You should feel free to think non-traditionally, projects do not need to be screen-based and there is no requirement to use a particular aspect of JavaScript or programming. Final projects can be collaborations with anyone in any class. Final projects can be one part of a larger project integrated with a different class.
thought:
wanted to make something that attempts to ‘learn’, being inspired from genetic algorithms in noc_class-10.
thought it’d be nice to collaborate with someone; chose aram because of his interest in ‘expressive-machines’.
outputs:
wip.
spent a little bit of time brainstorming.

was pretty sold on the idea that the computer needs to learn how to program. i’d be okay with it being a performative piece too — it has to teach itself to write a simple function of adding something.
aram is more ambitious; while i’m more conservative (keeping in mind that i have a big build for sound-studio).

after a long session going back & forth, aram & i froze on our idea:

i then began to write simple programs to demonstrate the workings of the idea.
made the basic wordle algorithm + added a dictionary for dialogues for each stage (so that the bot can shuffle between dialogues).
//260414; noc-final-wip.
let word;
/*
we use the following states:
generate -> await -> evaluate -> result -> if right: go to generate; else if wrong: go to wait.
*/
let state = "null";
let p_state = state;
//text to speech stuff:
let speech;
//dialogues are in key-value pairs.
let dialogues = {
in_generate: [
"guess this stupid word",
"hey you — guess the word i'm thinking of",
],
in_await: [],
in_evaluate: [],
all_correct: ["ok ... now"],
some_correct: [
"nooooo, try again",
"ugh no you idiot",
"god no",
"close but not quite",
],
all_wrong: [
"god you're so dumb",
"no you idiot",
"stupid shit work ... try again and do better",
],
};
let input_str;
let result = [];
let attempts = [];
function setup() {
// createCanvas(1000, 562); //in 16:9 aspect ratio.
createCanvas(800, 800); //square to handle calculations better.
speech = new p5.Speech();
//assign a random voice. we wait a little bit to run this block of code for it to get all the voices.
// setTimeout(() => {
// let all_voices = speech.voices;
// let voice = Math.floor(random(all_voices.length));
// speech.setVoice(voice);
// console.log("current voice:", all_voices[voice].name);
// }, 500);
}
function draw() {
background(0);
for (let i = 0; i < attempts.length; i++) {
attempts[i].display();
}
if (state === "generate") {
state = "temp-hold"; //temp state to avoid looping multiple times (because it's in draw).
//clear previous attempts.
attempts = [];
fetch_word().then((result) => {
word = result;
console.log("garbled word -> " + word);
});
//say dialogue:
speech.speak(random(dialogues.in_generate));
//state change:
state = "await";
//prepare input string:
input_str = "";
} else if (state === "await") {
// state = "temp-hold"; //temp state to avoid looping multiple times (because it's in draw).
show_typing(input_str);
if (input_str.length === 5) {
//when it is 5, go to evaluate.
state = "evaluate";
}
} else if (state === "evaluate") {
result = [];
for (let i = 0; i < 5; i++) {
let c = input_str[i];
if (c === word[i]) {
result[i] = "correct";
} else if (word.includes(c)) {
result[i] = "wrong-pos";
} else {
result[i] = "wrong";
}
}
console.log(result);
attempts.push(new Attempt(input_str, result));
state = "result";
} else if (state === "result") {
let correct = result.filter((r) => r === "correct").length;
let wrong_pos = result.filter((r) => r === "wrong-pos").length;
let wrong_char = result.filter((r) => r === "wrong").length;
let dominant = Math.max(correct, wrong_pos, wrong_char);
if (dominant === correct) {
speech.speak(random(dialogues.all_correct));
state = "generate";
} else if (dominant === wrong_char) {
speech.speak(random(dialogues.all_wrong));
state = "await";
} else {
speech.speak(random(dialogues.some_correct));
state = "await";
}
//reset input.
input_str = "";
}
//state change:
if (state != p_state) {
console.log("state -> " + state);
}
p_state = state;
}
//show what is being typed.
function show_typing(input_str) {
textSize(24);
textAlign(CENTER, CENTER);
for (let i = 0; i < input_str.length; i++) {
fill(255);
text(input_str[i], width / 2 - 100 + i * 50, height - 100);
}
}
function mousePressed() {
//text to speech needs a user-action to begin everything. so, we keep this to start.
state = "generate";
}
function keyPressed() {
if (state === "await") {
input_str += key;
}
}
async function fetch_word() {
let res = await fetch("https://random-word-api.herokuapp.com/word?length=5");
let data = await res.json();
word = data[0];
console.log("og word -> " + word);
//garble the word:
let chars = word.split("");
for (let i = chars.length - 1; i > 0; i--) {
let j = Math.floor(random(i + 1));
[chars[i], chars[j]] = [chars[j], chars[i]];
}
return chars.join("");
}
class Attempt {
constructor(word, result) {
this.word = word;
this.result = result;
}
display() {
let index = attempts.indexOf(this);
let y = 100 + index * 60;
textSize(32);
textAlign(CENTER, CENTER);
for (let i = 0; i < this.word.length; i++) {
let x = width / 2 - 100 + i * 50;
if (this.result[i] === "correct") fill(0, 255, 0);
else if (this.result[i] === "wrong-pos") fill(255, 200, 0);
else fill(80);
text(this.word[i], x, y);
}
}
}32 x 32 display matrix: https://cdn-learn.adafruit.com/downloads/pdf/32x16-32x32-rgb-led-matrix.pdf
got the display matrix to work, but it didn’t line up well.
