Hierarchical Clustering in JavaScript - javascript

I have some markers on google maps and I would like to identify clusters by point-to-point distance between them. However, I am having a bit of difficulty:
First I loop through all the markers and create an array which is:
for (var i = 0; i < MARKERS.length - 1; i++) {
for (var j = i + 1; j < MARKERS.length; j++) {
var distance_between = google.maps.geometry.spherical.computeDistanceBetween(point_i, point_j)
var valueToPush = {}
valueToPush.fromMarker = name_i
valueToPush.toMarker = name_j
valueToPush.distance = distance_between
cluster_array.push(valueToPush)
}
}
What I would then like to do is run a hierarchical clustering algorithm like this:
var cluster = .cluster(cluster_array, MAX, threshold)
Where if I specify 500 for threshold then I get a list like this
Cluster 0: Marker A, Marker Y, Marker C
Cluster 1: Marker B
Cluster 2: Marker D, Marker E
etc.
Where each cluster shows me the markers that are within 500 metres of each other.
Thanks very much

If it helps this is what I ended up doing:
function the_clusterer(cluster_array, num_radius) {
console.log('Clustering distance array')
for (var i = 0; i < cluster_array.length - 1; i++) {
if (typeof(cluster_array[i]) != 'undefined') {
var size_outer = 0,
key_outer;
for (key_outer in cluster_array[i]) {
if (cluster_array[i].hasOwnProperty(key_outer));
size_outer++;
}
for (var j = 0; j < size_outer; j++) {
for (var k = i + 1; k < cluster_array.length; k++) {
if (typeof(cluster_array[i]) != 'undefined') {
var size_inner = 0,
key_inner;
for (key_inner in cluster_array[k]) {
if (cluster_array[k].hasOwnProperty(key_inner));
size_inner++;
}
var found_outer = 0
for (var l = 0; l < size_inner; l++) {
if (found_outer === 1) {
break;
}
if (cluster_array[k][l] == cluster_array[i][j]) {
found_outer++
}
}
if (found_outer > 0) {
for (var l = 0; l < size_inner; l++) {
var found_inner = 0
for (var m = 0; m < size_outer; m++) {
if (cluster_array[i][m] == cluster_array[k][l]) {
found_inner++
}
}
if (found_inner == 0) {
cluster_array[i][size_outer] = cluster_array[k][l]
size_outer++
}
}
delete cluster_array[k];
}
}
}
}
}
}
txtOutput.value += "Start Clusters: " + num_radius + "m.\n"
var k = 0
for (var i = 0; i < cluster_array.length - 1; i++) {
var size_outer = 0,
key_outer;
for (key_outer in cluster_array[i]) {
if (cluster_array[i].hasOwnProperty(key_outer));
size_outer++;
}
if (size_outer > 0) {
k++
var temp_line = "Cluster " + k + ":"
for (var j = 0; j < size_outer; j++) {
temp_line = temp_line + " Marker " + cluster_array[i][j]
}
txtOutput.value += temp_line + ".\n"
}
}
}

Related

A* Pathfinding, path not showing up

I have this code, in script (p5.js), I am running it and works as expected, but the moment I include the path code, that helps in finding the previous parents to form a path to the end goal, the browser crushes, as the images show. It fist colors the 3 cells then crashes. Here is the code.
var col = 12, row = 12, grid = new Array(col), openSet = [], closeSet = [], start, end, w, h, path = [];
function removefromArray(array_, element){
for(var i = array_.length - 1; i >= 0; i--){
if(array_[i] == element){
array_.splice(i, 1);
}
}
}
function heuristic(a, b){
var distance = abs(a.i - b.i) + abs(a.j - b.j);
return distance;
}
function Spot(i, j){
this.i = i;
this.j = j;
this.f = 0;
this.g = 0;
this.h = 0;
this.neighbor = [];
this.parent = undefined;
this.wall = false;
this.show = function (color){
fill(color);
if(this.wall){
fill(0);
}
noStroke();
rect(this.i * w, this.j * h, w - 1, h - 1);
}
this.addNeighbor = function(grid){
var i = this.i, j = this.j;
if(i < col - 1){
this.neighbor.push(grid[i+1] [j]);
}
if(i > 0){
this.neighbor.push(grid[i-1] [j]);
}
if(j < row-1){
this.neighbor.push(grid[i] [j+1]);
}
if(j > 0){
this.neighbor.push(grid[i] [j-1]);
}
}
}
function setup(){
createCanvas(500,500);
console.log("A*");
w = width / col;
h = height / row;
for( var i = 0; i< col; i++){
grid[i] = new Array(row);
}
//Adding a spot
for( var i = 0; i< col; i++){
for( var j = 0; j< row; j++){
grid[i][j] = new Spot(i,j);
}
}
//Adding a neighbor
for( var i = 0; i< col; i++){
for( var j = 0; j< row; j++){
grid[i][j].addNeighbor(grid);
}
}
start = grid[0][0];
end = grid[col - 1][row - 1];
openSet.push(start);
}
function draw(){
var winner = 0;
if(openSet.length > 0){
for( var i = 0; i< openSet.length; i++){
if(openSet[i].f < openSet[winner].f){
winner = i;
}
}
var current = openSet[winner];
if(current === end){
noLoop();
console.log("Done!");
}
removefromArray(openSet, current);
closeSet.push(current);
var neighbors = current.neighbor;
for(var i = 0; i < neighbors.length; i++){
var the_neighbor = neighbors[i];
if(!closeSet.includes(the_neighbor)){
var tempG = current.g + 1;
}
if(openSet.includes(the_neighbor)){
if(tempG < the_neighbor.g){
the_neighbor.g = tempG;
}
}
else{
the_neighbor.g = tempG;
openSet.push(the_neighbor);
}
the_neighbor.h = heuristic(the_neighbor, end);
the_neighbor.f = the_neighbor.g + the_neighbor.h;
the_neighbor.parent = current; // the previous node
}
}
else{
// no solution
}
background(0)
for( var i = 0; i< col; i++){
for( var j = 0; j< row; j++){
grid[i][j].show(color(255));
}
}
for( var i = 0; i< openSet.length; i++){
openSet[i].show(color("green"));
}
for( var i = 0; i< closeSet.length; i++){
closeSet[i].show(color("red"));
}
// path = [];
// var temp = current;
// path.push(temp);
// while(temp.parent){
// path.push(temp.parent);
// temp = temp.parent;
// }
// for(var i = 0; i < path.length; i++){
// path[i].show(color(0,0,255));
// }
}
If I try to remove the comments slash for this last part, the system will run for about 5secs then crashes. Someone with the solution, I will highly appreciate.
Result when the path part is uncommented
You are generating a cycle somehow in the chain of parents (i.e. Spot A has parent Spot B and Spot B has parent Spot A), which is causing an infinite loop. I'm not sure exactly where/why this is happening. Your code is a bit hard to read. You should avoid nondescript one letter variable & property names.
Also there are several scoping issues that may be causing unexpected behavior. The keyword var is the worst element of any programming language since goto and it should be scoured from the face of the internet with the fire of 1000 suns. Please use let. See the comments below for more explanation.
var col = 12,
row = 12,
grid = new Array(col),
openSet = [],
closeSet = [],
start, end, w, h, path = [];
function removefromArray(array_, element) {
for (let i = array_.length - 1; i >= 0; i--) {
if (array_[i] == element) {
array_.splice(i, 1);
}
}
}
function heuristic(a, b) {
var distance = abs(a.i - b.i) + abs(a.j - b.j);
return distance;
}
function Spot(i, j) {
this.i = i;
this.j = j;
this.f = 0;
this.g = 0;
this.h = 0;
this.neighbor = [];
this.parent = undefined;
this.wall = false;
this.show = function(color) {
fill(color);
if (this.wall) {
fill(0);
}
noStroke();
rect(this.i * w, this.j * h, w - 1, h - 1);
}
this.addNeighbor = function(grid) {
let i = this.i,
j = this.j;
if (i < col - 1) {
this.neighbor.push(grid[i + 1][j]);
}
if (i > 0) {
this.neighbor.push(grid[i - 1][j]);
}
if (j < row - 1) {
this.neighbor.push(grid[i][j + 1]);
}
if (j > 0) {
this.neighbor.push(grid[i][j - 1]);
}
}
}
function setup() {
createCanvas(500, 500);
console.log("A*");
w = width / col;
h = height / row;
for (let i = 0; i < col; i++) {
grid[i] = new Array(row);
}
//Adding a spot
for (let i = 0; i < col; i++) {
for (let j = 0; j < row; j++) {
grid[i][j] = new Spot(i, j);
}
}
//Adding a neighbor
for (let i = 0; i < col; i++) {
for (let j = 0; j < row; j++) {
grid[i][j].addNeighbor(grid);
}
}
start = grid[0][0];
end = grid[col - 1][row - 1];
openSet.push(start);
}
function draw() {
let winner = 0;
let current
if (openSet.length > 0) {
for (let i = 0; i < openSet.length; i++) {
if (openSet[i].f < openSet[winner].f) {
winner = i;
}
}
current = openSet[winner];
if (current === end) {
noLoop();
console.log("Done!");
}
removefromArray(openSet, current);
closeSet.push(current);
var neighbors = current.neighbor;
for (let i = 0; i < neighbors.length; i++) {
var the_neighbor = neighbors[i];
// The use of var here results in very weird behavior
// where tempG's value is preserved from the previous
// iteration of this loop even when it is not assigned
// a value. If that is desired you should declare this
// variable outside of the for loop.
//
// If you always use let isntead of var you will get
// errors instead of bizarre behavior. That will help
// you be deliberate about your variable scoping.
if (!closeSet.includes(the_neighbor)) {
var tempG = current.g + 1;
} else {
print('tempG not set');
}
if (openSet.includes(the_neighbor)) {
if (tempG < the_neighbor.g) {
the_neighbor.g = tempG;
}
} else {
print(`tempG: ${tempG}`);
the_neighbor.g = tempG;
openSet.push(the_neighbor);
print(`openSet: ${openSet.length}`);
}
the_neighbor.h = heuristic(the_neighbor, end);
the_neighbor.f = the_neighbor.g + the_neighbor.h;
the_neighbor.parent = current; // the previous node
}
} else {
// no solution
}
background(0)
for (let i = 0; i < col; i++) {
for (var j = 0; j < row; j++) {
grid[i][j].show(color(255));
}
}
for (let i = 0; i < openSet.length; i++) {
openSet[i].show(color("green"));
}
for (let i = 0; i < closeSet.length; i++) {
closeSet[i].show(color("red"));
}
path = [];
let temp = current;
path.push(temp);
while (temp.parent) {
if (path.includes(temp.parent)) {
print('Cycle detected!');
console.log({ current: { i: temp.i, j: temp.j }, parent: { i: temp.parent.i, j: temp.parent.j } });
break;
}
path.push(temp.parent);
temp = temp.parent;
}
for (let i = 0; i < path.length; i++) {
path[i].show(color(0, 0, 255));
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.js"></script>
Update: Infinite Loop Fix
The part of your code that updates neighbors deviates from the definition of A* pretty substantially. Here's what I came up with (single letter variable names replaces with meaningful names):
let tentativePathScore = current.shortestPathScore + 1;
if (the_neighbor.heuristicScore === undefined) {
the_neighbor.heuristicScore = heuristic(the_neighbor, end);
}
if (the_neighbor.combinedScore === undefined ||
tentativePathScore + the_neighbor.heuristicScore < the_neighbor.combinedScore) {
// Update the path score and combined score for this neighbor.
the_neighbor.shortestPathScore = tentativePathScore;
the_neighbor.combinedScore = the_neighbor.shortestPathScore + the_neighbor.heuristicScore;
the_neighbor.parent = current; // the previous node
if (!openSet.includes(the_neighbor)) {
openSet.push(the_neighbor);
}
}
And here's a working snippet with walls added:
let col = 12,
row = 12,
grid = new Array(col),
openSet = [],
closeSet = [],
start, end, w, h, path = [];
function removefromArray(array_, element) {
for (let i = array_.length - 1; i >= 0; i--) {
if (array_[i] == element) {
array_.splice(i, 1);
}
}
}
function heuristic(a, b) {
if (a.wall) {
return Infinity;
}
return abs(a.i - b.i) + abs(a.j - b.j);
}
function Spot(i, j) {
this.i = i;
this.j = j;
this.combinedScore = undefined;
this.shortestPathScore = undefined;
this.heuristicScore = undefined;
this.neighbor = [];
this.parent = undefined;
this.wall = false;
this.show = function(color) {
fill(color);
if (this.wall) {
fill(0);
}
noStroke();
rect(this.i * w, this.j * h, w - 1, h - 1);
}
this.addNeighbor = function(grid) {
let i = this.i,
j = this.j;
if (i < col - 1) {
this.neighbor.push(grid[i + 1][j]);
}
if (i > 0) {
this.neighbor.push(grid[i - 1][j]);
}
if (j < row - 1) {
this.neighbor.push(grid[i][j + 1]);
}
if (j > 0) {
this.neighbor.push(grid[i][j - 1]);
}
}
}
function setup() {
createCanvas(500, 500);
console.log("A*");
w = width / col;
h = height / row;
for (let i = 0; i < col; i++) {
grid[i] = new Array(row);
}
//Adding a spot
for (let i = 0; i < col; i++) {
for (let j = 0; j < row; j++) {
grid[i][j] = new Spot(i, j);
}
}
//Adding a neighbor
for (let i = 0; i < col; i++) {
for (let j = 0; j < row; j++) {
grid[i][j].addNeighbor(grid);
}
}
// make walls
for (let i = 0; i < col; i++) {
for (let j = 0; j < row; j++) {
if ((i > 1 || j > 1) && (i < col - 2 || j < row - 2) && random() < 0.2) {
grid[i][j].wall = true;
}
}
}
start = grid[0][0];
end = grid[col - 1][row - 1];
start.shortestPathScore = 0;
start.heuristicScore = heuristic(start, end);
start.combinedScore = start.shortestPathScore + start.heuristicScore;
openSet.push(start);
}
function draw() {
let winner = 0;
let current;
if (openSet.length > 0) {
for (let i = 0; i < openSet.length; i++) {
if (openSet[i].combinedScore < openSet[winner].combinedScore) {
winner = i;
}
}
current = openSet[winner];
if (current === end) {
noLoop();
console.log("Done!");
}
removefromArray(openSet, current);
closeSet.push(current);
var neighbors = current.neighbor;
for (let i = 0; i < neighbors.length; i++) {
var the_neighbor = neighbors[i];
let tentativePathScore = current.shortestPathScore + 1;
if (the_neighbor.heuristicScore === undefined) {
the_neighbor.heuristicScore = heuristic(the_neighbor, end);
}
if (the_neighbor.combinedScore === undefined ||
tentativePathScore + the_neighbor.heuristicScore < the_neighbor.combinedScore) {
// Update the path score and combined score for this neighbor.
the_neighbor.shortestPathScore = tentativePathScore;
the_neighbor.combinedScore = the_neighbor.shortestPathScore + the_neighbor.heuristicScore;
the_neighbor.parent = current; // the previous node
if (!openSet.includes(the_neighbor)) {
openSet.push(the_neighbor);
}
}
}
} else {
// no solution
}
background(0)
for (let i = 0; i < col; i++) {
for (let j = 0; j < row; j++) {
grid[i][j].show(color(255));
}
}
for (let i = 0; i < openSet.length; i++) {
openSet[i].show(color("green"));
}
for (let i = 0; i < closeSet.length; i++) {
closeSet[i].show(color("red"));
}
path = [];
let temp = current;
path.push(temp);
while (temp.parent) {
if (path.includes(temp.parent)) {
print('Cycle detected!');
break;
}
path.push(temp.parent);
temp = temp.parent;
}
for (let i = 0; i < path.length; i++) {
path[i].show(color(0, 0, 255));
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.js"></script>

SCRIPT16389: SCRIPT16389: Unspecified error. Edge Console

I know that some other questions posted are related to this topic but their answers don't help me.
I'm trying to implement battleship in js and while debugging I get SCRIPT16389: SCRIPT16389: Unspecified error. in the microsoft edge console.
Here's my js code so far: (I'm a beginner in javascript so sorry if serious mistakes)
var board = null;
var boats = null;
var rows = 8;
var columns = 8;
$(document).ready(function(){
if(typeof(Storage)!=="undefined"){
boats = JSON.parse(localStorage.getItem("boats"));
console.log(boats);
if(boats===null){
boats = [
{size:2, letter:'f', name:'fragate'},
{size:3, letter:'b', name:'buque'},
{size:3, letter:'s', name:'submarine'},
{size:4, letter:'d', name:'destructor'},
{size:5, letter:'p', name:'portplanes'},
];
localStorage.setItem("boats", JSON.stringify(boats));
}
rows = parseInt(localStorage.getItem("rows"));
columns = parseInt(localStorage.getItem("columns"));
if(isNaN(rows)|| isNaN(columns)){
rows = 8;
columns = 8;
localStorage.setItem("rows", 8);
localStorage.setItem("columns", 8);
}
}else {
console.log("We don't have localStorage")
}
});
function createMatrix(row,col){
var matrix;
matrix = new Array(row);
for (var i=0; i<row; i++){
matriz[i] = new Array(col);
}
return matrix;
}
function createFullMatrix(row,col,inside){
var matrix = new Array(row);
for(var i=0; i<row; i++){
matrix[i] = new Array(col);
for(var j=0; j<col; j++){
matrix[i][j]=inside;
}
}
return matrix;
}
function matrix2console(matrix){
var aux;
for(var i=0; i<matrix.length; i++){
aux = "";
for(var j=0; j<matrix[i].length; j++){
aux+=matrix[i][j]+'\t';
}
console.log(aux);
}
}
function createBoard(){
var html='<table>';
for(var i=0; i<rows; i++){
html+='<tr>';
for (var j=0; j<columns; j++){
html+='<td id="cel_'+i+'_'+j+'" class = "water"+ onclick=shoot("celd_'+i+'_'+j+'",'+i+','+j+')></td>';
}
html+='</tr>';
}
html+='</table>'
document.getElementById("match").innerHTML=html;
}
function createBoardjQ(){
$("#match").empty();
var table = $("<table />");
for(var i=0; i<rows; i++){
var row = $("<tr/>");
for(var j=0; j<columns; j++){
var celd = $('<td id="celd_'+i+'_'+j+'" onclick=shoot("celd_'+i+'_'+j+'",'+i+','+j+') > </td>');
celd.addClass("water");
row.append(celd);
}
table.append(row);
}
$("#match").append(table);
}
function createMatch(){
board = createMatrix(rows,columns);
startMatrix('a',board);
setBoats(board);
createBoardjQ();
matrix2console(board);
}
function shoot(celd, i, j){
switch (board[i][j]) {
case 'a':
board[i][j]= 'A';
$('#'+celd).removeClass('water');
$('#'+celd).addClass('miss')
break;
case 'b':
board[i][j]= 'B';
$('#'+celd).removeClass('water');
$('#'+celd).addClass('boats')
break;
case 'd':
board[i][j]= 'd';
$('#'+celd).removeClass('water');
$('#'+celd).addClass('boats')
break;
case 'f':
board[i][j]= 'F';
$('#'+celd).removeClass('water');
$('#'+celd).addClass('boats')
break;
case 'p':
board[i][j]= 'P';
$('#'+celd).removeClass('water');
$('#'+celd).addClass('boats')
break;
case 's':
board[i][j]= 'S';
$('#'+celd).removeClass('water');
$('#'+celd).addClass('boats')
break;
}
}
function startMatrix(data, matrix){
for(var i=0; i<matrix.length;){
for(var j=0; j<matrix[i].length;){
matrix[i][j]=data;
}
}
}
function dice(value){
var random;
random = Math.floor(Math.random()*(value));
return random;
}
function coin(){
return (dice(2));
}
function setBoats(matrix){
for (var i=0; i<boats.length; i++){
var boats = boats[i];
do{
var free=true;
var direction = coin();
if(!direction){
var row = dice(matrix.length);
var col = dice(matrix[row].length-boat.size);
for(var j=0; j<boat.size;j++){
if(matrix[row][j]!='a'){
free = false;
}
}
if(free){
for(var j=0; j<boat.size; j++){
matrix[row][j+col]=boat.letter;
}
}
}else{
var row = dice(matrix.length-boat.size);
var col = dice(matrix[row].length);
var row = dice(matrix.length);
var col = dice(matrix[row].length-boat.size);
for(var j=0; j<boat.size;j++){
if(matrix[j+row][col]!='a'){
free = false;
}
}
if(free){
for(var j=0; j<boat.size; j++){
matrix[j+row][col]=boat.letter;
}
}
}
}while(!free);
}
}
After correcting a number of typos and reviewing the logic, the primary issue reported was in startMatrix() where the for loops were not incrementing their counters. This caused an infinite loop.
Consider the following to fix:
function startMatrix(data, matrix) {
var singleRow, singleCol;
for (var r = 0; r < matrix.length; r++) {
for (var c = 0; c < matrix[r].length; c++) {
matrix[r][c] = data;
}
}
console.log("SM: Matrix Complete", matrix);
}
Full example: https://jsfiddle.net/Twisty/L1m6jw5q/58/
HTML
<div id="match">
</div>
CSS
#match td {
width: 20px;
height: 20px;
}
#match .water {
background-color: #ccf;
}
#match .miss {
background-color: #eee;
}
#match .boats {
background-color: #ccc;
}
JavaScript
var board = null;
var boats = null;
var rows = 8;
var columns = 8;
function createMatrix(row, col) {
var matrix;
matrix = new Array(row);
for (var i = 0; i < row; i++) {
matrix[i] = new Array(col);
}
console.log("CM: New Matrix Created", matrix);
return matrix;
}
function startMatrix(data, matrix) {
var singleRow, singleCol;
for (var r = 0; r < matrix.length; r++) {
for (var c = 0; c < matrix[r].length; c++) {
matrix[r][c] = data;
}
}
console.log("SM: Matrix Complete", matrix);
}
function createFullMatrix(row, col, inside) {
var matrix = new Array(row);
for (var i = 0; i < row; i++) {
matrix[i] = new Array(col);
for (var j = 0; j < col; j++) {
matrix[i][j] = inside;
}
}
return matrix;
}
function matrix2console(matrix) {
var aux;
for (var i = 0; i < matrix.length; i++) {
aux = "";
for (var j = 0; j < matrix[i].length; j++) {
aux += matrix[i][j] + '\t';
}
console.log(aux);
}
}
function createBoardjQ() {
$("#match").empty();
var table = $("<table />");
for (var i = 0; i < rows; i++) {
var row = $("<tr/>");
for (var j = 0; j < columns; j++) {
var celd = $('<td id="celd_' + i + '_' + j + '" data-shoot="celd_' + i + '_' + j + ',' + i + ',' + j + '"></td>');
celd.addClass("water");
row.append(celd);
}
table.append(row);
}
$("#match").append(table);
}
function createMatch() {
console.log("CMa: Make Board");
board = createMatrix(rows, columns);
console.log("CMa: Start Matrix", 'a', board);
startMatrix('a', board);
console.log("CMa: Set Boats", board);
setBoats(board);
console.log("CMa: Create Board jQ");
createBoardjQ();
console.log("CMa: Matrix to Console");
matrix2console(board);
}
function shoot(celd, i, j) {
switch (board[i][j]) {
case 'a':
board[i][j] = 'A';
$('#' + celd).removeClass('water');
$('#' + celd).addClass('miss');
console.log("Miss");
break;
case 'b':
board[i][j] = 'B';
$('#' + celd).removeClass('water');
$('#' + celd).addClass('boats');
console.log("Hit");
break;
case 'd':
board[i][j] = 'd';
$('#' + celd).removeClass('water');
$('#' + celd).addClass('boats');
console.log("Hit");
break;
case 'f':
board[i][j] = 'F';
$('#' + celd).removeClass('water');
$('#' + celd).addClass('boats');
console.log("Hit");
break;
case 'p':
board[i][j] = 'P';
$('#' + celd).removeClass('water');
$('#' + celd).addClass('boats');
console.log("Hit");
break;
case 's':
board[i][j] = 'S';
$('#' + celd).removeClass('water');
$('#' + celd).addClass('boats');
console.log("Hit");
break;
}
}
function dice(value) {
var random;
random = Math.floor(Math.random() * (value));
return random;
}
function coin() {
return (dice(2));
}
function setBoats(matrix) {
var i, j, row, col, free;
for (i = 0; i < boats.length; i++) {
var boat = boats[i];
do {
free = true;
var direction = coin();
if (!direction) {
row = dice(matrix.length);
col = dice(matrix[row].length - boat.size);
for (j = 0; j < boat.size; j++) {
if (matrix[row][j] != 'a') {
free = false;
}
}
if (free) {
for (j = 0; j < boat.size; j++) {
matrix[row][j + col] = boat.letter;
}
}
} else {
row = dice(matrix.length - boat.size);
col = dice(matrix[row].length);
//row = dice(matrix.length);
//col = dice(matrix[row].length - boat.size);
for (j = 0; j < boat.size; j++) {
var k = (j + row) >= 1 ? (j + row) - 1 : 0;
console.log(j, row, k, boat.size);
if (k > matrix.length) {
free = false;
} else {
if (matrix[k][col] != 'a') {
free = false;
}
}
}
if (free) {
for (j = 0; j < boat.size; j++) {
matrix[j + row][col] = boat.letter;
}
}
}
} while (!free);
}
}
$(document).ready(function() {
if (typeof(Storage) !== "undefined") {
boats = JSON.parse(localStorage.getItem("boats"));
console.log(boats);
if (boats === null) {
boats = [{
size: 2,
letter: 'f',
name: 'fragate'
},
{
size: 3,
letter: 'b',
name: 'buque'
},
{
size: 3,
letter: 's',
name: 'submarine'
},
{
size: 4,
letter: 'd',
name: 'destructor'
},
{
size: 5,
letter: 'p',
name: 'portplanes'
},
];
localStorage.setItem("boats", JSON.stringify(boats));
}
rows = parseInt(localStorage.getItem("rows"));
columns = parseInt(localStorage.getItem("columns"));
if (isNaN(rows) || isNaN(columns)) {
rows = 8;
columns = 8;
localStorage.setItem("rows", 8);
localStorage.setItem("columns", 8);
}
console.log(rows, columns);
createMatch();
$(".water").click(function(e) {
console.log("Firing Shot", $(this));
var c = $(this).data("shoot").split(",");
shoot(c[0], c[1], c[2]);
});
} else {
console.log("We don't have localStorage");
}
});
Once the infinite loop was addressed, there was another logical error in setBoards(). Basically, there was a point where j + row would be greater than the index of matrix. You will want to review it and maybe even draw it out to make sure boats do not get placed off the board (which was always my favorite way to beat my brother at Battleship as a kid).
I also moved the click callback to jQuery. Just made it easier, so I stored the shot data in a data attribute for each cell. Easy to parse out and pass to shoot() for each click.
Hope that helps.

If and else both executed in nested loop

In google apps spreadsheet I am parsing json and filling up cells. After seting value to cell I check if the row has this value and if it does I go to the next cell and set new value, then I check the second value and so on. But something goes wrong and the if and else are both executing..
var customfields = SpreadsheetApp.openById('id').getSheetByName('Form').getRange('J25').getValue();
if (customfields == true) {
var jj = 2;
var ii = 1;
for each(item in data) {
var size = Object.keys(data[k].customfields).length;
if (size == 0) {
k = k + 1;
continue;
}
Logger.log(k)
for (j = 0; j < size; j++) {
var vl = data[k].customfields[j].value;
var nm = data[k].customfields[j].name;
var rng = SpreadsheetApp.openById('id').getSheetByName('Data').getMaxColumns();
for (var cn = 0; cn <= rng; cn++) {
var dat = sheet.getRange(1, cn).getValue();
Logger.log("IF STATEMENT")
if (dat == nm) {
sheet.getRange(ii, cn).setValue(nm);
} else {
sheet.getRange(ii, br).setValue(nm);
}
}
Logger.log(nm)
br = br + 1;
}
k = k + 1;
}
}

variable assignment doesn't work javascript

In the following code, the console.log from the line 92 and 93 (switchPosition function) doesn't provide the same result. I am, I have to admit, stuck.
Any thoughts, ideas, explanations?
Thanks you for the time taken,
var Carrousel = (function () {
var self = {},
config = {
item: 3, // item to be displayed
scroll: 2 // number of items to be scrolled
},
container = null,
items = null,
nbItems = null,
nbSlide = null,
position = [],
searchPositionDepending = []
;
self.init = function (opts) {
options = opts || {}
execute();
}
// Private Method
execute = function () {
container = document.getElementById('carrousel');
items = document.getElementsByClassName('flux');
var containerWidth = container.offsetWidth;
var containerHeight = items[0].offsetHeight * 1.5;
container.style.height = '' + containerHeight + '';
nbItems = document.getElementsByClassName('flux').length;
nbSlide = nbItems / config.item;
// Initialisation du Carrousel
for (i = 0; i < nbItems; i++) {
items[i].style.width = '' + (containerWidth / config.item) + '';
items[i].style.display = 'none';
items[i].style.position = 'absolute';
items[i].style.top = "0";
items[i].style.left = "0";
items[i].setAttribute('data-position', '' + (i + 1) + '');
items[i].setAttribute('data-number', '' + i + '');
}
searchPosition();
placement();
document.getElementById('next').onclick = function () {
next();
searchPosition();
switchPosition();
placement();
// position();
}
document.getElementById('previous').onclick = function () {
// previous();
// searchPosition();
// position();
}
}
searchPosition = function () {
for (i = 0; i < config.item; i++) {
searchPositionDepending[i] = (function () { //Appending a function searchPosition per item displayed
for (j = 1; j <= config.item; j++) { //Passing through the first items to get their position
if (items[i].dataset.position === '' + j + '') {
position[j] = items[i];
return true;
} else {
}
}
;
})();
}
}
switchPosition = function () {
for (i = 0, j = 0; i < nbItems; i++, j++) {
if (items[i].dataset.position === '' + j + '') {
position[i] = position[i];
}
}
for (i = config.item, j = 1; i < nbItems; i++, j++) { //Replacing in good order, except for the one that are place into the variable position[];
items[i] = items[j];
}
for (i = (nbItems - config.item +1), j = 1; i <= nbItems; i++, j++) { //Replacing in good order the one that are place into variable position[];
items[i] = position[j];
console.log(i);
console.log(j);
console.log(position[j]);
console.log(items[i]);
}
for (i = 0; i < nbItems; i++) {
console.log(items[i]);
}
console.log(items[10]);
}
placement = function () {
for (i = 1; i <= config.item; i++) {
var rect = items[0].getBoundingClientRect();
item_width = Math.floor(rect.width);
item_height = Math.floor(rect.height);
var x = item_width * (i - 1) * 1.1;
items[i].style.display = 'block';
items[i].style.transform = "translate3D(" + x + "px, 0px, 0px)";
}
}
next = function () {
for (i = config.item, j = 1; i < nbItems; i++, j++) { //Updating all dataset position, except for the items that are displayed.
items[i].dataset.position = j;
}
for (i = 1, j = 2; i <= config.item; i++, j--) {
position[i].dataset.position = nbItems - j;
position[i].style.display = "none";
}
}
return self;
})();

Randomly getting Uncaught TypeError: Cannot read property 'substring' of undefined

success: function(data) {
var timeslots = new Array('09:00am', '09:15am', '09:30am', '09:45am', '10:00am', '10:15am', '10:30am', '10:45am', '11:00am', '11:15am', '11:30am', '11:45am', '02:00pm', '02:15pm', '02:30pm', '02:45pm', '03:00pm', '03:15pm', '03:30pm', '03:45pm', '04:00pm', '04:15pm', '04:30pm');
var booked = '';
var bookedSlots = [];
var t_slots;
if (data.bookedslots.length == timeslots.length) {
if (manageDay) {
$('.manageSlots .timeSlot').remove();
}
alert('No Available Slots');
$(where).find('select.time').empty();
return false;
}
for (var t = 0; t < data.bookedslots.length; t++) {
booked = data.bookedslots[t]['time'].substr(0, data.bookedslots[t]['time'].length - 3);
bookedSlots.push(booked);
}
for (var i = 0; i < timeslots.length; i++) {
for (var j = 0; j < bookedSlots.length; j++) {
///// getting the error on this line ////////if(timeslots[i].substring(0,5) === bookedSlots[j]){
timeslots.splice(i, 1);
}
}
}
for (var z = 0; z < timeslots.length; z++) {
t_slots += '<option value="' + timeslots[z] + '">' + timeslots[z] + '</option>';
}
}
The problem is that you have spliced out timeslots[i], but in the next iteration of j you try to use it. If it was the last item in the array you will get an error. If you splice, you should break on the next line to abort the rest of the j loop.
for (var i = 0; i < timeslots.length; i++) {
for (var j = 0; j < bookedSlots.length; j++) {
if(timeslots[i].substring(0,5) === bookedSlots[j]){
timeslots.splice(i, 1);
break;
}
}
}

Categories

Resources