probability in javascript help? - javascript

Sorry, I'm new to JS and can't seem to figure this out: how would I do probability?
I have absolutely no idea, but I'd like to do something: out of 100% chance, maybe 0.7% chance to execute function e(); and 30% chance to execute function d(); and so on - they will add up to 100% exactly with a different function for each, but I haven't figured out exactly how to do this in any form.
What I found is mostly strange high school math tutorials "powered by" Javascriptkit or something.

For instance we define a number of functions
function a () { return 0; }
function b () { return 1; }
function c () { return 2; }
var probas = [ 20, 70, 10 ]; // 20%, 70% and 10%
var funcs = [ a, b, c ]; // the functions array
That generic function works for any number of functions, it executes it and return the result:
function randexec()
{
var ar = [];
var i,sum = 0;
// that following initialization loop could be done only once above that
// randexec() function, we let it here for clarity
for (i=0 ; i<probas.length-1 ; i++) // notice the '-1'
{
sum += (probas[i] / 100.0);
ar[i] = sum;
}
// Then we get a random number and finds where it sits inside the probabilities
// defined earlier
var r = Math.random(); // returns [0,1]
for (i=0 ; i<ar.length && r>=ar[i] ; i++) ;
// Finally execute the function and return its result
return (funcs[i])();
}
For instance, let's try with our 3 functions, 100000 tries:
var count = [ 0, 0, 0 ];
for (var i=0 ; i<100000 ; i++)
{
count[randexec()]++;
}
var s = '';
var f = [ "a", "b", "c" ];
for (var i=0 ; i<3 ; i++)
s += (s ? ', ':'') + f[i] + ' = ' + count[i];
alert(s);
The result on my Firefox
a = 20039, b = 70055, c = 9906
So a run about 20%, b ~ 70% and c ~ 10%.
Edit following comments.
If your browser has a cough with return (funcs[i])();, just replace the funcs array
var funcs = [ a, b, c ]; // the old functions array
with this new one (strings)
var funcs = [ "a", "b", "c" ]; // the new functions array
then replace the final line of the function randexec()
return (funcs[i])(); // old
with that new one
return eval(funcs[i]+'()');

Something like this should help:
var threshhold1 = 30.5;
var threshhold2 = 70.5;
var randomNumber = random() * 100;
if (randomNumber < threshhold1) {
func1()
}
else if (randomNumber < threshhold2) {
func2()
}
else {
func3()
}
This will execute func1() with 30.5% probability, func2() with 40%, and func3() with 29.5%.
You could probably do it more elegantly using a dictionary of threshholds to function pointers, and a loop that finds the first dictionary entry with a threshhold greater than randomNumber.

// generate cumulative distribution function from weights
function cdf(weights) {
// calculate total
var total = 0;
for(var i=0; i<weights.length; i++) {
total += weights[i];
}
// generate CDF, normalizing with total
var cumul = [];
cumul[0] = weights[0]/total;
for(var i=1; i<weights.length; i++) {
cumul[i] = cumul[i-1] + (weights[i]/total);
}
return cumul;
}
// pick the index using the random value
function selectInd(cumul,rand) {
for(var i=0; (i < cumul.length) && (rand > cumul[i]); ++i) {};
return i;
}
Code block to use the above
// setup (do this once)
var weights = [70,20,10];
var cumul = cdf(weights)
// get the index and pick the function
var ran = Math.random(); // 0 : 1
var func = funcs[selectInd(cumul,ran)];
// call the function
var someArgVal = 5;
var myResult = func(someArgVal);
// do it in one line
var myResult = (funcs[selectInd(cumul,Math.random())])(someArgVal);
Simplify calling code with a reusable object
function CumulDistributor(cumul,funcs) {
var funcArr = funcs;
var cumulArr = cumul;
function execRandomFunc(someArg) {
var func = funcArr[selectInd(cumulArr,Math.random())];
return func(someArg);
}
}
// example usage
var cdistor = new CumulDistributor(cumul,funcs);
var myResult = cdistor.execRandomFunc(someArgValue);

var decide = function(){
var num = parseInt(Math.random() * 10) + 1; // assigns num randomly (1-10)
num > 7 ? d() : e(); // if num > 7 call d(), else call e()
};

Look up how to get random numbers in JavaScript, and then depending on where that number falls, call each function.

Sounds like what you really want is the Javascript random() function.

Related

Algorithm to calculate if 'n' or more intervals intersect & the total of the respective intersections

I need help developing a weird algorithm. I have a JavaScript object containing people and an array for each person of start and end time intervals in milliseconds:
var person = [
(1533242595, 1533242999),
(1533242595, 1533242999),
(1533242595, 1533242999)
]
I need to determine if any intervals intersect/overlap, but for n or more intersections (for example, determining if 4+ intervals overlap) and calculate the total sum of the n or more intersecting intervals.
A function that takes a n parameter and the person object would be perfect.
First the person must be defined as list of lists:
var person = [
[1533242595, 1533242999],
[1533242595, 1533242999],
[1533242595, 1533242999]
];
Here you can find a sample of function:
function limit_intersection(limit, person) {
var arrayLength = person.length;
var intersections = 0;
var intersectionsum = 0;
var min, max = 0;
var tmp;
var intervals = [];
for (var i = 0; i < arrayLength-1; i++) {
if(person[i][0] > person[i][1]) {
tmp = person[i][1];
person[i][1] = person[i][0];
person[i][0] = tmp;
}
for (var j = i+1; j < arrayLength; j++) {
if(person[j][0] > person[j][1]) {
tmp = person[j][1];
person[j][1] = person[j][0];
person[j][0] = tmp;
}
min = 0;
max = 0;
if(person[i][1] <= person[j][0] || person[i][0] >= person[j][1]){
// no intersection
continue;
}
intersections +=1;
if(person[i][0] >= person[j][0]) {
min = person[i][0];
} else {
min = person[j][0];
}
if(person[i][1] >= person[j][1]) {
max = person[j][1];
} else {
max = person[i][1];
}
intervals.push([min,max]);
intersectionsum += max-min;
}
}
return {'n' : intersections, 'sum' : intersectionsum, 'intervals' : intervals};
}
An here the working demo on jsfiddle.net
Are you sure that's how your data is structured? Because that does not look like a Javascript object to me, correct me if I'm wrong.
Break your code in to bite sized problems. What is an overlap? How do we check if two intervals overlap each other? When you make that function, use that to loop through your person intervals. Make a variable that contains the sum of the matches and return that.
function overlaps(startX, endX, startY, endY) {
if(endX < startY || endY < startX) return false;
return true;
}
console.log(overlaps(1,2,1,4)) // true
console.log(overlaps(10,20,1,11)) // true
console.log(overlaps(1,2,3,4)) // false
console.log(overlaps(4,3,2,1)) // false
Now find a way to loop over your persons checking for overlaps with this bite sized function.
Edited, here's an example of answer with bite-sized readable functions instead of the spagetti code in the selected answer:
// Check if two intervals overlap
function overlaps(startX, endX, startY, endY) {
if(endX < startY || endY < startX) return false;
return true;
}
// Check how many times two person arrays overlap
function comparePersons(person1, person2){
var matches = 0;
person1.forEach(function(elementX) {
person2.forEach(function(elementY) {
if(overlaps(
elementX[0],elementX[1],
elementY[0],elementY[1]
)) matches +=1
});
});
return matches;
}
// Check how many times all persons overlap with another
function compareAll(persons, n){
var totalMatches = 0;
persons.forEach(function(element, index1) {
var compareMatches = 0;
persons.forEach(function(compareElement, index2) {
if(index1 !== index2) {
compareMatches += comparePersons(element, compareElement)
}
});
if(compareMatches >= n) totalMatches += 1;
});
return totalMatches;
}
// Create persons to test
var person1 = [
[10,20],
[100,200]
]
var person2 = [
[1,2000],
[50,1000]
]
var person3 = [
[10,200],
[0,1],
[1000,2000],
[100,2000]
]
// Create one array with all persons
var allPersons = [
person1, person2, person3
]
// Test by console logging
console.log(compareAll(allPersons, 5));

Newtons Method In JS Being Inaccurate

So, I am trying to write a js function that takes 3 inputs (polynomial, guess and limit) and make them return the approximate root of the polynomial. The problem is that, even with a limit of 1000, the result is still very inaccurate. Does anybody have any ideas on why this may be?
The Method
The code:
var derivativeOfATerm = function(arr) {
var one = arr[0];
var two = arr[1];
var derivative = [];
if (two <= 0) {
return [0, 0];
} else {
derivative.push(one * two);
derivative.push(two - 1);
return derivative;
}
};
var derivativeOfPolynomial = function(arr, order = 1) {
var derivative = [];
for (var i = 0; i < arr.length; i++) {
//console.log(arr[i]);
derivative.push(derivativeOfATerm(arr[i]));
}
if (order === 1) {
return derivative;
} else {
return derivativeOfPolynomial(derivative, order - 1);
}
};
var runPolynomial = function(poly, num) {
var array = [];
for (var i = 0; i < poly.length; i++) {
array.push(Math.pow(num, poly[i][1]) * poly[i][0]);
}
return array.reduce((a, b) => a + b);
};
var newtonRootFind = function(polynomial, guess, limit = 10) {
var derivative = derivativeOfPolynomial(polynomial);
var previous = guess;
var next;
for (var i = 0; i < limit; i++) {
next = previous - (runPolynomial(polynomial, previous)) / (runPolynomial(derivative, previous));
previous = next;
console.log("%o : x=%o, p(x)=%o", i+1, next, runPolynomial(polynomial, next));
}
return previous;
};
console.log("result x=",newtonRootFind([[1,2],[1,1],[-5,0]], 5, 10));
I'm only 12 so try not to use that many technical terms.
For example, entering [[1,2],[1,1],[-5,0]] or x^2+x-5, it returns 1.79128784747792, which isn't accurate enough. It equals 4.79... when it should be very close to 5.
As worked out in the comments, the presented code works as intended, the problem was that in checking the solution x^2 was used for the square x*x.
However, x^y in most C- or Java-like languages is the bitwise "exclusive or", XOR, not the power operation. x^y as symbol for the power operation is usually found in Computer Algebra Systems. Script languages as python or gnuplot tend to use x**y.

"Look and say sequence" in javascript

1
11
12
1121
122111
112213
122211
....
I was trying to solve this problem. It goes like this.
I need to check the former line and write: the number and how many time it was repeated.
ex. 1 -> 1(number)1(time)
var antsArr = [[1]];
var n = 10;
for (var row = 1; row < n; row++) {
var lastCheckedNumber = 0;
var count = 1;
antsArr[row] = [];
for (var col = 0; col < antsArr[row-1].length; col++) {
if (lastCheckedNumber == 0) {
lastCheckedNumber = 1;
antsArr[row].push(lastCheckedNumber);
} else {
if (antsArr[row-1][col] == lastCheckedNumber) {
count++;
} else {
lastCheckedNumber = antsArr[row-1][col];
}
}
}
antsArr[row].push(count);
antsArr[row].push(lastCheckedNumber);
}
for (var i = 0; i < antsArr.length; i++) {
console.log(antsArr[i]);
}
I have been on this since 2 days ago.
It it so hard to solve by myself. I know it is really basic code to you guys.
But still if someone who has a really warm heart help me out, I will be so happy! :>
Try this:
JSFiddle Sample
function lookAndSay(seq){
var prev = seq[0];
var freq = 0;
var output = [];
seq.forEach(function(s){
if (s==prev){
freq++;
}
else{
output.push(prev);
output.push(freq);
prev = s;
freq = 1;
}
});
output.push(prev);
output.push(freq);
console.log(output);
return output;
}
// Sample: try on the first 11 sequences
var seq = [1];
for (var n=0; n<11; n++){
seq = lookAndSay(seq);
}
Quick explanation
The input sequence is a simple array containing all numbers in the sequence. The function iterates through the element in the sequence, count the frequency of the current occurring number. When it encounters a new number, it pushes the previously occurring number along with the frequency to the output.
Keep the iteration goes until it reaches the end, make sure the last occurring number and the frequency are added to the output and that's it.
I am not sure if this is right,as i didnt know about this sequence before.Please check and let me know if it works.
var hh=0;
function ls(j,j1)
{
var l1=j.length;
var fer=j.split('');
var str='';
var counter=1;
for(var t=0;t<fer.length;t++)
{
if(fer[t]==fer[t+1])
{
counter++;
}
else
{
str=str+""+""+fer[t]+counter;
counter=1;
}
}
console.log(str);
while(hh<5) //REPLACE THE NUMBER HERE TO CHANGE NUMBER OF COUNTS!
{
hh++;
//console.log(hh);
ls(str);
}
}
ls("1");
You can check out the working solution for in this fiddle here
You can solve this by splitting your logic into different modules.
So primarily you have 2 tasks -
For a give sequence of numbers(say [1,1,2]), you need to find the frequency distribution - something like - [1,2,2,1] which is the main logic.
Keep generating new distribution lists until a given number(say n).
So split them into 2 different functions and test them independently.
For task 1, code would look something like this -
/*
This takes an input [1,1,2] and return is freq - [1,2,2,1]
*/
function find_num_freq(arr){
var freq_list = [];
var val = arr[0];
var freq = 1;
for(i=1; i<arr.length; i++){
var curr_val = arr[i];
if(curr_val === val){
freq += 1;
}else{
//Add the values to the freq_list
freq_list.push([val, freq]);
val = curr_val;
freq = 1;
}
}
freq_list.push([val, freq]);
return freq_list;
}
For task 2, it keeps calling the above function for each line of results.
It's code would look something like this -
function look_n_say(n){
//Starting number
var seed = 1;
var antsArr = [[seed]];
for(var i = 0; i < n; i++){
var content = antsArr[i];
var freq_list = find_num_freq(content);
//freq_list give an array of [[ele, freq],[ele,freq]...]
//Flatten so that it's of the form - [ele,freq,ele,freq]
var freq_list_flat = flatten_list(freq_list);
antsArr.push(freq_list_flat);
}
return antsArr;
}
/**
This is used for flattening a list.
Eg - [[1],[1,1],[1,2]] => [1,1,1,1,2]
basically removes only first level nesting
**/
function flatten_list(li){
var flat_li = [];
li.forEach(
function(val){
for(ind in val){
flat_li.push(val[ind]);
}
}
);
return flat_li;
}
The output of this for the first 10 n values -
OUTPUT
n = 1:
[[1],[1,1]]
n = 2:
[[1],[1,1],[1,2]]
n = 3:
[[1],[1,1],[1,2],[1,1,2,1]]
n = 4:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1]]
n = 5:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1],[1,1,2,2,1,3]]
n = 6:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1],[1,1,2,2,1,3],[1,2,2,2,1,1,3,1]]
n = 7:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1],[1,1,2,2,1,3],[1,2,2,2,1,1,3,1],[1,1,2,3,1,2,3,1,1,1]]
n = 8:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1],[1,1,2,2,1,3],[1,2,2,2,1,1,3,1],[1,1,2,3,1,2,3,1,1,1],[1,2,2,1,3,1,1,1,2,1,3,1,1,3]]
n = 9:
[[1],[1,1],[1,2],[1,1,2,1],[1,2,2,1,1,1],[1,1,2,2,1,3],[1,2,2,2,1,1,3,1],[1,1,2,3,1,2,3,1,1,1],[1,2,2,1,3,1,1,1,2,1,3,1,1,3],[1,1,2,2,1,1,3,1,1,3,2,1,1,1,3,1,1,2,3,1]]

Javascript: Random number out of 5, no repeat until all have been used

I am using the below code to assign a random class (out of five) to each individual image on my page.
$(this).addClass('color-' + (Math.floor(Math.random() * 5) + 1));
It's working great but I want to make it so that there are never two of the same class in a row.
Even better would be if there were never two of the same in a row, and it also did not use any class more than once until all 5 had been used... As in, remove each used class from the array until all of them have been used, then start again, not allowing the last of the previous 5 and the first of the next 5 to be the same color.
Hope that makes sense, and thanks in advance for any help.
You need to create an array of the possible values and each time you retrieve a random index from the array to use one of the values, you remove it from the array.
Here's a general purpose random function that will not repeat until all values have been used. You can call this and then just add this index onto the end of your class name.
var uniqueRandoms = [];
var numRandoms = 5;
function makeUniqueRandom() {
// refill the array if needed
if (!uniqueRandoms.length) {
for (var i = 0; i < numRandoms; i++) {
uniqueRandoms.push(i);
}
}
var index = Math.floor(Math.random() * uniqueRandoms.length);
var val = uniqueRandoms[index];
// now remove that value from the array
uniqueRandoms.splice(index, 1);
return val;
}
Working demo: http://jsfiddle.net/jfriend00/H9bLH/
So, your code would just be this:
$(this).addClass('color-' + (makeUniqueRandom() + 1));
Here's an object oriented form that will allow more than one of these to be used in different places in your app:
// if only one argument is passed, it will assume that is the high
// limit and the low limit will be set to zero
// so you can use either r = new randomeGenerator(9);
// or r = new randomGenerator(0, 9);
function randomGenerator(low, high) {
if (arguments.length < 2) {
high = low;
low = 0;
}
this.low = low;
this.high = high;
this.reset();
}
randomGenerator.prototype = {
reset: function() {
this.remaining = [];
for (var i = this.low; i <= this.high; i++) {
this.remaining.push(i);
}
},
get: function() {
if (!this.remaining.length) {
this.reset();
}
var index = Math.floor(Math.random() * this.remaining.length);
var val = this.remaining[index];
this.remaining.splice(index, 1);
return val;
}
}
Sample Usage:
var r = new randomGenerator(1, 9);
var rand1 = r.get();
var rand2 = r.get();
Working demo: http://jsfiddle.net/jfriend00/q36Lk4hk/
You can do something like this using an array and the splice method:
var classes = ["color-1", "color-2", "color-3", "color-4", "color-5"];
for(i = 0;i < 5; i++){
var randomPosition = Math.floor(Math.random() * classes.length);
var selected = classes.splice(randomPosition,1);
console.log(selected);
alert(selected);
}
var used = [];
var range = [0, 5];
var generateColors = (function() {
var current;
for ( var i = range[0]; i < range[5]; i++ ) {
while ( used.indexOf(current = (Math.floor(Math.random() * 5) + 1)) != -1 ) ;
used.push(current);
$(" SELECTOR ").addClass('color-' + current);
}
});
Just to explain my comment to jfriend00's excellent answer, you can have a function that returns the members of a set in random order until all have been returned, then starts again, e.g.:
function RandomList(list) {
var original = list;
this.getOriginal = function() {
return original;
}
}
RandomList.prototype.getRandom = function() {
if (!(this.remainder && this.remainder.length)) {
this.remainder = this.getOriginal().slice();
}
return this.remainder.splice(Math.random() * this.remainder.length | 0,1);
}
var list = new RandomList([1,2,3]);
list.getRandom(); // returns a random member of list without repeating until all
// members have been returned.
If the list can be hard coded, you can keep the original in a closure, e.g.
var randomItem = (function() {
var original = [1,2,3];
var remainder;
return function() {
if (!(remainder && remainder.length)) {
remainder = original.slice();
}
return remainder.splice(Math.random() * remainder.length | 0, 1);
};
}());

JavaScript syntax issue

I'm doing "fifteen puzzle" game. I'm only a beginner, so I chose this project to implement. My problem is shuffle algorithm :
function shuffle() {
$('td').empty();
var p = 0;
var f = 0;
do {
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
var rand = arr[Math.floor(Math.random() * arr.length)];
if ($('#' + rand).is(':empty')) {
p = p + 1;
document.getElementById(rand).textContent = p
var f = $('td').not(":empty").length;
} else {}
} while (f < 15)
That works cool, but I've heard that almost 50% of all random shuffle like mine is unsolvable. So I found math formula at wikipedia.org for this game, explaining how you can avoid that.
Here's modified algorithm that doesn't work either. The way I know it is alert stuff: it launches only 2 times instead of 31.
array = [];
function algorithm (){
// alert('works')
for (var c=16; c<17; c++){
document.getElementById(c).textContent = '100';
}
for (var i=1; i<16; i++){
var curId = document.getElementById(i).id;
var curIdNum = Math.floor(curId);
alert('works')
var curIn = document.getElementById(i).textContent;
var curInNum = Math.floor(curIn);
array.push(i);
array[i] = new Array();
for (var j=1; j<15; j++){
var nextId = curIdNum + j; //curIdNum NOT cerIdNum
var nextIn = document.getElementById(nextId).textContent;
//alert('works')
if (nextId < 16){
var nextInNum = Math.floor(nextIn);
if (curInNum > nextInNum){
array[i].push(j)
}
}
}
var sum = 0;
for (var a=0; a<15; a++){
var add = array[a].length;
sum = sum + add;
}
var end = sum + 4;
if (end % 2 == 0){
document.getElementById('16').textContent = "";
}
else {
shuffle();
}
}
}
The question is the same:
What's wrong? Two-dimensional array doesn't work.If you've got any questions - ask.
Just to make it clear: 2 for loops with i and j should make a 2-dimensional array like this [ this is " var i" -->[1,3,4,5,7], this is "var i" too-->[5,7,9,14,15]]. Inside each i there's j. The for loop with var a should count the number of js inside each i. if the number of js is even, the code is finished and shuffle's accomplished, otherwise shuffle should be made once again.
var nextId = cerIdNum + j;
in that fiddle, I don't see this cerIdNum declared & defined neither as local nor as global variable, I suppose that is curIdNum
Please use the below definition of algorithm and let us know if this works. Basically, the alert messages would come only twice, since there were usages of undefined variables. For the purpose of illustration, I have placed comments at where the problem points occured. Due to these problems, your script would stop executing abruptly thereby resulting in the behavior you described.
Oh and by the way - I did not have time to go through the Wiki link provided - hence you will have to verify your logic is correct. However, I have definitely resolved the errors causing the behavior you observed.
As an aside - consider using jQuery, your code will be a lot cleaner...
function algorithm (){
// alert('works')
for (var c=16; c<17; c++){
document.getElementById(c).textContent = '100';
}
for (var i=1; i<16; i++){
var curId = document.getElementById(i).id;
var curIdNum = Math.floor(curId);
alert('works')
var curIn = document.getElementById(i).textContent;
var curInNum = Math.floor(curIn);
array.push(i);
for (var j=1; j<15; j++){
var nextId = curIdNum + j; //curIdNum NOT cerIdNum
var nextIn = document.getElementById(nextId).textContent;
//alert('works')
if (nextId < 16){
var nextInNum = Math.floor(nextIn);
if (curInNum > nextInNum){
array.push(j) //array[i].push does not make sense
}
}
}
var sum = 0;
for (var a=0; a<15; a++){
var add = array.length; //array[1].length does not make sense
sum = sum + add;
}
var end = sum + 4;
if (end % 2 == 0){
document.getElementById('16').textContent = "";
}
else {
shuffle();
}
}
}
I found the solution by totally rewriting the code. Thank everyone for help!
Here's what do work:
function shuffle (){
press = 1;
$('td').empty().removeClass();
p=0;
var f;
do {
var arr=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var rand=arr[Math.floor(Math.random()*arr.length)];
if ($('#'+ rand).is(':empty')){
p = p + 1;
document.getElementById(rand).textContent = p
var f = $('td').not(":empty").length;
}
else{}
}while(f < 15){
winChance();
}
}
function winChance (){
array = [];
for (i=1;i<16;i++){
array[i]= new Array();
var currentId = $('#' + i).attr('id');
var currentIn = $('#' + i).html()
var currentIdNum = parseInt(currentId, 10);
var currentInNum = parseInt(currentIn, 10);
for (j=1;j<16;j++){
var nextId = currentIdNum + j;
if (nextId < 16){
var nextIn = $('#' + nextId).html();
var nextInNum = parseInt(nextIn, 10);
if (currentInNum > nextInNum){
array[i].push(j);
}
}
}
}
checkSum();
}
function checkSum(){
var sum = 0;
for (var a=1; a<16; a++){
var add = array[a].length;
sum = sum + add;
}
var end = sum + 4;
if (end % 2 == 0){}
else {
shuffle();
}
}

Categories

Resources