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 am trying to get coding to find a range of colors and select them.
Someone was able to help with this code.
with (app.activeDocument) {
if (pathItems.length > 0) {
alert(pathItems.length);
for (var g = 0 ; g < pathItems.length; g++) {
if (pathItems[g].filled == true) {
if (
pathItems[g].fillColor.red > 200 == true &&
pathItems[g].fillColor.red < 210 == true &&
pathItems[g].fillColor.green > 200 == true &&
pathItems[g].fillColor.green < 210 == true &&
pathItems[g].fillColor.blue > 200 == true &&
pathItems[g].fillColor.blue < 210 == true
)
{
alert('R' + pathItems[g].fillColor.red + ' G' + pathItems[g].fillColor.green + ' B' + pathItems[g].fillColor.blue);
}
}
}
}
}
I have been trying to get it to use the numbers it is finding for the alert and use those as the RGB colors to select
with (app.activeDocument) {
if (pathItems.length > 0) {
alert(pathItems.length);
for (var i = 0 ; i < pathItems.length; i++) {
if (pathItems[i].filled == true) {
if (
pathItems[i].fillColor.red > 200 == true &&
pathItems[i].fillColor.red < 210 == true &&
pathItems[i].fillColor.green > 200 == true &&
pathItems[i].fillColor.green < 210 == true &&
pathItems[i].fillColor.blue > 200 == true &&
pathItems[i].fillColor.blue < 210 == true
);
var newRGBColor = pathItems[i].fillColor.red &&
pathItems[i].fillColor.green &&
pathItems[i].fillColor.blue;
{
app.activeDocument.defaultFillColor = newRGBColor;
app.executeMenuCommand("Find Fill Color menu item");
}
}
}
}
}
But this is not working. I am very much of not a coder my brain just can understand it. I know the basics but, that is about all can my brain will retain. This is about my 100th version of this code. I am really trying, so please don't be mad at me if i am missing something.
I have taken a javascripting class, read the illustrator scripting guilds, and am all over W3schools. My brain just can not understand much for coding, so please please do not get mad at me. I really am just looking for help.
Updates
Thank you for letting me know with is out dated but, I got this coding from someone else as shown on top and i dont know enough to update things. What i am trying to get it to do is Find the RGB color breakdowns in Illustrator on objects. app.activeDocument.defaultFillColor will change my set my default color fill and app.executeMenuCommand("Find Fill Color menu item") will fine the color i have selected(default color if not one selected)
if (
pathItems[g].fillColor.red > 200 == true &&
pathItems[g].fillColor.red < 210 == true &&
pathItems[g].fillColor.green > 200 == true &&
pathItems[g].fillColor.green < 210 == true &&
pathItems[g].fillColor.blue > 200 == true &&
pathItems[g].fillColor.blue < 210 == true
)
This will find the colors i need to select but i can get my defaultFillColor to be the colors for the code before
I have the feeling we are having an XY problem here as it would be useful to know what your ultimate goal is.
Since you mention using the "Find Fill Color" menu item, I will assume you want the script to select all objects with colors in the given range (R, G and B between 200 and 210).
Modifying Mouser's script will give us:
var appActiveDocumentPathItems = app.activeDocument.pathItems; //create var for this object;
var selectionArray = []; //create array for objects to be selected
if (appActiveDocumentPathItems.length > 0) {
for (var i = 0; i < appActiveDocumentPathItems.length; i++) {
if (appActiveDocumentPathItems[i].filled == true) {
var fill = appActiveDocumentPathItems[i].fillColor;
if (
fill.red > 200 == true &&
fill.red < 210 == true &&
fill.green > 200 == true &&
fill.green < 210 == true &&
fill.blue > 200 == true &&
fill.blue < 210 == true
) {
selectionArray [selectionArray.length] = appActiveDocumentPathItems[i]; //if an object matches the requirement, add it to the array
}
}
}
}
activeDocument.selection = selectionArray; //select the objects in the array
This would very easily result in an unwanted value because of the operator &&. You want to combine the different values into one string that represents a RGB-colour:
take a look:
var pathItems = [{fillColor : {red : 200, green : 240, blue : 156}}]; //array - filled with colors
var newRGBColor = pathItems[0].fillColor.red && pathItems[0].fillColor.green && pathItems[0].fillColor.blue;
console.log(newRGBColor); //not the result expected : 156
To get it to work you must define the red, green and blue properties of the object RGBColor
var pathItems = [{
fillColor: {
red: 205,
green: 206,
blue: 209
}
}]; //array - filled with colors
var newRGBColor = new RGBColor() //initial default colour
newRGBColor.red = pathItems[0].fillColor.red;
newRGBColor.green = pathItems[0].fillColor.green;
newRGBColor.blue = pathItems[0].fillColor.blue;
console.log(newRGBColor);
//dummy function to make demo work, not part of the solution
function RGBColor()
{
this.red;
this.green;
this.blue;
}
Final solution (without with):
var appActiveDocumentPathItems = app.activeDocument.pathItems; //create var for this object;
if (appActiveDocumentPathItems.length > 0) {
for (var i = 0; i < appActiveDocumentPathItems.length; i++) {
if (appActiveDocumentPathItems[i].filled == true) {
var fill = appActiveDocumentPathItems[i].fillColor;
if (
fill.red > 200 == true &&
fill.red < 210 == true &&
fill.green > 200 == true &&
fill.green < 210 == true &&
fill.blue > 200 == true &&
fill.blue < 210 == true
) {
var newRGBColor = new RGBColor(); //this is how you define a new color in Illustrator's extendscript
newRGBColor.red = pathItems[i].fillColor.red;
newRGBColor.green = pathItems[i].fillColor.green;
newRGBColor.blue = pathItems[i].fillColor.blue;
app.activeDocument.defaultFillColor = newRGBColor;
app.executeMenuCommand("Find Fill Color menu item");
}
}
}
}
Remember that the this will loop all shapes that have a color filled and the last iteration of the loop (the last filled shape) will be the defaulFillColor. You need more logic to select a different color than the last one.
Hey so I am making a 2D tile game, or really I am just messing around. I have made the map from an array, where 0 represents nothing, and other characters represents a walkable tile.
var map=[["t","t","t","t","t","t","t","t","t","t","t","t","t","t","t","t","t","t","t","t"],
["l","1","b","b","b","b","b","b","b","b","b","b","b","b","b","b","b","b","b","r"],
["l","r","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","r"],
["l","1","t","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","l","r"],
["l","1","1","t","t","t","t","t","t","t","t","t","t","t","t","r","0","0","l","r"],
["l","b","b","b","b","b","b","b","b","1","1","b","b","b","b","b","t","t","b","r"],
["0","0","0","0","0","0","0","0","0","l","r","0","0","0","0","0","0","0","0","0"],
["0","0","0","0","0","0","0","0","0","l","r","0","0","0","0","0","0","0","0","0"],
["0","0","0","0","0","0","0","0","0","l","r","0","0","0","0","0","0","0","0","0"],
["0","0","0","0","0","0","0","0","l","1","1","r","0","0","0","0","0","0","0","0"],
["0","0","0","0","0","0","0","l","1","1","1","1","r","0","0","0","0","0","0","0"],
["t","t","t","t","t","t","t","1","1","1","1","1","1","t","t","t","t","t","t","t"]];
On screen it looks like this
You see my moveable character here as well.
Now I have come this far, and I'd like my character to collide with the empty tiles represented as the value of 0 in my map array.
This is my code for checking collision (brackets are correct in the script):
function collisioncheck(ind){
for(var i in map){
for(var j in map[i]){
if(yass==true){
if(map[i][j]==0){
if(ind==0 && playerPosX==j*32+32 && playerPosY>i*32-32 && playerPosY<i*32+32){
return false;
}else if(ind==1 && playerPosX==j*32-32 && playerPosY>i*32-32 && playerPosY<i*32+32){
return false;
}else if(ind==2 && playerPosY==i*32+32 && playerPosX>j*32-32 && playerPosX<j*32+32){
return false;
}else if(ind==3 && playerPosY==i*32-32 && playerPosX>j*32-32 && playerPosX<j*32+32){
return false;
}else{
return true;
}
}
}else{
return true;
}
}
}
var yass=false;
function exist(){
for(var i in map){
for( var j in map[i]){
if(map[i][j]==0){
yass=true;
break;
}
}
}
So, this works. But only for the first 0 in the map. My problem is that the return statements breaks the for-loop and function. So my character will not collide with any other blank tile but the first one.
I will have to rewrite this, but is there any smart solution to this?
Link to jsfiddle here (Character not visible)
You're on the right track, your loop only runs for one iteration because you always return something after an iteration. However, you should only call return when you know the final result, because - as you said - it will exit the function.
It is correct to call 'return false' right away after a collision is detected, because if the player collides with at least one block, then there is a collision. On the opposite, 'return true' should only be called when you are sure that there are no collisions at all on the entire board, and you need to test every block on the map before you can confirm this.
function collisioncheck(ind) {
for (var i in map) {
for (var j in map[i]) {
if (yass == true) {
if (map[i][j] == 0) {
if (ind == 0 && playerPosX == j * 32 + 32 && playerPosY > i * 32 - 32 && playerPosY < i * 32 + 32) {
return false;
} else if (ind == 1 && playerPosX == j * 32 - 32 && playerPosY > i * 32 - 32 && playerPosY < i * 32 + 32) {
return false;
} else if (ind == 2 && playerPosY == i * 32 + 32 && playerPosX > j * 32 - 32 && playerPosX < j * 32 + 32) {
return false;
} else if (ind == 3 && playerPosY == i * 32 - 32 && playerPosX > j * 32 - 32 && playerPosX < j * 32 + 32) {
return false;
}
// else: do nothing. (i.e. let the loop run for the next block)
}
} else {
return true;
}
}
}
return true;
}
What we do here is go through all the blocks, if we find a collision we return false and exit the function. We only reach the 'return true' statement if we went through all the blocks without finding any collision, which is exactly what you want.
You need to use continue instead of return in the last else of your main if/else block on line 15
I am trying to alert "yes" if ether of the conditions in my if statement are true:
var a = 2;
var b = 1;
if (a = 1 or b = 1 ) {
alert('yes');// should alert in this case
} else {
alert('no');
}
https://jsfiddle.net/90z7urvd/1/
What do I use for the if, if this is possible?
a = 1 will set the value 1 to variable a. It is not doing a comparison. For comparison, you use === or ==
=== (Identity operator) is the correct way to compare if both the types are same.
if (a === 1 || b === 1 ) {
=== operator won't do the type conversion before the comparison while == does the type conversion before the comparison.
For your or case, You may use || operator
var bootresul = someExpression || anotherExpression
Corrected code
var a = 2;
var b = 1;
if (a === 1 || b === 1 ) {
alert('yes');
} else {
alert('no');
}
You are assiging value rather then comparing
Try like this
if (a == 1 || b == 1)
To compare strictly use ===
Like this
if (a === 1 || b === 1)
JSFIDDLE
you can do this
var a = 2;
var b = 1;
if ((a == 1) || (b == 1 )) {
alert('yes');// should alert in this case
} else {
alert('no');
}
the == is one of the relational operator for checking equality and || is a logical operator that is a notion of logical OR
use this to compare just values
if (a == 1 || b == 1){
}
OR use this to compare values and type of variable
if (a === 1 || b === 1){
}
note : == will just check of values and === this will check value with type of variable
var a = 2;
var b = 1;
if (a == 1 || b == 1 ) {
alert('yes');// should alert in this case
} else {
alert('no');
}
I think you were doing assignment instead of comparison
Try using this:
if(a === 1 || b === 1){
alert('YES!')
}else{
alert('NO!')
}
OR you can use ternary operator condition instead of if else
(a == 1 || b == 1) ? alert('YES!') : alert('NO!')