I am trying to build a graph using elk.js, and to be able to do that I need to have x value for each node. Nodes on the left should have x value smaller than those on the right.
The graph contains nodes that are divided into rows.
Nodes are created 1 by 1 so a check is done every time a new node is created
Newly created nodes are added always on the right
Numbers inside nodes are x values.
Steps 1, 2, 3, etc. indicates the order in which we added nodes.
I also listed a number of different conditions I need to check (this is something which I need help with)
What I currently have:
I know x values on the right and on the left
I know x values of children in the same parent node
I know x values in each row
I have everything to make it work and in fact, it does work perfectly fine but my main issue is this code below. I am looking for a way to simplify this somehow and I am struggling a lot so any help would be appreciated.
If you have totally different approach than this one I will gladly know those.
if (allNodesFromCurrentRow.length === 0) {
newNode.nodeLayout.x = parentX + 10;
} else {
if (currentValue > 0 && rightValue === 0 && leftValue === 0) {
newNode.nodeLayout.x = currentValue + 1;
} else if (
currentValue === 0 &&
leftValue === 0 &&
rightValue > 0
) {
newNode.nodeLayout.x = rightValue - 1;
} else if (currentValue === 0 && leftValue > 0 && rightValue > 0) {
newNode.nodeLayout.x = (leftValue + rightValue) / 2;
} else if (currentValue > 0 && leftValue === 0 && rightValue > 0) {
newNode.nodeLayout.x = (rightValue + currentValue) / 2;
} else if (
leftValue > 0 &&
currentValue === 0 &&
rightValue === 0
) {
newNode.nodeLayout.x = leftValue + 1;
} else if (leftValue > 0 && currentValue > 0 && rightValue === 0) {
newNode.nodeLayout.x = currentValue + 1;
} else if (leftValue > 0 && currentValue > 0 && rightValue > 0) {
newNode.nodeLayout.x = (rightValue + currentValue) / 2;
}
}
Related
well, i'm trying to do a snake game using basic imports, but at some time, i got stuck, because of a javascript assignment.
i assigned the value the oldSnake as the value of the snake before its changes.
but as i get into the forEach, the value already assigned changes and i don't know why.
Before getting into the forEach
After getting into the forEach
i searched about it, and didn't get anywhere, Does someone know what's happening?
import { snake } from "/snake.js";
let lastDirection = {y: 1, x:0};
export function updateGame(direction){
let oldSnake = snake;
if (!(direction.y == 0 && direction.x == 0)){
if((lastDirection.y == 1 && direction.y == -1 || lastDirection.y == -1 && direction.y == 1)
||(lastDirection.x == 1 && direction.x == -1 || lastDirection.x == -1 && direction.x == 1)){
direction = lastDirection;
}
snake.forEach((snakeSlice, index)=>{
lastDirection = direction;
if (index === 0){
snakeSlice.ypos+= direction.y;
snakeSlice.xpos+= direction.x;
}
else{
snakeSlice.ypos = oldSnake[index-1].ypos;
snakeSlice.xpos = oldSnake[index-1].xpos;
}
});
}
}
I am building an application similar to minesweeper where a user will click a square on a grid and the app will tell the user how many of the surrounding squares contain an 'X'. I have my code working when I only check up, down, left, and right. My code is beginning to get very long since there are quite a few edge cases to account for. I am going to begin checking diagonals for 'X's and I want to come up with a shorter way to check these cases.
Can anyone help me develop a for loop or other short hand way to write this code. Here is what I have so far for a 8x8 grid.
Here is my sandbox: https://codesandbox.io/s/6y6wzo001w
showNumber= () => {
let Xcounter = 0;
console.log(this.props.keys)
console.log(this.props.reduxState.reducer.board[this.props.keys])
if(this.props.keys% 8 ===0){
if(this.props.reduxState.reducer.board[this.props.keys +1] === 'X'){
Xcounter++
}
}
if(this.props.keys% 8 ===7){
if(this.props.reduxState.reducer.board[this.props.keys -1] === 'X'){
Xcounter++
}
}
if(this.props.keys/8 <1){
if(this.props.reduxState.reducer.board[this.props.keys +8] === 'X'){
Xcounter++
}
}
if(this.props.keys/8 >=7){
if(this.props.reduxState.reducer.board[this.props.keys -8] === 'X'){
Xcounter++
}
}
if(this.props.keys % 8 !== 0 && this.props.keys % 8 !== 7){
if(this.props.reduxState.reducer.board[this.props.keys +1] === 'X'){
Xcounter++
}
if(this.props.reduxState.reducer.board[this.props.keys -1]=== 'X'){
Xcounter++
}
}
if(Math.floor(this.props.keys)/8 > 0 && Math.floor(this.props.keys)/ 8 < 7){
if(this.props.reduxState.reducer.board[this.props.keys +8] === 'X'){
Xcounter++
}
if(this.props.reduxState.reducer.board[this.props.keys -8]=== 'X'){
Xcounter++
}
}
if(this.props.id === 'X'){
this.setState({...this.state, clicked: true, counter: 'X'})
return this.state.counter;
}
this.setState({...this.state, clicked: true, counter: Xcounter})
return this.state.counter;
}
Assuming you have an array this.props.reduxState.reducer.boardof length 64 with 'X's or non-'X's, one could simply loop through the x and y directions like so:
let Xcounter = 0;
//save the board for shorter and more readable code
let board = this.props.reduxState.reducer.board;
//the current index we've clicked on
let c = this.props.keys;
//we're going to check if we're at the edge of the board.
//I'll explain these later.
let minX = c%8 == 0 ? 0 : -1;
let maxX = c%8 == 7 ? 0: 1;
let minY = (c-minX)/8 == 0 ? 0 : -1;
let maxY = (c-minY)/8 == 7 ? 0 : 1;
for( let x = minX; x <= maxX; ++x ){
for( let minY = -1; y <= maxY; ++y ){
if( board[c+x+8*y)] == 'X' ){ Xcounter++; }
}
}
//we also checked the square itself, but we didn't want to
if( board[c] == 'X' ){ Xcounter--; }
This assumes the indeces of the board are from right to left, and then top to bottom, not the other way around (i.e. board[7] is the top-right corner, not the bottom-left one).
As far as what this actually does; essentially, we look whether or not we're at the edge of a board, and find the relative x- and y-coordinates we have to check. To visualize:
Here minX=0, because going to the left of the current clicked square c would throw us off the board. maxX=1 though, because we can check to the right of the clicked square. Similarly, we check the y-coordinates.
Assuming that your checks are already correct, let's work with what you already have.
Try to rewrite what you actually have with more condensed style to get an overview as a first step and introduce a board side constant as a second:
showNumber = () => {
const BOARD_SIDE = 8;
let Xcounter = 0;
let keys = this.props.keys;
let board = this.props.reduxState.reducer.board;
console.log(keys);
console.log(board[this.props.keys]);
for (let edge = BOARD_SIDE; edge < BOARD_SIDE * BOARD_SIDE; edge += BOARD_SIDE) {
if (keys % edge === 0 && board[keys + 1] === "X") Xcounter++;
if (keys % edge === (edge - 1) && board[keys - 1] === "X") Xcounter++;
if (keys / edge < 1 && board[keys + edge] === "X") Xcounter++;
if (keys / edge >= (edge - 1) && board[keys - edge] === "X") Xcounter++;
if (keys % edge !== 0 && keys % edge !== (edge - 1)) {
if (board[keys + 1] === "X") Xcounter++;
if (board[keys - 1] === "X") Xcounter++;
}
if (Math.floor(keys) / edge > 0 && Math.floor(keys) / edge < (edge - 1)) {
if (board[keys + edge] === "X") Xcounter++;
if (board[keys - edge] === "X") Xcounter++;
}
}
if (this.props.id === "X") {
this.setState({ ...this.state, clicked: true, counter: "X" });
return this.state.counter;
}
this.setState({ ...this.state, clicked: true, counter: Xcounter });
return this.state.counter;
};
I want to exectute a function, preferably inside the forEach, for every element that is surrendered by 2 higher or equal number, or if its first or last element, just compared to second, or second last number.
I come up with this code, but I'm sure there is a better way:
var Pointdata = [98,59,39,0,48,85,19,43,3,98,65,100];
Pointdata.forEach(function(Current,i,array){
if (Current <= array[i+1] && Current <= array[i-1]) {
DrawPoint(Current,i,array);
}
else if (Current <= array[i+1] && i == 0) {
DrawPoint(Current,i,array);
}
else if(Current <= array[i-1] && i+1 == array.length) {
DrawPoint(Current,i,array);
}
function DrawPoint(Current,i,array) {
// marks peak points of canavas chart.
}
You could use just a single condition inside, Current is a.
if ((i + 1 === array.length || a <= array[i + 1]) && (i === 0 || a <= array[i - 1])) {
DrawPoint(a, i, array);
}
What about this?
for (i = 1; i < array.length - 1; i++) {
var Current = array[i];
if (Current <= array[i+1] && Current <= array[i-1]) {
DrawPoint(Current,i,array);
}
}
Couple of benefits:
You can skip edge cases like start and end indices
Only one conditional to think about
But if you want to keep those edge cases you can write them all in one if block separating them by or conditions like if ((Current <= array[i+1] && Current <= array[i-1]) || (Current <= array[i+1] && i == 0) || (Current <= array[i-1] && i+1 == array.length))
function markPeaks(data, draw) {
var xs = [Infinity].concat(data).concat(Infinity)
xs.forEach(function(x, i, array) {
if (Number.isFinite(x)) // skip first and last
if (array[i-1] >= x && x <= array[i+1]) // n-1 ≥ n ≤ n+1
draw(x, i-1, array) // minus1 because of 1st 'helper' Infinity
})
}
markPeaks(/*pointdata, /*drawpoint*/)
I'm trying to compare the values of a node. Using the flood-fill algorithm I was able to check vertically and horizontally every node of my grid. Now I have to update my code to check the cells that sit on the diagonal, as in the image below:
In red you have the current node, in yellow are the cells that need to be checked.
Here is a snippet of what I have so far:
var mapWidth = Math.sqrt(mapData.length);
var currentCell = $('[data-x="'+ x +'"][data-y="'+ y +'"]');
if (x < 0 || y < 0 || x > mapWidth || y > mapWidth) {
return;
}
if(mapData[x*mapWidth+y] !== 0 || currentCell.hasClass('cell-grey')) {
if(mapData[x*mapWidth+y] > 0) {
currentCell.addClass('cell-grey').css('opacity', '1');
}
if(mapData[(x-1)*mapWidth+(y-1)] > 0 && mapData[(x-1)*mapWidth+(y-1)] < mapWidth) {
currentCell.addClass('cell-grey').css('opacity', '1');
return;
}
if(mapData[(x-1)*mapWidth+(y+1)] > 0 && mapData[(x-1)*mapWidth+(y+1)] < mapWidth) {
currentCell.addClass('cell-grey').css('opacity', '1');
return;
}
if(mapData[(x+1)*mapWidth+(y-1)] > 0 && mapData[(x+1)*mapWidth+(y-1)] < mapWidth) {
currentCell.addClass('cell-grey').css('opacity', '1');
return;
}
if(mapData[(x+1)*mapWidth+(y+1)] > 0 && mapData[(x+1)*mapWidth+(y+1)] < mapWidth) {
currentCell.addClass('cell-grey').css('opacity', '1');
return;
}
return true;
}
mapWidth is the variable that contains all the cells of the grid, and currentCell is the current node cell. This snippet is not really working for me.
When you evaluate mapData[(x-1)*mapWidth+(y-1)], the values of x-1 and y-1 may cause an out-of-bounds reference, which returns undefined. You have to validate the cell coordinates before accessing the array.
You can iterate over the four diagonal neighbors like this:
for (var neighborX = x - 1; neighborX <= x + 1; neighborX += 2) {
if (neighborX < 0 || neighborX >= mapWidth) {
continue;
}
for (var neighborY = y - 1; neighborY <= y + 1; neighborY += 2) {
if (neighborY < 0 || neighborY >= mapWidth) {
continue;
}
currentCell.addClass('cell-grey').css('opacity', '1');
}
}
I'm not sure exactly what you're trying to accomplish, but it looks like there are other bugs in your code. You probably don't want to return immediately after turning a cell gray, for example. If you want each of the diagonal neighbors to turn gray, the loop above should do the trick.
This line near the beginning of your code contains a subtle error:
if (x < 0 || y < 0 || x > mapWidth || y > mapWidth) {
Valid indices range from 0 through mapWidth - 1, so you should write:
if (x < 0 || y < 0 || x >= mapWidth || y >= mapWidth) {
I have a feeling this isn't possible? I'm trying to check sets of conditions here and my tests should be passing after I moved a couple of those sets out of 2 other methods and into this if statement below as to combine all the checks into one if statement:
if ((move.coordinates.x === 0 && move.coordinates.y === 0 ||
move.coordinates.x === 0 && move.coordinates.y === 1 ||
move.coordinates.x === 0 && move.coordinates.y === 2)
||
(move.coordinates.x === 1 && move.coordinates.y === 0 ||
move.coordinates.x === 1 && move.coordinates.y === 1 ||
move.coordinates.x === 1 && move.coordinates.y === 2)
||
(move.coordinates.x === 2 && move.coordinates.y === 0 ||
move.coordinates.x === 2 && move.coordinates.y === 1 ||
move.coordinates.x === 2 && move.coordinates.y === 2))
{
...then do something
}
Doesn't seem the parens are making a difference here in separating out the conditional sets.
I'm trying to trim down on duplicate code I had those 3 sets in different methods where the logic was mostly the same, but checked for different states.
So I pasted in the two other state sets (sets meaning the group of 3 ors that make up a given state) and trying to check these 3 rows basically in one method instead of splitting out into 3 to cut down dup code.
Simplifying the notation, you have
(x == 0 && y == 0 || x == 0 && y == 1 || x == 0 && y == 2)
||
(x == 1 && y == 0 || x == 1 && y == 1 || x == 1 && y == 2)
||
(x == 2 && y == 0 || x == 2 && y == 1 || x == 2 && y == 2)
Since the operator || is associative, you can remove the parentheses.
And then you can use the distributive property to group the x.
x == 0 && (y == 0 || y == 1 || y == 2) ||
x == 1 && (y == 0 || y == 1 || y == 2) ||
x == 2 && (y == 0 || y == 1 || y == 2)
And even use the distributive property again
(x == 0 || x == 1 || x == 2) && (y == 0 || y == 1 || y == 2)
Finally, you can store the allowed values in an array and use indexOf to avoid repeating the variables:
var values = [0, 1, 2];
values.indexOf(x) >= 0 && values.indexOf(y) >= 0;
you can use logical rules that cover all the possibilities you allow. if you look at the repeating values in your code, you see that you are trying to exhaust all combinations of x values 0,1,2 with combinations of y values 0,1,2. so if you make a rule that will encompass x values from 0 to 2 and the same with y values from 0 to 2, you can simplify your if statement like the example below.
var coordx = move.coordinates.x;
var coordy = move.coordinates.y;
if ((coordx >= 0 && coordx <= 2) && (coordy >= 0 && coordy <=2)) {
// do something
}
One issue I see with your code is the order of operations (take a look here to see the basics), consider using more brackets to be as explicit as possible. It looks like you want to do this:
if (( (move.coordinates.x === 0 && move.coordinates.y === 0) ||
(move.coordinates.x === 0 && move.coordinates.y === 1) ||
(move.coordinates.x === 0 && move.coordinates.y === 2))
||
...
But, if you want to be a little more efficient and clear, I would recommend reformatting your logic with nested if statements:
if (x==0 || x==1 || x==2)
{
if(y==0 || y==1 || y==2)
{
do something...