I'm developing a game "Minesweeper" for Andoid on Java and I have a problem when opening the cells. How to make sure that I click on the cell opened adjacent empty cells? (How it is done in Miner for Windows).
Introduction: I have an array which i receive from bluetooth socket stream. Array like this :
1 9 1 0
1 1 1 0
0 0 0 0
0 0 0 0
9-is a mine
0-is blank cell
1-nearest mines count
After that i calculate game field
array = Model.getGameField();
int size = array.length;
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
{
((TableRow) table.getChildAt(i)).getChildAt(j).setTag(array[i][j] + "");
}
OnClick function :
if (iWantToSetFlag == 0)
{
tmpBtn = ((Button) v);
if (!(tmpBtn.getTag().equals("9")))
{
OpenButtons(tmpBtn.getId() / 10, tmpBtn.getId() % 10);
recreateTable();
}
else
startLose();
}
else
{
if (((Button) v).getText().equals("M"))
((Button) v).setText("");
else
((Button) v).setText("M");
}
I have a function
private void OpenButtons(int x, int y)
{
array[x][y] = -1;
for (int k = -1; k < 2; k++)
{
for (int k1 = 1; k1 >= -1; k1--)
{
if (x + k >= 0 && x + k < array.length && y - k1 >= 0 && y - k1 < array[x + k].length)
if (array[x + k][y - k1] == 0)
OpenButtons(x + k, y - k1);
}
}
}
which recursively open cells but i have a StackOverFlow error. Help please.
You should be calling your recursion with changed parameters:
if (array[x + k][y - k1] == 0)
OpenButtons(x + k, y - k1);
And of course, as has been mentioned in the comments of the question, you should check for the array bounds yourself instead of just ignoring the exceptions:
if (x + k >= 0 && x + k < array.length &&
y - k1 >= 0 && y - k1 < array[x + k].length) { ...
put before your other if-clause will only check fields which actually exist. Ridding you of your malicious empty try-catch.
Since the recursive algorithm will still cause a StackOverflowException for large fields, an iterative algorithm might be better suited here.
private void OpenButtons(int x, int y) {
Queue<Point> toOpen = new LinkedBlockingQueue<>();
toOpen.add(new Point(x, y));
array[x][y] = -1;
while (!toOpen.isEmpty()) {
Point p = toOpen.poll();
x = p.x;
y = p.y;
for (int k = -1; k < 2; k++) {
for (int k1 = 1; k1 >= -1; k1--) {
if (x + k >= 0 && x + k < array.length && y - k1 >= 0
&& y - k1 < array[x + k].length)
if (array[x + k][y - k1] == 0) {
array[x + k][y - k1] = -1;
toOpen.add(new Point(x + k, y - k1));
}
}
}
}
}
Related
I have an exercise where I have a 2D array in Java. I take user input, a String, that looks something like "F3 F7" and I mark the coordinates given on the array. Please see below picture.
2DArray
My problem is the fact that I need to check the neighbors of the input to make sure that future inputs do not touch (neither vertically, nor horizontally).
I found the below code in a post here, but I simply do not have the inspiration on how to implement it in order to check only for a specific set in the array.
for (i = 0; i < array.length; i++) {
for (j = 0; j < array[i].length; j++) {
for (x = Math.max(0, i - 1); x <= Math.min(i + 1, array.length); x++) {
for (y = Math.max(0, j - 1); y <= Math.min(j + 1,
array[i].length); y++) {
if (x >= 0 && y >= 0 && x < array.length
&& y < array[i].length) {
if(x!=i || y!=j){
System.out.print(array[x][y] + " ");
}
}
}
}
System.out.println("\n");
}
}
I have an issue with my math skills here. So I need to calculate the positions (x, y, z) of a specific amount of dots per aixs. For example take this image
final double gapX = lengthX / dotsPerXAxis;
final double gapY = lengthY / dotsPerYAxis;
final double gapZ = lengthZ / dotsPerZAxis;
for (BlockFace blockFace : BlockHandler.DIRECT_RELATIVES) {
final DecimalVector3D minCorner = new DecimalVector3D(
blockFace.getModX(),
blockFace.getModY(),
blockFace.getModZ()
);
for (int x = 0; x < dotsPerXAxis || x == 0; x++) {
for (int y = 0; y < dotsPerYAxis; y++) {
for (int z = 0; z < dotsPerZAxis; z++) {
}
}
}
My question now is: how can I iterate over all the dots except those that are inside the cuboid and calculate their position and put them in an ImmutableList?
You need to treat point if at least one coordinate of it is zero or dotsPerZAxis.
So set flags - if X-coordinate lies on face, if Y-coordinate lies on face. If both flags are not set - get only the first and the last Z-coordinates, otherwise walk through all Z-coordinates.
Unchecked Java:
for (int x = 0; x < dotsPerXAxis; x++) {
bool atX = (x == 0) || (x == dotsPerXAxis - 1);
for (int y = 0; y < dotsPerYAxis; y++) {
bool atY = (y == 0) || (y == dotsPerYAxis - 1);
int zstep = (atX || atY)? 1: dotsPerZAxis - 1;
for (int z = 0; z < dotsPerZAxis; z+=zstep) {
treat(x,y,z)
}
}
}
Ideone Python working code as proof-of-concept gives n^3 - (n-2)^3 points (26 surface points for n=3, 56 for n=4, 98 for n=5)
Based on the help of MBo I figured this out
for (BlockFace blockFace : BlockHandler.DIRECT_RELATIVES) {
for (int x = 0; x < dotsPerXAxis || x == 0 || x == dotsPerXAxis - 1; x++) {
for (int y = 0; y < dotsPerXAxis || y == 0 || y == dotsPerYAxis - 1; y++) {
for (int z = 0; z < dotsPerXAxis || z == 0;
z += (y == 0 || y == dotsPerYAxis - 1) || (x == 0 || x == dotsPerXAxis - 1) ? 1 :
dotsPerZAxis - 1) {
results.add(new DecimalVector3D(
x,
y,
z
));
}
}
}
}
I am implementing the matlab 'bwmorph(img, 'thin')' algorithm in Java ImageJ. I've searched all over the net pretty much and found some similar implementations that work better, but I can't find the issue in my code. Any ideas?
My code:
public void run(ImageProcessor ip) {
MakeBinary(ip);
int sum2 = processThin(ip);
int sum = -1;
while (sum2 != sum) {
sum = sum2;
sum2 = processThin(ip);
}
}
public int processThin(ImageProcessor ipOriginal) {
int sum = 0;
// first iteration
ImageProcessor ip = ipOriginal.duplicate();
for (int i = 1; i < ip.getWidth() -1; i++)
for (int j = 1; j < ip.getHeight() -1; j++) {
int[] neighbors = selectNeighbors(ip, i, j);
if (G1(neighbors) == 1 && G2(neighbors) >= 2 && G2(neighbors) <= 3 && G3(neighbors) == 0)
ip.putPixel(i,j, 0);
}
// second iteration
for (int i = 1; i < ip.getWidth() -1; i++)
for (int j = 1; j < ip.getHeight()-1; j++) {
int[] neighbors = selectNeighbors(ip, i, j);
if (G1(neighbors) == 1 && G2(neighbors) >= 2 && G2(neighbors) <= 3 && G3prime(neighbors) == 0)
ip.putPixel(i,j, 0);
}
for(int i = 0; i < ip.getWidth(); i++)
for(int j = 0; j < ip.getHeight(); j++) {
if (ip.getPixel(i,j) != 0) sum++;
ipOriginal.putPixel(i, j, ip.getPixel(i, j));
}
return sum;
}
private int G1(int[] input) {
int xh = 0;
for (int i = 1; i <= 4; i++) {
if (input[2 * i - 1] == 0 && (input[2 * i] == 1 || (2 * i + 1 <= 8 ? input[2 * i + 1] == 1 : input[1] == 1)))
xh += 1;
}
return xh;
}
private int G2(int[] input) {
int n1 = 0, n2 = 0;
n1 = toInt(toBool(input[4]) || toBool(input[3])) + toInt(toBool(input[1]) || toBool(input[2])) +
toInt(toBool(input[8]) || toBool(input[7])) + toInt(toBool(input[6]) || toBool(input[5]));
n2 = toInt(toBool(input[2]) || toBool(input[3])) + toInt(toBool(input[1]) || toBool(input[8])) +
toInt(toBool(input[6]) || toBool(input[7])) + toInt(toBool(input[4]) || toBool(input[5]));
return Math.min(n1,n2);
}
private int G3 (int[] input){
return toInt((toBool(input[2]) || toBool(input[3]) || !toBool(input[8])) && toBool(input[1]));
}
private int G3prime (int[] input){
return toInt((toBool(input[6]) || toBool(input[7]) || !toBool(input[4])) && toBool(input[5]));
}
private boolean toBool(int i ){
return i == 1;
}
private int toInt(boolean i) {
return i ? 1 : 0;
}
private int[] selectNeighbors(ImageProcessor ip, int i, int j) {
int[] result = new int[9];
result[1] = ip.getPixel(i+1,j);
result[2] = ip.getPixel(i+1,j+1);
result[3] = ip.getPixel(i,j+1);
result[4] = ip.getPixel(i-1,j+1);
result[5] = ip.getPixel(i-1,j);
result[6] = ip.getPixel(i-1,j-1);
result[7] = ip.getPixel(i,j-1);
result[8] = ip.getPixel(i+1,j-1);
for (int x = 0; x < result.length; x++)
if (result[x] != 0) result[x] = 1;
return result;
}
The main issue appears to be with the horizontal lines, but not only that.
Note: I've added the toBool and toInt methods to deal with convenient data types, the code was binary before and the result is the same apparently.
EDIT:
After editing the code and omitting doing modifications between two iterations, I ended up with this result now.
The code looks like this now.
public int processThin(ImageProcessor ip) {
int sum = 0;
// first iteration
int[][] mask = new int[ip.getWidth()][ip.getHeight()];
for (int i = 1; i < ip.getWidth() -1; i++)
for (int j = 1; j < ip.getHeight() -1; j++) {
int[] neighbors = selectNeighbors(ip, i, j);
if (G1(neighbors) == 1 && G2(neighbors) >= 2 && G2(neighbors) <= 3 && G3(neighbors) == 0)
mask[i][j]++;
}
// second iteration
for (int i = 1; i < ip.getWidth() -1; i++)
for (int j = 1; j < ip.getHeight()-1; j++) {
int[] neighbors = selectNeighbors(ip, i, j);
if (G1(neighbors) == 1 && G2(neighbors) >= 2 && G2(neighbors) <= 3 && G3prime(neighbors) == 0)
mask[i][j]++;
}
for(int i = 0; i < ip.getWidth(); i++)
for(int j = 0; j < ip.getHeight(); j++) {
if (mask[i][j] != 0) sum++;
ip.putPixel(i, j, mask[i][j] > 0 ? 0 : ip.getPixel(i,j));
}
return sum;
}
The problem in your original code is that you write into your input image. In the very first iteration, moving left to right, you remove successive pixels because each has, after modifying the previous pixel, a background pixel as neighbor.
There are different ways to implement the thinning operation, but the simplest one that works in-place like your code does requires two passes through the image for each iteration of the thinning:
Go through the image and mark all candidate pixels. These are the pixels that have a background neighbor. Marking a pixel can be as simple as setting the pixel value to a given constant, for example 42 (assuming background is 0 and foreground is 1 or 255 or whatever you decided on).
Go through the image again and for each marked pixel, determine if removing it would change the geometry of the foreground. If not, remove it. In this test, take the marked pixels that haven't been removed yet as foreground.
I have matrix each cell contain number I need to calculate the cell and its neighbor cells and come out with an average of that cells.
Look at the code that I wrote.
public Matrix imageFilterAverage() {
for (int i=0; i < _array.length;i++)
for (int j=0; i < _array[i].length;j++){
_array[i][j] = (_array[i][j] + _array[i][j+1] + _array[i+1][j] + _array[i+1][j+1]) / 4;
}
return this;
}
My code return error on index issue when j+1 reach 3 it is out of bound because the cells are 0 1 2.
So for example, if I have a matrix like this
10 5 7 3
50 3 2 1
60 2 5 2
The results matrix should be like this.
17 12 3 3
21 16 2 3
28 20 2 2
I have posted the images one matrix source and matrix results
Thank you very much for your time and help.
/**
* Takes the given array and transforms each slot in the array as an average of the slots around it.
* #return an array with each where each slot in the array is "blurred" by the slots around it.
*/
public Matrix imageFilterAverage() {
int avgArray[][] = new int[_twoDiPicture.length][];
int numOfCellsAround = 0;
int cellsSum = 0;
for (int y = 0; y < _twoDiPicture.length; y++) {
avgArray[y] = new int[_twoDiPicture[y].length];
for (int x = 0; x < _twoDiPicture[y].length; x++) {
numOfCellsAround = 0;
cellsSum = 0;
numOfCellsAround += cellsAround(y, x);
cellsSum += cellsSum(y, x);
avgArray[y][x] = cellsSum / numOfCellsAround;
}
}
return new Matrix(avgArray);
}
/* a private method that deals with index out of bound exceptions. */
private boolean isInBounds(int y, int x) {
return y < _twoDiPicture.length && y >= 0 && x < _twoDiPicture[y].length && x >= 0;
}
/* A private methods that uses "isInBounds" to find how many cells are surrounding the target array. */
private int cellsAround(int y, int x) {
int cells = 1;
if (isInBounds(y + 1, x)) {
cells++;
}
if (isInBounds(y - 1, x)) {
cells++;
}
if (isInBounds(y, x + 1)) {
cells++;
}
if (isInBounds(y, x - 1)) {
cells++;
}
if (isInBounds(y - 1, x + 1)) {
cells++;
}
if (isInBounds(y - 1, x - 1)) {
cells++;
}
if (isInBounds(y + 1, x - 1)) {
cells++;
}
if (isInBounds(y + 1, x + 1)) {
cells++;
}
return cells;
}
/*A private method that returns the sum of all the adjacent cells around target cell. */
private int cellsSum(int y, int x) {
int sum = _twoDiPicture[y][x];
if (isInBounds(y + 1, x)) {
sum += _twoDiPicture[y + 1][x];
}
if (isInBounds(y - 1, x)) {
sum += _twoDiPicture[y - 1][x];
}
if (isInBounds(y, x + 1)) {
sum += _twoDiPicture[y][x + 1];
}
if (isInBounds(y, x - 1)) {
sum += _twoDiPicture[y][x - 1];
}
if (isInBounds(y - 1, x + 1)) {
sum += _twoDiPicture[y - 1][x + 1];
}
if (isInBounds(y - 1, x - 1)) {
sum += _twoDiPicture[y - 1][x - 1];
}
if (isInBounds(y + 1, x - 1)) {
sum += _twoDiPicture[y + 1][x - 1];
}
if (isInBounds(y + 1, x + 1)) {
sum += _twoDiPicture[y + 1][x + 1];
}
return sum;
}
I have an ugly solution which can be improved:
public static void main(String[] args) {
int[][] matrix = {{10, 5, 7, 3},
{50, 3, 2, 1},
{60, 2, 5, 2}};
int[][] average = new int[matrix.length][matrix[0].length];
for(int i = 0; i< matrix.length; i++){
for(int j = 0; j< matrix[0].length; j++){
int sum = 0;
int div = ((i==0 && j ==0) ||
(i==0 && j == matrix[0].length-1) ||
(i== matrix.length-1 && j ==0)||
(i== matrix.length-1 && j == matrix[0].length-1)) ? 4 :
((i==0 && j > 0) ||
(i>0 && j == 0) ||
(i== matrix.length-1 && j >0)||
(i> 0 && j == matrix[0].length-1))? 6 : 9;
for(int k = Math.max(i-1, 0); k <= Math.min(i+1, matrix.length-1); k++){
for(int t = Math.max(j-1, 0); t <= Math.min(j+1, matrix[0].length-1); t++){
sum += matrix[k][t];
}
}
average[i][j] = sum / div;
}
}
for(int[] r:average){
System.out.println(Arrays.toString(r));
}
}
I have the following code translated as best I could from Java to C#:
public double maxProfit(double[] prices, int K)
{
if (K == 0 || prices.Length == 0)
{
return 0;
}
var dp = new double[K + 1, prices.Length];
for (int i = 1; i < K + 1; i++)
{
double maxDiff = -prices[0];
for (int j = 1; j < prices.Length; j++)
{
dp[i, j] = Math.Max(dp[i, j - 1], prices[j] + maxDiff);
maxDiff = Math.Max(maxDiff, dp[i - 1, j] - prices[j]);
}
}
printTrans(dp, prices, K);
return dp[K, prices.Length - 1];
}
public void printTrans(double[,] dp, double[] prices, int K)
{
int i = K - 1;
int j = prices.Length;
var priceList = new List<double>();
while (true)
{
if (i == 0 || j == 0)
{
break;
}
if (dp[i, j] == dp[i, j - 1])
{
j = j - 1;
}
else
{
priceList.Add(j);
double maxDiff = dp[i, j] - prices[j];
for (int z = j - 1; z >= 0; z--)
{
if (dp[i - 1, z] - prices[z] == maxDiff)
{
i = i - 1;
j = z;
priceList.Add(j);
break;
}
}
}
}
while (priceList.Count > 0)
{
Console.WriteLine("Buy # " + prices[priceList.IndexOf(0)]);
Console.WriteLine("Sell # " + prices[priceList.IndexOf(0)]);
}
}
Error occurs in the second method on lines:
if (dp[i, j] == dp[i, j - 1])
and
for (int z = j - 1; z >= 0; z--)
{
if (dp[i - 1, z] - prices[z] == maxDiff)
I am getting an Index was outside the bounds of the array. error. I understand what this error means but I have no clue on my to fix it. It took me quite a bit to understand the first part of this code but for the second part, I am at a loss.
Also what is the C# equivalent of the Java pollFirst() method?
Probably this line is the cause
public void printTrans(double[,] dp, double[] prices, int K)
{
int i = K - 1;
int j = prices.Length; // <=== this line is the cause
its causing the j to refer an index outside the bounds of the 2D array.
If you have ported from java recheck your java code.
Either make that line
int j = prices.Length - 1;
Or you need to make changes to how you create your array
var dp = new double[K + 1, prices.Length]; // <-- prices.Length would have to change here