Javascript switch and if statements with multiple conditions doing something really strange? - javascript

I'm trying to make a function that changes the value of the attribute x or y of the dot object four times, each time only if two conditions are met. The variable permissionSomething has to be 1, and x or y has to be more or less then a certain number, because in this case it is used for a moving dot on a canvas, which has to stay within the canvas. PermissionSomething is set to 1 if a certain key is pressed down, and changes back to the default value of -1 if that key goes up again.
var permissionLeft = -1;
var permissionRight = -1;
var permissionUp = -1;
var permissionDown = -1;
function update()
{
switch (true)
{
case permissionLeft = 1 && dot.x > 29:
dot.x--;
break;
case permissionRight = 1 && dot.x < 841:
dot.x++;
break;
case permissionUp = 1 && dot.y > 29:
dot.y--;
break;
case permissionDown = 1 && dot.y < 541:
dot.y++;
break;
}
}
If I run this, even without pressing any key, it starts to move in some strange way, stops and starts moving back and forth. If I don't press any keys permissionSomething should never be 1 so it should never move. The same thing happens if I write four if-statements like this:
if (permissionLeft = 1 && dot.x > 29) {
dot.x--};
if (.....

Related

Why "if" works but "switch" doesn't work?

// It is simple code
var num = prompt("put number");
// This way is not worked
switch (num) {
case num > 0:
console.log("num++");
break;
case num < 0:
console.log(num-2);
break;
}
// But this worked
if (num > 0){
console.log(num++);
} else if (num < 0){
console.log(num -2);
}
My first way by "switch" is not worked but "if" method worked.
I tried all of thing for changing code or other ways but the same result.
Please guys help me.
Because the statement num > 0 inside you case will return true or false.
If you do this:
switch (true) {
case num > 0:
console.log("num++");
break;
case num < 0:
console.log(num-2);
break;
}
It will work.
Cases cannot be expressions, you must normalize your input first.
Although it is valid to place an expression in a case, in this scenario a more tried-and-true way of dealing with this is to first normalize your input first.
You can determine direction for example:
var num = parseInt(prompt("put number"), 10);
var direction = num < 0 ? -1 : 1;
switch (direction) {
case 1:
console.log("num++");
break;
case -1:
console.log(num - 2);
break;
}
The switch acts as a case switcher, meaning you cannot make comparisons to create cases, just list cases by case, and perform some function from this case. The if / else structure is suitable for making comparisons, as the expected result in the if call is always a boolean.
Example:
const a = 1;
if (a === 1) {
console.log('hello');
} else {
console.log('sad');
switch (a) {
case 1 : console.log('hello'); break;
default: console.log('sad'); break;
In your case, I recommend using if/else if/else, as it is more recommended.

How to Make Time Buffering for keyPressed() Function in P5.js?

I made a simple Snake game in the P5.js environment,
and I have one thing that I want to fix.
So, I have this code for keyPressed() function
function keyPressed(){
if(keyCode === LEFT_ARROW) {
if(snake.yspeed == 1 || snake.yspeed == -1) {
snake.yspeed = 0;
snake.xspeed = -1;
}
}else if(keyCode === RIGHT_ARROW) {
if(snake.yspeed == 1 || snake.yspeed == -1) {
snake.yspeed = 0;
snake.xspeed = 1;
}
}else if(keyCode === UP_ARROW) {
if(snake.xspeed == 1 || snake.xspeed == -1) {
snake.xspeed = 0;
snake.yspeed = -1;
}
}else if(keyCode === DOWN_ARROW) {
if(snake.xspeed == 1 || snake.xspeed == -1) {
snake.xspeed = 0;
snake.yspeed = 1;
}
}
}
yspeed is the vertical movement, and xspeed is the horizontal movement.
So, if the snake is moving to the right, even if I pressed the LEFT_ARROW , the snake won't turn to the left. But, if I pressed UP_ARROW or DOWN_ARROW and quickly press the LEFT_ARROW, the snake will immediately turn left and hit itself.
So, I want to add a buffering time for the keyPressed() function after one of the arrow keys being pressed.
How can I do this in P5.js?
I also made a snake game and encountered this exact problem.
I wrote it in vanilla javascript and had set the fps to 12, which give the player enough time to change direction twice between two cycles.
Solution
My solution was to have a buffer variable that stores the last pressed direction. in your case, it could look like so
let dir = '';
function keyPressed(){
if(keyCode === LEFT_ARROW) dir = 'LEFT';
if(keyCode === RIGHT_ARROW) dir = 'RIGHT';
if(keyCode === UP_ARROW) dir = 'UP';
if(keyCode === DOWN_ARROW) dir = 'DOWN';
}
And actually change its direction only before I called the snake's update() method in draw():
function draw() {
...
snake.direction(dir);
snake.update();
snake.draw();
...
}
You only need to check whether or not the move is valid within the direction() method.
this.direction = function(d) {
switch(d) {
case 'LEFT':
if (this.xv != 1) {this.xv = -1; this.yv = 0;}
break;
case 'RIGHT':
if (this.xv != -1) {this.xv = 1; this.yv = 0;}
break;
case 'UP':
if (this.yv != 1) {this.xv = 0; this.yv = -1;}
break;
case 'DOWN':
if (this.yv != -1) {this.xv = 0; this.yv = 1;}
break;
default:
this.xv = this.yv = 0;
}
}
(I copied this from my code, but you get the idea)
How it works
Lets take your example.
In your game, what is happening is that it first changes the velocity of the snake to point UP, then to the LEFT, all before the next snake.update() is called.
Now all it does is change the dir variable to UP, then LEFT before the next snake.update() is called. So the next snake.direction() gets a dir argument containing LEFT, which is ignored (because the snake is pointing RIGHT) and the snake doesn't go backward on itself.
I hope this made some sense, you can check my code here if it helps.
You could try to add a time limit on the key presses, by doing something like checking that draw() was called at least once between key presses. Something like this:
var canPress = true;
function keyPressed(){
if(canPress){
// respond to key press
}
canPress = false;
}
function draw(){
// draw the frame
canPress = true;
}
But my guess is that this will make your game feel clunky and unresponsive.
Instead of restricting user input based on time, there are two general solutions for this:
Option 1: Move the snake immediately when the user presses the corresponding key. You'd do this by calling something like an update() function, both at the beginning of each frame, and when you press a key.
Option 2: Prevent the snake from moving in a direction that would kill itself immediately. You'd do this by checking whether the square you're about to go in is occupied, and ignoring the key press if so.
Which approach you take depends on how you want your game to work. You could even take a hybrid approach and do both.

enable/disable button using case statement

Hello, need help pleaseI already tried adding a break on both end of condition ..I Have 5 Textboxes, 1 Button and a Javascript for their function. What i want to do is this..
CASE 1: When the value of Stat variable is "N", The program must require an input on Area, Capital and Code for the ADD button to enable else it will disable.
CASE 2 When the value of Stat variable is "R", The program must require an input on Area, Gross and Code textboxes for the ADD button to enable else it will disable. I have tried to code it this way.. But it didn't work.
function SetButtonStatus() {
var Stat = document.getElementById('<%=_oTextBoxNRC.ClientID%>').value;
var Area = document.getElementById('<%=_oTextBoxArea.ClientID%>').value;
var Capital = document.getElementById('<%=_oTextBoxCapital.ClientID%>').value;
var Code = document.getElementById('<%= _oTextboxBusLineCode.ClientID%>').value;
var Gross = document.getElementById('<%=_oTextBoxGrossRec.ClientID%>').value;
//Change these conditions as your requirement
switch (Stat) {
case 'N':
if (parseFloat(Area) >= 1 && parseFloat(Capital) >= 1 && Code.length >= 1)
document.getElementById('<%=_oButtonAdd.ClientID%>').disabled = false;
else
document.getElementById('<%=_oButtonAdd.ClientID%>').disabled = true;
break;
case 'R':
if (parseFloat(Area) >= 1 && parseFloat(Gross) >= 1 && Code.length >= 1)
document.getElementById('<%=_oButtonAdd.ClientID%>').disabled = false;
else
document.getElementById('<%=_oButtonAdd.ClientID%>').disabled = true;
break;
}
}
Use setAttribute and removeAttribute like this:
if (parseFloat(Area) >= 1 && parseFloat(Capital) >= 1 && Code.length >= 1)
{
document.getElementById('<%=_oButtonAdd.ClientID%>')
.setAttribute("disabled","disabled");
}
else
{
document.getElementById('<%=_oButtonAdd.ClientID%>')
.removeAttribute('disabled');
}

Recursive function to check 2d Array

I am creating a minesweeper game for a javascript project and have run into a problem that I can't get my head round. When you click on an empty cell (one which does not have any mines around it and so does not display a number) in the minesweeper game for those who don't know, this will reveal the whole block of empty cells that are neighbouring eachother, stopping when the "wall of numbers" containing these empty blocks is found. Example below:
[1]http://datagenetics.com/blog/june12012/hole.png
This requires a recursive function to figure out which blocks are to be revealed. My code at the moment only reveals the block that is clicked on:
function revealGridContents()
{
switch (positionClickContents)
{
case 0:
ctx.drawImage(clickedImage, (xClick*20), (yClick*20));
break;
case 1:
ctx.drawImage(num1Image, (xClick*20), (yClick*20));
break;
case 2:
ctx.drawImage(num2Image, (xClick*20), (yClick*20));
break;
case 3:
ctx.drawImage(num3Image, (xClick*20), (yClick*20));
break;
case 4:
ctx.drawImage(num4Image, (xClick*20), (yClick*20));
break;
case 5:
ctx.drawImage(num5Image, (xClick*20), (yClick*20));
break;
case 6:
ctx.drawImage(num6Image, (xClick*20), (yClick*20));
break;
case 7:
ctx.drawImage(num7Image, (xClick*20), (yClick*20));
break;
case 8:
ctx.drawImage(num8Image, (xClick*20), (yClick*20));
break;
};
};
The number passed into the switch statement is the value of the data in the array grid[xClick][yClick]; eg a 4 symbolises a block with 4 mines around it, so the image for 4 will be displayed.
Case 0 is the case that a blank block is clicked and so the code for this needs modifying but I really can't think what to do.
From what I can understand, I will need to call the revealGridContents(); function from case 0, but passing in new values for xClick and yClick (the x and y values of the array position) for each square that I want to check.
Any help shedding the light on what I need to do next would be greatly appreciated!
Without knowing slightly more of your program it's hard to give you an exact solution. You'll probably need a separate function to do this, as just using the same function will reveal everything (which is obviously not how the game works). You'll also need some way of keeping track of revealed cells, otherwise you'll get into a loop (I'm assuming this is stored in another 2d array revealed[x][y]).
You probably want to do something like this (I haven't tested this so there may be errors in it - apologies):
function revealGridContents(){
switch (positionClickContents){
case 0:
ctx.drawImage(clickedImage, (xClick*20), (yClick*20));
checkAdjacentCells(xClick, yClick);
break;
...
}
}
function checkAdjacentCells(x,y){
var cellsToCheck = [
[x,y+1],
[x,y-1],
[x+1,y],
[x-1,y]];
var x,y;
for(var i=0; i<=cellsToCheck.length; i++){
x = cellsToCheck[i][0];
y = cellsToCheck[i][1];
if(!revealed[x][y] && grid[x][y] == 0){
ctx.drawImage(clickedImage, x*20, y*20);
checkAdjacentCells(x,y);
}
}
}
Just as a general advice, you need a better separation between the model of your game and the UI.
Here is the begining of my interpretation of the minesweeper game:
function init() {
var i,j; // indexes
map = []; // global map, because i'm lazy
for (i=0; i<10; i++) {
var row = [];
for (j=0; j<10; j++)
row.push({
bomb : Math.round(Math.random()-0.4), // set bombs randomly, change to your correct ratio
revealed : false, // nothing is visible at start
count : 0 // counts will be computed after all the map is created
});
map.push(row);
}
// set adjacent bomb counts
for (i=0; i<10; i++)
for (j=0; j<10; j++) {
if (map[i-1] && map[i-1][j-1] && map[i-1][j-1].bomb) map[i][j].count++;
if (map[i-1] && map[i-1][j] && map[i-1][j].bomb) map[i][j].count++;
if (map[i-1] && map[i-1][j+1] && map[i-1][j+1].bomb) map[i][j].count++;
if (map[i] && map[i][j-1] && map[i][j-1].bomb) map[i][j].count++;
if (map[i] && map[i][j+1] && map[i][j+1].bomb) map[i][j].count++;
if (map[i+1] && map[i+1][j-1] && map[i+1][j-1].bomb) map[i][j].count++;
if (map[i+1] && map[i+1][j] && map[i+1][j].bomb) map[i][j].count++;
if (map[i+1] && map[i+1][j+1] && map[i+1][j+1].bomb) map[i][j].count++;
}
}
function print() { // uses console to display instead of canvas
var output = '\n';
for (var i=0; i<10; i++) {
for (var j=0; j<10; j++) {
var item = map[i][j];
output += (item.revealed ? item.count : 'x') + ' ';
}
output += '\n';
}
console.log(output);
}
function click(x,y) {
reveal(x,y);
print(map);
}
function reveal(x,y) {
// break early if click is invalid (invalid clicks are generated)
if (x < 0 || x > 9 || y < 0 || y > 9 || map[x][y].revealed) return;
// mark the square as clicked
map[x][y].revealed = true;
if (map[x][y].bomb) { // losing click
console.log('You lost');
} else if (map[x][y].count === 0) { // click on 0 adjacent bombs
reveal(x-1, y);
reveal(x, y-1);
reveal(x, y+1);
reveal(x+1, y);
}
}
init();
console.log('First print');
print();
console.log('Click 1,3');
click(1,3);
The difficult part is in the click() function.
Try this demo (click 'run with JS' several times until you don't lose and hit a 0):
http://jsbin.com/iqeganU/1/edit

JavaScript switch statement 1-100

I am trying to write a JavaScript switch where the user enters a number from 1-100 and they receive a message based on what range the number falls into. This is what I have written so far.
I am doing this for an intro to programing class, and I don't fully understand how to get this to work, my problem is that I can't figure out how to show a range, ie: 1-25,
<script>
var number = prompt("Enter 1-100");
switch(number)
{
case 1-25:
document.write("1-25");
break;
case 26-50;
document.write("26-50");
break;
case 51-100:
document.write("51-75");
break;
case "4":
document.write("76-100");
break;
}
</script>
Just figuring it out with a little math is probably a better approach :
var number = prompt("Enter 1-100"),
message = ['1-25', '26-50', '51-75', '76-100'];
document.write(message[Math.ceil(number/25)-1])
FIDDLE
Divide the returned number with 25, round up to nearest whole number, which gives you 1,2,3 ... etc, and since array indices starts at zero, subtract 1.
EDIT:
If you have to do a switch, you'd still be better off with a little math, and not writing a hundred case's :
var number = prompt("Enter 1-100");
number = Math.ceil(number / 25 );
switch(number) {
case 1:
document.write("1-25");
break;
case 2:
document.write("26-50");
break;
case 3:
document.write("51-75");
break;
case 4:
document.write("76-100");
break;
}
FIDDLE
You can use conditions with switch like this:
var number = prompt("Enter 1-100");
switch (true) {
case number >= 1 && number <= 25:
alert("1-25");
break;
case number >= 26 && number <= 50:
alert("26-50");
break;
case number >= 51 && number <= 75:
alert("51-75");
break;
case number >= 76 && number <= 100:
alert("76-100");
break;
}
http://jsfiddle.net/dfsq/T3zJR/
You cannot use ranges in switch statements. To check whether a value is contained in a range, you need to compare against lower and upper bounds:
number = parseInt(number, 10);
if (number >= 1 && number <= 25)
document.write("1-25");
else if (number >= 26 && number <= 50)
document.write("26-50");
else if (number >= 51 && number <= 75)
document.write("51-75");
else if (number >= 75 && number <= 100:
document.write("76-100");
else
document.write(number+" is not a valid number between 1 and 100");
Of course, as the number of if-elses grows, you should look for an alternative. An algorithmic solution would be the simplest (dividing by 25 and rounding to find the 25-multiple interval the number is contained in):
number = parseInt(number, 10);
var range = Math.floor((number-1)/25);
if (range >= 0 && range < 4)
document.write( (1+range*25) + "-" + (1+range)*25);
If you can't use that (for example because of erratic intervals) a for-loop (or even a binary search) over an array of interval boundaries would be the way to go (as demonstrated by #jfriend00).
If you want simple ranges of 25, you can do this:
if (number < 1 || number > 100)
document.write("out of range");
else {
var low = Math.floor(number / 25) * 25 + 1;
var high = low + 24;
document.write(low + "-" + high);
}
You need a single value to match a case, or a switch takes longer than if elses...
you can get the range before switching-
var number = prompt("Enter 1-100", '');
var s= (function(){
switch(Math.floor((--number)/25)){
case 0: return "1-25";
case 1: return "26-50";
case 2: return "51-75";
default: return "76-100";
}
})();
alert(s);
Here's a table driven approach that allows you to add more items to the table without writing more code. It also adds range checking.
<script>
var breaks = [0, 25, 50, 75, 100];
var number = parseInt(prompt("Enter 1-100"), 10);
var inRange = false;
if (number) {
for (var i = 1; i < breaks.length; i++) {
if (number <= breaks[i]) {
document.write((breaks[i-1] + 1) + "-" + breaks[i]);
inRange = true;
break;
}
}
}
if (!inRange) {
document.write("Number not in range 1-100");
}
</script>

Categories