Cellular automata works in Python, not Javascript - javascript

Edit: I put a JavaScript snippet at the bottom.
I've made two versions of the same celluar automata in JavaScript and Python.
The Python version works perfectly as expected, whereas the JavaScript doesn't...
The problem is the third generation.
How it looks in Python:
How it looks in JavaScript:
Two cells (C and D) should change from defectors back to cooperators (blue cell). This is because these cells have a cooperator in their neighbourhood that scores a 6 (6 > 5.7). On the other hand, cells A and B change rightfully back to cooperators. My confusion is that this automata is perfectly symmetrical. Why is A and B working, but not C and D when they are, in theory, existing under the exact same conditions?
Some where in the update function I suspected the cells C and D have a neighbor whose score in generation= 3 is 6 (a cooperator. Only a cooperator could score this. See picture of generation = 2 below to see what I mean) but this neighbor's actual strategy is for some reason being written as a defector, when is should be a cooperator.
this.updateCell = function(row, col) {
let player = this.active_array[row][col];
let best_strat = 0;
let highest_score = 0;
player.neighbours.forEach(coords => {
let x_coord = coords[0];
let y_coord = coords[1];
let neighbour = this.active_array[x_coord][y_coord];
if (neighbour.score > highest_score) {
highest_score = neighbour.score;
best_strat = neighbour.strat;
}
});
if (player.score < highest_score) {
return best_strat;
}
if (player.score >= highest_score) {
return player.strat;
}
}
I ran some console logs in the third generation and it seems to be the case. When cells C and D update, highest_score is returning a 6 (hence, a cooperator) but best_strategy is returning a 1 (meaning a defector). Meaning, cells C and D must have a neighbor whose strategy should be a cooperator but it's actually a defector (even though the scores are correct). If I'm right, I'm not sure how to fix this.
What's equally annoying is that I've tried basically copying the logic from the working Python version in JavaScript exactly, but no matter what I change, nothing seems to fix it. I can't find any difference between the two! :<
Again, the first two generations of the JavaScript version work perfectly.
For reference, the working Python code (JavaScript snippet below):
from calendar import c
from random import choices, sample, shuffle
import numpy as np
import pandas as pd
import copy
import matplotlib.pyplot as plt
from collections import Counter
v = 1.96
generations = 100
width = 100
height = 100
# cooperate = 0, defect = 1
strategies = ['0', '1']
next_cells = {}
temp = [0.2, 0.8]
payoffs = np.array([[1, 0], [1 + v, 0]])
rpm = pd.DataFrame(payoffs, columns=['0', '1'])
rpm.index = ['0', '1']
cpm = rpm.T
output2 = []
for x in range(width):
for y in range(height):
if (x == width/2) and (y == height/2):
strat = '1'
else:
strat = '0'
next_cells[(x, y)] = {
'strategy': strat,
'prev_strat': None,
'score': 0,
'neighbours': [((x + 1) % width, y), ((x - 1) % width, y), (x, (y - 1) % height), (x, (y + 1) % height),
((x + 1) % width, (y - 1) % height), ((x + 1) % width, (y + 1) % height), ((x - 1) % width, (y - 1) % height), ((x - 1) % width, (y + 1) % height)
]
}
for gen in range(generations):
output = np.zeros(shape=(width, height))
cells = copy.deepcopy(next_cells)
for coord, cell in cells.items():
score = 0
if cell['strategy'] == '0':
score += 1
for neighbour in cell['neighbours']:
if cell['strategy'] == '0' and cells[neighbour]['strategy'] == '0':
score += 1
if cell['strategy'] == '1' and cells[neighbour]['strategy'] == '0':
score += v
cell['score'] = score
for coord, cell in cells.items():
highest_score = 0
best_strat = None
for neighbour in cell['neighbours']:
if cells[neighbour]['score'] > highest_score:
highest_score = cells[neighbour]['score']
best_strat = cells[neighbour]['strategy']
if cell['score'] < highest_score:
next_cells[coord]['strategy'] = best_strat
next_cells[coord]['prev_strat'] = cell['strategy']
if cell['score'] >= highest_score:
next_cells[coord]['strategy'] = cell['strategy']
next_cells[coord]['prev_strat'] = cell['strategy']
x, y = coord[0], coord[1]
if next_cells[coord]['strategy'] == '0' and next_cells[coord]['prev_strat'] == '1':
output[x][y] = 2
elif next_cells[coord]['strategy'] == '1' and next_cells[coord]['prev_strat'] == '0':
output[x][y] = 3
else:
output[x][y] = int(next_cells[coord]['strategy'])
plt.imshow(output, interpolation='nearest')
plt.colorbar()
plt.pause(0.01)
plt.savefig(f"images/foo{gen}.png")
plt.close("all")
plt.show()
class Cell4 {
constructor() {
this.score = 0;
this.neighbours;
this.strat;
this.prev_strat;
this.initNeighbours = function(row, col) {
let array = [];
array.push(
[(((row - 1) % rows) + rows) % rows, (((col - 1) % cols) + cols) % cols],
[(((row + 1) % rows) + rows) % rows, (((col + 1) % cols) + cols) % cols],
[(((row - 1) % rows) + rows) % rows, (((col + 1) % cols) + cols) % cols],
[(((row + 1) % rows) + rows) % rows, (((col - 1) % cols) + cols) % cols],
[(((row - 1) % rows) + rows) % rows, col],
[(((row + 1) % rows) + rows) % rows, col],
[row, (((col - 1) % cols) + cols) % cols],
[row, (((col + 1) % cols) + cols) % cols],
)
this.neighbours = array;
};
}
}
class FractalPD {
constructor() {
this.u = 1.96;
this.cooperator_color = 'blue';
this.defect_color = 'red';
this.was_defect_color = 'cyan';
this.was_coop_color = 'yellow';
this.active_array = [];
this.inactive_array = [];
this.makeGrid = function() {
for (let i = 0; i < rows; i++) {
this.active_array[i] = [];
for (let j = 0; j < cols; j++) {
this.active_array[i][j] = 0;
}
}
this.inactive_array = this.active_array;
};
this.randomizeGrid = function() {
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
const cell = new Cell4();
cell.strat = 0;
cell.prev_strat = 0;
cell.initNeighbours(i, j);
this.active_array[i][j] = cell;
if (i === parseInt(rows/2) && j === parseInt(cols/2)) {
this.active_array[i][j].strat = 1;
this.active_array[i][j].prev_strat = 1;
}
}
}
};
this.fillGrid = function() {
// cooperate = 0 defect = 1
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
if (this.active_array[i][j].strat === 0 && this.active_array[i][j].prev_strat === 0) {
ctx.fillStyle = this.cooperator_color;
}
if (this.active_array[i][j].strat === 1 && this.active_array[i][j].prev_strat === 1) {
ctx.fillStyle = this.defect_color;
}
if (this.active_array[i][j].strat === 1 && this.active_array[i][j].prev_strat === 0) {
ctx.fillStyle = this.was_coop_color;
}
if (this.active_array[i][j].strat === 0 && this.active_array[i][j].prev_strat === 1) {
ctx.fillStyle = this.was_defect_color;
}
ctx.fillRect(j * cell_size, i * cell_size, cell_size - 1, cell_size - 1);
ctx.textAlign="center";
ctx.textBaseline = "middle";
ctx.fillStyle = "black";
ctx.fillText(`${this.active_array[i][j].score.toFixed(1)}`, (j * cell_size) + cell_size/2 , (i * cell_size) + cell_size/2)
}
}
};
this.playRound = function(row, col) {
const player = this.active_array[row][col];
const neighbours = player.neighbours;
let score = 0;
if (player.strat === 0) {
score += 1;
}
neighbours.forEach(coords => {
let x_coord = coords[0];
let y_coord = coords[1];
let neighbour = this.active_array[x_coord][y_coord];
if (player.strat === 0 && neighbour.strat === 0) {
score += 1;
}
if (player.strat === 1 && neighbour.strat === 0) {
score += this.u;
}
});
player.score = score;
};
this.updateCell = function(row, col) {
let player = this.active_array[row][col];
let best_strat = 0;
let highest_score = 0;
player.neighbours.forEach(coords => {
let x_coord = coords[0];
let y_coord = coords[1];
let neighbour = this.active_array[x_coord][y_coord];
if (neighbour.score > highest_score) {
highest_score = neighbour.score;
best_strat = neighbour.strat;
}
});
if (player.score < highest_score) {
return best_strat;
}
if (player.score >= highest_score) {
return player.strat;
}
}
this.updateGrid = function() {
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
this.playRound(i, j);
}
}
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
let old_state = this.active_array[i][j].strat;
let new_state = this.updateCell(i, j);
this.inactive_array[i][j].strat = new_state;
this.inactive_array[i][j].prev_strat = old_state;
}
}
this.active_array = this.inactive_array;
};
this.gameSetUp = () => {
this.makeGrid();
};
this.runGame = () => {
this.updateGrid();
this.fillGrid();
};
}
}
const canvas = document.querySelector("#gamefield");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext("2d");
let PD = new FractalPD();
let cell_size = 19;
let cols = Math.floor(canvas.width / cell_size);
let rows = Math.floor(canvas.height / cell_size);
PD.gameSetUp();
PD.randomizeGrid();
PD.fillGrid();
setInterval(function() {
PD.runGame();
}, 3000)
body {
font-family: 'Poppins', sans-serif;
background: #1d1d1d;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="content">
<canvas id="gamefield" width="1500" height="1000"></canvas>
</div>
<script src="fractalPD.js"></script>
</body>
</html>

At a glance, I would guess the problem is this line in your makeGrid method:
this.inactive_array = this.active_array;
This a reference assignment, not a deep copy, so you don't actually have two arrays, but just two references to the same array. When you try to update inactive_array in updateGrid, you're actually also updating active_array, since they're the same array.
To fix this issue, you could make a deep copy of the array with structuredClone(). Or just have a method that creates a single array and returns it, and call it twice to get two independent arrays.

Related

Pattern of star in JavaScript

I have a problem in JavaScript programing. I am beginner and from last 24 hrs I just completed one task that made pyramid star pattern which only work in console but the problem is this, that the same coding doesn't work on browser. In the browser the triangle become 📐 such type of triangle.
I added br to code for the browser but the triangle become 📐 right angle triangle.
use pre tag to render your result, so it doesn't remove extra spaces. most html tag will remove extra spaces because it thinks those are useless.
let starCount = 1;
const row = 35
let result = "";
for (let i = 0; i < row; i++) {
let starString = "";
const p = starCount;
for (let j = 0; j < row; j++) {
if (j >= ((row - p) / 2) && j < (((row - p) / 2) + p)) {
starString += "*";
continue;
}
starString += " "
}
result += starString + "\n";
if (row % 2 == 0) {
if (i < (row / 2) - 1) {
starCount += 2;
}
if (i > ((row / 2) - 1)) {
starCount -= 2;
}
} else {
if (i < Math.floor(row / 2)) {
starCount += 2;
} else {
starCount -= 2;
}
}
}
document.querySelector("pre").innerHTML = result;
<pre></pre>

Getting a type error: cannot read properties of undefined (reading 'value) when implementing quick sort in javascript

Please excuse the bad structure of the program. I'm a newbie programmer trying my first project in creating a sorting visualizer. I was able to implement bubble sort, but when I came around to trying to see if quick sort worked with the values in the child divs, I keep getting this error. My partition function correctly changes the value in each div, but my quick sort function shoots this error out. What's going on?
return Math.floor(Math.random() * (max - min) + min);
}
function rand_num_height(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
//Visuals
let speed = 500;
let c = 0;
let delay = 10000 / (Math.floor(10 / 10) * speed);
let p = "#75DF5B";
let p1 = "#63D7D8";
let p2 = "#008FF9";
let sorted = "#A946DA";
let p3 = "#E9EC13";
let p4 = "#F50101";
const anim = (bar, height, color) => {
setTimeout(() => {
bar.style.height = height + "px";
bar.style.backgroundColor = color;
}, (c += delay + 50));
};
const bar_container = document.getElementById("bar-container");
let children = bar_container.children;
const generate = document.getElementById("generate");
const btn = document.getElementById("sort-btn");
const reset = document.getElementById("reset");
generate.addEventListener("click", () => {
generateNewArray(rand_num_bars(10, 15));
});
function generateNewArray(rand_num_bars) {
bar_container.innerHTML = "";
//Inserting child bars into parent bar container, using rand_num function to generate # of bars
for (let i = 0; i < rand_num_bars; i++) {
document.getElementById(
"bar-container"
).innerHTML += `<div id = 'indiv_bar'></div>`;
}
//Randomizing the height for each child bar
for (i = 0; i < children.length; i++) {
var rand_height = rand_num_height(100, 500);
children[i].style.height = `${rand_height}px`;
//Setting values of each element in bar_con array to the current child height to use for sorting later
children[i].value = rand_height;
}
}
function disableBtn() {
//Prevent buttons from triggering an event
generate.style.pointerEvents = "none";
btn.style.pointerEvents = "none";
//Styling the elements to visually show user buttons are disabled
generate.style.color = "#FF0000";
btn.style.color = "#FF0000";
}
//Bubble Sort Algorithm
function bubbleSort(arr) {
const n = arr.length;
for (let i = 0; i < n; i++) {
for (let j = 0; j < n - i - 1; j++) {
anim(arr[j], arr[j].value, p1);
anim(arr[j + 1], arr[j + 1].value, p2);
if (arr[j].value > arr[j + 1].value) {
[arr[j].value, arr[j + 1].value] = [arr[j + 1].value, arr[j].value];
anim(arr[j], arr[j].value, p2);
anim(arr[j + 1], arr[j + 1].value, p1);
}
anim(arr[j], arr[j].value, p);
anim(arr[j + 1], arr[j + 1].value, p);
}
anim(arr[n - i - 1], arr[n - i - 1].value, sorted);
}
sortState = true;
c = 0;
}
//Quick Sort Algorithm
function partition(arr, low, high) {
let i = low;
let j = high;
pivotEl = arr[low].value;
do {
do {
i++;
} while (arr[i].value <= pivotEl);
do {
j--;
} while (arr[j].value > pivotEl);
if (i <= j) {
[arr[i].value, arr[j].value] = [arr[j].value, arr[i].value];
}
} while (i < j);
[arr[low].value, arr[j].value] = [arr[j].value, arr[low].value];
return j;
}
function quickSort(arr, low, high) {
var j;
if (low < high) {
j = partition(arr, low, high);
quickSort(arr, low, j - 1);
quickSort(arr, j + 1, high);
}
}
btn.addEventListener("click", () => {
disableBtn();
quickSort(children, 0, children.length - 1);
});

js pass parameter to a function so i can sort some numbers

why when i paste my code in playcode.io it works like this
function Nums(args) {
let n = Number(args[0]);
let p1 = 0;
let p2 = 0;
let p3 = 0;
let p4 = 0;
let p5 = 0;
for (let i = 1; i < n; i++) {
let currentNum = Number(args[i])
if (currentNum < 200) {
p1++;
} else if (currentNum < 400) {
p2++;
} else if (currentNum < 600) {
p3++;
} else if (currentNum < 800) {
p4++;
} else if (currentNum <= 1000) {
p5++;
}
}
console.log(p1);
console.log(p2);
console.log(p3);
console.log(p4);
console.log(p5);
}
Nums(["4", "1", "3", "999"]);
I want to sort some numbers but aren't arrays starting from 0,why when i type 4 as first number calcs it correct? if i type 2 it places my 1 and 3 if fist variable and the last varibale is empty
You could take an array for counting the number in a certain slot.
function nums(values) {
let counts = [0, 0, 0, 0, 0];
values.forEach(v => counts[Math.min(Math.floor(v / 200), 4)]++);
return counts;
}
console.log(...nums([4, 1, 3, 999, 1000]));
Hello friends i got it working the way i wanna. I don't explain clear enough in the first place sorry.Here is the correction :
function Histogram(args) {
let n = Number(arguments[0]);
let v1 = 0.0;
let v2 = 0.0;
let v3 = 0.0;
let v4 = 0.0;
let v5 = 0.0;
for (let i = 1; i <= n; i++) {
let currentNum = Number(arguments[i])
if (currentNum < 200) {
v1++;
}
else if (currentNum < 400) {
v2++;
}
else if (currentNum < 600) {
v3++;
}
else if (currentNum < 800) {
v4++;
}
else if (currentNum < 1000) {
v5++;
}
}
console.log(v1);
console.log(v2);
console.log(v3);
console.log(v4);
console.log(v5);
}
Histogram('3','1', '2', '999');
Now i'm wondering why when i insert more code it breaks again...
let p1Percantage = 0;
let p2Percantage = 0;
let p3Percantage = 0;
let p4Percantage = 0;
let p5Percantage = 0;
p1Percantage = (v1 / n * 100);
p1Percantage = (v2 / n * 100);
p1Percantage = (v3 / n * 100);
p1Percantage = (v4 / n * 100);
p1Percantage = (v5 / n * 100);
console.log(p1Percantage.toFixed(2) + "%");
console.log(p2Percantage.toFixed(2) + "%");
console.log(p3Percantage.toFixed(2) + "%");
console.log(p4Percantage.toFixed(2) + "%");
console.log(p5Percantage.toFixed(2) + "%");
The variable that is suppost to show the last it shows as first...
Expected output
66.67%
0.00%
0.00%
0.00%
33.33%
Main:
33.33%
0.00%
0.00%
0.00%
00.00%
The whole program supposed to sort the histogram array in the correct variables by their values and show the percentage of each variables p1Percantage = (v1 / n * 100); .

Javascript: PI (π) Calculator

Is there a way to calculate pi in Javascript? I know there you can use Math.PI to find pie like this:
var pie = Math.PI;
alert(pie); // output "3.141592653589793"
but this is not accurate. What I want is to be able to calculate it, to have as many digits as you want, not anything like pie = 3.141592.... But still, what I want is not have just have some more digits, but as much as you can (like having one thousand digits, but I need more).
Here is an implementation of a streaming algorithm described by Jeremy Gibbons in Unbounded Spigot Algorithms for the Digits of Pi (2004), Chaper 6:
function * generateDigitsOfPi() {
let q = 1n;
let r = 180n;
let t = 60n;
let i = 2n;
while (true) {
let digit = ((i * 27n - 12n) * q + r * 5n) / (t * 5n);
yield Number(digit);
let u = i * 3n;
u = (u + 1n) * 3n * (u + 2n);
r = u * 10n * (q * (i * 5n - 2n) + r - t * digit);
q *= 10n * i * (i++ * 2n - 1n);
t *= u;
}
}
// Demo
let iter = generateDigitsOfPi();
let output = document.querySelector("div");
(function displayTenNextDigits() {
let digits = "";
for (let i = 0; i < 10; i++) digits += iter.next().value;
output.insertAdjacentHTML("beforeend", digits);
scrollTo(0, document.body.scrollHeight);
requestAnimationFrame(displayTenNextDigits);
})();
div { word-wrap:break-word; font-family: monospace }
<div></div>
I found this code on this website:
mess = "";
Base = Math.pow(10, 11);
cellSize = Math.floor(Math.log(Base) / Math.LN10);
a = Number.MAX_VALUE;
MaxDiv = Math.floor(Math.sqrt(a));
function makeArray(n, aX, Integer) {
var i = 0;
for (i = 1; i < n; i++) aX[i] = null;
aX[0] = Integer
}
function isEmpty(aX) {
var empty = true
for (i = 0; i < aX.length; i++)
if (aX[i]) {
empty = false;
break
}
return empty
}
function Add(n, aX, aY) {
carry = 0
for (i = n - 1; i >= 0; i--) {
aX[i] += Number(aY[i]) + Number(carry);
if (aX[i] < Base) carry = 0;
else {
carry = 1;
aX[i] = Number(aX[i]) - Number(Base)
}
}
}
function Sub(n, aX, aY) {
for (i = n - 1; i >= 0; i--) {
aX[i] -= aY[i];
if (aX[i] < 0) {
if (i > 0) {
aX[i] += Base;
aX[i - 1]--
}
}
}
}
function Mul(n, aX, iMult) {
carry = 0;
for (i = n - 1; i >= 0; i--) {
prod = (aX[i]) * iMult;
prod += carry;
if (prod >= Base) {
carry = Math.floor(prod / Base);
prod -= (carry * Base)
} else carry = 0;
aX[i] = prod
}
}
function Div(n, aX, iDiv, aY) {
carry = 0;
for (i = 0; i < n; i++) {
currVal = Number(aX[i]) + Number(carry * Base);
theDiv = Math.floor(currVal / iDiv);
carry = currVal - theDiv * iDiv;
aY[i] = theDiv
}
}
function arctan(iAng, n, aX) {
iAng_squared = iAng * iAng;
k = 3;
sign = 0;
makeArray(n, aX, 0);
makeArray(n, aAngle, 1);
Div(n, aAngle, iAng, aAngle);
Add(n, aX, aAngle);
while (!isEmpty(aAngle)) {
Div(n, aAngle, iAng_squared, aAngle);
Div(n, aAngle, k, aDivK);
if (sign) Add(n, aX, aDivK);
else Sub(n, aX, aDivK);
k += 2;
sign = 1 - sign
}
mess += "aArctan=" + aArctan + "<br>"
}
function calcPI(numDec) {
var ans = "";
t1 = new Date();
numDec = Number(numDec) + 5;
iAng = new Array(10);
coeff = new Array(10);
arrayLength = Math.ceil(1 + numDec / cellSize);
aPI = new Array(arrayLength);
aArctan = new Array(arrayLength);
aAngle = new Array(arrayLength);
aDivK = new Array(arrayLength);
coeff[0] = 4;
coeff[1] = -1;
coeff[2] = 0;
iAng[0] = 5;
iAng[1] = 239;
iAng[2] = 0;
makeArray(arrayLength, aPI, 0);
makeArray(arrayLength, aAngle, 0);
makeArray(arrayLength, aDivK, 0);
for (var i = 0; coeff[i] != 0; i++) {
arctan(iAng[i], arrayLength, aArctan);
Mul(arrayLength, aArctan, Math.abs(coeff[i]));
if (coeff[i] > 0) Add(arrayLength, aPI, aArctan);
else Sub(arrayLength, aPI, aArctan)
}
Mul(arrayLength, aPI, 4);
sPI = "";
tempPI = "";
for (i = 0; i < aPI.length; i++) {
aPI[i] = String(aPI[i]);
if (aPI[i].length < cellSize && i != 0) {
while (aPI[i].length < cellSize) aPI[i] = "0" + aPI[i]
}
tempPI += aPI[i]
}
for (i = 0; i <= numDec; i++) {
if (i == 0) sPI += tempPI.charAt(i) + ".<br>";
else {
if (document.getElementById("cbCount").checked) addcount = " (" + (i) + ")";
else addcount = "";
if (document.getElementById("cbSpace").checked) thespace = " ";
else thespace = "";
if ((i) % 50 == 0 && i != 0) sPI += tempPI.charAt(i) + addcount + "<br>";
else if (i % 5 == 0) sPI += tempPI.charAt(i) + thespace;
else sPI += tempPI.charAt(i)
}
}
ans += ("PI (" + numDec + ")=" + sPI + "<br>");
ans += ("Win PI=<br>3.1415926535897932384626433832795<br>");
t2 = new Date();
timeTaken = (t2.getTime() - t1.getTime()) / 1000;
ans += "It took: " + timeTaken + " seconds";
var myDiv = document.getElementById("d1");
myDiv.innerHTML = ans
}
<form name="" onsubmit="calcPI(this.t1.value);return false;">
Number of Digits:<br>
<input type="text" name="t1" id="t1" value="100" size="25" maxlength="25">
<br>Add Count:
<input type="checkbox" name="cbCount" id="cbCount" value="" checked="checked">
<br>Add Spaces:
<input type="checkbox" name="cbSpace" id="cbSpace" value="" checked="checked">
<br>
<input type="button" value="Calculate Pi" onclick="calcPI(this.form.t1.value)">
</form>
<div id="d1"></div>
You can approximate the value of π through the use of Monte Carlo simulation. Generate a random X and Y each in the range [-1,1] Then the likelihood (X, Y) is in the unit circle centered at the origin is π/4. More samples yields a better estimate of its value. You can then estimate π by comparing the ratio of samples in the unit circle with the total number of samples and multiply by 4.
this.pi = function(count) {
var inside = 0;
for (var i = 0; i < count; i++) {
var x = random()*2-1;
var y = random()*2-1;
if ((x*x + y*y) < 1) {
inside++
}
}
return 4.0 * inside / count;
}
Here is my implementation using Infinite Series
function calculatePI(iterations = 10000){
let pi = 0;
let iterator = sequence();
for(let i = 0; i < iterations; i++){
pi += 4 / iterator.next().value;
pi -= 4 / iterator.next().value;
}
function* sequence() {
let i = 1;
while(true){
yield i;
i += 2;
}
}
return pi;
}
You can use this for your purpose
Math.PI.toFixed(n)
where n is the number of decimals you wish to display.
It displays the rounded value of pi. It can be considered fairly correct upto 15 decimal places.

Try to use quatitize.js but got error message "Uncaught TypeError: Object #<error> has no method 'palette'"

I am learning to use the quantitize.js
but getting the error "Uncaught TypeError: Object # has no method 'palette'". I don't know what is wrong. PLease help. Thanks.
Here is the code:
<div></div>
<script
src="jquery-2.0.3.min.js"></script>
<script>
/*!
* quantize.js Copyright 2008 Nick Rabinowitz.
* Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
*/
// fill out a couple protovis dependencies
/*!
* Block below copied from Protovis: http://mbostock.github.com/protovis/
* Copyright 2010 Stanford Visualization Group
* Licensed under the BSD License: http://www.opensource.org/licenses/bsd-license.php
*/
if (!pv) {
var pv = {
map: function (array, f) {
var o = {};
return f ? array.map(function (d, i) {
o.index = i;
return f.call(o, d);
}) : array.slice();
},
naturalOrder: function (a, b) {
return (a < b) ? -1 : ((a > b) ? 1 : 0);
},
sum: function (array, f) {
var o = {};
return array.reduce(f ? function (p, d, i) {
o.index = i;
return p + f.call(o, d);
} : function (p, d) {
return p + d;
}, 0);
},
max: function (array, f) {
return Math.max.apply(null, f ? pv.map(array, f) : array);
}
};
}
/**
* Basic Javascript port of the MMCQ (modified median cut quantization)
* algorithm from the Leptonica library (http://www.leptonica.com/).
* Returns a color map you can use to map original pixels to the reduced
* palette. Still a work in progress.
*
* #author Nick Rabinowitz
* #example
*/
// array of pixels as [R,G,B] arrays
var myPixels = [
[190, 197, 190],
[202, 204, 200],
[207, 214, 210],
[211, 214, 211],
[205, 207, 207]
// etc
];
var maxColors = 4;
var cmap = MMCQ.quantize(myPixels, maxColors);
var newPalette = cmap.palette();
var newPixels = myPixels.map(function (p) {
return cmap.map(p);
});
// */
var MMCQ = (function () {
// private constants
var sigbits = 5,
rshift = 8 - sigbits,
maxIterations = 1000,
fractByPopulations = 0.75;
// get reduced-space color index for a pixel
function getColorIndex(r, g, b) {
return (r << (2 * sigbits)) + (g << sigbits) + b;
}
// Simple priority queue
function PQueue(comparator) {
var contents = [],
sorted = false;
function sort() {
contents.sort(comparator);
sorted = true;
}
return {
push: function (o) {
contents.push(o);
sorted = false;
},
peek: function (index) {
if (!sorted) sort();
if (index === undefined) index = contents.length - 1;
return contents[index];
},
pop: function () {
if (!sorted) sort();
return contents.pop();
},
size: function () {
return contents.length;
},
map: function (f) {
return contents.map(f);
},
debug: function () {
if (!sorted) sort();
return contents;
}
};
}
// 3d color space box
function VBox(r1, r2, g1, g2, b1, b2, histo) {
var vbox = this;
vbox.r1 = r1;
vbox.r2 = r2;
vbox.g1 = g1;
vbox.g2 = g2;
vbox.b1 = b1;
vbox.b2 = b2;
vbox.histo = histo;
}
VBox.prototype = {
volume: function (force) {
var vbox = this;
if (!vbox._volume || force) {
vbox._volume = ((vbox.r2 - vbox.r1 + 1) * (vbox.g2 - vbox.g1 + 1) * (vbox.b2 - vbox.b1 + 1));
}
return vbox._volume;
},
count: function (force) {
var vbox = this,
histo = vbox.histo;
if (!vbox._count_set || force) {
var npix = 0,
i, j, k;
for (i = vbox.r1; i <= vbox.r2; i++) {
for (j = vbox.g1; j <= vbox.g2; j++) {
for (k = vbox.b1; k <= vbox.b2; k++) {
index = getColorIndex(i, j, k);
npix += (histo[index] || 0);
}
}
}
vbox._count = npix;
vbox._count_set = true;
}
return vbox._count;
},
copy: function () {
var vbox = this;
return new VBox(vbox.r1, vbox.r2, vbox.g1, vbox.g2, vbox.b1, vbox.b2, vbox.histo);
},
avg: function (force) {
var vbox = this,
histo = vbox.histo;
if (!vbox._avg || force) {
var ntot = 0,
mult = 1 << (8 - sigbits),
rsum = 0,
gsum = 0,
bsum = 0,
hval,
i, j, k, histoindex;
for (i = vbox.r1; i <= vbox.r2; i++) {
for (j = vbox.g1; j <= vbox.g2; j++) {
for (k = vbox.b1; k <= vbox.b2; k++) {
histoindex = getColorIndex(i, j, k);
hval = histo[histoindex] || 0;
ntot += hval;
rsum += (hval * (i + 0.5) * mult);
gsum += (hval * (j + 0.5) * mult);
bsum += (hval * (k + 0.5) * mult);
}
}
}
if (ntot) {
vbox._avg = [~~(rsum / ntot), ~~ (gsum / ntot), ~~ (bsum / ntot)];
} else {
// console.log('empty box');
vbox._avg = [~~(mult * (vbox.r1 + vbox.r2 + 1) / 2), ~~ (mult * (vbox.g1 + vbox.g2 + 1) / 2), ~~ (mult * (vbox.b1 + vbox.b2 + 1) / 2)];
}
}
return vbox._avg;
},
contains: function (pixel) {
var vbox = this,
rval = pixel[0] >> rshift;
gval = pixel[1] >> rshift;
bval = pixel[2] >> rshift;
return (rval >= vbox.r1 && rval <= vbox.r2 &&
gval >= vbox.g1 && rval <= vbox.g2 &&
bval >= vbox.b1 && rval <= vbox.b2);
}
};
// Color map
function CMap() {
this.vboxes = new PQueue(function (a, b) {
return pv.naturalOrder(
a.vbox.count() * a.vbox.volume(),
b.vbox.count() * b.vbox.volume()
)
});;
}
CMap.prototype = {
push: function (vbox) {
this.vboxes.push({
vbox: vbox,
color: vbox.avg()
});
},
palette: function () {
return this.vboxes.map(function (vb) {
return vb.color
});
},
size: function () {
return this.vboxes.size();
},
map: function (color) {
var vboxes = this.vboxes;
for (var i = 0; i < vboxes.size(); i++) {
if (vboxes.peek(i).vbox.contains(color)) {
return vboxes.peek(i).color;
}
}
return this.nearest(color);
},
nearest: function (color) {
var vboxes = this.vboxes,
d1, d2, pColor;
for (var i = 0; i < vboxes.size(); i++) {
d2 = Math.sqrt(
Math.pow(color[0] - vboxes.peek(i).color[0], 2) +
Math.pow(color[1] - vboxes.peek(i).color[1], 2) +
Math.pow(color[1] - vboxes.peek(i).color[1], 2)
);
if (d2 < d1 || d1 === undefined) {
d1 = d2;
pColor = vboxes.peek(i).color;
}
}
return pColor;
},
forcebw: function () {
// XXX: won't work yet
var vboxes = this.vboxes;
vboxes.sort(function (a, b) {
return pv.naturalOrder(pv.sum(a.color), pv.sum(b.color))
});
// force darkest color to black if everything < 5
var lowest = vboxes[0].color;
if (lowest[0] < 5 && lowest[1] < 5 && lowest[2] < 5)
vboxes[0].color = [0, 0, 0];
// force lightest color to white if everything > 251
var idx = vboxes.length - 1,
highest = vboxes[idx].color;
if (highest[0] > 251 && highest[1] > 251 && highest[2] > 251)
vboxes[idx].color = [255, 255, 255];
}
};
// histo (1-d array, giving the number of pixels in
// each quantized region of color space), or null on error
function getHisto(pixels) {
var histosize = 1 << (3 * sigbits),
histo = new Array(histosize),
index, rval, gval, bval;
pixels.forEach(function (pixel) {
rval = pixel[0] >> rshift;
gval = pixel[1] >> rshift;
bval = pixel[2] >> rshift;
index = getColorIndex(rval, gval, bval);
histo[index] = (histo[index] || 0) + 1;
});
return histo;
}
function vboxFromPixels(pixels, histo) {
var rmin = 1000000,
rmax = 0,
gmin = 1000000,
gmax = 0,
bmin = 1000000,
bmax = 0,
rval, gval, bval;
// find min/max
pixels.forEach(function (pixel) {
rval = pixel[0] >> rshift;
gval = pixel[1] >> rshift;
bval = pixel[2] >> rshift;
if (rval < rmin) rmin = rval;
else if (rval > rmax) rmax = rval;
if (gval < gmin) gmin = gval;
else if (gval > gmax) gmax = gval;
if (bval < bmin) bmin = bval;
else if (bval > bmax) bmax = bval;
});
return new VBox(rmin, rmax, gmin, gmax, bmin, bmax, histo);
}
function medianCutApply(histo, vbox) {
if (!vbox.count()) return;
var rw = vbox.r2 - vbox.r1 + 1,
gw = vbox.g2 - vbox.g1 + 1,
bw = vbox.b2 - vbox.b1 + 1,
maxw = pv.max([rw, gw, bw]);
// only one pixel, no split
if (vbox.count() == 1) {
return [vbox.copy()]
}
/* Find the partial sum arrays along the selected axis. */
var total = 0,
partialsum = [],
lookaheadsum = [],
i, j, k, sum, index;
if (maxw == rw) {
for (i = vbox.r1; i <= vbox.r2; i++) {
sum = 0;
for (j = vbox.g1; j <= vbox.g2; j++) {
for (k = vbox.b1; k <= vbox.b2; k++) {
index = getColorIndex(i, j, k);
sum += (histo[index] || 0);
}
}
total += sum;
partialsum[i] = total;
}
} else if (maxw == gw) {
for (i = vbox.g1; i <= vbox.g2; i++) {
sum = 0;
for (j = vbox.r1; j <= vbox.r2; j++) {
for (k = vbox.b1; k <= vbox.b2; k++) {
index = getColorIndex(j, i, k);
sum += (histo[index] || 0);
}
}
total += sum;
partialsum[i] = total;
}
} else { /* maxw == bw */
for (i = vbox.b1; i <= vbox.b2; i++) {
sum = 0;
for (j = vbox.r1; j <= vbox.r2; j++) {
for (k = vbox.g1; k <= vbox.g2; k++) {
index = getColorIndex(j, k, i);
sum += (histo[index] || 0);
}
}
total += sum;
partialsum[i] = total;
}
}
partialsum.forEach(function (d, i) {
lookaheadsum[i] = total - d
});
function doCut(color) {
var dim1 = color + '1',
dim2 = color + '2',
left, right, vbox1, vbox2, d2, count2 = 0;
for (i = vbox[dim1]; i <= vbox[dim2]; i++) {
if (partialsum[i] > total / 2) {
vbox1 = vbox.copy();
vbox2 = vbox.copy();
left = i - vbox[dim1];
right = vbox[dim2] - i;
if (left <= right)
d2 = Math.min(vbox[dim2] - 1, ~~ (i + right / 2));
else d2 = Math.max(vbox[dim1], ~~ (i - 1 - left / 2));
// avoid 0-count boxes
while (!partialsum[d2]) d2++;
count2 = lookaheadsum[d2];
while (!count2 && partialsum[d2 - 1]) count2 = lookaheadsum[--d2];
// set dimensions
vbox1[dim2] = d2;
vbox2[dim1] = vbox1[dim2] + 1;
// console.log('vbox counts:', vbox.count(), vbox1.count(), vbox2.count());
return [vbox1, vbox2];
}
}
}
// determine the cut planes
return maxw == rw ? doCut('r') :
maxw == gw ? doCut('g') :
doCut('b');
}
function quantize(pixels, maxcolors) {
// short-circuit
if (!pixels.length || maxcolors < 2 || maxcolors > 256) {
// console.log('wrong number of maxcolors');
return false;
}
// XXX: check color content and convert to grayscale if insufficient
var histo = getHisto(pixels),
histosize = 1 << (3 * sigbits);
// check that we aren't below maxcolors already
var nColors = 0;
histo.forEach(function () {
nColors++
});
if (nColors <= maxcolors) {
// XXX: generate the new colors from the histo and return
}
// get the beginning vbox from the colors
var vbox = vboxFromPixels(pixels, histo),
pq = new PQueue(function (a, b) {
return pv.naturalOrder(a.count(), b.count())
});
pq.push(vbox);
// inner function to do the iteration
function iter(lh, target) {
var ncolors = 1,
niters = 0,
vbox;
while (niters < maxIterations) {
vbox = lh.pop();
if (!vbox.count()) { /* just put it back */
lh.push(vbox);
niters++;
continue;
}
// do the cut
var vboxes = medianCutApply(histo, vbox),
vbox1 = vboxes[0],
vbox2 = vboxes[1];
if (!vbox1) {
// console.log("vbox1 not defined; shouldn't happen!");
return;
}
lh.push(vbox1);
if (vbox2) { /* vbox2 can be null */
lh.push(vbox2);
ncolors++;
}
if (ncolors >= target) return;
if (niters++ > maxIterations) {
// console.log("infinite loop; perhaps too few pixels!");
return;
}
}
}
// first set of colors, sorted by population
iter(pq, fractByPopulations * maxcolors);
// Re-sort by the product of pixel occupancy times the size in color space.
var pq2 = new PQueue(function (a, b) {
return pv.naturalOrder(a.count() * a.volume(), b.count() * b.volume())
});
while (pq.size()) {
pq2.push(pq.pop());
}
// next set - generate the median cuts using the (npix * vol) sorting.
iter(pq2, maxcolors - pq2.size());
// calculate the actual colors
var cmap = new CMap();
while (pq2.size()) {
cmap.push(pq2.pop());
}
return cmap;
}
return {
quantize: quantize
}
})();
</script>
The code is from quantitize.js. Thanks alot.
It seems like the problem is happening when it gets to the function 'quantize'. It seems you aren't passing it the pixels properly, or setting the maxcolors too high or too low.
Try adding some console.logs in it and see if pixels are 0 or max colors are bad.
:
function quantize(pixels, maxcolors) {
// short-circuit
if (!pixels.length || maxcolors < 2 || maxcolors > 256) {
console.log('wrong number of maxcolors');
console.log("pixellength: " + pixels.length);
console.log("maxcolors:" + maxcolors);
return false;
}
console.log(pixels.length);
If you open the link to the current version of the script, you will see that this section of the code is commented out. Also on lines 38 and 39 it is specified that:
* Returns a color map you can use to map original pixels to the reduced
* palette. Still a work in progress.
Therefore, I wouldn't expect it to work, perhaps there are some missing libraries. I suggest you update your code with the latest version at https://gist.github.com/nrabinowitz/1104622.
Also, you can keep your page clean and separate the module. For example create a subdirectory assets, put the quantize.js in there and in your page include:
<script src="/assets/quantize.js" type="text/javascript"></script>

Categories