I'm creating a minesweeper game and I really need a fast and Efficient way of calculating the neighbors of a mine, Actually im storing my tiles in an Arraylist so I can use them in a gridview, so the position is lineal but the rendering will be a matrix n*n. I have a way to do it but I think someone can have a more efficient way.
What I want to achieve:
0 1 1 1
0 1 * 1
0 1 1 1
0 0 0 0
So given that matrix having the indexes in a lineal List the position should be the following:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
So I need an efficient way of obtaining 2, 3, 4, 6, 8, 10, 11, 12 giving the index 7.
Code to generate bombs:
public void plantMines(){
Random rand = new Random();
//Used set so we dont get duplicates
Set<Integer> mineCoords = new LinkedHashSet<>(mDifficulty.mines);
//First we randomly select all coordenates
while (mineCoords.size() < mDifficulty.mines){
Integer coord = rand.nextInt(mListCap) + 1;
mineCoords.add(coord);
}
//Now we can set the mines accordingly
for (Integer coord: mineCoords){
mTiles.get(coord).setMine(true);
}
}
Actual code to find neighbors:
for (int row = 0; row < ROW_SIZE; row++) {
for (int col = 0; col < COL_SIZE; col++) {
int neighbourBombSize = 0;
// TOP ROW
if ((row-1) >= 0 && (col-1) >= 0) {
if (getTile(row-1, col-1).hasBomb()) {
neighbourBombSize++;
}
}
if ((row-1) >= 0) {
if (getTile(row-1, col).hasBomb()) {
neighbourBombSize++;
}
}
if ((row-1) >= 0 && (col+1) < COL_SIZE) {
if (getTile(row-1, col+1).hasBomb()) {
neighbourBombSize++;
}
}
// SAME ROW
if ((col-1) >= 0) {
if (getTile(row, col-1).hasBomb()) {
neighbourBombSize++;
}
}
if ((col+1) < COL_SIZE) {
if (getTile(row, col+1).hasBomb()) {
neighbourBombSize++;
}
}
// BOTTOM ROW
if ((row+1) < ROW_SIZE && (col-1) >= 0) {
if (getTile(row+1, col-1).hasBomb()) {
neighbourBombSize++;
}
}
if ((row+1) < ROW_SIZE) {
if (getTile(row+1, col).hasBomb()) {
neighbourBombSize++;
}
}
if ((row+1) < ROW_SIZE && (col+1) < COL_SIZE) {
if (getTile(row+1, col+1).hasBomb()) {
neighbourBombSize++;
}
}
getTile(row, col).setNeighbourBombSize(neighbourBombSize);
}
}
Help will be appreciated, thanks.
WARNING : I've take your code as starting point, but your index start a 1, but in java array index start at 0, so it may not work.
I would do something like that :
int neighbourBombSize = 0;
// Compute currentCell row / col
int currentCellCol = ((currentCellIndex - 1) % COL_SIZE) + 1;
int currentCellRow = ((currentCellIndex - 1) / COL_SIZE) + 1;
System.out.println("Neighbors of " + currentCellIndex + " (" + currentCellRow + ", " + currentCellCol + ")");
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
if (x == 0 && y == 0) {
continue; // Current cell index
}
int neighborCol = currentCellCol + y;
int neighborRow = currentCellRow + x;
if (neighborCol > 0 && neighborRow > 0 && neighborCol <= COL_SIZE && neighborRow <= ROW_SIZE ) {
int computedNeighborIndex = neighborCol + ((neighborRow - 1) * COL_SIZE);
if (getTile(neighborRow , neighborCol ).hasBomb()) {
neighbourBombSize++;
}
}
}
}
You can see a running example (computing neighbors index for all case) here : Running example
Are you planning to write the whole game referring to cells using this 1-based linear index? If so, you will want to isolate the conversion to and from coordinates. Otherwise you will eventually mess up somewhere.
Try something like this:
class Board {
final int rows;
final int cols;
Board(int cols, int rows) {
this.rows = rows;
this.cols = cols;
}
int col(int index) {
assert index > 0 && index <= rows * cols;
return (index - 1) % cols; // -1 because you are using 1-based indexing.
}
int row(int index) {
assert index > 0 && index <= rows * cols;
return (index - 1) / cols;
}
int index(int x, int y) {
assert x >= 0 && x < cols && y >= 0 && y < rows;
return y * cols + x + 1;
}
int[] neighbors(int point) {
int x = col(point);
int y = row(point);
int[] result = new int[8];
int cnt = 0;
// go over possible neighbors and collect valid ones
for (int ny = max(y - 1, 0); ny < min(y + 2, rows); ny++) {
for (int nx = max(x - 1, 0); nx < min(x + 2, cols); nx++) {
if (nx != x || ny != y) {
result[cnt++] = index(nx, ny);
}
}
}
return Arrays.copyOf(result, cnt);
}
}
Board brd = new Board(4, 4);
int colOf7 = brd.col(7); // 2 (0-based from left)
int rowOf7 = brd.row(7); // 1 (0-based from top)
int[] neighborsOf7 = brd.neighbors(7); // [2, 3, 4, 6, 8, 10, 11, 12]
int index = brd.index(2,1); // 7 (1-based linear index)
Related
I have this number generator, which generates me a 2d matrix with random values. The values in column 4 and 5 are either 1, 3, 7 or 20. But when column 4 is a 1, column 5 should be either 3, 7 or 20 (they should never have the same values).
I tried it with the double x and double y declaration under the second for-loop, but that doesn't work. So in my next try, I would try it with a do-while-loop, but I don't know, how to implement that loop in my code.
public class HelloWorld{
public static void main(String[] args) {
Number[][] values = new Number[10][26];
for (int i = 0; i < values.length; i++) {
for (int j = 0; j < values[i].length; j++) {
double x = Math.random();
double y = x < 0.25 ? 1 : x < 0.5 ? 0.74 : x < 0.75 ? 0.49 : 0.01;
if (j == 0) {
values[i][j] = Math.random() < 0.5 ? 0 : 1;
} else if (j == 1) {
values[i][j] = (int)Math.floor(((Math.random() * (250000000 - 500000)) + 500000));
} else if (j == 2) {
values[i][j] = (int)(Math.random() * (23)) + 1;
} else if (j == 3) {
values[i][j] = x < 0.25 ? 1 : x < 0.5 ? 3 : x < 0.75 ? 7 : 20;
} else if (j == 4) {
values[i][j] = y < 0.25 ? 1 : y < 0.5 ? 3 : y < 0.75 ? 7 : 20;
} else {
values[i][j] = Math.floor(Math.random() * 100000) / 100000;
}
System.out.print(values[i][j] + " ; ");
}
System.out.println();
}
}
}
There are probably many different ways of achieving the same result. The solution I came up with looks like so:
Declare a list of all possible ints for a given row - outside of the inner loop
For columns 3 or 4 get a random index from range 0 - sizeOfList
Take element with that index from the List and assign to your matrix
Remove element with that index from the List so it isn't reused later on
Note that I used Random.nextInt(sizeOfList) here, it's just cleaner than Math.random().
public class MyClass {
public static void main(String[] args) {
Number[][] values = new Number[10][26];
Random r = new Random();
for (int i = 0; i < values.length; i++) {
List<Integer> possibleInts = new ArrayList<Integer>(Arrays.asList(1, 3, 7, 20));
for (int j = 0; j < values[i].length; j++) {
if (j == 0) {
values[i][j] = Math.random() < 0.5 ? 0 : 1;
} else if (j == 1) {
values[i][j] = (int)Math.floor(((Math.random() * (250000000 - 500000)) + 500000));
} else if (j == 2) {
values[i][j] = (int)(Math.random() * (23)) + 1;
} else if (j == 3) {
int index = r.nextInt(possibleInts.size());
values[i][j] = possibleInts.get(index);
possibleInts.remove(index);
} else if (j == 4) {
int index = r.nextInt(possibleInts.size());
values[i][j] = possibleInts.get(index);
possibleInts.remove(index);
} else {
values[i][j] = Math.floor(Math.random() * 100000) / 100000;
}
System.out.print(values[i][j] + " ; ");
}
System.out.println();
}
}
}
I am trying to find the expected output to the below program..But I am getting the error
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at programbasics.CountingConnections.count(CountingConnections.java:7)
at programbasics.CountingConnections.main(CountingConnections.java:26)
My question is about a matrix m*n. The elements in matrix are populated with values 1 and 0.
1 indicates in establishing connection and 0 indicates Not establishing connection.
we need to connect the available adjacent positions vertically, horizontally and diagonally and count the number of distinct connections established
My piece of code is
package programbasics;
class CountingConnections
{
static int count(int a[][], int i, int j) {
int rows = a.length;
int cols = a[0].length;
if(a[i][j] == 0) return 0;
if (i == rows - 1 && j == cols - 1)
return a[i][j];
else if (i == rows - 1)
return a[i][j + 1];
else if (j == cols - 1)
return a[i + 1][j];
else if (a[i][j] == 1)
return count(a, i + 1, j) + count(a, i, j + 1);
else
return 0;
}
public static void main(String[]args)
{
int a[][] = {{1,0,0,1},
{0,1,1,1},
{1,0,0,1}};
int i = 3;
int j = 4;
System.out.println(count(a, i, j));;
}
}
The expected output is 8. Like the positions are connected as follows
1)(0,0) -> (1,1)
2)(2,0) -> (1,1)
.
.
.
.
8) (0,3) -> (1,3)
It fails to get the expected output 8.
public static int count(int[][] a) {
int[][] paths = new int[a.length][a[0].length];
if ((paths[0][0] = a[0][0]) == 0) {
return 0;
}
for (int c = 1; c < a[0].length; c++) {
paths[0][c] = a[0][c] * paths[0][c - 1];
}
for (int r = 1; r < a.length; r++)
{
paths[r][0] = a[r][0] * paths[r - 1][0];
for (int c = 1; c < a[r].length; c++)
{
paths[r][c] = a[r][c] * (paths[r - 1][c] + paths[r][c - 1]);
}
}
return paths[a.length - 1][a[0].length - 1];
}
public static int count(int[][] a, int m, int n) {
int count = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (a[i][j] == 1) {
if (i - 1 >= 0 && j - 1 >= 0 && a[i - 1][j - 1] == 1) {
count = count + 1;
}
if (i - 1 >= 0 && a[i - 1][j] == 1) {
count = count + 1;
}
if (i - 1 >= 0 && j + 1 < n && a[i - 1][j + 1] == 1) {
count = count + 1;
}
if (j + 1 < n && a[i][j + 1] == 1) {
count = count + 1;
}
}
}
}
return count;
}
You call if(a[i][j] == 0) in your code where you pass 3 as i and 4 as j. However Array's are zero indexed, so when you try to call a[3][4] you are trying to call
0 1 2 3 4
0 {1, 0, 0, 1}
1 {0, 1, 1, 1}
2 {1, 0, 0, 1}
3 X
4
The index where the X is. Clearly this is not a valid index in your Array.
Also your method at different points calls a[i + 1][j] and a[i][j + 1] which means that you will have to take this in account when making sure the code stays in bounds.
As to your actual method your logic seems a bit off. if(a[i][j] == 0) return 0; will return 0 and stop the recursion and return 0 without checking to see if there are any more connections. Your logic should be something more like this:
Start at 0,1.
If the index is a 1
Look one index to the right, one down and to the right (The diagonal) down one, and down one and to the left (The second diagonal).
If any of the numbers at those index's are 1's then up the counter.
Continue to iterate through the matrix, but keep in mind that you are checking one row down and over, so you will only loop until less than length -1 for for both the row and column. Also make sure that you are starting at index a[i][1] as you will be needing to check a[a+1][j-1] and if j == 0 you will be trying to call a[a+1][-1] which will cause another index out of bounds
private int countConnections(int[][] a, int rows, int columns) {
//cartesian plane coordinates around a point
final int[] x = {1, 1, 1, -1, -1, -1, 0, 0};
final int[] y = {1, -1, 0, 1, -1, 0, 1, -1};
int count = 0;
boolean[][] visited = new boolean[rows][columns];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
for (int k = 0; k < 8; k++) {
int l = i + x[k];
int m = j + y[k];
//check for connections only if the given cell has value 1
if (a[i][j] == 1 && canVisit(l, m, rows, columns, visited) && a[l][m] == 1) {
count++;
}
}
visited[i][j] = true;
}
}
return count;
}
private boolean canVisit(int i, int j, int rows, int columns, boolean [][] visited) {
return i < rows && j < columns && i >= 0 && j >= 0 && !visited[i][j];
}
Check all the 8 cells around a cell whose cell value is 1 and when traversed mark it as visited.
I'm working on a coding question and I'm given an array for example something like this: [1, 7, 3, 21, 13, 19]
I'm suppose to pair up items in the array. Then after that I'm suppose to apply this simple rule.
Say I choose a pair x and y:
Rule:
if x > y : y = 2*y and x = x - y
if y > x : x = 2*x and y = y - x
if x == y : break # x and y is a pair that does not cause an infinite loop
Example:
Say x = 7 and y = 3
1st round : x = 7 and y = 3
2nd round : x = 4 and y = 6
3rd round : x = 8 and y = 2
4th round : x = 6 and y = 4
at this point you know that this pair will loop forever
If for example x = 1 and y = 3
1st round : x = 1 and y = 3
2nd round : x = 2 and y = 2
At this point you know that this pair doesn't loop
So in order to solve this problem. I saw it as some kind of TSP but instead of minimizing path, I'm maximizing path.
So first step I did is create a graph of nodes and label whether a pair is a loop or not
In this array the graph generated (adjacency matrix) is this:
0 0 0 1 1 1
0 0 1 0 1 1
0 1 0 0 0 1
1 0 0 0 1 1
1 1 0 1 0 0
1 1 1 1 0 0
the index in the graph represent index in the array. For example let's say that i is row and j is column. If you look at i=0, j=2 that represents array[i] = x, array[j] = y which is array[0] = x = 1, array[2] = y = 3. From the above example we know that that is not a loop. Therefore there is a 0 weight on that index.
Then I do a nearest neighbor TSP algorithm (modified to be max route) in order to get the max pair that maximized the amount of loop pairs. This method passes the coding test cases except for one. I can't identify an array of integers that would fail my code. And the test cases on the coding challenge does not give me any info on what test it is failing on.
Here is my code:
import java.util.HashMap;
public class DistractTheGuards {
private static boolean IsPairLoop(int first, int second)
{
long result = first + second;
boolean success = true;
while ((result & 1) == 0)
{
if (first == second)
{
success = false;
break;
}
else if (first > second)
{
first = (first - second) / 2;
}
else
{
second = (second - first) / 2;
}
result = first + second;
}
return success;
}
public static void GenWeights(int[][] graph, int[] banana_list)
{
for (int i = 0; i < graph.length; ++i)
{
for (int j = 0; j < graph.length; ++j)
{
if (IsPairLoop(banana_list[i], banana_list[j]))
{
graph[i][j] = 1;
}
else
{
graph[i][j] = 0;
}
}
}
}
private static boolean AreAllNodesVisited(boolean[] visited)
{
boolean all_visited = true;
for (int i = 0; i < visited.length; ++i)
{
all_visited &= visited[i];
if (!all_visited)
break;
}
return all_visited;
}
private static int FindMaxTourKey(HashMap<Integer, int[]> tours)
{
int cur_max_r = -1;
for (Integer rank : tours.keySet())
{
if (cur_max_r < rank)
cur_max_r = rank;
}
return cur_max_r;
}
private static int GetN(int[][] graph, int[] max_tour, int n)
{
for (int i = 0; i < max_tour.length; i += 2)
{
if (i + 1 >= max_tour.length)
break;
if (graph[max_tour[i]][max_tour[i+1]] == 0)
{
n -= 2;
}
}
return n;
}
public static int answer(int[] banana_list)
{
int n = banana_list.length;
if (n < 1)
return 0;
if (n == 1)
return 1;
int[][] graph = new int[n][n];
GenWeights(graph, banana_list);
HashMap<Integer, int[]> tours = new HashMap<>();
for (int i = 0; i < n; ++i)
{
int[] cur_tour = new int[n];
boolean[] visited = new boolean[n];
int start_node = i;
int cur_tour_i = 0;
while (!AreAllNodesVisited(visited))
{
int s_n = start_node;
visited[start_node] = true;
cur_tour[cur_tour_i++] = start_node;
int cur_max = 0;
for (int j = 0; j < n; ++j)
{
if (!visited[j])
{
if (cur_max < graph[start_node][j])
{
cur_max = graph[start_node][j];
start_node = j;
break;
}
}
}
if (s_n == start_node)
{
for (int x = n - 1; x >= 0; --x)
{
if (!visited[x])
{
start_node = x;
break;
}
}
}
}
int cur_tour_r = 0;
for (int x = 0; x < n; x += 2)
{
if (x + 1 >= n)
break;
cur_tour_r += graph[cur_tour[x]][cur_tour[x+1]];
}
tours.put(cur_tour_r, cur_tour.clone());
if (cur_tour_r == n - 1)
break;
}
int cur_max_r = FindMaxTourKey(tours);
if (tours.size() == 0)
return 0;
int[] max_tour = tours.get(cur_max_r);
return GetN(graph, max_tour, n);
}
}
I just need help identifying an edge case that would fail my method. Can anyone help me or give me an array that would certainly fail my method? I can take it from there. Thanks
Update
Constraints
1 <= integers <= 2^30
1 <= len(array) <= 100
I have a 3x4 matrix represented by a 2D array:
. 0 1 2 3
0 a c f i
1 b e h k
2 d g j l
and my approach to traverse the diagonal slice was to treat each slice as a sum, like this:
a = (0+0) = 0
b,c = (0+1),(1+0) = 1
d,e,f = (0+2),(1+1),(2+0) = 2
g,h,i = (1+2),(2+1),(3+0) = 3
j, k = (2+2),(3+1) = 4
l = (3+2) = 5
However, my code right now prints it in the opposite way that I want it to, which is from upper right to bottom left.
Current Output is:
acbfedihgkjl
Desired Output is:
abcdefghijkl
for (int sum = 0; sum <= numRows + numColumns - 2; sum++) {
for (int i = 0; i < numRows; i++) {
int j = sum - i;
if ((i >= 0 && i < numRows) && (j >= 0 && j < numColumns)) {
System.out.print(array[i][j]);
}
}
}
Can somebody point me in the right direction on how to fix my code to get the output that I want?
While it isn't very pretty, I think this will do it:
int i = 0;
int j = 0;
while (true) {
System.out.println("" + array[i][j]);
--i;
++j;
if (i < 0) {
if (j == numCols)
break;
i = Math.min(j, numRows - 1);
j = Math.max(j - numCols + 2, 0);
} else if (j >= numCols) {
if (i == numRows - 2)
break;
i = numRows - 1;
j = Math.max(j + 2 - numCols + i, 0);
}
}
int i = 0;
int j = 0;
int n = 0;
int x = 3;
int y = 4;
int newSize = Math.max(x,y) * Math.max(x,y);
while(n < newSize){
if(i <= x && j <= y)
System.out.println(array[i][j]);
n++;
if(i == 0) {
i = n:
j = 0;
} else {
--i;
++j;
}
}
I set up a two dimensional array, 10 by 10, and each slot is (x*y) for its respective position. I'm trying to add up all numbers in columns 3, 5, and 7 into cTotal and add up all numbers in rows 2, 4, and 6 into rTotal. My coding seems sound but I just can't seem to make it work. Any ideas?
public static void arrayMath()
{
int cTotal = 0;
int rTotal = 0;
//int tDiffValue = (rTotal - cTotal);
int twodimarr[][] = new int[10][10];
int row = 10;
int col = 10;
int x = 0;
int y = 0;
for(x = 0; x < row; x++)
{
for(y = 0; y < col; y++)
{
twodimarr[x][y] = x*y;
}
}
for(x = 0; x < row; x++)
{
for(y = 0; y < col; y++)
{
if( (x+y) < col )
{
//System.out.print( " " );
}
//System.out.print(" " + (twodimarr[x][y]));
}
//System.out.println();
}
for(x = 0; x < twodimarr.length; x++) //Problems start down here.
{
for( y= 0; y<twodimarr.length; y++)
{
if(y == 2 || y == 4 || y == 6)
{
rTotal = ((rTotal + twodimarr[x][y]));
}
}
}
System.out.println("rTotal is " + rTotal + ".");
for(x = 0; x < twodimarr.length; x++)
{
for(y = 0; y < twodimarr.length; y++)
{
if(x == 3 || x == 5 || x == 7)
{
cTotal = ((cTotal + twodimarr[x][y]));
}
}
}
System.out.print("cTotal is " + cTotal + ".");
}
x==3 isn't the third column, it's the 4th(0,1,2,3). That meaning it's the column of 3*0, 3*1, etc. and the 675/540 numbers are correct in that case.
Array indexes start at 0. To get the rows/columns you want you need to subtract 1 from the numbers you are checking. For rows 2, 4, 6 check if y == 1, 3, 5. For columns 3, 5, 7 check if x == 2, 4, 6.