I'm making a singleplayer Battleship game in Processing 3.
To generate the playing field, I create a two-dimensional array that holds a boolean value for whether the grid cell has been clicked. To generate this array, I use to following function:
boolean[][] clicked = {};
void initArray(int gridSize) {
boolean[] row = {};
for (int i = 0; i < gridSize; i++) row = (boolean[]) append(row, false);
for (int i = 0; i < gridSize; i++) clicked = (boolean[][]) append(clicked, row);
}
The issue I'm having is that whenever I try to change one cell's value to true, all the values in that row become true as well. This is the code I use to change and print the array:
void setup() {
initArray(3);
clicked[2][1] = true;
println(clicked[0]);
println(clicked[1]);
println(clicked[2]);
}
I only want to change the second value of the third row, but instead it changes the second value of every row. Here is the output:
[0] false
[1] true
[2] false
[0] false
[1] true
[2] false
[0] false
[1] true
[2] false
I'm not allowed to use OOP for this assignment.
Thanks in advance.
You create only one row object and you append this object to each row. At the end each row refers to the same row object. So it seems to be that changing the element of one row affects the other rows too.
Create a sparte row object for each row of the grid, to solve your issue:
boolean[][] clicked = {};
void initArray(int gridSize) {
for (int i = 0; i < gridSize; i++) {
boolean[] row = {}; // <--- new object for each row
for (int j = 0; j < gridSize; j++)
row = (boolean[]) append(row, false);
clicked = (boolean[][]) append(clicked, row);
}
}
Related
So, I am building a method to check a 2d array for a target value and replace each adjacent element with that target value. I have literally tried to brainstorm the solution to this for about an hour and I just want to know if anyone can help me with this, this is the code I have so far
public int[][] replaceValue(int n, int[][]y){
int [][]temp0 = new int[y.length][y[0].length];
int[]top, down ,left, right = new int[y[0].length];
for(int row = 0; row < y.length; row++){
for(int col = 0; col < y[row].length; col++){
temp0[row][col] = y[row][col];// new array so I wouldn't mess with the array passed in
}
}
for(int row = 0; row < temp0.length; row++){
for(int col = 0; col < temp0[row].length; col++){
top[row] = temp0[row-1][col];
down[row] = temp0[row+1][col];
right[row] = temp0[row][col+1];
left[row] = temp0[row] [col-1];
}
}
I got error messages such as I didn't initialize my top and left and right and down variables but I simply don't understand how the logic works for checking the adjacent elements and making sure the whole array is not replaced with the target value. Thanks
The question is a little confusing so I will try to interpret it.
What you are given is a 2-dimensional array with some integer values. Your function should scan the 2-d array, and if you find some target value,
return a 2-d array with the adjacent indices as the target value as well.
For example, if we have a 3x3 array and the target is 2...
1 1 1 1 2 1
1 2 1 ====> 2 2 2
1 1 1 1 2 1
Your problem is that you can't think of a way to change the value without changing the entire array to 2.
Solution One: You scan for the target value in the given array, but you update the values in the temporary array.
Solution Two: You scan the temporary array, and store whether or not it should be changed using a 2-d boolean array.
Solution One is much better in terms of efficiency (both memory and time), so I'll just give you my solution #2, and leave you to do Solution One on your own.
Also, please use more descriptive variable names when it matters :P (why is the input called temp??)
public static int[][] replaceValue(int target, int[][] currArray){
int[][] temp = new int[currArray.length][];
//get a boolean array of same size
//NOTE: it is initialized as false
boolean[][] needsChange = new boolean[currArray.length][currArray[0].length];
//copy the current array into temp
for(int i = 0; i < currArray.length; i++){
temp[i] = currArray[i].clone();
}
//Go through each value in the 2d array
for(int i = 0; i < temp.length; i++){
for(int j = 0; j < temp[0].length; j++){
//if it is the target value, mark it to be changed
if(temp[i][j] == target){
needsChange[i][j] = true;
}
}
}
//Go through each value in the 2d array
for(int i = 0; i < temp.length; i++){
for(int j = 0; j < temp[0].length; j++){
if(needsChange[i][j]){ //NOTE: same as "needsChange[i][j] = true;"
//Now, we will check to make sure we don't go out of bounds
//Top
if(i > 0){
temp[i-1][j] = target;
}
//Bottom
if(i + 1 < temp.length){
temp[i+1][j] = target;
}
//Left
if(j > 0){
temp[i][j-1] = target;
}
//Right
if(j + 1 < temp[0].length){
temp[i][j+1] = target;
}
}
}
}
//return the new array we made
return temp;
}
You have not initialized your local variables before first use. So you need to change your 3rd line to some thing like the below code:
int[] top = new int[temp[0].length], down = new int[temp[0].length],
left = new int[temp[0].length], right = new int[temp[0].length];
After that your code is compiled and you can check your logic.
I'm currently trying to figure out how to add values into a full 2d array. Any help would be appreciated.
This is what i currently have.
public static ObjectA[][] addValue(ObjectA value, ObjectA[][] oldArray)
{
//Creates a new array with an extra row
ObjectA[][] newArray = new ObjectA[oldArray.length +1][oldArray[0].length]
for (int i= 0 ; i < newArray.length; i++)
{
for (int ii = 0; ii <= newArray[0].length; ii++)
{
// when the index exceeds the oldArray
// it will add the value to the newArray
if (i <= oldArray.length)
{
newArray[i][ii] = oldArray[i][ii];//copies all values into newArray
}
else
{
newArray[i][ii] = value; //adds value to the last row
}
}
}
return newArray;
}
What I currently have done is input a value to the new row however the method is going to be called multiple times to add more than one value. Which mean it's going to create multiple rows rather than adding to the next available column.
EDIT:
mistyped the data type the array and value are suppoed to be objects.
First, your code throws an IndexOutOfBoundsException. Here is why:
Consider the if (i <= oldArray.length) clause. Say, oldArray.length is 3. When i = 3, newArray[i][ii] = oldArray[i][ii] line seeks the oldArray[3][ii] elements but there are no such elements. All the possible elements of oldArray is oldArray[0][ii], oldArray[1][ii] and oldArray[2][ii], since counting starts with 0 in programming.
Second, I didn't get the point of adding another row for each next value. If you're not going to add a set of values to each row, then, why do you consider expanding number of rows?
This is a typical situation when you need to make a tradeoff between element access complexity and complexity of adding new column
If you need fast column adding without new structure allocation you should use LinkedList as a storage of rows and call list.add(row) every time you need to add a new column so your code will look like:
public static void addValue(int value, LinkedList<int[]> list) {
int[] row_you_need_to_add = new int[list.get(0).length];
for (int i = 0; i < list.get(0).length; i++) {
row_you_need_to_add[i] = value;
}
list.add(row_you_need_to_add);
}
As 2D Array is an Array which consist of an array within an Array. So at every index of 2D array there is another array is present and has a specific size.
public static ObjectA[][] addValue(ObjectA value, ObjectA[][] oldArray) {
ObjectA[][] newArray = new ObjectA[oldArray.length +1][oldArray[0].length]
for (int i= 0 ; i < newArray.length; i++) {
for (int ii = 0; ii <= newArray[0].length; ii++) {
// when the index exceeds the oldArray
// it will add the value to the newArray
if (i <= oldArray.length) {
newArray[i][ii] = oldArray[i][ii];//copies all values into newArray
} else {
newArray[i][ii] = value; //adds value to the last row
}
}
}
return newArray;
}
I want to write a board game using LibGDX and during a game I want make it possible to add or remove rows / columns on that board. First, I made some tests to prepare myself to that. Here is the code :
public class Test extends Game {
Skin skin;
Stage stage;
Texture texture1;
static int columns = 7;
static int rows = 12;
Window window2;
Table table2;
ArrayList<ArrayList<TextButton>> buttons;
#Override
public void create () {
skin = new Skin(Gdx.files.internal("data/uiskin.json"));
buttons = new ArrayList<ArrayList<TextButton>>();
for(int i = 0 ; i< rows; ++i)
{
buttons.add(new ArrayList<TextButton>());
for( int k = 0; k < columns; ++k)
{
buttons.get(i).add(new TextButton(("ASD" + i + k), skin));
}
}
texture1 = new Texture(Gdx.files.internal("data/badlogicsmall.jpg"));
TextureRegion image = new TextureRegion(texture1);
stage = new Stage(new ScreenViewport());
Gdx.input.setInputProcessor(stage);
ImageButtonStyle style = new ImageButtonStyle(skin.get(ButtonStyle.class));
style.imageUp = new TextureRegionDrawable(image);
ImageButton iconButton = new ImageButton(style);
window2 = new Window("Dialog2", skin);
window2.getTitleTable().add(new TextButton("X", skin)).height(window2.getPadTop());
window2.setSize(300, 400);
table2 = new Table();
for(int i = 0 ; i< rows; ++i)
{
for( int k = 0; k < columns; ++k)
{
table2.add(buttons.get(i).get(k));
}
table2.row();
}
ScrollPane pane= new ScrollPane(table2,skin);
pane.setScrollbarsOnTop(false);
pane.setFadeScrollBars(false);
window2.add(iconButton).row();
window2.add(pane);
stage.addActor(window2);
iconButton.addListener(new ChangeListener() {
public void changed (ChangeEvent event, Actor actor) {
new Dialog("Some Dialog", skin, "dialog") {
protected void result (Object object) {
System.out.println("Chosen: " + object);
if((Boolean) object )
{
for(int i = 0 ; i <columns; ++i){
table2.getCells().removeIndex(0).getActor().remove();}
}
}
}.text("Are you enjoying this demo?").button("Yes", true).button("No", false).key(Keys.ENTER, true)
.key(Keys.ESCAPE, false).show(stage);
}
});
}
#Override
public void render () {
Gdx.gl.glClearColor(0.2f, 0.2f, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(Math.min(Gdx.graphics.getDeltaTime(), 1 / 30f));
stage.draw();
}
As you can see here, I'm creating a standalone button and a table and fill it with buttons. Then after button clicked I want to remove first row of that table and also move rest of rows up. It works but only once (for first row), then (with second click) I got this exception :
Exception in thread "LWJGL Application" java.lang.IndexOutOfBoundsException: index can't be >= size: 70 >= 70
Don't know what to do and how to fix it. Hope you can help me with this.
UPDATE
Thanks for reply; my code looks like this now :
// initialization
for(int i = 0 ; i< rows; ++i)
{
for( int k = 0; k < columns; ++k)
{
table2.add(new TextButton(("ASD" + i + k), skin));
}
table2.row();
}
// sample operation - remove left column
for(int i = 0 ; i <rows; ++i){
table2.removeActor( table2.getChildren().get(i*columns-i) );
}
columns--;
Also, I got similar Array in logical model and want to change state of UI table based on that array. So is this approach correct or should I change something?
The issue is about row() you are using - before the first row there is no row cell (marked with row() method) and that's why it does not cause error but when removing the second one it does.
Compare with table2 without any rows to test it:
for(int i = 0 ; i< rows; ++i)
{
for( int k = 0; k < columns; ++k)
{
table2.add(buttons.get(i).get(k));
}
//table2.row(); - we don't want any rows!
}
Ok we know where problem lays but it is not the solution (ok maybe some solution it is:) ). Instead of hard removing indexes of Table cells you should operate on Actors of table using following code:
for(int i = 0 ; i <columns; ++i){
table2.removeActor( table2.getChildren().first() );
}
Working with a table in such a way is a bit cumbersome, at least I don't know better. A quick fix for your code would be:
// Global field
int removedRows = 0;
// In your listener
System.out.println("Chosen: " + object);
if ((Boolean) object)
{
for (int i = 0; i < columns; ++i)
{
table2.getCells().get(i + columns * removedRows).clearActor();
}
removedRows++;
}
But if you want to remove complete rows, I would use a VerticalGroup and add each row there, so you can directly access a row and remove it from the VerticalGroup. If you use a fixed size for the buttons then it will align properly, too.
table2.getCells()
Returns an Array, this means we now operate on that Array and NOT the table2 anymore!
This means if you execute this:
table2.getCells().removeIndex(0);
It will just remove that cell from the array. This does NOT update the table2 as a complete object, just the cells array of that table (since no copy of that array is returned)
In other words you are doing this:
Array<Cell> table2Cells = table2.getCells();
Cell tableCell = table2Cells.removeIndex(0);
tableCell.clearActor();
So you delete the cell from the table2 cell array, and then you clear the cells contents (actor in this case). But you are not updating the table to reflect the changes of the removed cell, table2 still "thinks" that the cell is there, but you deleted it.
Thus you get the index error, because the stage draws the table, and the table wants to draw a cell that no longer exists.
So if you want to create some kind of board for a game the best way would be to code your own class that provides the functionality you desire.
A workaround would be that you reset the table and fill it again:
int table2Rows = table2.getRows();
table2.reset();
// Omit the first row
for (int i = rows - table2Rows + 1; i < rows; ++i)
{
for (int k = 0; k < columns; ++k)
{
table2.add(buttons.get(i).get(k));
}
table2.row();
}
table2.layout();
Thus the first cell will contain the first button and so on, since the table internal values are properly updated.
public boolean searchSummaryData(String textToFind) {
int fromRow, fromCol;
fromRow = summaryTable.getSelectedRow();
fromCol = summaryTable.getSelectedColumn();
if (fromRow < 0) {
fromRow = 0; //set to start point, first row
}
if (fromCol < 0) {
fromCol = 0;
} else {
fromCol++;//incremental search - look through each columns, then switch to next row
if (fromCol >= summaryTable.getColumnCount()) {
fromCol = 0;
fromRow++;
}
}
for (int i = fromRow; i < summaryTableModel.getRowCount(); i++) {
for (int j = fromCol; j < summaryTableModel.getColumnCount(); j++) {
final Object valueAt = summaryTableModel.getValueAt(i, j); //point to object at i,j
if (valueAt != null) {
textToFind = textToFind.toLowerCase();
if (valueAt.toString().toLowerCase().contains(textToFind)) {
//Map the index of the column/row in the table model at j/i to the index of the column/row in the view.
int convertRowIndexToView = summaryTable.convertRowIndexToView(i);
int convertColIndexToView = summaryTable.convertColumnIndexToView(j);
summaryTable.setRowSelectionInterval(i, i);
summaryTable.setColumnSelectionInterval(j, j);
//Return a rectangle for the cell that lies at the intersection of row and column.
Rectangle rectToScrollTo = summaryTable.getCellRect(convertRowIndexToView, convertColIndexToView, true);
tableSp.getViewport().scrollRectToVisible(rectToScrollTo);
return true;
}
}
}
}
return false;
}
I am having a problem with my search method above. The way I did it, It only allows me to search a particular matched keyword once. While being in the same GUIscreen, if I do a second search, even if a keyword is matched, no result is found. I am pretty sure the last searched index is kept and not reset is the problem, but Im unsure where and how to change this.
You are setting the fromRow and fromCol vars to be the selected row and column. And then you are changing the selection to be where the first result is found. If the second search would have only found things to the left or above the current selection, it won't find anything.
Why don't you just set fromRow and fromCol to be 0, 0 in the first place?
Let's say you have a table of 10 row with 5 columns.
There are matches in:
2, 2
4, 1
9, 0
First time you will find 2, 2.
So next time you start in row 2 and column 3. Your algorithm will only look for values in
column 3 and 4 (4 is the last column of your table).
What you should have is:
first look from cell 2, 3 until cell 2, 4
Then use your loops to start from row 3 and column 0 and increment columns--> no match on row 3
Then increment row to 4 and reset column to 0. As you increment column to 1, you will then find your second match.
etc...
I have not tested yet, but I think that in your inner-loop, you should initiate the increment like this
int j = fromCol
should be replaced by
int j = (i == fromRow ? fromCol : 0);
Hey I'm having trouble getting my code to compare the integers of a given row or column and block to make sure there are no duplicates within those parameters. I don't know if it would be a good idea separating the three contraints in 3 different methods or just trying to attempt to do all at once.
public static rowCheck(int[][] nsudokuBoard) {
for (int i =0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
// (nsudokuBoard)
}
}
}
this is my code im starting. before you guys bash on me for not even being able to compile this im stuck on how to compare all the values of a row of the 2d array.
You can compare all the values of the 2d array as shown in the code below:
void validate(final int[][] nsudokuBoard) {
final int width = nsudokuBoard[0].length;
final int depth = nsudokuBoard.length;
for (int i = 0; i < width; i++) {
int j = i;
int reference = nsudokuBoard[i][j];
do {
if (j < width) {
int current = nsudokuBoard[i][j];
if (current == reference) {
// invalid entry found do something
}
}
if (j < depth) {
// note reversed indexes
int current = nsudokuBoard[j][i];
if (current == reference) {
// invalid entry found do something
}
}
++j;
} while ((j >= width) || (j >= depth));
}
}
I haven't tried to compile this code, but it should give you an idea of how to accomplish your task. I would suggest that rather than passing in int[][] sudokuBoard that you should define a class which encapsulates the concept of a SudokuSquare and pass in SudokuSquare[][] , that way your validate method can return a List<SudokuSquare> containing all the offending entries.
I'll show how you might do it for one row, and then you can figure out the rest. I'm assuming your values are 1 through 9 inclusive, and that you don't have any zeroes or any "unfilled entries."
boolean isRowValid(int[][] grid, int row) {
boolean[] seen = new boolean[9];
int row; // chosen somewhere else
for (int col = 0; col < 9; col++) {
if (seen[grid[row][col] - 1]) { // if we've seen this value before in this row
return false; // there is a duplicate, and this is a bad sudoku
}
seen[grid[row][col] - 1] = true; // mark us as having seen this element
}
return true; // we're all good
}
return true; // this row is fine
make a class Cell with fields row,col,block,value; then make a class Matrix with field cells = cell[], fill matrix.
make a class checker with main method Matrix matrix = init(int[][]) and check(matrix), where init(ยท) fills the matrix.
boolean ok = check(matrix) where check(Matrix) does if(!rowcheck())return false; if(!colcheck()) return false etc;
create some methods like getrows(), getrow(r) and for(Cell cell: matrix.values()) to filter out the ones you want.
a bit tedious but i have done it and it is solid as rock.
As a note, filtering over matrix may seem stupid but computers are fast and the problem is O(1) since it is 9x9.