How to fill selected cells on a grid with a selected color?

Proppsicle

I'm creating a game in which the user has to match a randomly generated target image made up of a grid of squares. The user can select an entire row (circle selectors on left) an entire column( circle selectors on top) and one individual cell and that counts as one move. Currently my program allows me to select the row, column and cells (and deselected them) but i haven't been able to figure out a way to fill the selected cells from my color selector at the top of the canvas. I was wondering if anyone could give me any tips on how to achieve this?

final color RED = #D12020;
final color BLUE = #515DD8;
final color GREEN = #21AF20;
final color YELLOW = #F5EF74;
final color ORANGE = #F59219;
final color PURPLE = #B219F5;
final color WHITE = #FFFFFF;
final int ROWS = 12;
final int COLUMNS = 8;
final int BLOCK_SIZE = 40;
int blockSize;
int spacing;
int cornerX;
int cornerY;
int size;
int space;
int cell = -1;
int col = -1;
int row = -1;
color[] colour = {RED, BLUE, GREEN, YELLOW, ORANGE, PURPLE, WHITE};

void setup() {
  size(1000, 1000);
  background(0);
  cornerX = width/8;
  cornerY = height/8;
  size = height/33;
  space = width/100;
  targetImage();
}

void draw() {
  //background(0);
  colourCells();
  grid();
  selectCell();
  columnSelectors();
  rowSelectors();
  counter();
}

//draws the colour selectors
void colourCells() {
  int blockSize = width/20;
  int spacing = width/200;
  int colourBlocks = 7;
  int squareX = blockSize;
  for (int i=0; i < colourBlocks; i++) {
    stroke(167);
    fill(colour[i]);
    rect(squareX, 0, blockSize, blockSize);
    squareX += spacing+blockSize;
  }
}

//draws the grid
void grid() {
  cornerX = width/8;
  cornerY = height/5;
  noFill();
  stroke(167);
  strokeWeight(1);
  for (int i = 0; i<ROWS; i++) {
    cornerX = width/8;
    for (int j = 0; j<COLUMNS; j++) {
      rect(cornerX, cornerY, BLOCK_SIZE, BLOCK_SIZE);
      cornerX += BLOCK_SIZE;
    }
    cornerY += BLOCK_SIZE;
  }
}

//changes the selected cell stroke to red (or deselected cell outline back to grey)
void selectCell() {

  cornerX = width/8;
  cornerY = height/5;
  if (cell != -1) {  
    stroke(RED);
    rect(cornerX + (cell % COLUMNS) * BLOCK_SIZE, cornerY + (cell / COLUMNS) * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE);
    stroke(167);
  }
}

//creates the circular column selectors
void columnSelectors() {

  int columnX = (cornerX) + (size/2) + (space/2);
  int columnY = (cornerY) - (size/2) - space;

  noFill();
  for ( int i = 0; i<COLUMNS; i++) {
    if (col != -1 && col == i)
      stroke(RED);
    else
      stroke(167);

    ellipse(columnX, columnY, size, size);
    columnX += size + space;
  }
}

//creates the circular row selectors
void rowSelectors() {

  int rowX = (cornerX) - (size/2) - space;
  int rowY = (cornerY) + (size/2) + (space/2);
  noFill(); 
  for ( int j = 0; j<ROWS; j ++) {
    if (row  != -1 && row == j)
      stroke(RED);
    else
      stroke(167);

    ellipse(rowX, rowY, size, size);
    rowY += size + space;
  }
}

//creates the score counter at the bottom of canvas
void counter() {
  float x = width/3;
  float y = 4*height/5;
  float boxLength = width/3;
  float boxHeight = height/20;
  int counter = 0;
  fill(255);
  rect(x, y, boxLength, boxHeight);
  String counterText = "Num Moves: " + counter;
  fill(0);
  textSize(40);
  text(counterText, x + (boxLength*1/14.0), y + (boxHeight*3/4.0));
}

//loads in a random target image
void targetImage() {
  float y = height/5;
  float x = width/2;
  String [] file = {"target0.png", "target1.png", "target2.png", "target3.png", "target4.png"};
  PImage target;// create a variable that can point to an off-screen buffer
  String filename = file[int(random(0, 4))]; //"target" + int(random(0,4)) + ".png";// create filename
  target = loadImage(filename);// load image file into off-screen buffer
  image(target, x, y, width/3.125, height/2.08);// display the buffer on canvas at location x, y
}

//allows the user to select/deselect individual cells
int cellSelected() {

  int x;
  int y;
  int xPos= mouseX - cornerX;
  int yPos= mouseY - cornerY;
  x = xPos/BLOCK_SIZE;
  y = yPos/BLOCK_SIZE;
  int num = x + (y*COLUMNS);
  if (num == cell)
    return -1;
  else
    return num;
}

//allows the user to select/deselect a column
int selectColumn() {

  int x;
  int xPos= mouseX - cornerX;
  x = xPos/(size+space);
  if (x == col)
    return -1;
  else
    return x;
}

//allows the user to select/deselect a row
int selectRow() {

  int y;
  int yPos= mouseY - cornerY;
  y = yPos/(size+space);
  if (y == row)
    return -1;
  else
    return y;
}

//mouse click functions for selecting cells/rows/columns/colour
void mouseClicked() {

  spacing = width/200;
  blockSize = width/20;

  if (mouseX > cornerX && mouseY > cornerY && mouseX < cornerX + COLUMNS*BLOCK_SIZE 
    && mouseY < cornerY + ROWS*BLOCK_SIZE) {
    cell = cellSelected();
  }

  if (mouseX > cornerX && mouseY > (cornerY - (space + size)) && mouseX < cornerX + COLUMNS*BLOCK_SIZE 
    && mouseY < cornerY) {
    col = selectColumn();
  }

  if (mouseX > (cornerX - (space + size)) && mouseY > cornerY && mouseX < cornerX 
    && mouseY < cornerY + ROWS*BLOCK_SIZE) {
    row = selectRow();
  }

  if (mouseX < blockSize && mouseX > ((blockSize*colour.length) + (spacing*(colour.length - 1)))) {
    for (int c = 0; c < colour.length; c++) {
      if (get(mouseX, mouseY) == colour[c]) {
        fill(colour[c]);
        break;
      }
    }
  }
}

/*
to do
fill colour
increse score counter
*/```


  [1]: https://i.stack.imgur.com/eyX4g.png
laancelot

I like your project. And I especially like that you commented it. Good job so far. I should be sleeping, but I'll give you a hand instead. And, let's face it, I'm bad at sleeping anyway.

First, as you can guess, to color your solution you'll have to stock these informations somewhere.

Then, to verify if the player has found the right answer, you'll have to be able to compare his work to the solution.

I see you used an image to show the targeted state. I suggest you code it instead, so then you can compare it more easily (and you can also generate many different "levels" easily).

Java is object-oriented. You didn't wrote any class, so I suppose that you're still learning. Let me tell you something: class are awesome. They are their own object, with their own methods and variables. You can instantiate them in many ways. Like, let's say... an array of your very own object. An object which could be... let's say... a square? A colored square?

Yes. Instead of drawing about 100 squares, you could define one class and let them draw themselves. And remember their own color. And know if they have been clicked on.

And, basically, whatever you want.

Here's an example of a Square class:

class Square{
  //modal variables
  private float xPos = 0;
  private float yPos = 0;
  private float myWidth = 0;
  private float myHeight = 0;
  public color myColor = color(0);  //myColor and isSelected are public because I want to access them directly from outside the class
  public boolean isSelected = false;  //public modal variables are not a popular choice, with good reasons, but for now let's just roll with it

  //this is a constructor. Every time you instantiate this class, you must call it's constructor. This one can be overloaded with the square's cordinates and size
  public Square(int xx, int yy, float ww, float hh) {
    xPos = xx;
    yPos = yy;
    myWidth = ww;
    myHeight = hh;
  }

  //you can call this method to make the square draw itself
  public void Render() {    
    if (isSelected) {
      stroke(RED);
    } else {
      stroke(167);
    }
      fill(myColor);
    rect(xPos, yPos, myWidth, myHeight);
  }

  //give coordinates to this function to know if this squared has been clicked on
  public boolean ClickedOn(float xx, float yy) {
    return ((xx > xPos && xx < xPos + myWidth) && (yy > yPos && yy < yPos + myHeight));
  }
}

Now, I'm not going to re-write the whole thing, but here's a minimal, reproductible example of this class's power (you can copy and paste the following code into Processing and learn from it):

final color RED = #D12020;
final color BLUE = #515DD8;
final color GREEN = #21AF20;
final color YELLOW = #F5EF74;
final color ORANGE = #F59219;
final color PURPLE = #B219F5;
final color WHITE = #FFFFFF;
final int ROWS = 12;
final int COLUMNS = 8;
final color[] colour = {RED, BLUE, GREEN, YELLOW, ORANGE, PURPLE, WHITE};
ArrayList <Square> picker, grid, answer;  //there are 3 groups of squared to manage

class Square{
  //modal variables
  private float xPos = 0;
  private float yPos = 0;
  private float myWidth = 0;
  private float myHeight = 0;
  public color myColor = color(0);  //myColor and isSelected are public because I want to access them directly from outside the class
  public boolean isSelected = false;  //public modal variables are not a popular choice, with good reasons, but for now let's just roll with it

  //this is a constructor. Every time you instantiate this class, you must call it's constructor. This one can be overloaded with the square's cordinates and size
  public Square(float xx, float yy, float ww, float hh) {
    xPos = xx;
    yPos = yy;
    myWidth = ww;
    myHeight = hh;
  }

  //you can call this method to make the square draw itself
  public void Render() {    
    if (isSelected) {
      stroke(RED);
    } else {
      stroke(167);
    }
      fill(myColor);
    rect(xPos, yPos, myWidth, myHeight);
  }

  //give coordinates to this function to know if this squared has been clicked on
  public boolean ClickedOn(float xx, float yy) {
    return ((xx > xPos && xx < xPos + myWidth) && (yy > yPos && yy < yPos + myHeight));
  }
}

//setup() is meant for you to initialize stuff before the main loop, which is draw()
void setup() {
  size(1000, 1000);
  InitializeSquares();
}

//let's initialize EVERYTHING SQUARE-SHAPED!
public void InitializeSquares(){
  float blockSize = width/20;
  float cornerX = width/12;
  float cornerY = height/8;
  float answerCornerX = cornerX * 6.5;
  float answerCornerY = cornerY;
  float pickerSize = blockSize * 1.5;
  float pickerCornerX = cornerX/2;
  float pickerCornerY = cornerY - (pickerSize * 1.5);

  //the grid:
  grid = new ArrayList <Square>();
  for (int i = 0; i<ROWS; i++) {
    for (int j = 0; j<COLUMNS; j++) {
      grid.add(new Square(cornerX + (j*blockSize), cornerY + (i*blockSize), blockSize, blockSize));
    }
  }

  //the target answer:
  answer = new ArrayList <Square>();
  for (int i = 0; i<ROWS; i++) {
    for (int j = 0; j<COLUMNS; j++) {
      answer.add(new Square(answerCornerX + (j*blockSize), answerCornerY + (i*blockSize), blockSize, blockSize));
      answer.get(answer.size()-1).myColor = colour[floor(random(colour.length))];
    }
  }

  //the color pickers
  picker = new ArrayList <Square>();
  for (int i = 0; i < colour.length; i++) {
    picker.add(new Square(pickerCornerX + (i*pickerSize), pickerCornerY, pickerSize, pickerSize));
    picker.get(picker.size()-1).myColor = colour[picker.size()-1];
  }
}

void draw() {
  background(0);  //it's ok, the squares will draw themselves

  //let's draw the player's squares
  for (Square s : grid) {
    s.Render();
  }
  for (Square s : grid) {
    //I'm drawing the selected squared over the unselected ones so we see them better
    if (s.isSelected) {s.Render();}
  }

  //drawing the answer grid
  for (Square s : answer) {
    s.Render();
  }

  //drawing the color pickers
  for (Square s : picker) {
    s.Render();
  }
}

void mouseClicked() {
  //checking if is the player selecting squares
  for (Square s : grid) {
    if (s.ClickedOn(mouseX, mouseY)) {
      s.isSelected = !s.isSelected;
    }
  }

  //checking if the player is coloring squares. If so, coloring the squared and unselecting them
  for (Square p : picker) {
    if (p.ClickedOn(mouseX, mouseY)) {
      for (Square s : grid) {
        if (s.isSelected) {
          s.isSelected = false;
          s.myColor = p.myColor;
        }
      }
    }
  }
}

From what I read from your code, I'm confident that you will be able to use these lines to reach your goals. Your code showed that you had still a lot to learn, but still it showed a lot of promises. If you did it all by yourself, then I'm also confident that you'll get very good at this, and very soon. So I'm not going to list every little thing you did which was wrong or whatever. You'll learn in due time.

Don't forget to have fun while learning. It's more than half the work! I'll hang around in case you have questions.

---------------------------------------------------

Here's some code based on your original post. It's an implementation of "being able to select one column and one row and one cell" and the putting some color in there, but without any class.

I'll be honest here, this was way harder than what I did yesterday.

final color RED = #D12020;
final color BLUE = #515DD8;
final color GREEN = #21AF20;
final color YELLOW = #F5EF74;
final color ORANGE = #F59219;
final color PURPLE = #B219F5;
final color WHITE = #FFFFFF;
final int ROWS = 12;
final int COLUMNS = 8;
final int BLOCK_SIZE = 40;
int blockSize;
int spacing;
int cornerX;
int cornerY;
int size;
int space;
int cell = -1;
int col = -1;
int row = -1;
color[] colour = {RED, BLUE, GREEN, YELLOW, ORANGE, PURPLE, WHITE};

//I added these variables. The color array is 2 dimentional, so you can use it like if it had grid coordinates (square [0][2] is third on the first line)
PVector square_selected;  //this will hold the grid coordinates of the currently selected square, or -1 for "nothing"
color[][] square_color;
int columnSelected = -1;
int rowSelected = -1;

void setup() {
  size(1000, 1000);
  background(0);
  cornerX = width/8;
  cornerY = height/8;
  size = height/33;
  space = width/100;
  targetImage();

  //initializing the new array
  square_color = new color[COLUMNS][ROWS];
  for (int i=0; i<COLUMNS; i++) {
    for (int j=0; j<ROWS; j++) {
      square_color[i][j] = color(0);
    }
  }
  square_selected = new PVector(-1, -1);

  //You might have heard about this or not, but as a general rule global variables are shunned upon. That's because when the program becomes more complex, they become exponentially harder to control,
  //and can cause unexpected behavior. No joke, Toyota programmers actually caused death because of these (search for "Toyota spaghetti code" if you're curious)
  //So I'm initializing these here and removing the places where the code would change them unexpectedly.
  //You may have had a better idea of what you're doing that I do, though, so you can chalk up this decision to my coding preferences.
  blockSize = width/20;
  spacing = width/200;
}

void draw() {
  background(0);
  grid();
  colourCells();
  //selectCell();
  columnSelectors();
  rowSelectors();
  counter();
}

//draws the colour selectors
void colourCells() {
  int colourBlocks = 7;
  int squareX = blockSize;
  for (int i=0; i < colourBlocks; i++) {
    stroke(167);
    fill(colour[i]);
    rect(squareX, 0, blockSize, blockSize);
    squareX += spacing+blockSize;
  }
}

//draws the grid
void grid() {
  for (int i=0; i<ROWS; i++) {
    for (int j=0; j<COLUMNS; j++) {
      stroke(167);
      fill(square_color[j][i]);
      rect(cornerX + (BLOCK_SIZE * j), cornerY + (BLOCK_SIZE * i), BLOCK_SIZE, BLOCK_SIZE);
    }
  }
  //drawing the selected square over the others
  if (square_selected.x > -1) {
    stroke(RED);
    fill(square_color[(int)square_selected.x][(int)square_selected.y]);
    rect(cornerX + (BLOCK_SIZE * (int)square_selected.x), cornerY + (BLOCK_SIZE * (int)square_selected.y), BLOCK_SIZE, BLOCK_SIZE);
  }
}

//creates the circular column selectors
void columnSelectors() {

  int columnX = (cornerX) + (size/2) + (space/2);
  int columnY = (cornerY) - (size/2) - space;

  noFill();
  for ( int i = 0; i<COLUMNS; i++) {
    if (i == columnSelected) {
      stroke(RED);
    } else {
      stroke(167);
    }
    ellipse(columnX, columnY, size, size);
    columnX += size + space;
  }
}

//creates the circular row selectors
void rowSelectors() {

  int rowX = (cornerX) - (size/2) - space;
  int rowY = (cornerY) + (size/2) + (space/2);
  noFill(); 

  for ( int j = 0; j<ROWS; j ++) {
    if (j == rowSelected) {
      stroke(RED);
    } else {
      stroke(167);
    }
    ellipse(rowX, rowY, size, size);
    rowY += size + space;
  }
}

//creates the score counter at the bottom of canvas
void counter() {
  float x = width/3;
  float y = 4*height/5;
  float boxLength = width/3;
  float boxHeight = height/20;
  int counter = 0;
  fill(255);
  rect(x, y, boxLength, boxHeight);
  String counterText = "Num Moves: " + counter;
  fill(0);
  textSize(40);
  text(counterText, x + (boxLength*1/14.0), y + (boxHeight*3/4.0));
}

//loads in a random target image
void targetImage() {
  float y = height/5;
  float x = width/2;
  String [] file = {"target0.png", "target1.png", "target2.png", "target3.png", "target4.png"};
  PImage target;// create a variable that can point to an off-screen buffer
  String filename = file[int(random(0, 4))]; //"target" + int(random(0,4)) + ".png";// create filename
  target = loadImage(filename);// load image file into off-screen buffer
  //image(target, x, y, width/3.125, height/2.08);// display the buffer on canvas at location x, y
}

//allows the user to select/deselect a column
int selectColumn() {
  int x;
  int xPos= mouseX - cornerX;
  x = xPos/(size+space);
  if (x == col)
    return -1;
  else
    return x;
}

//allows the user to select/deselect a row
int selectRow() {

  int y;
  int yPos= mouseY - cornerY;
  y = yPos/(size+space);
  if (y == row)
    return -1;
  else
    return y;
}

//mouse click functions for selecting cells/rows/columns/colour
void mouseClicked() {
  //user is clicking inside the grid
  if (mouseX > cornerX && mouseY > cornerY && mouseX < cornerX + COLUMNS*BLOCK_SIZE 
    && mouseY < cornerY + ROWS*BLOCK_SIZE) {
    //cell = cellSelected();
    square_selected.x = floor((mouseX - cornerX)/BLOCK_SIZE);
    square_selected.y = floor((mouseY - cornerY)/BLOCK_SIZE);
  }

  //user is selectong a column
  if (mouseX > cornerX && mouseY > (cornerY - (space + size)) && mouseX < cornerX + COLUMNS*BLOCK_SIZE 
    && mouseY < cornerY) {
    if (columnSelected == selectColumn()) {
      columnSelected = -1;
    } else {
      columnSelected = selectColumn();
    }
  }

  //user is selecting a row
  if (mouseX > (cornerX - (space + size)) && mouseY > cornerY && mouseX < cornerX 
    && mouseY < cornerY + ROWS*BLOCK_SIZE) {
    if (rowSelected == selectRow()) {
      rowSelected = -1;
    } else {
      rowSelected = selectRow();
    }
  }

  //user is picking a color
  if (mouseY < blockSize) {
    //validating the color
    for (int c = 0; c < colour.length; c++) {
      if (get(mouseX, mouseY) == colour[c]) {
        //if a square has been selected
        if (square_selected.x > -1) {
          square_color[(int)square_selected.x][(int)square_selected.y] = colour[c];
          square_selected = new PVector(-1,-1);
        }

        //if a row has been selected
        if (rowSelected > -1) {          
          for (int i = 0; i < COLUMNS; i++) {
            square_color[i][rowSelected] = colour[c];
          }
          rowSelected = -1;
        }

        //if a column has been selected
        if (columnSelected > -1) {          
          for (int i = 0; i < ROWS; i++) {
            square_color[columnSelected][i] = colour[c];
          }
          columnSelected = -1;
        }
        break;
      }
    }    
  }
}

The trick is to keep everything tidy and to avoid unexpected changes. To realize this, some good working habits helps a lot. Habits like:

  • Commenting the code
  • Splitting tasks into well named functions (remember, smaller functions are better because they are more human-friendly!)
  • Keeping variables tidy
  • Good code formatting

So, you'll see it in the code, but basically I'm just adding a couple variables which will track the squares' colors, and which cell or row/column is currently selected. I also tweaked the functions which draws your objects so the colors are depending on attributes (in the variables I just mentioned) and not just something the program draws once when it happens - so a new iteration of the loop isn't going to erase them. Oh, and I erased functions which weren't necessary anymore because of these changes.

As with last time, I'll stick around, so don't hesitate to ask questions about anything which don't stick or that you don't get. And have fun!

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Fill all cells of grid with selected color using vanilla JS

How to change the color of selected row in ag grid?

How to fill selected cells in 3D Matplotlib?

In ag-grid how do I make the active row color change to the selected row when the keyboard is used to navigate cells

How to effectively use a map to generate a config based on selected cells in a grid?

How to get Kendo Dropdown selected should fill Kendo grid

Vaadin grid selected row color

How can I change the background color if cells are selected?

How to set cell color in Vaadin 8 Grid only if row is not selected

(ag-Grid)How to put the background color to multiple selected rows

How to change color of selected row in kendo grid in angular

Retrieving selected cells on a given grid using Python

Kendo grid change multiple selected cells value

Changing the fill color of a selected area using ImageMapster

Vaadin set background color for selected row in a grid

How to calculate the color of the selected color in a color palette?

How to change the color of selected columns?

How to change the color of the image that is selected?

How to custom color selected cell?

How can I change the fill color or hide other continent which is not selected onRegionClick in jvectormap

How to make selected color the background color in listview

How to compare cells of one column for selected rows?

How to selected a range cells with mouse in react?

How to extract a list of selected cells into a CSV file

How to add and remove a FontStyle to selected cells of a DataGridView

How to clear contents of selected cells in JTable?

In asp.net MVC Telerik grid, How to change background color of selected row

How to fill input file if I selected something

How to fill object with the selected value of dropdown in Vue