JavaScript shortening long if-else - javascript

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;
};

Related

How to refactor multiple variables and multiple if conditions

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;
}
}

javascript imports are real-time?

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;
}
});
}
}

JavaScript if/else Statement Input Data [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
Please help me, I am studying on my own and need help, I want to create an "JavaScript else if statement" but this doesn't work.
Who wants to make input
// If "x" is greater than or equal to 1 and "x" is less than 10, and "y" is equal to 100, output "+"
// If "x" is greater than or equal to 11 and "x" is less than 100, and "y" is equal to 100, output "++"
// If "x" is greater than or equal to 1 and "x" is less than 10, and "y" is equal to 1, output "+++"
// If "x" is greater than or equal to 10, and "y" is equal to 1, output "++++"
The code that I tried to make, below
<!DOCTYPE html>
<html>
<body>
<p>Please Help:</p>
<input id="numb1" type="text">
<input id="numb2" type="text">
<button type="button" onclick="myFunction()">Submit</button>
<p id="tes"></p>
<script>
function myFunction() {
var x, y, text;
x = document.getElementById("numb1").value;
y = document.getElementById("numb2").value;
if (x > 1 || x < 10 || y == 100) {
text = "+";
} else if (x > 11 || x < 100 || y == 100) {
text = "++";
} else if (x > 1 || x < 10 || y == 1) {
text = "+++";
} else if (x > 10 || y == 1) {
text = "++++";
}
document.getElementById("tes").innerHTML = text;
}
</script>
</body>
</html>
Full Working Code:
<!DOCTYPE html>
<html>
<body>
<p>Please Help:</p>
<input id="numb1" type="text">
<input id="numb2" type="text">
<button type="button" onclick="myFunction()">Submit</button>
<p id="tes"></p>
<script>
function myFunction() {
var x, y, text;
x = document.getElementById("numb1").value;
y = document.getElementById("numb2").value;
if (x >= 1 && x < 10 && y == 100) {
text = "+";
} else if (x >= 11 && x < 100 && y == 100) {
text = "++";
} else if (x >= 1 && x < 10 && y == 1) {
text = "+++";
} else if (x >= 10 && y == 1) {
text = "++++";
}
document.getElementById("tes").innerHTML = text;
}
</script>
</body>
</html>
Explanation:
You were using || which means or in logical statements, where you meant to use && to represent and.
Furthermore, when using logical statements, more than or equal to would be represented by >= and not >.
What you used:
if (x > 1 || x < 10 || y == 100) {
text = "+";
} else if (x > 11 || x < 100 || y == 100) {
text = "++";
} else if (x > 1 || x < 10 || y == 1) {
text = "+++";
} else if (x > 10 || y == 1) {
text = "++++";
}
What you were supposed to use:
if (x >= 1 && x < 10 && y == 100) {
text = "+";
} else if (x >= 11 && x < 100 && y == 100) {
text = "++";
} else if (x >= 1 && x < 10 && y == 1) {
text = "+++";
} else if (x >= 10 && y == 1) {
text = "++++";
}
To learn more about JavaScript Operators and Comparison Logical Operators (i.e. ||, &&, >, >=, == or !=), visit:
https://www.w3schools.com/js/js_comparisons.asp
https://www.w3schools.com/jsref/jsref_operators.asp
Recommended changes to code:
I would strongly recommend adding an else statement to the conditional statement in you code, as then if all other conditions don't apply there will be a back-up, and your code will not error out and print out undefined.
first: the OR - || opartor returns true even if only one of the expression in is both sides are true. the AND - && operator returns true only if both of them are true, and this is what you are looking for.
so you have to replece all the OR opartors with AND operators.
second: to check if a value is greater than or equal to another value, you have to combine both operators > and = together.
if (x >= 1 && x < 10 && y == 100) {
text = "+";
} else if (x >= 11 && x < 100 && y == 100) {
text = "++";
} else if (x >= 1 && x < 10 && y == 1) {
text = "+++";
} else if (x >= 10 && y == 1) {
text = "++++";
}

finding lowest number between its 2 neighboor in an array

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*/)

Check the diagonal neighbors of a node

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) {

Categories

Resources