Prevent Subsequent Random Results Repeating In Javascript - javascript

On my website I have a button that selects a random quote from a list of quotes and projects the randomly selected quote into a text box. This is done using JavaScript.
Although I have this working, I'd like an additional piece of code that will prevent the directly subsequent quote being the same as the previous. I'd like any quote used to be able appear again however, just not directly following.
If possible I'd also like it so any quote used does not appear again for a minimum of another 3 clicks - but this would just be a bonus.
Anyway the code I currently have is as follows:
<head>
<script language="javascript"><!--
function GenerateQuote(){var aquote=new Array;
aquote[0]="\"Quote0\"";
aquote[1]="\"Quote1\"";
aquote[2]="\"Quote2\""
aquote[3]="\"Quote3\"";
aquote[4]="\"Quote4\"";
aquote[5]="\"Quote5\"";
aquote[6]="\"Quote6\"";
rdmQuote=Math.floor(Math.random()*aquote.length);
document.getElementById("quoteBox").value=aquote[rdmQuote];
}
-->
</script>
</head>
<body>
<textarea id="quoteBox" readonly></textarea>
<button onClick="GenerateQuote()">Entertainment & Hobbies</button>
</body>
Thanks in advance; I'm sure it won't be too hard for you brainiacs!

Fill an array of quotation, then create a copy.
Scramble the copy of the array (you can just use .sort() method or even better you can look for a js implementation of Fisher-Yates alghoritm
Call pop() over the array on each click event so you will generate every time a different quote until the array is fully consumed
When length of the array is zero goto 1)
Reference:
http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/pop

<head>
<script type="text/javascript">
!function (){
var quotes = ["quote0", "quote1", "quote2", "quote3", "quote4", "quote5", "quote6", "quote7", "quote8"],
shuffleAfter = quotes.length, cur = 0;
function shuffle( arr ) {
var l = arr.length, j, i, tmp;
for( i = l - 1; i > 0; --i ) {
j = ( Math.random() * ( i + 1 ) ) >>> 0;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
return arr;
}
function generateQuote(){
var r;
if( cur++ % shuffleAfter === 0 ) {
shuffle(quotes);
}
r = quotes.shift();
quotes.push( r );
return r;
}
window.generateQuote = generateQuote;
}()
</script>
</head>
<body>
<textarea id="quoteBox" readonly></textarea>
<button onClick="document.getElementById('quoteBox').value = generateQuote()">Entertainment & Hobbies</button>
</body>
Results from calling generateQuote() 27 times:
2,9,7,5,8,1,3,4,6,9,6,1,7,5,4,3,2,8,3,1,6,5,2,7,9,4,8,2
As you can see, after a full cycle the quotes are shuffled again and there is a chance the same quote will appear if it was last in the last cycle and is first in the new cycle. It should be much better than playlist shuffling in my mp3 player at least :P

use
var lastQuote=-1;
outside your function, then
var rdmQuote=lastQuote;
while (rdmQuote==lastQUote) rdmQuote=Math.floor(Math.random()*aquote.length);
lastQuote=rdmQuote;
inside your function

you can tweak dontRepeatUntil to sweats your need
There's certainly better way but this one should work
var latestQuote = []
, dontRepeatUntil=3
, rdmQuote = null
, quotes=[
"\"Quote0\""
,"\"Quote2\""
,"\"Quote3\""
,"\"Quote4\""
,"\"Quote5\""
,"\"Quote6\""
]
;
function GenerateQuote(){
if(latestQuote.length >= dontRepeatUntil){
latestQuote = latestQuote.slice(latestQuote.length-dontRepeatUntil+1);
}
do{
rdmQuote=Math.floor(Math.random()*quotes.length);
}while(latestQuote.join(',').match(new RegExp('(^|,)'+rdmQuote+'(,|$)')));
latestQuote.push(rdmQuote);
document.getElementById("quoteBox").value=quotes[rdmQuote];
}

Related

Replace content at multiple indexes in an array Javascript

I'm trying to make a Hangman game with Javascript, where the user enters a word for another person to guess. The word is sent to a function (makeUnderlines) and is made into an array of underlines and returned to the player with a prompt to enter a letter that they want to guess. The letter and the word is sent to a function that finds the positions of the letters (getPosition) in the word and sends the positions to another function. The function (insertLetters) is supposed replace the underlines with the letter at the positions given. All of this works except that the function doesn't replace anything in the array. It only replaces the first letter if it only occurs once in the word. Any advice to solving this would be greatly appreciated. I would also like to know if there is a way to prevent the user to entering a number in a word or as a guess.
<!DOCTYPE HTML>
<HTML>
<HEAD>
<META CHARSET="UTF-8">
<TITLE>Hangman</TITLE>
</HEAD>
<BODY>
<SCRIPT TYPE="text/javascript">
function makeUnderlines(word) {
for(i = 0; i < word.length; i++){
underlines.push("\"_\"");
}
return underlines;
}
function getPositions(word, letter) {
for(var i=0; i< word.length;i++) {
if (word[i] === letter) positions.push(i);
}
insertLetters(underlines, positions, letter)
}
function insertLetters(underlines, positions, bokstav){
underlines[positions] = letter;
return underlines;
}
let word = prompt("Choose a word for the player!");
underlines = [];
positions = [];
makeUnderlines(word);
for(i = 7; i > 0; i--){
letter = prompt("["+underlines+"]\n Guess a letter. You have " + i + " guesses left");
getPositions(word, letter);
}
</SCRIPT>
</BODY>
</HTML>
One way to start digging into this is by tracing the flow of the application with a debugger. Chrome Dev Tools has a debugger that lets you step line by line to see what the current values of your variables are.
function insertLetters(underlines, positions, bokstav){
underlines[positions] = letter;
return underlines;
}
From looking at insertLetters, positions should be an array of integer index values but it is being directly used as an integer. Maybe try iterating through the values in positions and using those to index underlines.
function insertLetters(underlines, positions, letter){
for (let i = 0; i < positions.length; i++) {
const pos = positions[i];
underlines[pos] = letter;
}
}
And I think the last thing you could do in getPositions is to clear out the positions array with positions = [];.
Overall your code looks quite functional. Take care to try and pass variables to functions directly instead of relying on global variables.

Javascript print arrays

<!DOCTYPE html>
<html>
<head>
<title>100-Numbers</title>
</head>
<body>
<script>
function myarray()
var points = [];
for (var i = 0; i < 10000; i++) {
points.push[Math.round(Math.random() * 10)];
document.write(myarray(points));
}
</script>
<<button onclick="myarray"> OK </button>>
</body>
</html>
I am a beginner with javascript. I want to create a page that displays random numbers from 0 - 10. I am struggling to print an array. Is there a simple solution to this?
You should call the function from outside the function, not in the loop.
The function can just return the array, you can print it in the caller.
points.push is a function, you call it with (), not [].
You're missing {} around the function body.
The function doesn't take any arguments.
function myarray() {
var points = [];
for (var i = 0; i < 100; i++) {
points.push(Math.round(Math.random() * 10));
}
return points;
}
console.log(myarray());
There are too many syntax errors in your code and thsi suggests that you need a proper tutorial than an answer. However, the following snippet shows the conventional way of doing what you want.
function myarray(){
var points = [];
for (var i = 0; i < 10; i++) {
points.push(Math.round(Math.random() * 10));
}
document.getElementById('mySpan').innerHTML = 'Randoms: ' + points.toString();
}
myarray()
<span id="mySpan"></span>
You have some syntax errors as well as logic errors.
As pointed out in comments, for loop isn't executed.
A function is defined like function myarray() {}
A function is called with () like this myarray()
Array.push() is a method that you invoke using ().
You also seem to have rogue < in the HTML.
You can use an HTML element (In this case a <output> to display the contents of Array. The join('') method converts array content to a string.
function myarray() {
const el = document.querySelector('output');
var points = [];
for (var i = 0; i < 10; i++) {
points.push(Math.round(Math.random() * 10));
}
el.innerText = points.join('');
}
<button onclick="myarray()"> OK </button>
Results: <output></output>
You need to call the function to get the result intended.
points is an array and push is a function so it can be called using ().
function myarray() {
var points = [];
for (var i = 0; i < 10000; i++) {
const randomNumber = Math.round(Math.random() * 10);
points.push(randomNumber);
}
document.write(points);
}
<button onclick="myarray()"> OK </button>
You also need to make an another element or tag so we can place and show the result of our random numbers.
And render the result using something like this:
document.getElementById('generate-number').innerHTML = random_array.
Next, if you render the array directly to an element, it will output with a delimiter, which is a comma ,. The sample output would look like: 2,6,2,1,6. So if you don't want any delimiter, you can remove it by using the .join() function: random_array.join('').
Here's a working example to try:
function generateArray() {
// Creates 10 random numbers in an array
const rand_num_arr = new Array(10).fill(null).map(e => Math.floor(Math.random() * 10));
// Converts array into a string using .join()
const rand_num = rand_num_arr.join('');
// Display the random number in your div element "#generate-number"
document.getElementById('generate-number').innerHTML = rand_num;
}
<div id="generate-number"></div>
<button onclick="generateArray()">Generate Random Numbers</button>
//Arrow Function Expression
const demo = () => {
var temp = [];
for (var i = 0; i < 100; i++) {
temp.push(Math.round(Math.random() * 10));
}
return temp;
}
console.log(demo());
//Normal Function Expression
function demo() {
var temp = [];
for (var i = 0; i < 100; i++) {
temp.push(Math.round(Math.random() * 10));
}
return temp;
}
console.log(demo());
I found few mistakes both in javascript and HTML side + 1 never to do mistake
Some points are already mentioned in the accepted answer but here are a few new ones.
JavaScript Part
In your function myarray you have not used curly braces {}. All the codes of a function lie inside it.
The push is an array method so use a small bracket () not square bracket with it.
You are calling myarray function inside myarray function which causes infinite recursion.
(A never to do mistake) - You wanted to print array on webpage, never use document.write method, because when document.write is executed after a webpage is loaded it overwrites everything on the page. Instead you can use console.log or select an element and inject data in it using innerHTML method. (shown in the code below)
To print an array in javascript you can use index value with the array name. You can parallel print array elements as it is being pushed it reduce execution time. See in the code.
<!DOCTYPE html>
<html>
<head>
<title>100-Numbers</title>
</head>
<body>
<<button onclick="myarray()"> OK </button>>
<p id="output"></p>
<script>
const output = document.getElementById("output");
function myarray() {
var points = [];
for (var i = 0; i < 10000; i++) {
points.push(Math.round(Math.random() * 10));
output.innerHTML += points[i]; // printing array
}
}
</script>
</body>
</html>
HTML Part
One can't say these mistake but rather some modifications (also there is a mistake in the button).
(mistake) When you added onclick event listener to the button then call the function there, by adding parenthesis otherwise function will not execute on button click. Ex: onclick="myarray" => onclick="myarray()"
You should not use angle brackets directly in HTML, it confuses the browser whether it is part of a tag or not. Instead use HTML entity. For < use < and for > use >
Also you can put script tag at bottom of body it looks clean.

how can i print in javascript a string in parts

I have an exercise from my university that i have a string let's say i have that: "hello" and i want to print it like that:
hhehelhellhello (h he hel hell hello).
the thing that i stack is that they want to do it without loop!
Anyone can help me? :/
<!DOCTYPE html>
<html>
<body>
<h1>My First Web Page</h1>
<p>My first paragraph.</p>
<script>
var strin = "hello"
for (i = 0; i < strin.length; i++) {
document.write(strin.slice(0,i+1))
}
</script>
</body>
</html>
Use recursion. Code:
function r (s, i) {
if (i == undefined) i = 0;
if (i == s.length) return "";
return s.slice(0, i + 1) + r(s, i + 1);
}
r("hello"); // hhehelhellhello
There is probably a more efficient solution, but off the top of my head this should work:
var s = "hello";
var index = 0;
var len = 1;
var newString = '';
function appendToResult(str, index, len) {
newString += str.slice(index, len);
len++;
if (len !== s.length + 1) {
appendToResult(s, index, len);
}
}
appendToResult(s, index, len);
console.log(newString);
Maybe you can try a recursive approach:
function print(word, step){
if(word.length<step) return;
console.log(word.substring(1, step));
}
print('hello', 1);
Have you met.... Recursion?
What you need to achieve is something like this (for a string "hello"):
h
he
hel
hell
hello
A recursive call to a method (say, myPrinter()) could behave similarly:
call myPrinter(hello):
call myPrinter(hell):
call myPrinter(hel):
call myPrinter(he):
call myPrinter(h):
print 'h'
print 'he'
print 'hel'
print 'hell'
print 'hello'
done
So how do we go about writing this magical method of ours?
Take notice that at each call we make another call to our method but with a shorter input (in fact, the input has been truncated by one character from the end).
You could write something like this:
function myPrinter(myString):
myPrinter(myString - last character of myString);
print myString; // and maybe some space
if myString is empty:
return; // do nothing. just return
All that's left for you to do is translating the above idea into clean bug-free code.
Of course we have to loop this way or that way. Yet in the below code it is disguised as a recursive function. Yet i am using no counting variables at all. It has the potential to deceive inexperienced eyes. This is how i would do it;
function makeStringWeird(s){
var extend = (s, r=[]) => s !=="" ? (r.push(s),extend(s.slice(0,s.length-1),r)) : r;
return extend(s).reverse().join("");
}
console.log(makeStringWeird("hello"));
I landed up making two solutions for you. One is by using reduce function which doesn't explicitly uses any loop but when I checked its polyfill it uses a while loop to iterate. The code for that is given below and it can also be seen at this fiddle https://jsfiddle.net/vatsalpande/42590tre/
(function(){
var convertedString = [];
function reducer(previousValue, currentValue){
convertedString.push(previousValue+currentValue);
return previousValue+currentValue;
}
var string = "hello";
var stringArray = string.split("");
var totalVersion= stringArray.reduce(reducer,"");
console.info(convertedString.join(""));
})();
Since this was using iteration I created one more by using recursion alone. Below is the code and the fiddle link
https://jsfiddle.net/vatsalpande/tnxsuw75/
(function(){
var string = "hello";
var stringArray = string.split("");
var convertedValue = [];
function convert(initialValue, index){
if(index < stringArray.length){
convertedValue.push(initialValue+stringArray[index]);
convert(initialValue+stringArray[index], index+1);
}
}
convert("",0);
console.info(convertedValue.join(""));
})();
Hope these be of some help.
Any feedback to improve them is highly appreciated.
Happy Learning :)

JavaScript .join is not working

Here is my code:
board = [];
var rowsNum = 5;
var colsNum = 5;
function printBoard(board) {
for (row in board) {
document.write(" ").join(row);
}
}
function clearAndRestartBoard() {
board = [];
for (i = 0; i < rowsNum; i++) {
board.push("[ ]" * colsNum);
}
}
printBoard(board);
It does not throw an error, but it does not show up in my webpage. Do you know what I am doing wrong?
Just in case, here is the html without the css:
<!DOCTYPE html>
<html>
<head>
<link href="test.css" type="text/css"rel="stylesheet" />
<title> Test! </title>
</head>
<body>
<p id = "script"> <script src = "test.js"> </script> </p>
</body>
</html>
I am very new to JS so thank you so much for any help!
There are several issues there, but the main one is that you never call clearAndRestartBoard, and so board is empty, and so you never output anything.
Here's a list of all of the issues that I see off-the-cuff:
You never call clearAndRestartBoard.
Your code is falling prey to The Horror of Implicit Globals: Declare your variables.
You're using for-in to loop through an array. That's usually not a good idea, though there can be use cases for it; this answer outlines your various options for looping through an array.
"[ ]" * colsNum is NaN because * will convert both of its operands to numbers and then do mathematical multiplication. The string "[ ]" converts to NaN because it cannot be interpreted as a number, and then anything multiplied by NaN is NaN. It isn't colsNum blank arrays. To do that, you'd have to have a second loop creating the row arrays, pushing "[ ]" into them, and pushing those row arrays onto board.
You're using document.write. While that will work for simple experiments, it's not something you want to use in general.
You're calling join on the result of document.write, which I'm fairly certain isn't an array.
I would also suggest that you either use a global board, or always pass it as an argument, but not mix-and-match where one function uses the global and the other uses an argument.
You never output a line break between rows.
Here's a minimal update addressing those:
var board;
var rowsNum = 5;
var colsNum = 5;
function printBoard(board) {
board.forEach(function(row) {
document.write(row.join(""));
document.write("<br>");
});
}
function clearAndRestartBoard() {
var row;
board = [];
for (var r = 0; r < rowsNum; r++) {
row = [];
for (var c = 0; c < colsNum; c++) {
row.push("[ ]"); // If you really wanted the string [ ]
}
board.push(row);
}
}
clearAndRestartBoard();
printBoard(board);

Sum not being calculated properly

The program should do the following: The user should input numbers on the input field on the right and should click compute. The value will be pushed in the array. This will be done X times. At this moment X is hardcoded to 5 but that is not the problem.
The problem is that after the last number is pushed in the array, the sum of the array will be calculated and put out on the webpage. The visualisation isn't a problem and I am pretty sure that the calculations are correct. I think that the problem is how the input is read or inputet in the array. I might be wrong about this though.
One last thing, the function in which everything is calculated is compute1.
EDIT: the actual error: Uncaught TypeError: Cannot read property 'value' of null
This is the entire source code:
<!DOCTYPE HTML>
<head>
<title>Asd</title>
<style>
.btn{
width : 30px;
}
.btn2{
width : 100px;
height : 40px;
}
</style>
</head>
<body>
<center>
<table>
<tr>
<td>Number of elements:</td><td><input type="number" id="textField" class="btn"></input></td>
<td>Please enter a number.</td> <td><input type="number" id="textFiledInp" class="btn"></input></td>
</tr>
</table>
<button class="btn2" onclick="compute1()" >compute</button>
<p id="output"></p>
</center>
</body>
<script>
//var eleNum = parseInt(document.getElementById("textField"));
var eleNum = 5;
var arr = new Array;
function compute1()
{
console.log("hi");
if(eleNum > 0)
{
eleNum--;
arr.push(parseInt(document.getElementById("textFieldInp").value));
console.log(arr[arr.length-1]);
}
else{
var sum = 0;
for(var i = 0; i < arr.size; i++)
{
sum+= arr[i];
}
document.getElementById("output").innerHTML = sum;
}
}
</script>
You have a typo in the id of your element:
id="textFiledInp"
...should be:
id="textFieldInp"
Otherwise getElementById() can't find the element and returns null, hence the error message you quote.
And your for loop is trying to use arr.size but it should be arr.length.
Presetting eleNum to 5 seems a bit strange, but I'm not entirely clear what you're trying to do there so I'm not sure what to advise. I suspect you just need to move the commented out line inside your function and add .value (and uncomment it):
eleNum = parseInt(document.getElementById("textField").value, 10);
And also, never use parseInt() without specifying the radix in the second parameter. This is particularly important for user-entered data. (Because otherwise the browser may interpret a value with a leading 0 as octal, and a leading 0x as hexadecimal.)
After fixing the typos in your HTML, you should change the code to this:
var eleNum = 5;
var arr = []; //see explanation
function compute1(value) {
console.log("hi");
if (eleNum > 0) {
eleNum--;
arr.push(parseInt(document.getElementById("textFieldInp").value || 0, 10)); // see explanation
console.log(arr[arr.length - 1]);
} else {
var sum = 0;
for (var i = 0; i < arr.length; i++) {
sum += arr[i];
}
document.getElementById("output").innerHTML = sum;
}
}
You were using new Array; instead of new Array(), the better way is to use bracket notation. Or, in your case, you can define an array based on the length given by the user(with the input) or even using yours number of elements. It would be new Array(eleNum).
Why || 0? Because if the input is not defined by the user(value is null) then it sums up 0, otherwise you'll have NaN; remember to specify radix in parseInt, see nnnnnn's answer.
See a working fiddle of this.
You have wrong ID of input:
<td>Please enter a number.</td> <td><input type="number" **id="textFiledInp"** class="btn"></input></td>
and you try to get element of id "textFieldInp":
document.getElementById("textFieldInp").value);
Change id="textFiledInp" to id="textFieldInp" and it should work.
And size is not correct property of javascript array. You should use length property in your loop.
If you want to push in arr the amount of numbers you've declared you should write something like this (I don't know if this is what you want):
function compute1()
{
console.log("hi");
if(eleNum > 0)
{
eleNum--;
arr.push(parseInt(document.getElementById("textFieldInp").value));
console.log(arr[arr.length-1]);
}
else{
var sum = 0;
for(var i = 0; i < arr.length; i++)
{
sum+= arr[i];
}
document.getElementById("output").innerHTML = sum;
}
}
As far as I can tell, your calculations are correct, but you're missing a bracket console.log(arr[arr.length-1)
It should be:
console.log(arr[arr.length-1]);

Categories

Resources