Related
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'm doing a program , it is about an "object" (element) that move in 8way direction based on input.
My questions are : How can I make this element to visit cells of the board (2D Array) only once? How do I make it stay it current position if it can not move according to rules?
Start is position (0,0)
As input it get n-> number of dimension Matrix n x n , direction and t-> seconds. The other thing I don't get how to implement is input seconds, I get input seconds and directions because based on those I have to move the element into this 2D array list.
I've completed mostly of the program. I can give you my code here if you want to check it and give me advice. I'm stuck in it and I need help.
I want to print number of cells that are not visited. My idea is to give a number 0 to all cells that are not visited and the rest that are visited give number 1 as value. Like cell[x][x]=1; And in the end I count all cells that have number 0 as value and print count.
For a valid move in a particular direction, the object must move to a previously unoccupied cell, or else wait until the next direction.
You have defined cell[row][col] to represent the visited state; 0=unvisited, 1=visited. At the end, the number of unvisited cells will be the number of cell elements equal to zero.
To determine if the object should be moved, two checks must be done:
Make sure the next position is a valid matrix position (you are doing this correctly)
Make sure the next position has not yet been visited (will show below)
// Iterate through all k movements
for (i = 0; i < arrTime.length - 1; i++) {
// Move by 1 second until reach next instruction
for (j = arrTime[i]; j < arrTime[i + 1]; j++) {
// South East
if (arrDirection[i].equals("SE")) {
// Check #1 above (a valid matrix position)
if (nCurrRow < n - 1 && nCurrCol < n - 1) {
// Check #2 above (only move into unvisited position)
if (cell[nCurrRow+1][nCurrCol+1] == 0) {
// Move, and record that cell has been visited
nCurrRow++;
nCurrCol++;
cell[nCurrRow][nCurrCol] = 1;
}
}
}
// Other directions following the template for South East
Now to count unvisited cells:
int unVisited=0;
for (int i=0; i<n; i++)
for (int j=0; j<n; j++)
if (cell[i][j] == 0) unVisited++;
EDIT: To describe the two issues with the code.
1) The first issue relates to the j loop. The current j loop is
for(j = arrTime[i]; j <= arrTime[i + 1]; j++)
But must be:
for(j = arrTime[i]; j < arrTime[i + 1]; j++)
The way it was moves the object one more time than it should
2) The final movement was not being performed. The original code was:
arrTime[k] = arrTime[k - 1];
But must be:
arrTime[k] = arrTime[k - 1] + n;
Once you make these two changes, both test cases will work.
EDIT #2: A way to reduce the j loop
Previously, the j loop would run each iteration to the next i value. Here, we short circuit and leave the j loop as soon the object is unable to move. In the second test case, this reduced the number of j iterations from 50 to 28.
for (i = 0; i < arrTime.length - 1; i++) {
boolean canMove = true;
for (j = arrTime[i]; j < arrTime[i + 1] && canMove; j++) {
if (arrDirection[i].equals("SE")) {
if (nCurrRow < n - 1 && nCurrCol < n - 1 && cell[nCurrRow + 1][nCurrCol + 1] == 0) {
nCurrRow++;
nCurrCol++;
cell[nCurrRow][nCurrCol] = 1;
} else
canMove = false;
} else if (arrDirection[i].equals("NE")) {
if (nCurrRow > 0 && nCurrCol < n - 1 && cell[nCurrRow - 1][nCurrCol + 1] == 0) {
nCurrRow--;
nCurrCol++;
cell[nCurrRow][nCurrCol] = 1;
} else
canMove = false;
} ...
EDIT: Looking for test cases that will fail
Looking at your new comments, it is legal that the wind changes when t=1000000 (the maximum allowed value for t).
Consider this very simple test case:
3 2 (3x3 matrix, two wind changes)
0 E (wind blows east right away; robot moves to 0,2)
1000000 S (wind blows south at 1000000s, robot should move to 2,2)
Result should be: 4, but your current code will give 6 because it doesn't accept t=1000000.
If you change the line:
if(seconds >=0 && seconds<1000000 && k >=2 && k<1000000) {
to
if(seconds >=0 && seconds<=1000000 && k >=2 && k<=1000000) {
Then you get the expected answer of 4. It is very likely that at least one test case will push all the input boundaries, including when t=1000000.
EDIT: Faster algorithm #2
The current algorithm can be improved by reducing the number of if statements. There are two important improvements:
1) The former code had to use if to check both a) Valid matrix location b) If the location had been previously visited. You can use one 1 if for this, if you create a border around the matrix, and pre-populate with the value 1. Because of the border, the starting position is 1,1 and not 0,0.
2) Inside the j loop, the code unnecessarily looked up the direction. Now the direction is determined prior to the j loop, making the code inside the j loop much faster.
Also the number of unvisited cells is dynamic; no need to count them after the i loop completes. I changed the type to long because when n gets large, then the number of unvisited cells can be up to n*n which requires a type long. This might solve some of the incorrect answers.
If you study the new code, compare it to the older one, you will see many less if statements. This should scale better under larger test cases. Lets see if some of the test cases that were timing out improve.
public class Robot {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int j = 0;
int i = 0;
int n = in.nextInt();
int k = in.nextInt();
int[] arrTime = new int[k + 1];
String[] arrDirection = new String[k];
for (j = 0; j < k; j++) {
int seconds = in.nextInt();
if (seconds >= 0 && seconds <= 1000000) {
arrTime[j] = seconds;
}
String direction = in.next();
arrDirection[j] = direction;
}
arrTime[k] = arrTime[k - 1] + n;
// Add a border around the matrix with values of 1
int N = n + 2;
int[][] cell = new int[N][N];
for (j = 0; j < cell.length; j++) {
cell[0][j] = 1; // Top border
cell[j][0] = 1; // Left border
cell[j][N - 1] = 1; // Right border
cell[N - 1][j] = 1; // Bottom border
}
int nCurrRow = 1;
int nCurrCol = 1;
cell[nCurrRow][nCurrCol] = 1;
long R = n * n - 1; // Number of remaining unvisited cells
for (i = 0; i < arrTime.length - 1; i++) {
boolean canMove = true;
int xDir = 0;
int yDir = 0;
if (arrDirection[i].equals("SE")) {
xDir = 1;
yDir = 1;
} else if (arrDirection[i].equals("NE")) {
xDir = 1;
yDir = -1;
} else if (arrDirection[i].equals("E")) {
xDir = 1;
} else if (arrDirection[i].equals("N")) {
yDir = -1;
} else if (arrDirection[i].equals("NW")) {
xDir = -1;
yDir = -1;
} else if (arrDirection[i].equals("W")) {
xDir = -1;
} else if (arrDirection[i].equals("SW")) {
xDir = -1;
yDir = 1;
} else if (arrDirection[i].equals("S")) {
yDir = 1;
}
for (j = arrTime[i]; j < arrTime[i + 1] && canMove; j++) {
if (cell[nCurrRow + yDir][nCurrCol + xDir] == 0) {
nCurrRow += yDir;
nCurrCol += xDir;
cell[nCurrRow][nCurrCol] = 1;
R--;
} else
canMove = false;
}
}
//printArray(cell);
System.out.println(R);
in.close();
}
static void printArray(int[][] arr) {
for (int row = 0; row < arr.length; row++) {
for (int col = 0; col < arr.length; col++)
System.out.print(arr[row][col]);
System.out.println();
}
}
}
EDIT #3: More efficient memory usage; using BitSet
I suspect that the higher test cases are failing because the value of n is large in those cases. It is simple to test that when n=100000 that the cell array is too large, causing java memory error. So this code make the cell array very compact by using bitset. Lets see how this code does:
public class Robot {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int j = 0;
int i = 0;
int n = in.nextInt();
int k = in.nextInt();
int[] arrTime = new int[k + 1];
String[] arrDirection = new String[k];
for (j = 0; j < k; j++) {
int seconds = in.nextInt();
if (seconds >= 0 && seconds <= 1000000) {
arrTime[j] = seconds;
}
String direction = in.next();
arrDirection[j] = direction;
}
if (k >= 2 && k < 1000000) {
arrTime[k] = arrTime[k - 1] + n;
}
int N = n + 2;
BitSet[] cell = new BitSet[N];
for (j = 0; j < cell.length; j++)
cell[j] = new BitSet(N);
for (j = 0; j < cell.length; j++) {
set(cell, 0, j);
set(cell, j, 0);
set(cell, j, N-1);
set(cell, N-1, j);
}
int nCurrRow = 1;
int nCurrCol = 1;
set(cell,nCurrRow,nCurrCol);
long R = n * n - 1;
for (i = 0; i < arrTime.length - 1; i++) {
boolean canMove = true;
int xDir = 0;
int yDir = 0;
if (arrDirection[i].equals("SE")) {
xDir = 1;
yDir = 1;
} else if (arrDirection[i].equals("NE")) {
xDir = 1;
yDir = -1;
} else if (arrDirection[i].equals("E")) {
xDir = 1;
} else if (arrDirection[i].equals("N")) {
yDir = -1;
} else if (arrDirection[i].equals("NW")) {
xDir = -1;
yDir = -1;
} else if (arrDirection[i].equals("W")) {
xDir = -1;
} else if (arrDirection[i].equals("SW")) {
xDir = -1;
yDir = 1;
} else if (arrDirection[i].equals("S")) {
yDir = 1;
}
for (j = arrTime[i]; j < arrTime[i + 1] && canMove; j++) {
if (!isSet(cell,nCurrRow + yDir, nCurrCol + xDir)) {
nCurrRow += yDir;
nCurrCol += xDir;
set(cell,nCurrRow,nCurrCol);
R--;
} else
canMove = false;
}
}
//System.out.println();
//printArray(cell);
System.out.println(R);
in.close();
}
static boolean isSet(BitSet[] cell, int x, int y) {
BitSet b = cell[x];
return b.get(y);
}
static void set(BitSet[] cell, int x, int y) {
BitSet b = cell[x];
b.set(y);
}
static void printArray(int[][] arr) {
for (int row = 0; row < arr.length; row++) {
for (int col = 0; col < arr.length; col++)
System.out.print(arr[row][col]);
System.out.println();
}
}
}
EDIT: Attempt to read and process at the same time
This technique sometimes helps with large input. Rather than read all the input, then process in a second phase, process it as you read. In this case there is no need to store the data in two arrays (one for arrivalTime and one for direction). Lets see if this helps at all.
public class Robot2 {
static int nCurrRow = 1;
static int nCurrCol = 1;
static long R = 0;
static int[][] cell;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int i = 0;
int n = in.nextInt();
int k = in.nextInt();
// Add a border around the matrix with values of 1
int N = n + 2;
cell = new int[N][N];
for (i = 0; i < cell.length; i++) {
cell[0][i] = 1; // Top border
cell[i][0] = 1; // Left border
cell[i][N - 1] = 1; // Right border
cell[N - 1][i] = 1; // Bottom border
}
cell[nCurrRow][nCurrCol] = 1;
R = (long)n * n - 1; // Number of remaining unvisited cells
int sec1 = in.nextInt();
int sec2 = 0;
String dir1 = in.next();
String dir2;
for (i = 0; i < k - 1; i++) {
sec2 = in.nextInt();
dir2 = in.next();
move(sec2-sec1, dir1);
dir1 = dir2;
sec1 = sec2;
}
move(n, dir1);
System.out.println(R);
in.close();
}
static void move(int t, String dir1) {
boolean canMove = true;
int xDir = 0;
int yDir = 0;
if (dir1.equals("SE")) {
xDir = 1;
yDir = 1;
} else if (dir1.equals("NE")) {
xDir = 1;
yDir = -1;
} else if (dir1.equals("E")) {
xDir = 1;
} else if (dir1.equals("N")) {
yDir = -1;
} else if (dir1.equals("NW")) {
xDir = -1;
yDir = -1;
} else if (dir1.equals("W")) {
xDir = -1;
} else if (dir1.equals("SW")) {
xDir = -1;
yDir = 1;
} else if (dir1.equals("S")) {
yDir = 1;
}
for (int j = 0; j < t && canMove; j++) {
if (cell[nCurrRow + yDir][nCurrCol + xDir] == 0) {
nCurrRow += yDir;
nCurrCol += xDir;
cell[nCurrRow][nCurrCol] = 1;
R--;
} else
canMove = false;
}
}
}
EDIT: Combination of BitSet and one phase processing
public class Robot3 {
static int nCurrRow = 1;
static int nCurrCol = 1;
static long R = 0;
static BitSet[] cell;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int i = 0;
int n = in.nextInt();
int k = in.nextInt();
// Add a border around the matrix with values of 1
int N = n + 2;
cell = new BitSet[N];
for (i = 0; i < cell.length; i++)
cell[i] = new BitSet(N);
for (i = 0; i < cell.length; i++) {
set(cell, 0, i);
set(cell, i, 0);
set(cell, i, N-1);
set(cell, N-1, i);
}
set(cell, nCurrRow, nCurrCol);
R = (long)n * n - 1; // Number of remaining unvisited cells
int sec1 = in.nextInt();
int sec2 = 0;
String dir1 = in.next();
String dir2;
for (i = 0; i < k - 1; i++) {
sec2 = in.nextInt();
dir2 = in.next();
move(sec2-sec1, dir1);
dir1 = dir2;
sec1 = sec2;
}
move(n, dir1);
System.out.println(R);
in.close();
}
static void move(int t, String dir1) {
boolean canMove = true;
int xDir = 0;
int yDir = 0;
if (dir1.equals("SE")) {
xDir = 1;
yDir = 1;
} else if (dir1.equals("NE")) {
xDir = 1;
yDir = -1;
} else if (dir1.equals("E")) {
xDir = 1;
} else if (dir1.equals("N")) {
yDir = -1;
} else if (dir1.equals("NW")) {
xDir = -1;
yDir = -1;
} else if (dir1.equals("W")) {
xDir = -1;
} else if (dir1.equals("SW")) {
xDir = -1;
yDir = 1;
} else if (dir1.equals("S")) {
yDir = 1;
}
for (int j = 0; j < t && canMove; j++) {
if (!isSet(cell,nCurrRow + yDir, nCurrCol + xDir)) {
nCurrRow += yDir;
nCurrCol += xDir;
set(cell, nCurrRow, nCurrCol);
R--;
} else
canMove = false;
}
}
static boolean isSet(BitSet[] cell, int x, int y) {
return cell[x].get(y);
}
static void set(BitSet[] cell, int x, int y) {
cell[x].set(y);
}
}
EDIT: Replacing Scanner with BufferedReader
There is a chance that Scanner is too slow:
https://www.cpe.ku.ac.th/~jim/java-io.html
This may be worth a try:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.BitSet;
import java.util.StringTokenizer;
public class Robot3 {
static int nCurrRow = 1;
static int nCurrCol = 1;
static long R = 0;
static BitSet[] cell;
public static void main(String[] args) throws IOException {
Reader.init(System.in);
//Scanner in = new Scanner(System.in);
int i = 0;
int n = Reader.nextInt();
int k = Reader.nextInt();
// Add a border around the matrix with values of 1
int N = n + 2;
cell = new BitSet[N];
for (i = 0; i < cell.length; i++)
cell[i] = new BitSet(N);
for (i = 0; i < cell.length; i++) {
set(cell, 0, i);
set(cell, i, 0);
set(cell, i, N-1);
set(cell, N-1, i);
}
set(cell, nCurrRow, nCurrCol);
R = (long)n * n - 1; // Number of remaining unvisited cells
int sec1 = Reader.nextInt();
int sec2 = 0;
String dir1 = Reader.next();
String dir2 = "";
for (i = 0; i < k - 1; i++) {
sec2 = Reader.nextInt();
dir2 = Reader.next();
move(sec2-sec1, dir1);
dir1 = dir2;
sec1 = sec2;
}
move(n, dir1);
System.out.println(R);
}
static void move(int t, String dir1) {
boolean canMove = true;
int xDir = 0;
int yDir = 0;
if (dir1.equals("SE")) {
xDir = 1;
yDir = 1;
} else if (dir1.equals("NE")) {
xDir = 1;
yDir = -1;
} else if (dir1.equals("E")) {
xDir = 1;
} else if (dir1.equals("N")) {
yDir = -1;
} else if (dir1.equals("NW")) {
xDir = -1;
yDir = -1;
} else if (dir1.equals("W")) {
xDir = -1;
} else if (dir1.equals("SW")) {
xDir = -1;
yDir = 1;
} else if (dir1.equals("S")) {
yDir = 1;
}
for (int j = 0; j < t && canMove; j++) {
if (!isSet(cell,nCurrRow + yDir, nCurrCol + xDir)) {
nCurrRow += yDir;
nCurrCol += xDir;
set(cell, nCurrRow, nCurrCol);
R--;
} else
canMove = false;
}
}
static boolean isSet(BitSet[] cell, int x, int y) {
return cell[x].get(y);
}
static void set(BitSet[] cell, int x, int y) {
cell[x].set(y);
}
static class Reader {
static BufferedReader reader;
static StringTokenizer tokenizer;
/** call this method to initialize reader for InputStream */
static void init(InputStream input) {
reader = new BufferedReader(
new InputStreamReader(input) );
tokenizer = new StringTokenizer("");
}
/** get next word */
static String next() throws IOException {
while ( ! tokenizer.hasMoreTokens() ) {
//TODO add check for eof if necessary
tokenizer = new StringTokenizer(
reader.readLine() );
}
return tokenizer.nextToken();
}
static int nextInt() throws IOException {
return Integer.parseInt( next() );
}
static double nextDouble() throws IOException {
return Double.parseDouble( next() );
}
}
}
EDIT: Using a Set to store visited cells
It turns out that when n is large, creating BitSets is an expensive process. About 1.4s was taken just to create the array of BitSets. So arrays don't work, and BitSet creation is slow. After some thought, I realized that a regular HashSet<Long> should work to store visited cells, and it doesn't have the same cost to create it.
public class Robot4 {
static int nCurrRow = 1;
static int nCurrCol = 1;
static long R = 0;
static Set<Long> cell;
static long N;
public static void main(String[] args) throws IOException {
Reader.init(System.in);
int i = 0;
int n = Reader.nextInt();
int k = Reader.nextInt();
// Add a border around the matrix with values of 1
N = n + 2L;
cell = new HashSet<Long>(1000000);
for (i = 0; i < N; i++) {
set(0, i);
set(i, 0);
set(i, n+1);
set(n+1, i);
}
set(nCurrRow, nCurrCol);
R = (long)n * n - 1; // Number of remaining unvisited cells
int sec1 = Reader.nextInt();
int sec2 = 0;
String dir1 = Reader.next();
String dir2 = "";
for (i = 0; i < k - 1; i++) {
sec2 = Reader.nextInt();
dir2 = Reader.next();
move(sec2-sec1, dir1);
dir1 = dir2;
sec1 = sec2;
}
move(n, dir1);
System.out.println(R);
}
static void move(int t, String dir1) {
boolean canMove = true;
int xDir = 0;
int yDir = 0;
if (dir1.equals("SE")) {
xDir = 1;
yDir = 1;
} else if (dir1.equals("NE")) {
xDir = 1;
yDir = -1;
} else if (dir1.equals("E")) {
xDir = 1;
} else if (dir1.equals("N")) {
yDir = -1;
} else if (dir1.equals("NW")) {
xDir = -1;
yDir = -1;
} else if (dir1.equals("W")) {
xDir = -1;
} else if (dir1.equals("SW")) {
xDir = -1;
yDir = 1;
} else if (dir1.equals("S")) {
yDir = 1;
}
for (int j = 0; j < t && canMove; j++) {
if (!isSet(nCurrRow + yDir, nCurrCol + xDir)) {
nCurrRow += yDir;
nCurrCol += xDir;
set(nCurrRow, nCurrCol);
R--;
} else
canMove = false;
}
}
static boolean isSet(int x, int y) {
return cell.contains(indexId(x,y));
}
static void set(int x, int y) {
cell.add(indexId(x,y));
}
static long indexId(int x, int y) {
return x*N+y;
}
static class Reader {
static BufferedReader reader;
static StringTokenizer tokenizer;
/** call this method to initialize reader for InputStream */
static void init(InputStream input) {
reader = new BufferedReader(
new InputStreamReader(input) );
tokenizer = new StringTokenizer("");
}
/** get next word */
static String next() throws IOException {
while ( ! tokenizer.hasMoreTokens() ) {
tokenizer = new StringTokenizer(
reader.readLine() );
}
return tokenizer.nextToken();
}
static int nextInt() throws IOException {
return Integer.parseInt( next() );
}
static double nextDouble() throws IOException {
return Double.parseDouble( next() );
}
}
}
import java.util.Scanner;
public class Recursion
{
//variables to hold string values
public static String s1 = new String(new char[10]);
public static String s2 = new String(new char[10]);
public static String s3 = new String(new char[11]);
public static String charSet = new String(new char[11]);
//variables to hold number values
public static int numberOne;
public static int numberTwo;
public static int numberThree;
public static int maxCharCount;
public static int[] numberSet = new int[10];
//function which generates a number
public static void checkForEquality()
{
numberOne = numberTwo = numberThree = 0;
int i;
int j;
for (i = 0; i < s1.length(); i++)
{
for (j = 0; j < maxCharCount; j++)
{
if (s1.charAt(i) == charSet.charAt(j))
{
if (i == 0 && numberSet[j] == 0)
return;
//generate the number
numberOne = (numberOne * 10) + numberSet[j];
}
}
}
for (i = 0; i < s2.length(); i++)
{
for (j = 0; j < maxCharCount; j++)
{
if (s2.charAt(i) == charSet.charAt(j))
{
if (i == 0 && numberSet[j] == 0)
return;
//generate number
numberTwo = (numberTwo * 10) + numberSet[j];
}
}
}
for (i = 0; i < s3.length(); i++)
{
for (j = 0; j < maxCharCount; j++)
{
if (s3.charAt(i) == charSet.charAt(j))
{
if (i == 0 && numberSet[j] == 0)
return;
//generate the number
numberThree = (numberThree * 10) + numberSet[j];
}
}
}
}
public static void display(){
if (numberOne + numberTwo == numberThree) {
//display the output
int i=0;
System.out.println();
System.out.print(" Summation Puzzle solved. ");
System.out.print("n");
System.out.print(s1);
System.out.print("<==>");
System.out.print(numberOne);
System.out.print("n");
System.out.print(s2);
System.out.print("<==>");
System.out.print(numberTwo);
System.out.print("n");
System.out.print(s3);
System.out.print("<==>");
System.out.print(numberThree);
System.out.print("n");
//loop to show the result
for (i = 0; i < maxCharCount; i++)
{
System.out.println(charSet.charAt(i));
System.out.print("<==>");
System.out.print(numberSet[i]);
System.out.print("n");
}
System.exit(0);
}
}
//recursive function which will call itself
public static void Combinations(int indexCounter, int[] availableSet)
{
int i;
if (indexCounter != 0)
{
for (i = 0; i < 10; i++)
{
numberSet[indexCounter] = i;
if (availableSet[i] == 1)
{
availableSet[i] = 0;
Combinations(indexCounter + 1, availableSet);
availableSet[i] = 1;
}
}
}
if (indexCounter == maxCharCount)
checkForEquality();
}
public static void createCharSet()
{
int i;
int setIndex;
int present;
int j;
setIndex = 0;
for (i = 0; i < s1.length(); i++)
{
present = 0;
for (j = 0; j < setIndex; j++)
{
if (s1.charAt(i) == charSet.charAt(j))
{
present = 1;
}
}
if (present == 0)
{
charSet = StringFunctions.changeCharacter(charSet, setIndex++, s1.charAt(i));
}
}
for (i = 0; i < s2.length(); i++)
{
present = 0;
for (j = 0; j < setIndex; j++)
{
if (s2.charAt(i) == charSet.charAt(j))
{
present = 1;
}
}
if (present == 0)
{
charSet = StringFunctions.changeCharacter(charSet, setIndex++, s2.charAt(i));
}
}
for (i = 0; i < s3.length(); i++)
{
present = 0;
for (j = 0; j < setIndex; j++)
{
if (s3.charAt(i) == charSet.charAt(j))
{
present = 1;
}
}
if (present == 0)
{
charSet = StringFunctions.changeCharacter(charSet, setIndex++, s3.charAt(i));
}
}
maxCharCount = setIndex;
}
public static void calculateSummation()
{
int loop;
if (maxCharCount > 10)
{
System.out.print("Please check the input again");
return;
}
else
{
int[] avaliableSet = new int[10];
for (loop = 0; loop < 10; loop++)
{
avaliableSet[loop] = 1;
}
Combinations(0, avaliableSet);
}
}
//main method
public static void main(String[]args) {
Scanner scan = new Scanner(System.in);
System.out.print("Enter the first String :");
s1 = scan.next();
System.out.print("Enter the second String :");
s2 = scan.next();
System.out.print("Enter the thirsd String :");
s3 = scan.next();
createCharSet();
System.out.print(" result of your 3 three strings = ");
System.out.print(charSet);
calculateSummation();
checkForEquality();
display();
}
}
Every time I run the program it just assigns 0 to each value. I want to be able to assign a value from 1-10 to each non numeric character.
can someone help me out.?
it should look something like this
Sample output
First off, you may find debugging easier if you properly format your code. I remember you posting last night where you experienced similar issues resulting from syntax. You may find that your code is easier to read if you format it like this:
//function which generates a number
public static void checkForEquality(){
numberOne = numberTwo = numberThree = 0;
int i;
int j;
for (i = 0; i < s1.length(); i++){
for (j = 0; j < maxCharCount; j++){
if (s1.charAt(i) == charSet.charAt(j)){
if (i == 0 && numberSet[j] == 0)
return;
//generate the number
numberOne = (numberOne * 10) + numberSet[j];
}
}
}
for (i = 0; i < s2.length(); i++){
for (j = 0; j < maxCharCount; j++){
if (s2.charAt(i) == charSet.charAt(j)){
if (i == 0 && numberSet[j] == 0)
return;
//generate number
numberTwo = (numberTwo * 10) + numberSet[j];
}
}
}
Take a look at just this portion of your code and see if it still properly follows your algorithm. You may find an error which you could've located yourself with properly formatted code. If you take a look at a previous question of yours (which I answered) you'll find a helpful link that guides you to writing better code.
Also, I didn't try to compile this in my own IDE, but you should take a look at Eclipse. A lot of the small errors you're getting could be located automatically by Eclipse.
I am creating a game that is called "Shapeshifter" and can't figure out how to check the 2D array game board to see if the shape that the user made with the cursor is actually the shape wanted. Any amount of code works, it just needs to actually work with the rest of the game.
Here is the code that I have done:
public static final int COLS = 7;
public static final int ROWS = 7;
public static int ZEE = 0;
public static int TEE = 1;
public static int ES = 2;
public static int OH = 3;
public static int JAY = 4;
public static int EL = 5;
public static int NUM_POLYOMINOS = 6;
public static int PIECE_SIZE = 4;
public static int UP = 8;
public static int LEFT = 4;
public static int DOWN = 2;
public static int RIGHT = 6;
public static int QUIT = 5;
public static int EMPTY = 0;
public static int POLY_PIECE = 1;
public static int PLAYER = 2;
private static int[][] getRandomPoly()
{
int rint = new java.util.Random().nextInt(NUM_POLYOMINOS);
if (rint == ZEE)
return new int[][]{{1, 1, 0},
{0, 1, 1}};
else if (rint == TEE)
return new int[][]{{0, 1, 0},
{1, 1, 1}};
else if (rint == ES)
return new int[][]{{0, 1, 1},
{1, 1, 0}};
else if (rint == OH)
return new int[][]{{1, 1},
{1, 1}};
else if (rint == JAY)
return new int[][]{{1, 0, 0},
{1, 1, 1}};
else //if (rint == EL)
return new int[][]{{0, 0, 1},
{1, 1, 1}};
}
public void printCurrentPoly()
{
if (currentPoly == null)
return;
System.out.println("Current polyomino:");
System.out.println();
for (int i = 0; i < currentPoly.length; i++)
{
for (int j = 0; j < currentPoly[0].length; j++)
if (currentPoly[i][j] == 0)
System.out.print(" ");
else
System.out.print("#");
System.out.println();
}
System.out.println();
}
public void initializeBoard()
{
for (int i = 0; i < board.length; i++)
for (int j = 0; j < board[0].length; j++)
board[i][j] = 0;
currentRow = board.length / 2;
currentCol = board[0].length / 2;
board[currentRow][currentCol] = PLAYER;
for (int i = 0; i < PIECE_SIZE; i++)
{
int rrow = new java.util.Random().nextInt(ROWS),
rcol = new java.util.Random().nextInt(COLS);
while ((rrow == 0 || rrow == board.length - 1) ||
(rcol == 0 || rcol == board[0].length - 1) ||
(rrow == board.length / 2 && rcol == board[0].length / 2) ||
(board[rrow][rcol] == POLY_PIECE))
{
rrow = new java.util.Random().nextInt(ROWS);
rcol = new java.util.Random().nextInt(COLS);
}
board[rrow][rcol] = POLY_PIECE;
}
currentPoly = getRandomPoly();
}
public static void main(String args[])
{
boolean done = false;
ShapeShifter ss = new ShapeShifter();
ss.initializeBoard();
ss.printCurrentPoly();
ss.printBoard();
while (!done)
{
int move = ss.getMove();
if (move == QUIT)
done = true;
else
{
ss.executeMove(move);
if (ss.checkForMatch())
done = true;
System.out.println("\n");
ss.printCurrentPoly();
ss.printBoard();
}
}
ss.printResult();
}
private int[][] board = new int[ROWS][COLS];
private int[][] currentPoly;
private int numMoves, currentRow, currentCol;
private boolean winner;
private Scanner stdin = new Scanner(System.in);
public void printBoard()
{
System.out.println("+-------+");
for(int i = 0; i < board.length; i++)
{
System.out.print("|");
for(int j = 0; j < board[0].length; j++)
{
if(board[i][j] == POLY_PIECE)
System.out.print("#");
else if (board[i][j] == PLAYER)
System.out.print("H");
else
System.out.print(" ");
}
System.out.println("|");
}
System.out.println("+-------+");
}
public int getMove()
{
System.out.println("Were do you want to move? (4=left, 2=down, 8=up, 6=right or 5=quit)");
int move = stdin.nextInt();
while(move != LEFT && move != RIGHT && move != UP && move != DOWN && move != QUIT)
{
System.out.println("Invalid, only valid moves allowed are 4=left, 2=down, 8=up, 6=right or 5=quit");
move = stdin.nextInt();
}
return move;
}
public void executeMove(int move)
{
if(move == LEFT)
moveLeft(move);
if(move == RIGHT)
moveRight(move);
if(move == UP)
moveUp(move);
if(move == DOWN)
moveDown(move);
numMoves++;
}
private void moveLeft(int move)
{
int currentRow = 0, currentCol = 0;
for(int i = 0; i < board.length; i++)
for(int j = 0; j < board[0].length; j++)
if(board[i][j] == 2)
{ currentRow = i;
currentCol = j;
}
if(move == LEFT)
{
if(currentCol != 0 && board[currentRow][currentCol - 1] != POLY_PIECE)
{
board[currentRow][currentCol - 1] = PLAYER;
board[currentRow][currentCol] = EMPTY;
}
if(currentCol != 0 && board[currentRow][currentCol - 1] == POLY_PIECE && board[currentRow][currentCol - 2] != POLY_PIECE)
{
board[currentRow][currentCol - 1] = PLAYER;
board[currentRow][currentCol - 2] = POLY_PIECE;
board[currentRow][currentCol] = EMPTY;
}
}
}
private void moveRight(int move)
{
int currentRow = 0, currentCol = 0;
for(int i = 0; i < board.length; i++)
for(int j = 0; j < board[0].length; j++)
if(board[i][j] == 2)
{ currentRow = i;
currentCol = j;
}
if(move == RIGHT)
{ if (currentCol != 6 && board[currentRow][currentCol + 1] != POLY_PIECE)
{
board[currentRow][currentCol + 1] = PLAYER;
board[currentRow][currentCol] = EMPTY;
}
if(currentCol != 6 && board[currentRow][currentCol + 1] == POLY_PIECE && board[currentRow][currentCol + 2] != POLY_PIECE)
{
board[currentRow][currentCol + 1] = PLAYER;
board[currentRow][currentCol + 2] = POLY_PIECE;
board[currentRow][currentCol] = EMPTY;
}
}
}
private void moveUp(int move)
{
int currentRow = 0, currentCol = 0;
for(int i = 0; i < board.length; i++)
for(int j = 0; j < board[0].length; j++)
if(board[i][j] == 2)
{ currentRow = i;
currentCol = j;
}
if(move == UP)
{
if(currentRow != 0 && board[currentRow - 1][currentCol] != POLY_PIECE)
{
board[currentRow - 1][currentCol] = PLAYER;
board[currentRow][currentCol] = EMPTY;
}
if(currentRow != 0 && board[currentRow - 1][currentCol] == POLY_PIECE && board[currentRow - 2][currentCol] != POLY_PIECE)
{
board[currentRow - 1][currentCol] = PLAYER;
board[currentRow - 2][currentCol] = POLY_PIECE;
board[currentRow][currentCol] = EMPTY;
}
}
}
private void moveDown(int move)
{
int currentRow = 0, currentCol = 0;
for(int i = 0; i < board.length; i++)
for(int j = 0; j < board[0].length; j++)
if(board[i][j] == 2)
{ currentRow = i;
currentCol = j;
}
if(move == DOWN)
{ if(currentRow != 6 && board[currentRow + 1][currentCol] != POLY_PIECE)
{
board[currentRow + 1][currentCol] = PLAYER;
board[currentRow][currentCol] = EMPTY;
}
if(currentRow != 6 && board[currentRow + 1][currentCol] == POLY_PIECE && board[currentRow + 2][currentCol] != POLY_PIECE)
{
board[currentRow + 1][currentCol] = PLAYER;
board[currentRow + 2][currentCol] = POLY_PIECE;
board[currentRow][currentCol] = EMPTY;
}
}
}
public void printResult()
{
if(checkForMatch() == false)
System.out.println("You did not win. You used " + numMoves + " moves to fail.");
else
System.out.println("You won!!n/" + "It took " + numMoves + " moves to complete.");
}
}
Here is the final piece to the game that I am having trouble with:
public boolean checkForMatch()
{
}
You didn't say whether the polyomino (not polynomial) can be in any orientation. If so, I think you'll have to loop through the rotations and reflections and test each one. For each orientation there are not many positions where it can line up with the board. For each you need to check each spot and see if the player has filled them all in.
Since your polyominoes are defined in advance, for optimization you could also define constants for each one saying which ways it's symmetrical, so you can avoid redundant tests. Not that extra tests would actually matter.
You can "re-use" a lot of the code you already wrote for printCurrentPoly and printBoard to implement checkForWinner.
The idea is to go through all the cells of the board. For each cell check: if the current poly would start at this cell are all # cells in the poly matched with the player char (o or x) on the board. If yes, the player is a winner. Otherwise go to the next cell.
Here the relevant code:
/**
* Returns true when the current polyTicTacToc can be found at x,y of the
* board, with its cells filled for the given player.
*/
private boolean isPoly(int x, int y, char player) {
if (currentPoly == null)
return false;
for (int i = 0; i < currentPoly.length; i++) {
for (int j = 0; j < currentPoly[0].length; j++) {
char c = currentPoly[i][j];
if (c == '#') {
if (boardCellAt(x + i, y + j) != player) {
return false;
}
}
}
}
return true;
}
private char boardCellAt(int i, int j) {
if (i >= board.length || j >= board[0].length) {
return ' ';
}
return board[i][j];
}
/**
* Check the entire game board to see if the given player has constructed
* the polyomino.
*/
public boolean checkForWinner(char player)// Lab2
{
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
if (isPoly(i, j, player)) {
return true;
}
}
}
return false;
}
BTW: There is a bug in printBoard. The loop should look like this:
for(int j = 0; j < board[0].length; j++)
or you get an ArrayIndexOutOfBoundsException.
Also in printBoard you should change the first print to System.out.print("|"); otherwise it looks like there are extra cells left on the board.
What I need is a little modification to my code so that every part of my hollow diamond prints a letter of the word "HURRICANE"
My code is:
String st1 = "HURRICANE";
int a = 0;
for (int i = 5; i >= 1; i--) {
for (int j = 1; j <= 9; j++) {
if (j == i || (10 - i) == j) {
System.out.print(st1.charAt(a)); //needs change
} else {
System.out.print(' ');
}
}
System.out.println();
}
for (int i = 2; i <= 5; i++) {
for (int j = 1; j <= 9; j++) {
if (j == i || (10 - i) == j) {
System.out.print(st1.charAt(a)); //needs change
} else {
System.out.print(' ');
}
}
System.out.println();
}
The output comes out as:
H
H H
H H
H H
H H
H H
H H
H H
H
I need to modify my "charAt" statement a little so it comes out to be:
H
U U
R R
R R
I I
C C
A A
N N
E
How should I make my print statement?
It's worth noting that the example provided only works for Strings the same length as "HURRICANE". A superior solution would work for all strings.
Partial solution for you to complete, since I guess it's your coursework and I don't want you to copy / paste / fail exams :P
public static void main(String[] args) {
String st1 = "HURRICANE";
char[] st1CharArray = st1.toCharArray();
int maxSpaces = st1CharArray.length / 2 + 1;
for (int i = 0; i <= st1CharArray.length / 2; i++) {
if (i == 0) {
System.out.println(getSpacesString(maxSpaces) + st1CharArray[i]);
} else {
System.out.println(getSpacesString(maxSpaces - i)
+ st1CharArray[i] + getSpacesString(i * 2 - 1)
+ st1CharArray[i]);
}
}
// Loop from st1CharArray.length / 2 + 1 and get the second half done.
}
private static String getSpacesString(int numberOfSpaces) {
StringBuilder strBuilder = new StringBuilder();
for (int i = 0; i < numberOfSpaces; i++) {
strBuilder.append(" ");
}
return strBuilder.toString();
}
//: Playground - noun: a place where people can play
import UIKit
var name : String = "HURRICANE"
var dimensions : Int = name.count - 1
var k : Int = 0
for rows in 0...dimensions{
for columns in 0...dimensions{
k = abs( (dimensions/2) - rows )
if columns == k || columns == dimensions - k{
print(Array(name)[rows], terminator: "")
}
else{
print(" ", terminator: "" )
}
}
print("")
}
String st1 = "HURRICANE";
int a = 0;
for (int i = 5; i >= 1; i--) {
for (int j = 1; j <= 9; j++) {
if (j == i || (10 - i) == j) {
System.out.print(st1.charAt(5 - i));
} else {
System.out.print(' ');
}
}
System.out.println();
}
for (int i = 2; i <= 5; i++) {
for (int j = 1; j <= 9; j++) {
if (j == i || (10 - i) == j) {
System.out.print(st1.charAt(3 + i));
} else {
System.out.print(' ');
}
}
System.out.println();
}
Let's assume that a word has an odd number of characters, otherwise we get a crooked diamond.
Try it online!
public static void main(String[] args) {
String str = "abrahadabra";
int n = str.length() / 2;
for (int i = -n, ch = 0; i <= n && ch < str.length(); i++, ch++) {
for (int j = -n; j <= n; j++)
if (Math.abs(i) + Math.abs(j) == n)
System.out.print(str.charAt(ch));
else
System.out.print(" ");
System.out.println();
}
}
Output:
a
b b
r r
a a
h h
a a
d d
a a
b b
r r
a