Toggling JS button back and forth - javascript

my toggle button in javascript seems to work fine in turning on lightmode from default darkmode by running a function that changes the CSS. However, when I flip the button again, it does not change. This is somewhat expected since there's no reason it would change. How would I go about switching it back?
Button HTML:
<label for="ID_HERE" class="toggle-switchy" >
<input checked type="checkbox" id="ID_HERE">
<span class="toggle" onclick="lightmode();"></span>
<span class="switch"></span>
</span>
</label>
JS for button:
function lightmode() {
const bodyChanges = document.querySelectorAll('.margin_body');
for (let i = 0; i < bodyChanges.length; i++) {
bodyChanges[i].style.background = 'white';
}
/*const bodyChanges = document.querySelectorAll('.margin_body');
for (let i = 0; i < bodyChanges.length; i++) {
bodyChanges[i].style.backgroundImage = '';
} */
const paraChanges = document.querySelectorAll('.paragraph');
for (let i = 0; i < paraChanges.length; i++) {
paraChanges[i].style.color = 'black';
}
const topTitleChanges = document.querySelectorAll('.toptitle');
for (let i = 0; i < topTitleChanges.length; i++) {
topTitleChanges[i].style.color = 'black';
}
const alphabetSChanges = document.querySelectorAll('.AlphabetS');
for (let i = 0; i < alphabetSChanges.length; i++) {
alphabetSChanges[i].style.color = 'black';
}
const arowanaContainerChanges = document.querySelectorAll('.arowanacontainer');
for (let i = 0; i < arowanaContainerChanges.length; i++) {
arowanaContainerChanges[i].style.background = 'white';
}
const fishContainerChanges = document.querySelectorAll('.fishcontainer');
for (let i = 0; i < fishContainerChanges.length; i++) {
fishContainerChanges[i].style.background = 'white';
}
const articleContainerChanges = document.querySelectorAll('.articlescontainer');
for (let i = 0; i < articleContainerChanges.length; i++) {
articleContainerChanges[i].style.background = 'white';
}
const sideTextChanges = document.querySelectorAll('.sidetext');
for (let i = 0; i < sideTextChanges.length; i++) {
sideTextChanges[i].style.color = 'black';
}
const topMenuChanges = document.querySelectorAll('.topmenu');
for (let i = 0; i < topMenuChanges.length; i++) {
topMenuChanges[i].style.background = '#fff2f2';
}
const h3Changes = document.querySelectorAll('h3');
for (let i = 0; i < h3Changes.length; i++) {
h3Changes[i].style.background = '#fff2f2';
}
const articlePageChanges = document.querySelectorAll('.articlepage');
for (let i = 0; i < articlePageChanges.length; i++) {
articlePageChanges[i].style.color = 'black';
}
const articleTeaserChanges = document.querySelectorAll('.articleteaser');
for (let i = 0; i < articleTeaserChanges.length; i++) {
articleTeaserChanges[i].style.color = 'black';
}
/*const buttonTextChanges = document.querySelectorAll('.button_text');
for (let i = 0; i < buttonTextChanges.length; i++) {
buttonTextChanges[i].style.color = '#0C0C0C';*/
const box2Changes = document.querySelectorAll('.box2');
for (let i = 0; i < box2Changes.length; i++) {
box2Changes[i].style.color = 'rgb(245, 245, 245)';
}
const box3Changes = document.querySelectorAll('.box3');
for (let i = 0; i < box3Changes.length; i++) {
box3Changes[i].style.color = 'rgb(245, 245, 245)';
}
const projectPhoto1Changes = document.querySelectorAll('.projectphoto1');
for (let i = 0; i < projectPhoto1Changes.length; i++) {
projectPhoto1Changes[i].style.backgroundImage = 'linear-gradient(to bottom, #Fdfcfa 50%, lightgrey 50%)';
}
const section1Changes = document.querySelectorAll('.section1');
for (let i = 0; i < section1Changes.length; i++) {
section1Changes[i].style.backgroundColor = '#fff2f2';
}
const section1textChanges = document.querySelectorAll('.section1text');
for (let i = 0; i < section1textChanges.length; i++) {
section1textChanges[i].style.color = 'black';
}
const section1smalltextChanges = document.querySelectorAll('.section1smalltext');
for (let i = 0; i < section1smalltextChanges.length; i++) {
section1smalltextChanges[i].style.color = 'black';
}
const button_textChanges = document.querySelectorAll('.button_text');
for (let i = 0; i < button_textChanges.length; i++) {
button_textChanges[i].style.color = 'black';
}
const polygonfrontChanges = document.querySelectorAll('.polygonfront');
for (let i = 0; i < polygonfrontChanges.length; i++) {
polygonfrontChanges[i].style.fill = '#fff2f2';
}
const bgChanges = document.querySelectorAll('.bg');
for (let i = 0; i < bgChanges.length; i++) {
bgChanges[i].style.backgroundImage = 'url(".jpg")';
}
const bg2Changes = document.querySelectorAll('.bg2');
for (let i = 0; i < bg2Changes.length; i++) {
bg2Changes[i].style.backgroundImage = 'url(".jpg")';
}
const bg3Changes = document.querySelectorAll('.bg3');
for (let i = 0; i < bg3Changes.length; i++) {
bg3Changes[i].style.backgroundImage = 'url(".jpg")';
}
}

When clicking, you should check the input status to know if the mode should toggle to light or dark mode.
<span class="toggle" onclick="toggle()"></span>
function toggle() {
if(document.getElementById("ID_HERE").checked)
lightmode()
else
darkmode()
}

Related

How can I create a real lazy loading in Shopify

I have this code and its running. Its basically hiding the elements that are not in view and when they come into view the .lazy class is removed and they become visible. The issue with this method is, that its still loading all the elements at once for example on page load.
How can I change the code that its really only loading the first 6 elements, then the user scrolls down and its loads the next 6 elements and so on. The important thing is, that the list has to stay searchable.
The perfect example would be this page here:
https://de.louisvuitton.com/deu-de/herren/taschen/alle-taschen/_/N-t1uezqf4
This is my code:
<script>
const batchSize = 3;
let observer;
let currentIndex = 0;
const showNextBatch = (entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const endIndex = currentIndex + batchSize;
for (let i = currentIndex; i < endIndex && i < items.length; i++) {
items[i].classList.remove('lazy');
}
currentIndex = endIndex;
if (currentIndex >= items.length) {
observer.disconnect();
}
}
});
};
const options = {
rootMargin: '50px 0px',
threshold: 0.01
};
if ('IntersectionObserver' in window) {
let collectionList = document.querySelector('.swiper-wrapper');
let items = collectionList.querySelectorAll('.swiper-slide');
for (let i = 0; i < items.length; i++) {
items[i].classList.add('lazy');
}
observer = new IntersectionObserver(showNextBatch, options);
for (let i = 0; i < batchSize; i++) {
items[i].classList.remove('lazy');
}
currentIndex = 0;
for (let i = currentIndex; i < items.length; i++) {
observer.observe(items[i]);
}
}
const mutationObserver = new MutationObserver(() => {
resetObserver();
});
mutationObserver.observe(document.body, {
childList: true,
subtree: true
});
const resetObserver = () => {
observer.disconnect();
collectionList = document.querySelector('.swiper-wrapper');
items = collectionList.querySelectorAll('.swiper-slide');
for (let i = 0; i < items.length; i++) {
items[i].classList.add('lazy');
}
currentIndex = 0;
observer = new IntersectionObserver(showNextBatch, options);
for (let i = 0; i < batchSize; i++) {
items[i].classList.remove('lazy');
}
currentIndex = 0;
for (let i = currentIndex; i < items.length; i++) {
observer.observe(items[i]);
}
};
</script>

How do I place the glass pieces in my hand on the large plane in the most optimized way?

I can place my small parts in the most optimized way for a single large part in my project. The algorithm logic is as follows; The pieces I have are sorted by height from largest to smallest and then placed from left to right. when i have multiple large parts i keep those big parts in a state.
In the first large piece, when there is no suitable place for the small pieces to be added, I want the appropriate region to be queried in the second big piece. here is my code:
index.js
import React, { useContext, useEffect, useRef, useState } from 'react'
import data from '../data'
import Graph from './graph/graph'
import SmallAreaGraph from './graph/small-area-graph';
import { IndexContext } from './IndexContext';
function Index() {
var height = 50;
var width = 50;
const [defaultHeight, setDefaultHeight] = useState(50);
const [defaultWidth, setDefaultWidth] = useState(50);
const [planes, setPlanes] = useState();
const [testState, setTestState] = useState([]);
const [bigBoard, setBigBoard] = useState(new Array(defaultWidth).fill(0).map(() => new Array(defaultHeight).fill(0)));
const [smallPlanes, setSmallPlanes] = useState([]);
const [smallPlanesArea, setSmallPlanesArea] = useState([]);
const [freeSpaceAreas, setFreeSpaceAreas] = useState([]);
const [bigPlanes, setBigPlanes] = useState([{ bigBoard: bigBoard, planes: [], height: defaultHeight, width: defaultWidth, color: "pink" }]);
var totalWidth;
const heightRef = useRef();
const widthRef = useRef();
var smallPlane, totalArea = 0;
function Placement() {
let total = 0;
let totalHeight = 0;
let allArea = [];
for (let i = 0; i < smallPlanes.length; i++) {
if (i === 0) {
smallPlanes[i].x = 1;
} else {
if (allArea !== []) {
} else {
total = total + smallPlanes[i - 1].width + 2;
totalHeight = totalHeight + smallPlanes[i - 1].height + 2;
allArea.push(smallPlanes[i - 1]);
}
if (total + smallPlanes[i].width > Number(width)) {
total = 0;
allArea.push(smallPlanes[i]);
smallPlanes[i].x = 1;
smallPlanes[i].y = allArea[0].height + 2;
return total
} else {
smallPlanes[i].x = total;
}
}
}
}
function Sort() {
let gecici;
for (let i = 0; i <= testState.length - 1; i++) {
for (let j = i; j <= testState.length; j++) {
// >(büyük) işareti <(küçük ) olarak değiştirilirse büyükten küçüğe sıralanır
if (testState[i]?.height < testState[j]?.height) {
gecici = testState[j];
testState[j] = testState[i];
testState[i] = gecici;
setTestState(testState);
}
}
}
// Placement();
}
useEffect(() => {
if (testState !== [] || testState !== undefined) {
Sort();
}
}, [testState]);
function AddBigPlane() {
setBigPlanes([...bigPlanes, { bigBoard: bigBoard, planes: [], height: defaultHeight, width: defaultWidth, color: "pink" }])
}
function Revaluation(w, h, row, col, k) {
totalWidth = totalWidth + Number(w);
if (Number(col + w) <= bigPlanes[k].bigBoard.length) {
if (Number(row + h) <= bigPlanes[k].bigBoard[row].length) {
for (let i = row; i < Number(row + h); i++) {
for (let j = col; j < Number(col + w); j++) {
let bashData = bigPlanes[k];
bashData.bigBoard[i][j] = 1
setBigPlanes(bashData);
}
}
}
}
}
function test(w, h, row, col, index) {
if (Number(row + w) <= bigPlanes[index].width && Number(col + h) <= bigPlanes[index].height) {
for (let i = row; i < Number(row + w); i++) {
for (let j = col; j < Number(col + h); j++) {
if (bigPlanes[index].bigBoard[i][j] === 0) {
if (i === (Number(row + w) - 1) && j === (Number(col + h) - 1)) {
freeSpaceAreas[index] = freeSpaceAreas[index] - smallPlane;
setFreeSpaceAreas([...freeSpaceAreas]);
setTestState([...testState, {
height: Number(heightRef?.current?.value), width: Number(widthRef?.current?.value)
}])
// return Revaluation(Number(widthRef?.current?.value), Number(heightRef?.current?.value), row, col, index);
// let bashData = bigPlanes;
// bashData[k].planes.height = Number(heightRef?.current?.value);
// bashData[k].planes.width = Number(widthRef?.current?.value);
// setBigPlanes(bashData);
}
}
}
}
}
}
function Control(index) {
//ilk 0 değerine sahip row-col (coordinat) değerlri
console.log(index);
for (let row = 0; row < bigPlanes[index].bigBoard.length; row++) {
for (let col = 0; col < bigPlanes[index].bigBoard[row].length; col++) {
if (bigPlanes[index].bigBoard[row][col] === 0) {
//bulunduktan sonra test fonksiyonuna aktarılır.
return test(Number(widthRef.current.value), Number(heightRef.current.value), row, col, index);
}
}
}
}
useEffect(() => {
if (bigPlanes.length !== freeSpaceAreas.length) {
for (let i = 0; i < bigPlanes.length; i++) {
console.log(bigPlanes);
setFreeSpaceAreas([...freeSpaceAreas, bigPlanes[i].width * bigPlanes[i].height])
}
}
}, [bigPlanes]);
function AreaControl() {
// smallPlanesArea?.length && smallPlanesArea.map(area => {
// totalArea = totalArea + area;
// })
console.log("test");
for (let i = 0; i < freeSpaceAreas.length; i++) {
if (smallPlane <= freeSpaceAreas[i]) {
console.log(i);
return Control(i);
}
}
heightRef.current.value = "";
widthRef.current.value = "";
}
function handleKeyDown(e) {
if (e.key === "Enter") {
if (heightRef?.current.value !== "") {
if (widthRef.current.value !== "") {
smallPlane = Number(heightRef?.current.value) * Number(widthRef?.current.value);
AreaControl();
// widthRef.current.value = "";
// heightRef.current.value = "";
} else {
alert("Lütfen bir genişlik değeri giriniz");
}
} else {
alert("Lütfen bir yükseklik değeri giriniz");
}
}
}
useEffect(() => {
console.log(freeSpaceAreas);
}, [freeSpaceAreas]);
function AddAreas() {
// Gerçek zamanlı arr state'i güncelleme.
setPlanes([...smallPlanes]);
ResetSmallPlane();
ResetBigPlane();
for (let i = 0; i < testState.length; i++) {
findCoords(testState[i])
}
}
var totalWidth = 0, totalHeight = 0, totW = 0, totH = 0;
// function RevaluationTwo(w, h, row, col) {
// let bashData;
// for (let i = row; i < Number(row + h); i++) {
// for (let j = col; j < Number(col + w); j++) {
// bashData = bigBoard;
// bashData[i][j] = 1;
// setBigBoard(bashData);
// }
// }
// }
function ResetBigPlane() {
for (let k = 0; k < bigPlanes.length; k++) {
for (let row = 0; row < bigPlanes[k].bigBoard.length; row++) {
for (let col = 0; col < bigPlanes[k].bigBoard[row].length; col++) {
if (bigPlanes[k].bigBoard[row][col] === 1) {
let bashData = bigPlanes;
bashData[k].bigBoard[row][col] = 0
setBigPlanes(bashData);
}
}
}
}
}
function bigPlanesControl() {
for (let i = 0; i < bigPlanes.length; i++) {
}
}
function ResetSmallPlane() {
let arrAttributes = [];
for (let i = 0; i < bigPlanes.length; i++) {
var arr = bigPlanes[i].planes;
arr.length = 0;
arrAttributes.push(arr);
}
setBigPlanes([...arrAttributes]);
}
function createCoords(w, h, row, col, i) {
let bashData = [];
totW = totW + Number(w);
if (Number(col + w) <= bigPlanes[i].width) {
if (Number(row + h) <= bigPlanes[i].height) {
bashData = bigPlanes;
bashData[i].planes.push({ height: h, width: w, x: col + 1, y: row + 1 });
setBigPlanes([...bashData]);
} else {
return;
}
} else {
return;
}
}
function findCoords(test) {
console.log(test);
for (let k = 0; k < bigPlanes.length; k++) {
for (let row = 0; row < bigPlanes[k].bigBoard.length; row++) {
for (let col = 0; col < bigPlanes[k].bigBoard[row].length; col++) {
if (bigPlanes[k].bigBoard[row][col] === 0) {
Revaluation(test.width, test.height, row, col, k);
if (Number(bigPlanes[k].bigBoard[row].length - col) >= test.width) {
return createCoords(test.width, test.height, row, col, k);
}
else
return;
}
}
}
}
}
function Approve() {
ResetSmallPlane();
ResetBigPlane();
for (let i = 0; i < testState.length; i++) {
findCoords(testState[i])
}
}
return (
<div className='container mt-5'>
<div className='big-plane'>
</div>
<div className='d-flex justify-content-between '>
<div></div>
<div className='d-flex'>
<div className='me-4'>
<input className='input form-control ' type="text" ref={heightRef} placeholder="Yükseklik giriniz.." onKeyUp={handleKeyDown} />
</div>
<div className='me-4'>
<input className='input form-control ' type="text" ref={widthRef} placeholder="Genişlik giriniz.." onKeyUp={handleKeyDown} />
</div>
<div className='btn btn-success' onClick={() => Approve()}>
Onayla
</div>
<div className='btn btn-success' onClick={() => AddAreas()}>
Ekle
</div>
</div>
<div className='btn btn-danger d-flex align-items-center'>
<div onClick={() => AddBigPlane()}>Cam Plaka Ekle</div> <b style={{ fontWeight: "bolder", fontSize: "20px", marginLeft: "5px" }}>+</b>
</div>
</div>
{
testState?.length ? testState.map((plane, i) => {
return <SmallAreaGraph color="purple" key={i} data={data} height={Number(plane.height)} width={Number(plane.width)} />
}) : ""
}
<div className='mt-5'>
{/* where large parts are added */}
{
bigPlanes.length ? bigPlanes.map((plane, i) => {
totalWidth = totalWidth + bigPlanes[i].width;
return <Graph smallPlanesProps={plane.planes} data={plane.bigBoard} key={i} color={plane.color} height={plane.height} width={plane.width} x={0} y={0} position="absolute" zIndex="-10" left={totalWidth} />
}
) : ""
}
</div>
</div>
)
}
export default Index

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>

A* Algorithm - Javascript: Why does my algorithm not find the shortest path

I am working on visualizing A*. I have a problem where the algorithm finds a path, but it is not the shortest. If I remove the part of the A* function code which is commented as 'tie-breaking', the algorithm finds the shortest path, but it searches the whole grid just like Dijkstra's algorithm, which I don't think A* is supposed to do. These are the pictures of the results with and without tie-breaking:
With Tie-Breaking
Without Tie-Breaking
What is wrong? Here is my A* function:
async a_star_search() {
this.clearSearchNotWalls();
let openSet = [];
let closedSet = [];
let start, end;
let path = [];
this.findNeighbors();
//shapes is a 2d array of squares... a grid
for (let i = 0; i < this.shapes.length; i++) {
for (let j = 0; j < this.shapes[0].length; j++) {
if (this.shapes[i][j].type == "Start") {
start = this.shapes[i][j];
}
if (this.shapes[i][j].type == "End") {
end = this.shapes[i][j];
}
}
}
openSet.push(start);
while (openSet.length > 0) {
let lowestIndex = 0;
//find lowest index
for (let i = 0; i < openSet.length; i++) {
if (openSet[i].F < openSet[lowestIndex].F)
lowestIndex = i;
}
//current node
let current = openSet[lowestIndex];
//if reached the end
if (openSet[lowestIndex] === end) {
path = [];
let temp = current;
path.push(temp);
while (temp.cameFrom) {
path.push(temp.cameFrom);
temp = temp.cameFrom;
}
console.log("Done!");
for (let i = path.length - 1; i >= 0; i--) {
this.ctxGrid.fillStyle = "#ffff00";
this.ctxGrid.fillRect(path[i].x, path[i].y, 14, 14);
await new Promise(resolve =>
setTimeout(() => {
resolve();
}, this.animDelay / 2)
);
}
break;
}
this.removeFromArray(openSet, current);
closedSet.push(current);
let my_neighbors = current.neighbors;
for (let i = 0; i < my_neighbors.length; i++) {
var neighbor = my_neighbors[i];
if (!closedSet.includes(neighbor) && neighbor.type != "Wall") {
let tempG = current.G + 1;
let newPath = false;
if (openSet.includes(neighbor)) {
if (tempG < neighbor.G) {
neighbor.G = tempG;
newPath = true;
}
} else {
neighbor.G = tempG;
newPath = true;
openSet.push(neighbor);
}
if (newPath) {
neighbor.H = this.heuristic(neighbor, end);
neighbor.G = neighbor.F + neighbor.H;
neighbor.cameFrom = current;
}
}
}
//draw
for (let i = 0; i < closedSet.length; i++) { //BLUE
this.ctxGrid.fillStyle = "#4287f5";
this.ctxGrid.fillRect(closedSet[i].x, closedSet[i].y, 14, 14);
}
for (let i = 0; i < openSet.length; i++) { //GREEN
this.ctxGrid.fillStyle = "#00ff00";
this.ctxGrid.fillRect(openSet[i].x, openSet[i].y, 14, 14);
}
await new Promise(resolve =>
setTimeout(() => {
resolve();
}, 10)
);
}
if (openSet.length <= 0) {
//no solution
}
}
Here is my heuristic function:
heuristic(a, b) {
//let d = Math.sqrt(Math.pow(b.I - a.I, 2) + Math.pow(b.J - a.J, 2));
let d = Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));
return d;
}

How to add one more property to the dynamically created array?

var props = [
"current_day", "open_val", "high_val", "low_val", "close_val"
];
var data = [
{
"current_day":"2011-08-01",
"open_val":136.65,
"high_val":136.96,
"low_val":134.15,
"close_val":134.15
},
{
"current_day":"2011-08-02",
"open_val":135.26,
"high_val":135.95,
"low_val":131.50,
"close_val":131.85
}
]
var arrays = [];
for ( var i = 0; i < data.length; ++i )
{
var array = [];
for ( var j = 0; j < props.length; ++j )
{
array.push( data[i][props[j]] );
}
arrays.push(array);
}
console.log(JSON.stringify(arrays));
When i run the output of this is
[["2011-08-01",136.65,136.96,134.15,134.15],["2011-08-02",135.26,135.95,131.5,131.85]]
Could you please tell me how can i add close_value also at the end of the array so that it looks like this
[["2011-08-01",136.65,136.96,134.15,134.15,134.15],["2011-08-02",135.26,135.95,131.5,131.85,131.85]]
http://jsfiddle.net/4pxrhhvj/
Just like this? Updated your fiddle JSFiddle
var nprops = [
"close_val"
];
for ( var i = 0; i < data.length; ++i )
{
for ( var ii = 0; ii < arrays.length; ++ii )
{
for ( var j = 0; j < nprops.length; ++j )
{
var closeval = '';
closeval = data[i][nprops[j]] ;
}
arrays[ii].push(closeval);
}
}
for ( var i1 = 0; i1 < arrays.length; ++ii )
{
arrays[i1].pop();
}
console.log(JSON.stringify(arrays));
You can use if/else in the inner for loop:
var props = [
"current_day", "open_val", "high_val", "low_val", "close_val"
];
var data = [{
"current_day": "2011-08-01",
"open_val": 136.65,
"high_val": 136.96,
"low_val": 134.15,
"close_val": 134.15
}, {
"current_day": "2011-08-02",
"open_val": 135.26,
"high_val": 135.95,
"low_val": 131.50,
"close_val": 131.85
}]
var arrays = [];
for (var i = 0; i < data.length; ++i) {
var array = [];
for (var j = 0; j < props.length; ++j) {
if (props[j] !== "close_val") {
array.push(data[i][props[j]]);
} else {
array.push(data[i][props[j]]);
array.push(data[i][props[j]]);
}
}
arrays.push(array);
}
document.querySelector('pre').innerHTML = JSON.stringify(arrays);
<pre></pre>
Try this code
var props = [
"current_day", "open_val", "high_val", "low_val", "close_val"
];
var data = [{
"current_day": "2011-08-01",
"open_val": 136.65,
"high_val": 136.96,
"low_val": 134.15,
"close_val": 134.15
}, {
"current_day": "2011-08-02",
"open_val": 135.26,
"high_val": 135.95,
"low_val": 131.50,
"close_val": 131.85
}];
var arrays = [];
for (var i = 0; i < data.length; ++i) {
var array = [];
for (var j = 0; j < props.length; ++j) {
array[j] = data[i][props[j]];
}
arrays.push(array);
}
console.log(JSON.stringify(arrays));

Categories

Resources