prompt() in a loop never shows writeln() content - javascript

I am new to javascript, having trouble with this assignment. My professor suggested the problem was due to needing to parseInt, but even after I added the parseInt, it still isn't working.
This displays fine in Firefox, and the "higher" and "lower" statements are displayed, but when I run it in Chrome or Edge, only the window asking for a number will render. I did look for help, but I cant see what I'm doing wrong. Most of the suggestions Ive seen online, don't address the code directly. Is this problem specific code related or something else?
function play() {
let guess;
let randNum = Math.floor(1 + Math.random() * 999);
let guessed = false;
while (guessed == false) {
guess = window.prompt("Enter a number from 1 to 1000");
parseInt(guess);
if (guess == randNum) {
document.writeln("<li>" + "Congratulations! You guessed the correct number!</li>");
guessed = true;
document.writeln("</ol>");
document.writeln("Your guess: " + guess);
document.writeln("Actual number: " + randNum);
} else if (guess > randNum) {
document.writeln("<li>" + guess + " is Too High. Try Again.</li>");
document.writeln("</ol>");
} else if (guess < randNum) {
document.writeln("<li>" + guess + " is Too Low. Try Again.</li>");
document.writeln("</ol>");
}
}
}
window.addEventListener("load", play, false);

Don't use writeln. Use the proper methods like .append() or .insertAdjacentElement() or .insertAdjacentHTML() if you just want to insert HTML strings instead of Nodes.
Don't use alert, prompt, etc. Those Window methods will most likely get deprecated or at least discouraged in the near future.
Remember, use let for variables, and const for constants.
Use DOM methods like Element.querySelector() to get and store a DOM Element,
Use Document.createElement() to create a new one (a new LI Element in your case)
To ease the querying or creation of the desired DOM Elements — create two reusable functions:
// DOM utility functions:
const find = (selector, parent) => (parent || document).querySelector(selector);
const create = (tag, properties) => Object.assign(document.createElement(tag), properties);
that can be used to cache your Elements and use them later in your game logic
// Cache your DOM elements!
const elNumber = find("#number");
const elCheck = find("#check");
const elAnswers = find("#answers");
which will target and cache your three HTML elements by theri id attribute selector. As said above, instead of using prompt, use a better and less invasive UI (User interface) right into your App:
Enter a number from 1 to 10: <input id="number" type="text">
<button id="check" type="button">CHECK</button>
<ol id="answers"></ol>
Then create two let variables for the guessed state and one for the random number, so that when you start a new game you can change their values:
// Make available for multiple games!
let numRand;
let isGuessed;
then, giving your specific game, you need two more functions, one to start (and restart) the game and one for your game logic:
// Call this function to start a new game!
const start = () => {
// Clear old answers
// Reset old guessed state
// Generate a new random number
};
// Call this function on button CHECK click!
const check = () => {
// Game logic goes here!
}
// Assign listener to button:
elCheck.addEventListener("click", check);
// Start a new game!
start();
Demo time:
// DOM utility functions:
const find = (selector, parent) => (parent || document).querySelector(selector);
const create = (tag, properties) => Object.assign(document.createElement(tag), properties);
// Task:
// Cache your DOM elements!
const elNumber = find("#number"); // PS: remember, use const for constants!
const elCheck = find("#check");
const elAnswers = find("#answers");
// Make available for multiple games!
let numRand;
let isGuessed; // Try to prefix boolean variables with "is*"
// Call this function to start a new game!
const start = () => {
// Clear old answers:
elAnswers.innerHTML = "";
// Reset old guessed state
isGuessed = false;
// Generate a new random number 1 to 10:
numRand = Math.floor(Math.random() * 9) + 1;
};
// Call this function on button CHECK click!
const check = () => {
// Start a new game if needed
if (isGuessed) start();
// Get the user entered value
// Use parseInt with radix 10 and Math.abs
// to prevent negative numbers
const numUser = Math.abs(parseInt(elNumber.value, 10));
// Do nothing if invalid value entered:
if (!numUser) return;
// Update isGuessed state
isGuessed = numRand === numUser;
// Handle answer:
const textAnswer = `
You guessed: ${numUser}.
The number is ${isGuessed ? "correct!" : numUser > numRand ? "too high." : "too low."}
${isGuessed ? "Congratulations!" : "Try again"}
`;
// Create a LI element with the answer text
const elAnswer = create("li", {
textContent: textAnswer
});
// Append your LI element!
elAnswers.append(elAnswer);
// Clear the current value from input:
elNumber.value = "";
};
// Assign listener to button:
elCheck.addEventListener("click", check);
// Start a new game!
start();
Enter a number from 1 to 10: <input id="number" type="text">
<button id="check" type="button">CHECK</button>
<ol id="answers"></ol>
Additional learning resources:
Arrow_functions (MDN)
Template literals /Template strings (MDN)
Conditional (ternary) operator (MDN)

As I understand it, JavaScript is single-threaded, meaning that it has only one execution thread. Methods like prompt() and alert() block that thread. As long as prompt() is called in a loop, writeln content will not be rendered on the page.
One way to address this with your existing code is to use setTimeout() to delay the next call to prompt(), which allows content to be rendered in the meantime.
That being said, I recommend a more asynchronous method that does not rely on prompt() or writeln(). This answer is intended to explain the issue with your existing code; for a more robust strategy, see Roko's.
var randNum = Math.floor(1 + Math.random() * 999);
function ask() {
let guess = parseInt(window.prompt("Enter a number from 1 to 1000"));
if (guess == randNum) {
document.writeln("<div>Congratulations! You guessed the correct number!</div>");
document.writeln("<div>Your guess: " + guess + ". Actual number: " + randNum + "</div>");
} else if (guess > randNum) {
document.writeln("<div>" + guess + " is Too High. Try Again.</div>");
setTimeout(ask, 50);
} else if (guess < randNum) {
document.writeln("<div>" + guess + " is Too Low. Try Again.</div>");
setTimeout(ask, 50);
}
}
window.addEventListener("load", ask, false);

Related

Javascript stop setInterval

if (document.case.display.value.length >16 && document.case.display.value.length < 21) {
Notiflix.Notify.Info('Because you have a lot of charatchers font size is smaller');
document.getElementById("display").style.fontWeight = "550";
document.getElementById("display").style.fontSize = "2em";
} else if (document.case.display.value.length > 20) {
var str = document.case.display.value.length
Notiflix.Notify.Warning('Max characters you can see is 25 ');
Notiflix.Notify.Failure('Number of your characters' + str);
document.getElementById("display").style.fontWeight = "500";
document.getElementById("display").style.fontSize = "1.5em";
}
else {
document.getElementById("display").style.fontWeight = "500";
document.getElementById("display").style.fontSize = "2.5em";
}}
window.setInterval(function(){
testLength();
}, 100);
Notiflix is a JavaScript library for notification.
I have a display who font go down if have so much characters and i set time every 0.1 second he check number of characters. If number is higher than 16 he put a notification.
But he put every 0.1 second notification i want only one time/s. Do you have idea who can "block " this line of code for 10 second and after that read this without moving settimer down.
Sorry about bad English.
Any information will help me
You can try storing your setInterval() in a variable and calling it only when required. Else, you can stop that using that variable name.
let myInterval;
function start(){
myInterval = window.setInterval(function(){
testLength();
}, 100);
}
function stop(){
clearInterval(myInterval);
}
P.S: I would also like to advice on using onChange eventListener for checking test length rather than setInterval.
Update: Alternate method
You can also try removing setInterval thing and adding something like this:
document.addEventListener("DOMContentLoaded", function(event) {
var numbers = document.querySelectorAll(".digit")
console.log("numbers", numbers);
numbers.forEach(el => el.addEventListener('click', testLength))
});

How to have a function repeat until its value is the same as another function?

I am making a program to present to the other members of the CyberPatriots club I am in. I want someone to enter a password and have it iterate through all the possible ways until it gets it, my idea is that it counts in base 10, which is converted to base 95 using asci instead of numbers, the problem I have is having it count until the passwords match. The code so far is only the converting part.
function generate(state) {
const printables = ' !"#$%&\'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
var ones = state % printables.length
var newstate = Math.floor(state / printables.length)
if (newstate !== 0) {
return generate(newstate) + printables[ones]
} else {
return printables[ones]
}
}
console.log(generate(10000))
Thanks!

How to choose and work with a drop down list in js

I got this problem. I created a drop down list for choosing the algorithm to work with. It works with the first option but not all of them. Could you please help me?
Thanks in advance
var form1 = document.getElementById('form1');
var form2 = document.getElementById('form2');
var form3 = document.getElementById('form3');
var formArray = [];
formArray.push(form1.innerHTML);
formArray.push(form2.innerHTML);
formArray.push(form3.innerHTML);
//select drop down list//
function changeToCal() {
dropDownList.selectedIndex--;
document.getElementById('form').innerHTML = formArray[dropDownList.selectedIndex];
}
//Calculate //
document.getElementById('form').addEventListener("submit",
function(event) {
var fieldy = document.getElementById('fieldy');
var fieldx = document.getElementById('fieldx');
var resultField = document.getElementById('resultField');
var x = parseFloat(fieldx.value);
var y = parseFloat(fieldy.value);
if(!fieldy.value || !fieldx.value) {
alert("Please enter numbers in the fields!");
} else if (dropDownList.selectedIndex = 1) {
var result = (y / 100) * x;
resultField.innerText = "Answer: " + result + "."
event.preventDefault();
} else if (dropDownList.selectedIndex = 2) {
var result = (100 / y) * x;
resultField.innerText = "Answer: " + result + "."
event.preventDefault();
} else if (dropDownList.selectedIndex = 3) {
var result = (y / x) * 100;
resultField.innerText = "Answer: " + result + " %."
event.preventDefault();
} else {
resultField.innerText = "Error"
event.preventDefault();
}
}
);
https://codepen.io/anon/pen/VMZNwQ
This line:
} else if (dropDownList.selectedIndex = 1) {
needs to use a comparison equals operator rather than an assignment equals operator:
} else if (dropDownList.selectedIndex === 1) {
The other if/else clauses are similarly incorrect.
I highly recommend using a decent IDE, it would highlight potential mistakes like this for you.
You will also need to change this:
dropDownList.selectedIndex--;
document.getElementById('form').innerHTML = formArray[dropDownList.selectedIndex];
to this:
document.getElementById('form').innerHTML = formArray[dropDownList.selectedIndex - 1];
The selectedIndex is live, if you change it using -- that will cause the selected value to be updated.
The way the result is output assumes there is an <h3> with the id resultField but only one of your forms has that id set.
Other miscellaneous suggestions include...
The id attributes need to be unique throughout the document. You currently have 3 hidden forms and you copy around the HTML, leading to 4 elements with each id (resultField, fieldx, fieldy). Whether document.getElementById grabs the right one is down to luck.
Rather than copying around the innerHTML of those forms you'd be better off simply showing and hiding the existing forms using CSS. Alternatively you could use just 1 form and update the relevant text to match the current algorithm.
Listening for the submit event of the form seems odd. Why not use a regular button and listen for the click event?
If you do decide to keep the 3 forms I would suggest registering separate button handlers for each one. The fact that so much of your code is inside a big if/else is a sign that you actually need multiple functions rather than a single function that has to figure out which mode it is in. The code they share could be factored out if appropriate.

Unable to Get Output From While Loop in Javascript

I'm working on my final project of the Winter 2017 quarter to demonstrate how to use Regular Expressions in both C# and JavaScript code behind pages. I've got the C# version of my demonstration program done, but the JavaScript version is making me pull what little hair I have left on my head out (no small achievement since I got a fresh buzz cut this morning!). The problem involves not getting any output after applying a Regular Expression in a While loop to get each instance of the expression and printing it out.
On my HTML page I have an input textarea, seven radio buttons, an output textarea, and two buttons underneath (one button is to move the output text to the input area to perform multiple iterations of applying expressions, and the other button to clear all textareas for starting from scratch). Each radio button links to a function that applies a regular expression to the text in the input area. Five of my seven functions work; the sixth is the one I can't figure out, and the seventh is essentially the same but with a slightly different RegEx pattern, so if I fix the sixth function, the seventh function will be a snap.
(I tried to insert/upload a JPG of the front end, but the photo upload doesn't seem to be working. Hopefully you get the drift of what I've set up.)
Here are my problem children from my JS code behind:
// RegEx_Demo_JS.js - code behind for RegEx_Demo_JS
var inputString; // Global variable for the input from the input text box.
var pattern; // Global variable for the regular expression.
var result; // Global variable for the result of applying the regular expression to the user input.
// Initializes a new instance of the StringBuilder class
// and appends the given value if supplied
function StringBuilder()
{
var strings = [];
this.append = function (string)
{
string = verify(string);
if (string.length > 0) strings[strings.length] = string;
}
this.appendLine = function (string)
{
string = verify(string);
if (this.isEmpty())
{
if (string.length > 0) strings[strings.length] = string;
else return;
}
else strings[strings.length] = string.length > 0 ? "\r\n" + string : "\r\n";
}
this.clear = function () { strings = []; };
this.isEmpty = function () { return strings.length == 0; };
this.toString = function () { return strings.join(""); };
var verify = function (string)
{
if (!defined(string)) return "";
if (getType(string) != getType(new String())) return String(string);
return string;
}
var defined = function (el)
{
// Changed per Ryan O'Hara's comment:
return el != null && typeof(el) != "undefined";
}
var getType = function (instance)
{
if (!defined(instance.constructor)) throw Error("Unexpected object type");
var type = String(instance.constructor).match(/function\s+(\w+)/);
return defined(type) ? type[1] : "undefined";
}
}
Within the code of the second radio button (which will be the seventh and last function to complete), I tested the ScriptBuilder with data in a local variable, and it ran successfully and produced output into the output textarea. But I get no output from this next function that invokes a While loop:
function RegEx_Match_TheOnly_AllInstances()
{
inputString = document.getElementById("txtUserInput").value;
pattern = /(\s+the\s+)/ig; // Using an Flag (/i) to select either lowercase or uppercase version. Finds first occurrence either as a standalone word or inside a word.
//result = pattern.exec(inputString); // Finds the first index location
var arrResult; // Array for the results of the search.
var sb = getStringBuilder(); // Variable to hold iterations of the result and the text
while ((arrResult = pattern.exec(inputString)) !==null)
{
sb.appendLine = "Match: " + arrResult[0] ;
}
document.getElementById("txtRegExOutput").value = sb.toString();
/* Original code from C# version:
// string pattern = #"\s+(?i)the\s+"; // Same as above, but using Option construct for case insensitive search.
string pattern = #"(^|\s+)(?i)the(\W|\s+)";
MatchCollection matches = Regex.Matches(userTextInput, pattern);
StringBuilder outputString = new StringBuilder();
foreach (Match match in matches)
{
string outputRegExs = "Match: " + "\"" + match.Value + "\"" + " at index [" + match.Index + ","
+ (match.Index + match.Length) + "]" + "\n";
outputString.Append(outputRegExs);
}
txtRegExOutput.Text = outputString.ToString();
*/
} // End RegEx_Match_The_AllInstances
I left the commented code in to show what I had used in the C# code behind version to illustrate what I'm trying to accomplish.
The test input/string I used for this function is:
Don’t go there. If you want to be the Man, you have to beat The Man.
That should return two hits. Ideally, I want it to show the word that it found and the index where it found the word, but at this point I'd be happy to just get some output showing every instance it found, and then build on that with the index and possibly the lastIndex.
So, is my problem in my While loop, the way I'm applying the StringBuilder, or a combination of the two? I know the StringBuilder code works, at least when not being used in a loop and using some test data from the site I found that code. And the code for simply finding the first instance of "the" as a standalone or inside another word does work and returns output, but that doesn't use a loop.
I've looked through Stack Overflow and several other JavaScript websites for inspiration, but nothing I've tried so far has worked. I appreciate any help anyone can provide! (If you need me to post any other code, please advise and I'll be happy to oblige.)

How to create a Scramble function in Javascript

I'm am trying to create a simple slider game using javascript. It's i simple 4 by 4 number slider game with each button being labeled 1-15 with the last block being a blank block. I just have no idea on how to scramble the buttons in a random order to start the game.
Below is the code I currently have.
<body>
<h1> Slider Game </h1>
<script type="text/javascript">
var blankrow = 3;
var blankcol = 3;
for (var r=0; r<4; r++)
{
for (var c=0; c<4; c++)
{
var bid = "b"+r+c;
var val = 4*r+c+1;
if (bid==="b33")
val = ' ';
var s = '<input type = "button" id = "' + bid + '" value = "'
+ val + '" onclick = "makeMove(this.id);" />' + '\n';
document.write (s);
}
}
</script>
<input type = "button" id = "btnScramble" value = "Scramble" onclick = "scrambleBoard();"/>
<input type = "button" id = "btnReset" value = "Reset Board" onclick = "resetBoard();"/>
</body>
I created a function like this:
function scrambleBoard()
{
}
I just have no idea where to go from here. I am just learning Javascript so I am still learning how to code. Thanks!
Update:
This is the make move function I have
function makeMove(btnid)
{
//is btnid next to blank
var r = btnid.substr(1,1);
var c = btnid.substr(2,2);
if (blankrow==r && blankcol==c+1) // check right
{
blankid="b"+r+c;
document.getElementById(blankid).value = document.getElementById(btnid).value;
document.getElementById(btnid).value = ' ';
blankcol=c;
}
else if (blankrow==r && blankcol==c-1) // check left
{
blankid="b"+r+c;
document.getElementById(blankid).value = document.getElementById(btnid).value;
document.getElementById(btnid).value = ' ';
blankcol=c;
}
else if (blankrow==r+1 && blankcol==c) // check bottem
{
blankid="b"+r+c;
document.getElementById(blankid).value = document.getElementById(btnid).value;
document.getElementById(btnid).value = ' ';
blankrow=r;
}
else if (blankrow==r-1 && blankcol==c) // check top
{
blankid="b"+r+c;
document.getElementById(blankid).value = document.getElementById(btnid).value;
document.getElementById(btnid).value = ' ';
blankrow=r;
} else
alert("Move is invalid");
}
Now with this how would I take the function (makeMove) and put it into the scramble function. Sorry I am really having a hard time understanding this concept.
You will need a makeMove function that fills the hole from a selected direction anyway, in order to make the game. Scramble is very simple: repeat the makeMove operation a sufficient number of times with a random neighbour (ignoring invalid neighbours like sliding from left at the left edge).
EDIT: Style-wise, document.write is considered to be a bad practice. Much better would be to make an element such as
<div id="board"></div>
and then fill it up by either creating documents with document.createElement and adding it there, which is a bit of a pain, or you can go the easy route and assign HTML markup to innerHTML:
document.getElementById('board').innerHTML = allMyButtonsHTML;
Also, using onclick="..." is considered a bad practice; try to get used to not mixing JavaScript and HTML by simply leaving off the onclick="...", and instead assigning it from JavaScript:
var scrambleButton = document.getElementById('btnScramble');
scrambleButton.addEventListener('click', function() {
...
});
None of this is an error as it stands, but it will result in cleaner, more maintainable code in the future.
EDIT2: You would not be putting makeMove into the shuffle, you'd be calling it from there.
function shuffleBoard() {
// the hole starts here
var holeRow = 3, holeCol = 3;
// the number of shuffling moves
var moves = 100;
// repeat while moves is not yet at zero
loop: while (moves) {
// we want to move one space from our current hole, so start there
var nextRow = holeRow, nextCol = holeCol;
// get a random number from 0 to 3 using the |0 hack
// to convert a real number to an integer
var direction = (Math.random() * 4)|0;
// now to see what coordinate changes...
switch (direction) {
case 0:
// if we're going right, we increment the column
// if that puts us too far right, we jump to the start of the loop
// to pick a new direction again
if (nextCol++ > 3) continue loop;
break;
case 1:
// same deal for down
if (nextRow++ > 3) continue loop;
break;
case 2:
// and left
if (nextCol-- < 0) continue loop;
break;
case 3:
// and up
if (nextRow-- > 0) continue loop;
break;
}
// this should be more elegant but
// like this it will fit in with your existing function
makeMove('b' + nextRow + nextCol);
// now since we moved the hole, we update its current position
holeRow = nextRow;
holeCol = nextCol;
// that's one move down, lots to go!
moves--;
}
// or is it? nope, all done.
}
After you add the first button, loop through however many more you need to create. Use math.random to pick a random number 0-1. If the number is 0, use insertadjacenthtml to add a new button to the left. If the number is 1, add the button to the right.

Categories