I'm working on the coding exercise to build a text editor and add some operations like append, delete and move cursor. Can anyone please explain me why in the delete function, text.substring(cursorPosition + 1) gives me an empty string instead of 'ou!' like when I do text.substring(6).
function textEditor2_2(queries) {
// create cursurPosition, text and result text array variables
let cursorPosition = 0;
let text = "";
let textArray = [];
// append text function
const appendText = (string) => {
text += string;
cursorPosition += string.length;
textArray.push(text);
}
// move cursur position function
const moveCursor = (specifiedPosition) => {
if (specifiedPosition < 0) {
cursorPosition = 0;
} else if (specifiedPosition > cursorPosition) {
return;
} else {
cursorPosition = specifiedPosition
}
}
// delete text function
const deleteText = () => {
console.log(text) // 'Hey, you!'
console.log(cursorPosition) // '5'
console.log(text.substring(6)) // 'ou!'
console.log(text.substring(cursorPosition + 1)) // ''
text = string.substring(0, cursorPosition) + string.substring(cursorPosition + 1);
textArray.push(text);
}
// iterate thru queries and apply callback based on operation type
queries.forEach(operation => {
if (operation[0] === 'APPEND') {
appendText(operation[1])
} else if (operation[0] === 'MOVE') {
moveCursor(operation[1])
} else if (operation[0] === 'DELETE') {
deleteText()
}
})
return textArray;
}
let queriesSample = [
["APPEND", "Hey, you!"],
["MOVE", "5"],
["DELETE"],
]
console.log(textEditor2_2(queriesSample));
I just started learning Javascript this week to write a wordgame to help my kid. The idea is that it should show and play a random word from a dictionary, she writes it the entry is checked and random gets deleted from the dictionary. The game continues until the dictionary length===0, and the wrong words are summarised if there are any. Somehow, the program is unpredictable, it literally works 1 in 7 times, and I can't understand why. Giving the following error:
Uncaught (in promise) TypeError: Cannot read property 'word' of undefined
I do think it has something the do with the way I delete random, or check if the dictonary is empty. Underneath the code is pasted links to screenshots of the console.log; 1 is the result of the program completely finishing, the other of one that doesn't. The interesting thing is that the error also is unpredictable, sometimes after just 1 word, sometimes 2. The only thing I do is refresh the page and the program behaves differently. I also tried running it on different browsers.
Being a total noob, I was quite surprised that I get different results while trying to do the same thing. It was quite frustrating to find out what was happening :-)
<html>
<head>
<title>Aliyah's dictee spel</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="header">
<h1>Hej! Velkommen til Aliyahs diktee!</h1>
</div>
<div id="Random_word">
<h2 id="Empty">Click start to start</h2>
<button id="startGame">Start</button>
<button id="editList">Edit word list</button>
<h3 id="correctWord"></h3>
</div>
<script>
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
var dictionary = [
{ word: "apple",
audio: 'apple.mp3',
},
{
word: "baby",
audio: 'baby.mp3',
},
{
word: "car",
audio: 'car.mp3'
}
];
var wordsWrong = [];
var wordsCorrectCounter = 0;
var wordsWrongCounter = 0;
//var cheer = new Audio('correct.mp3');
//var boo = new Audio('wrong.mp3');
function editWords(){
console.log("under construction");
};
function startGame(){
document.getElementById("startGame").remove();
document.getElementById("editList").remove();
newWord(dictionary);
};
async function newWord(dictionary)
{
if (Object.entries(dictionary).length === 0){
endGame();
}
else {
var random = Math.floor(Math.random() * dictionary.length);
document.getElementById("Empty").innerHTML = dictionary[random].word;
console.log(dictionary[random].word);
console.log(dictionary);
await sleep(2000);
document.getElementById("Empty").innerHTML = " ";
createInputField(random);
}
};
function createInputField(random)
{
var entry = document.createElement("input");
entry.setAttribute("type", "text");
entry.id = "inputfield";
document.body.appendChild(entry);
let btn = document.createElement("button");
btn.id = "okBtn";
btn.innerHTML = "ok";
btn.type = "submit";
btn.name = "answerBtn";
document.body.appendChild(btn);
document.getElementById("okBtn").addEventListener("click", () => checkAnswer(random, entry.value));
};
function checkAnswer(random, entry)
{var answer = entry.toLowerCase();
if (dictionary[random].word == answer){
//cheer.play();
wordsCorrectCounter += 1;
document.getElementById("okBtn").remove();
document.getElementById("inputfield").remove();
delete dictionary[random];
console.log(dictionary);
newWord(dictionary);
}
else{
wordsWrong.push(dictionary[random].word);
wordsWrongCounter += 1;
document.getElementById("okBtn").remove();
document.getElementById("inputfield").remove();
//boo.play();
document.body.style.backgroundColor = "red";
document.getElementById("correctWord").innerHTML = dictionary[random].word;
let btn = document.createElement("button");
btn.id = "contBtn";
btn.innerHTML = "Continue";
btn.type = "submit";
btn.name = "continueBtn";
document.body.appendChild(btn);
document.getElementById("contBtn").addEventListener("click", () => wrongAnswer(random));
}
};
function wrongAnswer(random){
document.getElementById("contBtn").remove();
document.getElementById("correctWord").innerHTML = " "
delete dictionary[random];
newWord(dictionary);
};
function endGame()
{
document.getElementById("Empty").innerHTML = "you are done!" + "Correct: " + wordsCorrectCounter + "Wrong: " + wordsWrongCounter
+ "These words were wrong: " + wordsWrong;
};
function Refresh() {
window.parent.location = window.parent.location.href;
};
document.getElementById("startGame").addEventListener("click", () => startGame());
</script>
</body>
</html>
Console.log when program is able to finish
Console.log when program gets stuck
Short Explain
dictionary = [
{ word: "apple", audio: 'apple.mp3', },
{ word: "baby", audio: 'baby.mp3', },
{ word: "car", audio: 'car.mp3' }
];
you genrate a random index let's say 2
you can jsut use 2 and extract the word by dictionary[2].word
if you pass the random index
it could be invalid after you remove item from dictionary
which is why you get the error
for example:
you have the old random index 2
but you have already remove the item
the current dictionary is
dictionary = [
{ word: "apple", audio: 'apple.mp3', },
{ word: "baby", audio: 'baby.mp3', },
];
and then you try to access dictionary[2]
which doesn't exist anymore
Remove Item from Array
you can use Array.filter()
let dictionary = [
{ word: "apple", audio: 'apple.mp3', },
{ word: "baby", audio: 'baby.mp3', },
{ word: "car", audio: 'car.mp3' }
];
// only the item that item.word != "apple" will pass this
dictionary = dictionary.filter(item => item.word != "apple");
console.log(dictionary);
String and Variable
Template literals (Template strings)
use this to set string, it more readable & easier to edit
you can put variable in it by use ${variable_name}
example:
let x = "test";
console.log(`this is a ${x}`);
Find specific item in Array
I see you have audio file
If you need to find the item in dictionary
You can use Array.find()
Because we only pass word now
We can use it to find it
Let's say you want to find audio for apple
It will be like this
let dictionary = [
{ word: "apple", audio: 'apple.mp3', },
{ word: "baby", audio: 'baby.mp3', },
{ word: "car", audio: 'car.mp3' }
],
target = dictionary.find(item => item.word=="apple"),
audio = false;
if(target) audio = target.audio;
console.log(audio);
Complete Answer
I have add the comment in, you can check it
<html>
<head>
<title>Aliyah's dictee spel</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="header">
<h1>Hej! Velkommen til Aliyahs diktee!</h1>
</div>
<div id="Random_word">
<h2 id="Empty">Click start to start</h2>
<button id="startGame">Start</button>
<button id="editList">Edit word list</button>
<h3 id="correctWord"></h3>
</div>
<script>
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
var dictionary = [
{ word: "apple", audio: 'apple.mp3', },
{ word: "baby", audio: 'baby.mp3', },
{ word: "car", audio: 'car.mp3' }
];
var wordsWrong = [];
var wordsCorrectCounter = 0;
var wordsWrongCounter = 0;
//var cheer = new Audio('correct.mp3');
//var boo = new Audio('wrong.mp3');
function editWords() {
console.log("under construction");
}
function startGame() {
document.getElementById("startGame").remove();
document.getElementById("editList").remove();
newWord();
}
// dictionary is global variable, you don't need to pass it to access it
async function newWord() {
// I add this so the color will be reset after click continue
document.body.style.backgroundColor = "";
if (Object.entries(dictionary).length === 0) {
endGame();
} else {
var random = Math.floor(Math.random() * dictionary.length),
// get the random word here when it still exist in dictionary
random_word = dictionary[random].word;
document.getElementById("Empty").innerHTML = random_word;
console.log(random_word);
console.log(dictionary);
await sleep(2000);
document.getElementById("Empty").innerHTML = " ";
// direct pass the ramdom word, not the ramdom index
// ramdom index could be invalid after you remove item from dictionary
// which is why you get the error
createInputField(random_word);
}
}
function createInputField(random_word) {
var entry = document.createElement("input");
entry.setAttribute("type", "text");
entry.id = "inputfield";
document.body.appendChild(entry);
let btn = document.createElement("button");
btn.id = "okBtn";
btn.innerHTML = "ok";
btn.type = "submit";
btn.name = "answerBtn";
document.body.appendChild(btn);
document.getElementById("okBtn").addEventListener("click", () => checkAnswer(random_word, entry.value));
}
function checkAnswer(random_word, entry) {
var answer = entry.toLowerCase();
if (random_word == answer) {
//cheer.play();
// if you only need +1, you can use ++
wordsCorrectCounter++;
document.getElementById("okBtn").remove();
document.getElementById("inputfield").remove();
// use Array.filter() to remove random_word(answer) from the dictionary
// only word != random_word will pass
dictionary = dictionary.filter(item => item.word != random_word);
console.log(dictionary);
newWord();
} else {
// I didn't see this, so I add it
// if you only need +1, you can use ++
wordsWrongCounter++;
// because we pass the random_word(answer) now, we can just push it
wordsWrong.push(random_word);
document.getElementById("okBtn").remove();
document.getElementById("inputfield").remove();
//boo.play();
document.body.style.backgroundColor = "red";
document.getElementById("correctWord").innerHTML = random_word;
let btn = document.createElement("button");
btn.id = "contBtn";
btn.innerHTML = "Continue";
btn.type = "submit";
btn.name = "continueBtn";
document.body.appendChild(btn);
document.getElementById("contBtn").addEventListener("click", () => wrongAnswer(random_word));
}
}
function wrongAnswer(random_word) {
document.getElementById("contBtn").remove();
document.getElementById("correctWord").innerHTML = " ";
// same as above
// use Array.filter() to remove correct_word(answer) from the dictionary
// only word != correct_word will pass
dictionary = dictionary.filter(item => item.word != random_word);
newWord();
}
function endGame() {
/*
use `` to set string, it more readable & easier to edit
you can put variable in it by use ${variable_name}
example:
let x = "test";
console.log(`this is a ${x}`);
result:
this is a test
*/
document.getElementById("Empty").innerHTML =
`you are done! Correct: ${wordsCorrectCounter} Wrong: ${wordsWrongCounter} These words were wrong: ${wordsWrong}`;
}
function Refresh() {
window.parent.location = window.parent.location.href;
}
document.getElementById("startGame").addEventListener("click", () => startGame());
</script>
</body>
</html>
I just got the issue in your code, it's a bit conceptual thing and nothing much.
See what's going wrong in this screenshot of console
You can see there the length of the dictionary(array) is still the same after deleting the word(object).
Because you have used: delete keyword which deletes an item and replaces it with empty and size of the array remains the same.
Hence the new dictionary after deleting the first word became: [empty, {...}, {...}]
Now whenever you will try to get dictionary[0].word gives you an error: Cannot read property of undefine, because it's empty
Instead of using delete keyword you can simply use dictionary.splice(random, 1)
See the console screenshot after using splice
<html>
<head>
<title>Aliyah's dictee spel</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="header">
<h1>Hej! Velkommen til Aliyahs diktee!</h1>
</div>
<div id="Random_word">
<h2 id="Empty">Click start to start</h2>
<button id="startGame">Start</button>
<button id="editList">Edit word list</button>
<h3 id="correctWord"></h3>
</div>
<script>
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
var dictionary = [{
word: "apple",
audio: 'apple.mp3',
},
{
word: "baby",
audio: 'baby.mp3',
},
{
word: "car",
audio: 'car.mp3'
}
];
var wordsWrong = [];
var wordsCorrectCounter = 0;
var wordsWrongCounter = 0;
var cheer = new Audio('correct.mp3');
var boo = new Audio('wrong.mp3');
function editWords() {
console.log("under construction");
};
function startGame() {
document.getElementById("startGame").remove();
document.getElementById("editList").remove();
newWord(dictionary);
};
async function newWord(dictionary) {
if (Object.entries(dictionary).length === 0) {
endGame();
} else {
var random = Math.floor(Math.random() * dictionary.length);
console.log(random)
document.getElementById("Empty").innerHTML = dictionary[random].word;
console.log(dictionary[random].word);
console.log(dictionary);
await sleep(2000);
document.getElementById("Empty").innerHTML = " ";
createInputField(random);
}
};
function createInputField(random) {
var entry = document.createElement("input");
entry.setAttribute("type", "text");
entry.id = "inputfield";
document.body.appendChild(entry);
let btn = document.createElement("button");
btn.id = "okBtn";
btn.innerHTML = "ok";
btn.type = "submit";
btn.name = "answerBtn";
document.body.appendChild(btn);
document.getElementById("okBtn").addEventListener("click", () => checkAnswer(random, entry.value));
};
function checkAnswer(random, entry) {
var answer = entry.toLowerCase();
if (dictionary[random].word == answer) {
cheer.play();
wordsCorrectCounter += 1;
document.getElementById("okBtn").remove();
document.getElementById("inputfield").remove();
dictionary.splice(random, 1);
console.log(dictionary);
newWord(dictionary);
} else {
wordsWrong.push(dictionary[random].word);
wordsWrongCounter += 1;
document.getElementById("okBtn").remove();
document.getElementById("inputfield").remove();
boo.play();
document.body.style.backgroundColor = "red";
document.getElementById("correctWord").innerHTML = dictionary[random].word;
let btn = document.createElement("button");
btn.id = "contBtn";
btn.innerHTML = "Continue";
btn.type = "submit";
btn.name = "continueBtn";
document.body.appendChild(btn);
document.getElementById("contBtn").addEventListener("click", () => wrongAnswer(random));
}
};
function wrongAnswer(random) {
document.getElementById("contBtn").remove();
document.getElementById("correctWord").innerHTML = " "
delete dictionary[random];
newWord(dictionary);
};
function endGame() {
document.getElementById("Empty").innerHTML = "you are done!" + "Correct: " + wordsCorrectCounter + "Wrong: " + wordsWrongCounter +
"These words were wrong: " + wordsWrong;
};
function Refresh() {
window.parent.location = window.parent.location.href;
};
document.getElementById("startGame").addEventListener("click", () => startGame());
</script>
</body>
</html>
I've been trying to program a discord bot to play hangman except I'm doing it in embeds to learn how they work. Unfortunately, I've been at a roadblock trying to resend my embed after they got a letter right or not.
I tried to follow the discord.js guide and use the message.embeds[0] command but it doesn't output anything. The example embed just outputs with the field I added after.
Here's the important part:
const gameEmbed = new Discord.MessageEmbed()
.setColor(embedColour)
.setTitle('Hangman')
.setDescription('Play hangman in discord!')
.addFields(
{ name: chosenWord.length.toString() + '-letter word', value: seenWord },
);
const receivedEmbed = message.embeds[0];
const exampleEmbed = new Discord.MessageEmbed(receivedEmbed).addFields({ name: chosenWord.length.toString() + '-letter word', value: seenWord });
message.channel.send(gameEmbed);
collector.on('collect', m => {
if (!knownLetters.includes(m.content.toLowerCase()) || !incorrectLetters.includes(m.content.toLowerCase())) {
if (wordLetters.includes(m.content.toLowerCase())) {
message.channel.send('Congratulations! You guessed a letter correctly!');
knownLetters[wordLetters.indexOf(m.content.toLowerCase())] = m.content.toLowerCase();
updateWord();
message.channel.send(exampleEmbed);
}
And the whole program, in case there's anything you need:
module.exports = {
name: 'hangman',
description: 'Play hangman in discord!',
run(message, args, Discord) {
const words = require('./words.json');
const chosenWord = words.words[Math.floor(Math.random() * 981)];
const wordLetters = new Array();
const knownLetters = new Array();
const incorrectLetters = new Array();
let seenWord = '';
let i;
const embedColour = Math.floor(Math.random() * 16777215).toString(16);
for (i = 0; i < chosenWord.length; i++) {
wordLetters.push(chosenWord[i]);
}
for (i = 0; i < chosenWord.length; i++) {
knownLetters.push('\\_', ' ');
}
function updateWord() {
for (i = 0; i < knownLetters.length; i++) {
seenWord += knownLetters[i];
}
}
updateWord();
const filter = m => m.author.id === m.author.id && !m.author.bot && m.content.toLowerCase().length == 1;
const collector = new Discord.MessageCollector(message.channel, filter, {
time: 1000 * 30,
});
const gameEmbed = new Discord.MessageEmbed()
.setColor(embedColour)
.setTitle('Hangman')
.setDescription('Play hangman in discord!')
.addFields(
{ name: chosenWord.length.toString() + '-letter word', value: seenWord },
);
const receivedEmbed = message.embeds[0];
const exampleEmbed = new Discord.MessageEmbed(receivedEmbed).addFields({ name: chosenWord.length.toString() + '-letter word', value: seenWord });
message.channel.send(chosenWord);
message.channel.send(gameEmbed);
collector.on('collect', m => {
if (!knownLetters.includes(m.content.toLowerCase()) || !incorrectLetters.includes(m.content.toLowerCase())) {
if (wordLetters.includes(m.content.toLowerCase())) {
message.channel.send('Congratulations! You guessed a letter correctly!');
knownLetters[wordLetters.indexOf(m.content.toLowerCase())] = m.content.toLowerCase();
updateWord();
message.channel.send(exampleEmbed);
}
else {
message.channel.send('I\'m sorry, that letter is not in the word. Try again!');
}
}
else {
message.chanel.send('You have already guessed that letter. Try again!');
}
});
collector.on('end', (collected) => {
message.channel.send(`done, collected ${collected.size} messages`);
});
},
};
message.embeds is an empty array as the user only sends a simple message, so you can't use that. What you can do is... change the field you added to your embed and send that again:
gameEmbed.fields[0] = {
name: chosenWord.length.toString() + '-letter word',
value: seenWord,
};
message.channel.send(gameEmbed);
I've made quite a few changes (and added comments) in your code, but at least it seems to be working now:
const words = require('./words.json');
const chosenWord = words.words[Math.floor(Math.random() * words.length)];
// destructuring is easier than a for loop
const wordLetters = [...chosenWord];
// don't use new Array(), use [] instead
const knownLetters = [];
const incorrectLetters = [];
let seenWord = '';
for (let i = 0; i < chosenWord.length; i++) {
knownLetters.push('\\_', ' ');
}
function updateWord() {
// you need to reset seenWord, not just add new characters to it
seenWord = '';
for (let i = 0; i < knownLetters.length; i++) {
seenWord += knownLetters[i];
}
}
updateWord();
// m.author.id === m.author.id doesn't make sense
const filter = (m) => !m.author.bot && m.content.toLowerCase().length == 1;
const collector = new Discord.MessageCollector(message.channel, filter, {
time: 1000 * 30,
});
const gameEmbed = new Discord.MessageEmbed()
// you can use RANDOM to set the colour to random :)
.setColor('RANDOM')
.setTitle('Hangman')
.setDescription('Play hangman in discord!')
.addFields({
name: chosenWord.length.toString() + '-letter word',
value: seenWord,
});
message.channel.send(chosenWord);
message.channel.send(gameEmbed);
collector.on('collect', (m) => {
const letter = m.content.toLowerCase();
// try to return early to avoid ifs inside ifs inside ifs
if (knownLetters.includes(letter) || incorrectLetters.includes(letter)) {
return message.chanel.send(
'You have already guessed that letter. Try again!',
);
}
if (!wordLetters.includes(letter)) {
// don't forget to add letter to incorrectLetters
incorrectLetters.push(letter);
return message.channel.send(
"I'm sorry, that letter is not in the word. Try again!",
);
}
message.channel.send('Congratulations! You guessed a letter correctly!');
// you need to double the index if you added spaces between the underscores
// TODO: it only replaces the first occurrence, you need to replace all!
knownLetters[wordLetters.indexOf(letter) * 2] = letter;
updateWord();
// simply update the first field
gameEmbed.fields[0] = {
name: chosenWord.length.toString() + '-letter word',
value: seenWord,
};
// and send the same embed
message.channel.send(gameEmbed);
});
collector.on('end', (collected) => {
message.channel.send(`done, collected ${collected.size} messages`);
});
I have created a simple idea of Hangman game, which runs on console. Everything works, but when I try to use window.addEventListener('keypress, function(e) I cannot press the characters for the game.
const Hangman = function(word, remainguess) {
this.word = word.toLowerCase().split('')
this.remainguess = remainguess
this.guessedLetters = []
}
Hangman.prototype.getPuzzle = function() {
let puzzle = ' '
this.word.forEach(element => {
if (this.guessedLetters.includes(element) || element === ' ') {
puzzle += element
} else {
puzzle += '*'
}
});
return puzzle
}
Hangman.prototype.guessing = function(guess) {
guess = guess.toLowerCase()
const isUnique = !this.guessedLetters.includes(guess)
const isBaddGuess = !this.word.includes(guess)
if (isUnique) {
this.guessedLetters.push(guess)
}
if (isBaddGuess) {
this.remainguess--
}
// return this.remainguess
}
const game1 = new Hangman('cat', 1)
window.addEventListener('keypress', function(e) {
const guess = String.fromCharCode(e.charCode)
game1.guessing(guess)
console.log(game1.getPuzzle())
console.log(game1.remainguess)
})
I want to remove some words which start with # in the sentence which are duplicated in javascript how can I achieve it.
For example:
"This is #banker does banking in a #bank, this #banker is good."
Here in this sentence, I want to remove the extra word "#banker" from it.
How can I do it in javascript?
Consider every word that should be removed will start with "#"
Here is a possible solution:
const text = 'This is #banker does banking in a #bank, this #banker is good.';
const splittedWords = text.split(' ');
let newSentence = [];
splittedWords.forEach(word => {
if (word.startsWith('#')) {
if (newSentence.indexOf(word) === -1) {
newSentence.push(word);
}
} else {
newSentence.push(word);
}
});
console.log(newSentence.join(' '));
UPDATE
const text = 'This is #2, this is #3, this is #2';
const splittedWords = text.split(' ');
let newSentence = [];
splittedWords.forEach(word => {
if (word.startsWith('#')) {
cleanedSentence = newSentence.map(word => word.replace(/,/g, ''));
cleanedWord = word.replace(/,/g, '');
if (cleanedSentence.indexOf(cleanedWord) === -1) {
newSentence.push(word);
}
} else {
newSentence.push(word);
}
});
console.log(newSentence.join(' '));