I wrote the following javaScript to try to draw a random path in an svg.
<script>
window.onload = function() {
function randomPath(){
var x = Math.trunc(Math.random());
var y = Math.trunc(Math.random());
var xstep = 0;
var ystep = 0;
var path = '0,0';
for (i = 0; i < 2 ; i++) {
path += ' ';
path += (x).toString();
path += ',';
path += (y).toString();
xstep = Math.random();
ystep = Math.random();
xstep *= 10;
ystep *= 10;
x += Math.trunc(xstep);
y += Math.trunc(ystep);
};
return path;
};
var figure = document.createElementNS('http://www.w3.org/2000/svg','svg');
figure.id = 'brownian-figure';
figure.setAttribute('height', '400pt');
figure.setAttribute('width', '200pt');
var pathArray = [];
for (i = 0; i < 3; i++){
pathArray[i] = document.createElementNS('http://www.w3.org/2000/svg','polyline');
};
for (i = 0; i < 3; i++){
var path = randomPath();
alert(path);
pathArray[i].setAttribute('points', path);
pathArray[i].setAttribute('style', 'fill:none;stroke:rgba(0,0,0,1);stroke-width:1');
figure.appendChild(pathArray[i]);
};
var divfigure = document.createElement('div');
divfigure.id = 'divfigure';
divfigure.style = 'margin:0pt;padding:0pt;border:0pt none;background-color:rgba(240,240,240,1);position:absolute;top:100pt;left:100pt;width:200pt;height:400pt;';
divfigure.appendChild(figure);
document.body.appendChild(divfigure);
};
</script>
Notice there are only 2 steps in the for in the randomPath() function.
The code does run and draws with that small value for the number of steps. There is an alert(path) over there to let me see the path before I try to assign it.
However, with 3 steps or more in the for inside randomPath() the code breaks. The alert(path) still shows the longer path, but the script gives the error
TypeError: pathArray[i] is undefined
pathArray[i].setAttribute('points', path);
If I replace path in the line with the error, by an explicit path (output by randomPath()), say '0,0 0,0 4,8 8,15' it still doesn't work. But if I do it and also remove the call to the randomPath() function it works again.
I am confused. It seems to be that the function randomPath() works well since the alert displays a well-formed string. The svg also works with the same string input explicitly. But the two together don't work for some reason.
What is the problem?
The problem is becoz inside last for loop you have initialise i and incremented it and then you call randomPath() which also contain i and that function increment it to 3 times so when it comes out function you have i value 3
so you get error on pathArray[i].setAttribute('points', path); changed it to k or something in randomPath() and also intialize variable as var identifier if don't want it to be global
for (i = 0; i < 3; i++){
var path = randomPath();
}
window.onload = function() {
function randomPath(){
var x = Math.trunc(Math.random());
var y = Math.trunc(Math.random());
var xstep = 0;
var ystep = 0;
var path = '0,0';
for (k = 0; k < 3 ; k++) {
path += ' ';
path += (x).toString();
path += ',';
path += (y).toString();
xstep = Math.random();
ystep = Math.random();
xstep *= 10;
ystep *= 10;
x += Math.trunc(xstep);
y += Math.trunc(ystep);
}
return path;
}
var figure = document.createElementNS('http://www.w3.org/2000/svg','svg');
figure.id = 'brownian-figure';
figure.setAttribute('height', '400pt');
figure.setAttribute('width', '200pt');
var pathArray = [];
for (j = 0; j < 3; j++){
pathArray[j] = document.createElementNS('http://www.w3.org/2000/svg','polyline');
}
for (i = 0; i < 3; i++){
var path = randomPath();
alert(path);
pathArray[i].setAttribute('points', path);
pathArray[i].setAttribute('style', 'fill:none;stroke:rgba(0,0,0,1);stroke-width:1');
figure.appendChild(pathArray[i]);
}
var divfigure = document.createElement('div');
divfigure.id = 'divfigure';
divfigure.style = 'margin:0pt;padding:0pt;border:0pt none;background-color:rgba(240,240,240,1);position:absolute;top:100pt;left:100pt;width:200pt;height:400pt;';
divfigure.appendChild(figure);
document.body.appendChild(divfigure);
};
Related
I'm a beginning JavaScript user. I'd like to calculate a score of 15 questions from a program.
What I need:
I put the value I received to JSq1, JSq2, etc. then I add them up and divided by total question and round up a score. I can lay everything in many lines but that does not look efficient. I'm trying to figure out a way to use loop to get all the same result.
Please help.
THANKS
<script language = "JavaScript">
// the following may work
var JSq1 =Varq1score.getValue();
var JSq2 =Varq2score.getValue();
var JSq3 =Varq3score.getValue();
var JSq4 =Varq4score.getValue();
var JSq5 =Varq5score.getValue();
var JSq6 =Varq6score.getValue();
var JSq7 =Varq7score.getValue();
var JSq8 =Varq8score.getValue();
var JSq9 =Varq9score.getValue();
var JSq10 =Varq10score.getValue();
var JSq11 =Varq11score.getValue();
var JSq12 =Varq12score.getValue();
var JSq13 =Varq13score.getValue();
var JSq14 =Varq14score.getValue();
var JSq15 =Varq15score.getValue();
var totalScore = JSq1 + JSq2 + JSq3 + ...
var totalQuestion = 15
var finalScore = parseFloat(totalScore/totalQuestion*100).toFixed(0);
// I'd like to do the following but don't know how to specify JSq1, JSq2, etc in a loop so I don't have to repeat the lines so many times.
var totalQ = 15;
for (i = 0; i <= totalQ ; i++) {
var JSq+[i] = "Varq"+ i + "score.getValue()";
}
for (i = 0; i <= totalQ ; i++) {
var totalScore = totalScore + JSq + [i];
}
...
</script>
1) Build an object all_vars with all the variable. (Here with object shorthand property, { JSq1 } will be equivalent to { JSq1: Varq1score.getValue() }
2) Use Object.values to get values of above object in an array.
3) Use any loop (in this case we are using reduce) to build total score dynamically.
With these slight changes to your current code, you can achieve the result. Check the following sample code.
var JSq1 = 3;
var JSq2 = 3;
var JSq3 = 3;
var JSq4 = 3;
var JSq5 = 3;
var JSq6 = 3;
var JSq7 = 3;
var JSq8 = 3;
var JSq9 = 3;
var JSq10 = 3;
var JSq11 = 3;
var JSq12 = 3;
var JSq13 = 3;
var JSq14 = 3;
var JSq15 = 3;
var all_vars = {
JSq1,
JSq2,
JSq3,
JSq4,
JSq5,
JSq6,
JSq7,
JSq8,
JSq9,
JSq10,
JSq11,
JSq12,
JSq13,
JSq14,
JSq15
};
var totalScore = Object.values(all_vars).reduce((sum, jsq) => sum + jsq, 0);
var totalQuestion = 15;
var finalScore = parseFloat((totalScore / totalQuestion) * 100).toFixed(0);
console.log(finalScore)
I made this simple Mandelbrot Set generator in Javascript last night, but it outputs a really strange structure. I think it looks similar to the mandelbrot set, yet oddly deformed. I have no idea why it distorts like this, and I've been trying to find out all day. Does anyone know what causes this or how to fix this?
c = document.getElementById("canvas");
ctx = c.getContext("2d");
c.width = 4000;
c.height = 4000;
declareVariables();
calculateShape();
drawShape();
function declareVariables() {
Re = -2;
Im = -2;
input = [Re,Im];
precision = prompt("input precision (higher is better)");
precision = 1/(precision - precision%4);
segmentAmt = 4/precision;
segmentSize = c.width/segmentAmt;
iterate = prompt("input test amount (higher is better)");
set = [];
for (i=0; i<segmentAmt; i++) {
set[i] = [];
}
numberGrid = [];
for (i=0; i<segmentAmt; i++) {
numberGrid[i] = [];
for (j=0; j<segmentAmt; j++) {
}
}
}
function calculateShape() {
for (i=0; i<segmentAmt; i++) {
input[1] = -2;
input[0] += precision;
for (j=0; j<segmentAmt; j++) {
input[1] += precision;
set[i][j] = 0;
z = [0,0];
for (k=1; k<=iterate; k++) {
store = z;
z[0] = store[0]**2 - store[1]**2 + input[0];
z[1] = 2 * store[0] * store[1] + input[1];
if (z[0]**2 + z[1]**2 > 4) {
set[i][j] = k;
k = iterate+1;
}
}
}
}
}
function drawShape() {
ctx.fillStyle = "white";
ctx.fillRect(0,0,c.width,c.height);
for (i=0; i<segmentAmt; i++) {
for (j=0; j<segmentAmt; j++) {
if (set[i][j] == 0) {
ctx.fillStyle = "black";
} else if (set[i][j] >= 1) {
ctx.fillStyle = 'hsl(' + (25*(set[i][j]-1))**0.75 + ', 100%, 50%)';
}
convertCoords(i,j);
ctx.fillRect(xCoord,yCoord,segmentSize,segmentSize);
}
}
}
function convertCoords(var1,var2) {
xCoord = var1 * segmentSize;
yCoord = var2 * segmentSize;
}
Output image:
The error appears to be on this line in calculateShape():
store = z;
It seems you want store to be a copy of z, but this just ends up with store and z referring to the same array. The next line calculates z[0], but as store and z refer to the same array, store[0] has the new value of z[0] rather than the previous. Hence the calculation of z[1] in the line after that is incorrect.
Replace the above line with either
store = [z[0], z[1]];
or
store = z.slice();
Both of these lines ensure that store refers to a different array to z, so when you recalculate z[0], store[0] is unaffected.
I have a string that contains coordinates and some whitesace:
E.G. "SM10,10 50,50 20,10\nFM10,20 30,40"
I'd like to extract the list of coordinates:
["10,10", "50,50", "20,10", "10,20", "30,40"]
And then perform some transform (let's say scale by 5) and produce a resultant string:
"SM50,50 250,250 100,50\nFM50,100 140,200"
What's the most performant way to perform this transformation in JavaScript?
Update:
This should be exactly what you needed. It finds and makes the changes to the coordinates in the string and reassembles the string in the format that it started. Let me know if you think its missing something.
function adjust(input) {
var final = "";
var lastIndex;
var temp = [];
var regex;
var coords = input.match(/\d+,\d+/g);
if (coords) {
for (i = 0; i < coords.length; i++) {
temp = coords[i].split(",");
temp[0] *= 5;
temp[1] *= 5;
regex = new RegExp("([^0-9])?" + coords[i] + "([^0-9])?","g");
regex.exec(input);
lastIndex = parseInt(regex.lastIndex);
final += input.slice(0, lastIndex).replace(regex, "$1" + temp.join(",") + "$2");
input = input.slice(lastIndex, input.length);
temp.length = 0;
}
}
return final + input;
}
Previous answer:
Here, fast and effective:
var coords = "SM10,10 50,50 20,10\nFM10,20 30,40".match(/\d{1,2},\d{1,2}/g);
for (i = 0; i < coords.length; i++) {
var temp = coords[i].split(",");
temp[0] *= 5;
temp[1] *= 5;
coords[i] = temp.join(",");
}
alert (coords.join(","));
So. I have 4 for loops inside other for loops in JS, and my code appears (FireBug agrees with me) that my code is syntactically sound, and yet it refuses to work. I'm attempting to calculate the key length in a vigenere cipher through the use of the Index of Coincidence, and Kappa tests <- if that helps any.
My main problem is that the task seems to be too computationally intensive for Javascript to run, as Firefox shoots up past 1GB of memory usage, and 99% CPU when I attempt to run the keylengthfinder() function. Any ideas of how to solve this problem, even if it takes much longer to calculate, would be greatly appreciated. Here's a link to the same code - http://pastebin.com/uYPBuZZz - Sorry about any indenting issues in this code. I'm having issues putting it on the page correctly.
function indexofcoincidence(text){
text = text.split(" ").join("").toUpperCase();
var textL = text.length;
var hashtable = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (d=0; d<=25; d++) {
for (i=0; i < textL; i++){
if (text.charAt(i) === alphabet.charAt(d)){
hashtable[d] = hashtable[d] + 1;
}
}
}
var aa = hashtable[0]/textL;
var A = aa*aa;
var bb = hashtable[1]/textL;
var B = bb*bb;
var cc = hashtable[2]/textL;
var C = cc*cc;
var dd = hashtable[3]/textL;
var D = dd*dd;
var ee = hashtable[4]/textL;
var E = ee*ee;
var ff = hashtable[5]/textL;
var F = ff*ff;
var gg = hashtable[6]/textL;
var G = gg*gg;
var hh = hashtable[7]/textL;
var H = hh*hh;
var ii = hashtable[8]/textL;
var I = ii*ii;
var jj = hashtable[9]/textL;
var J = jj*jj;
var kk = hashtable[10]/textL;
var K = kk*kk;
var ll = hashtable[11]/textL;
var L = ll*ll;
var mm = hashtable[12]/textL;
var M = mm*mm;
var nn = hashtable[13]/textL;
var N = nn*nn;
var oo = hashtable[14]/textL;
var O = oo*oo;
var pp = hashtable[15]/textL;
var P = pp*pp;
var qq = hashtable[16]/textL;
var Q = qq*qq;
var rr = hashtable[17]/textL;
var R = rr*rr;
var ss = hashtable[18]/textL;
var S = ss*ss;
var tt = hashtable[19]/textL;
var T = tt*tt;
var uu = hashtable[20]/textL;
var U = uu*uu;
var vv = hashtable[21]/textL;
var V = vv*vv;
var ww = hashtable[22]/textL;
var W = ww*ww;
var xx = hashtable[23]/textL;
var X = xx*xx;
var yy = hashtable[24]/textL;
var Y = yy*yy;
var zz = hashtable[25]/textL;
var Z = zz*zz;
var Kappa = A+B+C+D+E+F+G+H+I+J+K+L+M+N+O+P+Q+R+S+T+U+V+W+X+Y+Z;
var Top = 0.027*textL;
var Bottom1 = 0.038*textL + 0.065;
var Bottom2 = (textL - 1)*Kappa;
var KeyLength = Top/(Bottom2 - Bottom1) ;
return Kappa/0.0385;
}
function keylengthfinder(text){
// Average Function Definition
Array.prototype.avg = function() {
var av = 0;
var cnt = 0;
var len = this.length;
for (var i = 0; i < len; i++) {
var e = +this[i];
if(!e && this[i] !== 0 && this[i] !== '0') e--;
if (this[i] == e) {av += e; cnt++;}
}
return av/cnt;
}
// Begin the Key Length Finding
var textL = text.length;
var hashtable = new Array(0,0,0,0,0,0,0,0,0,0,0,0);
for (a = 0; a <= 12; a++){ // This is the main loop, testing each key length
var stringtable = [];
for (z = 0; z <= a; z++){ // This allows each setting, ie. 1st, 4th, 7th AND 2nd, 5th, 8th to be tested
for (i = z; i < textL; i + a){
var string = '';
string = string.concat(text.charAt(i)); // Join each letter of the correct place in the string
stringtable[z] = indexofcoincidence(string);
}
}
hashtable[a] = stringtable.avg();
}
return hashtable;
}
Your problem is definitely right here
for (i = z; i < textL; i + a){
var string = '';
string = string.concat(text.charAt(i)); // Join each letter of the correct place in the string
stringtable[z] = indexofcoincidence(string);
}
Notice that if a=0 i never changes and therefore you are in an infinite loop.
Array.prototype.avg = function() {...}
should be only done once, and not every time keylengthfinder is called.
var Top = 0.027*textL;
var Bottom1 = 0.038*textL + 0.065;
var Bottom2 = (textL - 1)*Kappa;
var KeyLength = Top/(Bottom2 - Bottom1) ;
return Kappa/0.0385;
Why do you computer those variables if you don't use them at all?
var string = '';
string = string.concat(text.charAt(i)); // Join each letter of the correct place in the string
stringtable[z] = indexofcoincidence(string);
I don't know what you are trying to do in here. The string will always be only one character?
for (i = z; i < textL; i + a) {
...
stringtable[z] = ...
}
In this loop, you are computing values for i from z to textL - but you overwrite the same array item each time. So it would be enough to compute the stringtable[z] for i=textL-1 - or your algorithm is flawed.
A much shorter and more concise variant of the indexofcoincidence function:
function indexofcoincidence(text){
var l = text.replace(/ /g, "").length;
text = text.toUpperCase().replace(/[^A-Z]/g, "");
var hashtable = {};
for (var i=0; i<l; i++) {
var c = text.charAt(i);
hashtable[c] = (hashtable[c] || 0) + 1;
}
var kappa = 0;
for (var c in hashtable)
kappa += hashtable[c] * hashtable[c];
return kappa/(l*l)/0.0385;
}
All right. Now that we found your problem (including the infinite loop in case a=0, as detected by qw3n), let's rewrite the loop:
function keylengthfinder(text) {
var length = text.length,
probabilities = []; // probability by key length
maxkeylen = 13; // it might make more sense to determine this in relation to length
for (var a = 1; a <= maxkeylen; a++) { // testing each key length
var stringtable = Array(a); // strings to check with this gap
// read "a" as stringtable.length
for (var z = 0; z < a; z++) {
var string = '';
for (var i = z; i < textL; i += a) {
string += text.charAt(i);
}
// a string consisting of z, z+a, z+2a, z+3a, ... -th letters
stringtable[z] = string;
}
var sum = 0;
// summing up the coincidence indizes for current stringtable
for (var i=0; i<a; i++) {
sum += indexofcoincidence(stringtable[i]);
}
probabilities[a] = sum / a; // average
}
return probabilities;
}
Every of the loop statements has changed against your original script!
Never forget to declare the running variable to be local (var keyword)
a needs to start at zero - a key must have a minimum length of 1
to run from 1 to n, use i=1; i<=n; i++
to run from 0 to n-1, use i=0; i<n; i++ (nearly all loops, especially on zero-based array indizes).
Other loops than those two never occur in normal programs. You should get suspicious if you have loops from 0 to n or from 1 to n-1...
The update expression needs to update the running variable. i++ is a shortcut for i+=1 is a shortcut for i=i+1. Your expression, i + a, did not assign the new value (apart from the a=0 problem)!
I'm pretty new to programming and javascript/dom. Ultimately, I'm trying to make a sliding puzzle game but to start off with, I'm just trying to get the images loading up in a random order. It's going to be a 4x4 grid of images. The images are named Tree00, 01, 02, 03, 10, etc up to 33. Here's my code so far:
<html>
<head>
<title>Shuffle</title>
</head>
<body>
<script language="JavaScript">
<!--
Pics = new Array();
var Top = 16;
for(i = 0; i < Top; i++) {
document.write("<img><img><img><img><br>");
}
function RandomInt(Min, Max) {
RI = Math.floor(Math.random() * (Max - Min + 1)) + Min;
return(RI);
}
function Shuffle() {
N = RandomInt(0, 1);
this.Image.src=Pics[N];
this.Image.style.left = 220;
}
function ViewerObj(Image, Pics, i) {
this.Image = Image;
this.Image.style.left = 800;
this.Pics = Pics;
this.Shuffle = Shuffle;
this.Image.id = "ID" + i;
}
function Randomise() {
var i;
for(i = 0; i < Top; i++) {
Viewers[i].Shuffle();
Viewers[i].Image.style.left = 200;
}
}
Viewers = new Array();
var i;
for(i = 0; i < 3; i++) {
Pics[i] = "images/Tree" + (i) + (i + 1) + ".jpg";
}
for(i = 0; i < Top; i++) {
document.images[i].src = "images/Blank.jpg";
document.images[i].style.left = 300;
Viewers[i] = new ViewerObj(document.images[i], Pics, i);
}
//-->
</script>
<h1>Shuffle</h1>
<form>
<input type="button" value="Shuffle" onClick="Randomise();"/>
</form>
</body>
</html>
I just can't quite fathom what I need to be changing and how I'd go about it. Any help + explanation would be much appreciated. What I am trying to achieve is it loading every image but just in a random order, but with no duplicates.
Here are a few problems in your script :
first replace
for(i = 0; i < Top; i++) {
document.write("<img><img><img><img><br>");
}
by
for(i = 0; i < Top; i++) {
document.write("<img>");
if ((i+1)%4 == 0) {
document.write("<br>");
}
}
you will get only 16 IMG elements instead of 4*16 in your code
then you will need 16 different names for your images : replace
for(i = 0; i < 3; i++) {
Pics[i] = "images/Tree" + (i) + (i + 1) + ".jpg";
}
by
for(var i = 0; i < 4; i++) {
for(var j = 0; j < 4; j++) {
Pics[j+4*i] = "images/Tree" + (i) + (j) + ".jpg";
}
}
Then you biggest problem is the shuffling. You cannot shuffle the "Viewers" one-by-one because you want to avoid duplicates. Each viewer must randomly select a unique image.
For this you can use the technique in mdarwi's answer : shuffle the Pics table for instance.
check your modified code on jsbin here
If your problem is simply that you'd like the images to be properly shuffled, you can use the following code (taken directly from the Javascript sample code for the Fisher-Yates shuffle on Wikipedia:
var n = a.length;
for(var i = n - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
The easiest thing to do would be to rename your images Tree1 to TreeN, and then place N integers in an array and shuffle them using the above algorithm.
(This is a code-comment, not an answer)
Pics = new Array();
The Pics variable should be declared before using. Also, use the shorthand notation []
var Pics = [];
var Top = 16;
for (i = 0; i < Top; i++) {
document.write("<img><img><img><img><br>");
}
The i variable is declared only later in the code. It should be declared at the top of the program.
function RandomInt(Min, Max) {
RI = Math.floor(Math.random() * (Max - Min + 1)) + Min;
return (RI);
}
This is particularly dangerous: the RI variable is not declared inside the function, so it becomes an implicit global property. That should be avoided. Also, the parens in the return statement are superfluous.
function RandomInt(Min, Max) {
return Math.floor(Math.random() * (Max - Min + 1)) + Min;
}
function Shuffle() {
N = RandomInt(0, 1);
this.Image.src = Pics[N];
this.Image.style.left = 220;
}
Again, the N variable should be declared. Also, why is this "method" declared outside of the ViewerObj constructor? Either, put it inside, or - even better - add it to the constructors prototype object. That way, there will only be one Shuffle function object instead of many.
function ViewerObj(Image, Pics, i) {
this.Image = Image;
this.Image.style.left = 800;
this.Pics = Pics;
this.Shuffle = Shuffle;
this.Image.id = "ID" + i;
}
function Randomise() {
var i;
for (i = 0; i < Top; i++) {
Viewers[i].Shuffle();
Viewers[i].Image.style.left = 200;
}
}
Viewers = new Array();
var i;
As mentioned above, the i variable should be declared on top. Also, the Viewers variable should be declared.
var Viewers = [];
for (i = 0; i < 3; i++) {
Pics[i] = "images/Tree" + (i) + (i + 1) + ".jpg";
}
for (i = 0; i < Top; i++) {
document.images[i].src = "images/Blank.jpg";
document.images[i].style.left = 300;
Viewers[i] = new ViewerObj(document.images[i], Pics, i);
}