Related
I am trying to create a program that when given the location of a chess knight and the destination, all marked in chess notation, to return the number of moves it takes the knight to get from the location the destination. I have tried before using the algorithm to calculate every single possibility on a list, but it is very slow and kind of has problems. Here is my code:
private static int translateChessNotation(String chess) {
int returned = 8 * (Integer.valueOf(String.valueOf(chess.charAt(1)))- 1);
return returned + (convertAlphabet(chess.charAt(0))); // File
}
public static int knight(String start, String finish) {
int knightPosition = translateChessNotation(start), end = translateChessNotation(finish), i = 0;
ArrayList<Integer> currentPossibleKnightPositions = new ArrayList<>();
currentPossibleKnightPositions.add(knightPosition);
for (; i < 8; i++) {
ArrayList<Integer> newList = new ArrayList<>();
for (int position : currentPossibleKnightPositions) {
newList.add(position + 17);
newList.add(position + 15);
newList.add(position + 10);
newList.add(position + 6);
newList.add(position - 6);
newList.add(position - 10);
newList.add(position - 15);
newList.add(position - 17);
}
ArrayList<Integer> removed = new ArrayList<>();
for (int j : newList) {if (j < 1 || j > 64) {removed.add(j);}}
newList.removeAll(removed);
currentPossibleKnightPositions.clear();
currentPossibleKnightPositions.addAll(newList);
for (int n : currentPossibleKnightPositions) {
if (n == end) {return i + 1;}
}
}
return -1;
}
Thanks a lot if you help!
Here's a little Proggy to solve the so-called Knights-Tour problem, visiting all squares on the board starting from a particular location, so you could adapt that to set a particular to-position as your end-condition.
Its just Brute-Force, trying all possible combinations & takes about 50 minutes to find each full Knights-Tour solution.
If that helps, I'd be honoured to receive your vote.
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
public class KnightMove {
#SuppressWarnings("serial")
private static final class KnightMoveSolvedException extends RuntimeException {
private final byte[][] solution;
private KnightMoveSolvedException(final byte[][] solution) {
this.solution = solution;
}
}
private static final int SIZE_X = 8;
private static final int SIZE_Y = 8;
private static final int SIZE_X_Y = SIZE_X * SIZE_Y; // Max 127! (=0x7F)
private static final int [][] KNIGHT_MOVES = new int[8][];
/**/ static {
final AtomicInteger moveIndex = new AtomicInteger();
IntStream.of(2, -2).forEach(deltaX ->
IntStream.of(1, -1).forEach(deltaY -> {
/*
* Mirror the 4 combinations above to get all 8 possible Knight moves...
*/
KNIGHT_MOVES[moveIndex.getAndIncrement()] = new int[] {deltaX, deltaY};
KNIGHT_MOVES[moveIndex.getAndIncrement()] = new int[] {deltaY, deltaX};
}));
}
private static void nextMoveToXY(int moveCount, final int x, final int y, final byte[][] board) {
moveCount++;
board[x][y] = (byte) moveCount;
if (moveCount >= SIZE_X_Y) {
System.out.println("Solved!.....: count=" + moveCount);
for ( final byte[] column : board ) {
for (final byte square : column) {
System.out.print(square + "\t");
}
System.out.println();
}
return; // (Back up & keep looking for next solution)
/*
* If 1 solution is enough, just throw the Exception...
*/
// throw new KnightMoveSolvedException(board);
}
for (final int[] knightMove : KNIGHT_MOVES) {
final int newX = x + knightMove[0]; if (newX < 0 || newX >= SIZE_X) {continue;}
final int newY = y + knightMove[1]; if (newY < 0 || newY >= SIZE_Y) {continue;}
if (board[newX][newY] == 0) {
/*
* Target Square is vacant, so try this move recursively...
*/
nextMoveToXY(moveCount, newX, newY, deepPrimitive2DArrayClone(board));
}
}
}
/**
* {#link Object#clone()} can create a Deep Clone of a 1D array of Primitives
* but will <b>not</b> deliver the desired result with 2D,
* so we have to wrap the rest by hand...
*/
private static byte[][] deepPrimitive2DArrayClone(final byte[][] source) {
final byte[][] clone = new byte[source.length][];
/**/ int cix = 0;
for (final byte[] col : source) {
clone[cix++] = col.clone();
}
return clone;
}
public static void main(final String[] args) throws Exception {
IntStream.range(0, SIZE_X).forEach(x ->
IntStream.range(0, SIZE_Y).forEach(y -> {
try {
System.out.println("Solve starting at X/Y.: " + x +"/" + y);
nextMoveToXY(0, x, y, new byte[SIZE_X][SIZE_Y]);
}
catch (final KnightMoveSolvedException e) {
System.out.println(e.solution);
}
}));
}
}
I got this answer online. Hope this helps to the others who have the same question!
public static int knight(String...pos) {
int[][] ab=Stream.of(pos).map(s->new int[]{"abcdefgh".indexOf(s.charAt(0)),s.charAt(1)-48}).toArray(int[][]::new);
int[] dxy=IntStream.range(0,2).map(i->Math.abs(ab[0][i]-ab[1][i])).sorted().toArray();
if(dxy[0]==0&&dxy[1]==1) return 3;
if(dxy[0]==2&&dxy[1]==2||dxy[0]==1&&dxy[1]==1&&(pos[0]+pos[1]).matches(".*?(a1|h1|a8|h8).*")) return 4;
int delta=dxy[1]-dxy[0];
return delta-2*(int)Math.floor(1.0*(delta-dxy[0])/(dxy[0]>delta?3:4));
}
I've replaced the Chessboard Array in the previous Posting with a long.
(with 64 bits, its just large enough to represent the board)
The new Version is significantly faster.
Depending on starting-coordinates, a solution takes anywhere between 1 Minute & 12 Hours...
(I've put a couple of the faster ones first)
This example is designed to show the basics. There are various Mathematical Methods (see Wikipedia) to optimise it, but they make the Solution more complex.
A couple of Takeaways:
- use Primitives (byte, short, int, long,...) if you can: they are very fast
- avoid Objects like ArrayList when using Brute-Force: they are very slow
- use recursion: it saves & restores State for you. It may cost a little, but it makes life so much easier
- use final whenever you can: it's no faster, but aids understanding
Hope you like it. :-)
I've honed this thing down now. It is massively faster than the original (which was no slouch!), uses the Warnsdorff algorithm & can solve multiple starting positions, running on all available Threads simultaneously.
Most of the work is getting the Data Structures right & Initialisation.
The recursive nextMoveToXY solver Method itself is trivially simple.
The Warnsdorff Version:
import java.time.Instant;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.IntConsumer;
import java.util.stream.IntStream;
public class KnightsTourWarnsdorff {
private interface IntIntConsumer {
void accept(int t, int u);
}
private static final int MAX_INSTANT_TO_STRING_LENGTH = "2020-12-31T23:59:59.123456Z".length();
private static final int SIZE_X = 8;
private static final int SIZE_Y = 8;
private static final int SIZE_X_Y = SIZE_X * SIZE_Y;
/**/ static { check_SIZE_X_Y_withinCapacity();}
/**
* Do this in a Method (we don't want to mark the Class with SuppressWarnings)
*/
#SuppressWarnings("unused")
private static void check_SIZE_X_Y_withinCapacity() {
if (SIZE_X_Y > Long.SIZE) {
throw new UnsupportedOperationException("Number of squares on board exceeds capacity of long Solution");
}
}
/**
* Returns the unique offset corresponding to a Move or our position on the Board.
*/
private static int getDeltaXY(final int deltaX, final int deltaY) {
return deltaX + deltaY * SIZE_X; /* Yes, SIZE_X ! */
}
/**
* Returns a long with a single bit set, corresponding to our position on the Board.
*/
private static long getXYmaskBit(final int x, final int y) {
return 1L << (63 - getDeltaXY(x, y));
}
private static void walkBoard(final IntIntConsumer doXY) {
walkBoard(null, doXY, null);
}
private static void walkBoard(final IntConsumer doRowStart, final IntIntConsumer doXY, final Runnable doRowEnd) {
IntStream .range(0, SIZE_Y).forEach(y -> {if (doRowStart != null) {doRowStart.accept( y);}
IntStream.range(0, SIZE_X).forEach(x -> {if (doXY != null) {doXY .accept(x,y);}
}); if (doRowEnd != null) {doRowEnd .run ( );}
});
}
private static String toBinary(final long value) {
return leftPad(Long.SIZE, Long.toBinaryString(value)).replace('0', '_');
}
private static String leftPad (final int paddedLength, final String value) {
final int padCount = Math.max(0, paddedLength - value.length());
final char[] pad = new char[padCount];
Arrays.fill (pad, '0');
return String.valueOf(pad).concat(value);
}
private static String rightPad (final int paddedLength, final String value) {
final int padCount = Math.max(0, paddedLength - value.length());
final char[] pad = new char[padCount];
Arrays.fill (pad, '0');
return value.concat(String.valueOf(pad));
}
private static String header () {
return rightPad (MAX_INSTANT_TO_STRING_LENGTH, Instant.now().toString()) + " " + Thread.currentThread().getName() + " ";
}
/**
* Square on Board not only knows its x/y location, but also its position as an xyMask<br>
* (for checking whether a square is occupied & marking as occupied).<br>
* <br>
* It knows all possible Moves from this Square within the Board<br>
* (thus obviating the need to check whether we're still on the Board).<br>
* <br>
* Each Specific Move contains a reference to the Target Square, which in turn...<br>
* (these 2 measures speed up Navigation massively)
*/
private static final class Square {
private final int x;
private final int y;
/**
* Used to mark the Square as occupied on the Board
*/
private final long xyMask;
/**
* All possible Moves from this Square.<br>
* (initially all null: filled after all Squares have been instantiated)
*/
private final Move[] targetMove;
private Square(final int x, final int y) {
this.x = x;
this. y = y;
this.xyMask = getXYmaskBit(x, y);
this.targetMove = KNIGHT_MOVE_MAP.values().stream().filter(move -> {
final int newX = x + move.deltaX;
final int newY = y + move.deltaY;
return newX >= 0 && newX < SIZE_X
&& newY >= 0 && newY < SIZE_Y;
}).toArray(Move[]::new);
}
}
/**
* Either a Generic or a Specific Move
*/
private static final class Move {
private final int deltaX;
private final int deltaY;
private final int deltaXY;
private final Square target;
/**
* Create a Generic Move
*/
private Move(final int deltaX, final int deltaY) {
this.deltaX = deltaX;
this.deltaY = deltaY;
this.deltaXY = getDeltaXY(deltaX, deltaY);
this.target = null;
}
/**
* Create a Move to a specific Target Square
*/
private Move(final Move genericMove, final Square target) {
this.deltaX = genericMove.deltaX;
this.deltaY = genericMove.deltaY;
this.deltaXY = genericMove.deltaXY;
this.target = target;
}
}
#SuppressWarnings("serial")
private static final class KnightMoveSolvedException extends RuntimeException {
private final int[] solution;
private KnightMoveSolvedException(final int moveCount, final int[] solution) {
/*
* Trim the solution array down to the number of moves...
* (for those performing a partial walk)
*/
this.solution = Arrays.stream(solution).limit(moveCount).toArray();
synchronized (KnightMoveSolvedException.class) { // One Thread (= Solution) at a time please!
final int solution0 = this.solution[0];
final Move initialMove = BOARD_MAP.get(solution0);
final int initialX = initialMove.deltaX;
final int initialY = initialMove.deltaY;
System.out.println(header() + "Solution found for....: x/y: " + initialX + "/" + initialY + " \t" + toBinary(0L) + " \tlength=" + this.solution.length + " \t" + solution0);
this.printSolutionDetail();
}
}
private void printSolutionDetail() {
int x = 0;
int y = 0;
long board = 0;
for (int i=0; i < this.solution.length; i++) {
final int positionOrMove = this.solution[i];
final Move move = i == 0 ? BOARD_MAP.get(positionOrMove) : KNIGHT_MOVE_MAP.get(positionOrMove);
/**/ x = i == 0 ? move.deltaX : x + move.deltaX;
/**/ y = i == 0 ? move.deltaY : y + move.deltaY;
board |= getXYmaskBit(x, y);
System.out.println(header() + "Solution walk.........: x/y: " + x + "/" + y + " \t" + toBinary(board) + " \t" + move.deltaX + "\t" + move.deltaY + "\t" + positionOrMove);
}
}
}
private static final Map<Integer, Move> KNIGHT_MOVE_MAP;
/**/ static {
final Map<Integer, Move> Knight_Move_Map = new TreeMap<>();
IntStream.of(2, -2).forEach(deltaX ->
IntStream.of(1, -1).forEach(deltaY -> {
/*
* Mirror the 4 combinations above to get all 8 possible Knight moves...
*/
{final Move move = new Move(deltaX, deltaY); Knight_Move_Map.put(move.deltaXY, move);}
{final Move move = new Move(deltaY, deltaX); Knight_Move_Map.put(move.deltaXY, move);}
}));
KNIGHT_MOVE_MAP = Collections.unmodifiableMap(Knight_Move_Map);
}
private static final Map<Integer, Move> BOARD_MAP;
/**/ static {
final Map<Integer, Move> Board_Map = new TreeMap<>();
walkBoard((x,y) -> {
final Move move = new Move(x, y);
Board_Map.put(move.deltaXY, move);
});
BOARD_MAP = Collections.unmodifiableMap(Board_Map);
}
private static final Square[][] BOARD = new Square[SIZE_X] [SIZE_Y];
/**/ static {
/*
* Fill the Board with Squares...
*/
walkBoard( (x,y) -> BOARD[x][y] = new Square(x, y));
/**/ System.out.println("Onward Target Count:");
walkBoard( ( y) -> { System.out.print ( y + " : ");},
/**/ (x,y) -> {final Square square = BOARD[x][y]; System.out.print (square.targetMove.length + " ");},
/**/ ( ) -> { System.out.println() ;} );
/*
* So far the Target Moves array is filled with nulls. We MUST fill it...
*/
Arrays.stream(BOARD).flatMap(Arrays::stream).forEach(square -> {
final Move[] targetsSortedByOnwardPointCount = Arrays
.stream(square.targetMove)
.sorted((moveA, moveB) -> {
/*
* We use the Warnsdorff algorithm to sort it by the number of Onward Targets...
*/
final Square targetA = BOARD[square.x + moveA.deltaX] [square.y + moveA.deltaY];
final Square targetB = BOARD[square.x + moveB.deltaX] [square.y + moveB.deltaY];
return Integer.compare(
targetA.targetMove.length, // number of Onward Targets
targetB.targetMove.length); // number of Onward Targets
})
.map(move -> new Move(move, BOARD[square.x + move.deltaX] [square.y + move.deltaY]))
.toArray(Move[]::new);
/*
* Original & sorted arrays should be the same length if we got it right,
* so take max. length as a precaution to force an IndexOutOfBoundsException if we didn't...
*/
final int copyLength = Math.max(square.targetMove.length, targetsSortedByOnwardPointCount.length);
/*
* Overwrite the original Moves with the sorted version...
*/
System.arraycopy(targetsSortedByOnwardPointCount, 0, square.targetMove, 0, copyLength);
});
}
private final int[] SOLUTION = new int[SIZE_X_Y];
private void solve(final int initialX, final int initialY) {
final long initialBoard = getXYmaskBit(initialX, initialY);
System.out.println(header() + "Solve starting at.....: x/y: " + initialX +"/" + initialY + "\t" + toBinary(initialBoard));
try {
SOLUTION [0] = getDeltaXY(initialX, initialY); // First Entry contains Starting-Point
nextMoveToXY(0, BOARD[initialX][initialY], initialBoard);
}
catch (final KnightMoveSolvedException justIgnore_WereDone) {}
}
private void nextMoveToXY(int moveCount, final Square square, final long board) {
moveCount++;
if (moveCount >= SIZE_X_Y) {
final KnightMoveSolvedException solution = new KnightMoveSolvedException(moveCount, SOLUTION);
// return; // (Back up & keep looking for next solution)
/*
* If 1 solution is enough, just throw the Exception...
*/
throw solution;
}
for (final Move move : square.targetMove) {
/*
* Is Target Square vacant? (i.e. Mask Bit not set)...
*/
if ((board & move.target.xyMask) == 0) {
/*
* Yes: try next move recursively with new Position & Board...
*/
SOLUTION [moveCount] = move.deltaXY;
nextMoveToXY(moveCount, move.target, board | move.target.xyMask /* Set Mask Bit on new Board */);
}
}
}
public static void main(final String[] args) throws Exception {
final ExecutorService pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
/*
* We can handle rectangular boards, but for square boards the following holds:
* we only need to solve for 1/8 of the board (a triangle)...
* (the remaining 7/8 are either Mirrors or Rotations of the 1/8)
*/
IntStream .range(0, SIZE_X / 2).forEach(x -> {
IntStream.range(0, x + 1 ).forEach(y -> {
pool.submit(() -> {
try { TimeUnit.SECONDS.sleep(1); } catch (final InterruptedException e) {}
/*
* (Sleep very briefly, so our Thread won't start before the Output below has finished)
*/
new KnightsTourWarnsdorff().solve(x, y);
});
System.out.print("x=" + x + " y=" + y + "\t");
});
System.out.println();
});
pool.shutdown();
}
}
Original Version:
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
public class KnightsTour {
#SuppressWarnings("serial")
private static final class KnightMoveSolvedException extends RuntimeException {
private final int[][] solution;
private KnightMoveSolvedException(final int[][] solution) {
this.solution = deepPrimitive2DArrayClone (solution);
}
}
private static final int SIZE_X = 8;
private static final int SIZE_Y = 8;
private static final int SIZE_X_Y = SIZE_X * SIZE_Y;
private static final int[][] SOLUTION = new int[SIZE_X_Y][];
private static final int INDEX_X = 0;
private static final int INDEX_Y = 1;
private static final int KNIGHT_MOVES_LENGTH = 8;
private static final int [][] KNIGHT_MOVES = new int[KNIGHT_MOVES_LENGTH][];
/**/ static {
checkLongSolutionCapacity();
final AtomicInteger moveIndex = new AtomicInteger();
IntStream.of(2, -2).forEach(deltaX ->
IntStream.of(1, -1).forEach(deltaY -> {
/*
* Mirror the 4 combinations above to get all 8 possible Knight moves...
*/
KNIGHT_MOVES[moveIndex.getAndIncrement()] = new int[] {deltaX, deltaY};
KNIGHT_MOVES[moveIndex.getAndIncrement()] = new int[] {deltaY, deltaX};
}));
}
#SuppressWarnings("unused")
private static void checkLongSolutionCapacity() {
if (SIZE_X_Y > Long.SIZE) {
throw new UnsupportedOperationException("Number of squares on board exceeds capacity of long Solution");
}
}
private static long getXYmaskBit(final int x, final int y) {
return Long.MIN_VALUE >>> (x + y * SIZE_X /* Yes, SIZE-X ! */);
}
public static void solve(final int initialX, final int initialY) {
final long initialBoard = getXYmaskBit(initialX, initialY);
System.out.println("Solve starting at X/Y.: " + initialX +"/" + initialY + "\t" + toBinary(initialBoard));
try {
SOLUTION [0] = new int[] {initialX, initialY}; // First Entry contains Starting-Point
nextMoveToXY(0, initialX, initialY, initialBoard);
}
catch (final KnightMoveSolvedException e) {
System.out.println("One possible solution.: " + e.solution);
}
}
private static void nextMoveToXY(int moveCount, final int x, final int y, final long board) {
moveCount++;
if (moveCount >= SIZE_X_Y) {
System.out.println("Solved!...............: count=" + moveCount);
/*
* Print the answer or remember it somewhere...
*/
final int initialX = SOLUTION[0][INDEX_X];
final int initialY = SOLUTION[0][INDEX_Y];
for(final int[] move : SOLUTION) {
final int solutionX = move[INDEX_X];
final int solutionY = move[INDEX_Y];
System.out.println("Move (starting at X/Y): " + initialX +"/" + initialY + "\t" + toBinary(board) + "\t" + solutionX + "\t" + solutionY);
}
// return; // (Back up & keep looking for next solution)
/*
* If 1 solution is enough, just throw the Exception...
*/
throw new KnightMoveSolvedException(SOLUTION);
}
for(final int[] move : KNIGHT_MOVES) {
final int deltaX = move[INDEX_X]; final int newX = x + deltaX; if (newX < 0 || newX >= SIZE_X) {continue;}
final int deltaY = move[INDEX_Y]; final int newY = y + deltaY; if (newY < 0 || newY >= SIZE_Y) {continue;}
/*
* ok: Checks above mean we're on the board, so lets find the new Position Mask...
*/
final long newXYmaskBit = getXYmaskBit(newX, newY);
/*
* Is Target Square vacant (= Mask Bit not set)?...
*/
if ((board & newXYmaskBit) == 0) {
/*
* Yes: try next move recursively with new Position & Board...
*/
SOLUTION [moveCount] = move;
nextMoveToXY(moveCount, newX, newY, board | newXYmaskBit /* Set Mask Bit on new Board */);
}
}
}
public static String toHex (final int value) {
return leftPad(Integer.BYTES * 2, Integer.toHexString (value));
}
public static String toHex (final long value) {
return leftPad(Long .BYTES * 2, Long .toHexString (value));
}
public static String toBinary(final int value) {
return leftPad(Integer.SIZE, Integer.toBinaryString(value));
}
public static String toBinary(final long value) {
return leftPad(Long .SIZE, Long .toBinaryString(value));
}
private static String leftPad (final int paddedLength, final String binaryOrHex) {
final char[] lead = new char[paddedLength - binaryOrHex.length()];
Arrays.fill (lead, '0');
return String.valueOf(lead).concat(binaryOrHex).replace('0', '_');
}
/**
* {#link Object#clone()} can create a Deep Clone of a 1D array of Primitives
* but with 2D will only provide a Shallow Copy (meaning if the content of source
* changes, the content of clone will change!!) so we have to wrap 2D by hand...
*/
private static int[][] deepPrimitive2DArrayClone(final int[][] source) {
final int[][] clone = new int[source.length][];
/**/ int cix = 0;
for (final int[] col : source) {
clone[cix++] = col.clone(); // (ok: 1D, so Deep Clone)
}
return clone;
}
public static void main(final String[] args) throws Exception {
solve(0, 1); // Fast!: 2 Minutes
solve(0, 3); // Fast!: 1 Minute
IntStream.range(0, SIZE_X).forEach(x ->
IntStream.range(0, SIZE_Y).forEach(y -> {
solve(x, y);
}));
}
}
I have this .java datafile. The data file is a part of an imagej plugin.
The whole data structure is here:
enter link description here
package mosaic.plugins;
import ij.IJ;
import ij.ImagePlus;
import ij.macro.Interpreter;
import ij.measure.ResultsTable;
import ij.process.ByteProcessor;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.WindowConstants;
import mosaic.plugins.utils.PlugIn8bitBase;
import net.imglib2.Cursor;
import net.imglib2.IterableInterval;
import net.imglib2.RandomAccess;
import net.imglib2.img.ImagePlusAdapter;
import net.imglib2.img.Img;
import net.imglib2.img.ImgFactory;
import net.imglib2.img.array.ArrayImgFactory;
import net.imglib2.img.display.imagej.ImageJFunctions;
import net.imglib2.type.NativeType;
import net.imglib2.type.numeric.NumericType;
import net.imglib2.type.numeric.RealType;
import net.imglib2.type.numeric.integer.UnsignedByteType;
import net.imglib2.type.numeric.real.FloatType;
import net.imglib2.view.IntervalView;
import net.imglib2.view.Views;
public class Naturalization extends PlugIn8bitBase
{
// Precision in finding your best T
private static final float EPS = 0.0001f;
// Prior parameter for first oder
// In this case is for all channels
// Fixed parameter
private static final float T1_pr = 0.3754f;
// Number of bins for the Laplacian Histogram
// In general is 4 * N_Grad
// max of laplacian value is 4 * 255
private static final int N_Lap = 2041;
// Offset shift in the histogram bins
// Has to be N_Lap / 2;
private static final int Lap_Offset = 1020;
// Number of bins for the Gradient
private static final int N_Grad = 512;
// Offset for the gradient histogram shift
private static final int Grad_Offset = 256;
// Prior parameter for second order (Parameters learned from trained data set)
// For different color R G B
// For one channel image use an average of them
private final float T2_pr[] = {0.2421f ,0.2550f, 0.2474f, 0.24816666f};
// Keeps values of PSNR for all images and channels in case of RGB. Maps: imageNumber -> map (channel, PSNR value)
private final Map<Integer, Map<Integer, Float>> iPsnrOutput = new TreeMap<Integer, Map<Integer, Float>>();
private synchronized void addPsnr(int aSlice, int aChannel, float aValue) {
Map<Integer, Float> map = iPsnrOutput.get(aSlice);
boolean isNewMap = false;
if (map == null) {
map = new TreeMap<Integer, Float>();
isNewMap = true;
}
map.put(aChannel, aValue);
if (isNewMap) {
iPsnrOutput.put(aSlice, map);
}
}
#Override
protected void processImg(ByteProcessor aOutputImg, ByteProcessor aOrigImg, int aChannelNumber) {
// perform naturalization
final ImagePlus naturalizedImg = naturalize8bitImage(aOrigImg, aChannelNumber);
// set processed pixels to output image
aOutputImg.setPixels(naturalizedImg.getProcessor().getPixels());
}
#Override
protected void postprocessBeforeShow() {
// Create result table with all stored PSNRs.
final ResultsTable rs = new ResultsTable();
for (final Entry<Integer, Map<Integer, Float>> e : iPsnrOutput.entrySet()) {
rs.incrementCounter();
for (final Entry<Integer, Float> m : e.getValue().entrySet()) {
switch(m.getKey()) {
case CHANNEL_R: rs.addValue("Naturalization R", m.getValue()); rs.addValue("Estimated R PSNR", calculate_PSNR(m.getValue())); break;
case CHANNEL_G: rs.addValue("Naturalization G", m.getValue()); rs.addValue("Estimated G PSNR", calculate_PSNR(m.getValue())); break;
case CHANNEL_B: rs.addValue("Naturalization B", m.getValue()); rs.addValue("Estimated B PSNR", calculate_PSNR(m.getValue())); break;
case CHANNEL_8G: rs.addValue("Naturalization", m.getValue()); rs.addValue("Estimated PSNR", calculate_PSNR(m.getValue())); break;
default: break;
}
}
}
if (!Interpreter.isBatchMode()) {
rs.show("Naturalization and PSNR");
showMessage();
}
}
private ImagePlus naturalize8bitImage(ByteProcessor imp, int aChannelNumber) {
Img<UnsignedByteType> TChannel = ImagePlusAdapter.wrap(new ImagePlus("", imp));
final float T2_prior = T2_pr[(aChannelNumber <= CHANNEL_B) ? 2-aChannelNumber : CHANNEL_8G];
final float[] result = {0.0f}; // ugly but one of ways to get result back via parameters;
// Perform naturalization and store PSNR result. Finally return image in ImageJ format.
TChannel = performNaturalization(TChannel, T2_prior, result);
addPsnr(imp.getSliceNumber(), aChannelNumber, result[0]);
return ImageJFunctions.wrap(TChannel,"temporaryName");
}
/**
* Naturalize the image
* #param Img original image
* #param Theta parameter
* #param Class<T> Original image
* #param Class<S> Calculation Type
* #param T2_prior Prior to use
* #param result One element array to store nautralization factor
*/
private <T extends NumericType<T> & NativeType<T> & RealType<T>, S extends RealType<S>> Img<T> doNaturalization(Img<T> image_orig, S Theta,Class<T> cls_t, float T2_prior, float[] result) throws InstantiationException, IllegalAccessException
{
if (image_orig == null) {return null;}
// Check that the image data set is 8 bit
// Otherwise return an error or hint to scale down
final T image_check = cls_t.newInstance();
final Object obj = image_check;
if (!(obj instanceof UnsignedByteType)) {
IJ.error("Error it work only with 8-bit type");
return null;
}
final float Nf = findNaturalizationFactor(image_orig, Theta, T2_prior);
result[0] = Nf;
final Img<T> image_result = naturalizeImage(image_orig, Nf, cls_t);
return image_result;
}
private <S extends RealType<S>, T extends NumericType<T> & NativeType<T> & RealType<T>>
Img<T> naturalizeImage(Img<T> image_orig, float Nf, Class<T> cls_t)
throws InstantiationException, IllegalAccessException
{
// Mean of the original image
// S mean_original = cls_s.newInstance();
// Mean<T,S> m = new Mean<T,S>();
// m.compute(image_orig.cursor(), mean_original);
// TODO: quick fix for deprecated code above. Is new 'mean' utility introduced in imglib2?
float mean_original = 0.0f;
final Cursor<T> c2 = image_orig.cursor();
float count = 0.0f;
while (c2.hasNext()) {
c2.next();
mean_original += c2.get().getRealFloat();
count += 1.0f;
}
mean_original /= count;
// Create result image
final long[] origImgDimensions = new long[2];
image_orig.dimensions(origImgDimensions);
final Img<T> image_result = image_orig.factory().create(origImgDimensions, cls_t.newInstance());
// for each pixel naturalize
final Cursor<T> cur_orig = image_orig.cursor();
final Cursor<T> cur_ir = image_result.cursor();
while (cur_orig.hasNext()) {
cur_orig.next();
cur_ir.next();
final float tmp = cur_orig.get().getRealFloat();
// Naturalize
float Nat = (int) ((tmp - mean_original)*Nf + mean_original + 0.5);
if (Nat < 0)
{Nat = 0;}
else if (Nat > 255)
{Nat = 255;}
cur_ir.get().setReal(Nat);
}
return image_result;
}
private <S extends RealType<S>, T extends NumericType<T> & NativeType<T> & RealType<T>> float findNaturalizationFactor(Img<T> image_orig, S Theta, float T2prior) {
final ImgFactory<FloatType> imgFactoryF = new ArrayImgFactory<FloatType>();
// Create one dimensional image (Histogram)
final Img<FloatType> LapCDF = imgFactoryF.create(new long[] {N_Lap}, new FloatType());
// Two dimensional image for Gradient
final Img<FloatType> GradCDF = imgFactoryF.create(new long[] {N_Grad, 2}, new FloatType());
// GradientCDF = Integral of the histogram of the of the Gradient field
// LaplacianCDF = Integral of the Histogram of the Laplacian field
final Img<FloatType> GradD = create2DGradientField();
calculateLaplaceFieldAndGradient(image_orig, LapCDF, GradD);
convertGrad2dToCDF(GradD);
calculateGradCDF(GradCDF, GradD);
calculateLapCDF(LapCDF);
// For each channel find the best T1
// EPS=precision
// for X component
float T_tmp = (float)FindT(Views.iterable(Views.hyperSlice(GradCDF, GradCDF.numDimensions()-1 , 0)), N_Grad, Grad_Offset, EPS);
// for Y component
T_tmp += FindT(Views.iterable(Views.hyperSlice(GradCDF, GradCDF.numDimensions()-1 , 1)), N_Grad, Grad_Offset, EPS);
// Average them and divide by the prior parameter
final float T1 = T_tmp/(2*T1_pr);
// Find the best parameter and divide by the T2 prior
final float T2 = (float)FindT(LapCDF, N_Lap, Lap_Offset, EPS)/T2prior;
// Calculate naturalization factor!
final float Nf = (float) ((1.0-Theta.getRealDouble())*T1 + Theta.getRealDouble()*T2);
return Nf;
}
/**
* Calculate the peak SNR from the Naturalization factor
*
* #param Nf naturalization factor
* #return the PSNR
*/
String calculate_PSNR(double x)
{
if (x >= 0 && x <= 0.934)
{
return String.format("%.2f", new Float(23.65 * Math.exp(0.6 * x) - 20.0 * Math.exp(-7.508 * x)));
}
else if (x > 0.934 && x < 1.07)
{
return new String("> 40");
}
else if (x >= 1.07 && x < 1.9)
{
return String.format("%.2f", new Float(-11.566 * x + 52.776));
}
else
{
return String.format("%.2f",new Float(13.06*x*x*x*x - 121.4 * x*x*x + 408.5 * x*x -595.5*x + 349));
}
}
private Img<UnsignedByteType> performNaturalization(Img<UnsignedByteType> channel, float T2_prior, float[] result) {
// Parameters balance between first order and second order
final FloatType Theta = new FloatType(0.5f);
try {
channel = doNaturalization(channel, Theta, UnsignedByteType.class, T2_prior, result);
} catch (final InstantiationException e) {
e.printStackTrace();
} catch (final IllegalAccessException e) {
e.printStackTrace();
}
return channel;
}
// Original data
// N = nuber of bins
// offset of the histogram
// T current
private double FindT_Evalue(float[] p_d, int N, int offset, float T)
{
double error = 0;
for (int i=-offset; i<N-offset; ++i) {
final double tmp = Math.atan(T*(i)) - p_d[i+offset];
error += (tmp*tmp);
}
return error;
}
// Find the T
// data CDF Histogram
// N number of bins
// Offset of the histogram
// eps precision
private double FindT(IterableInterval<FloatType> data, int N, int OffSet, float eps)
{
//find the best parameter between data and model atan(Tx)/pi+0.5
// Search between 0 and 1.0
float left = 0;
float right = 1.0f;
float m1 = 0.0f;
float m2 = 0.0f;
// Crate p_t to save computation (shift and rescale the original CDF)
final float p_t[] = new float[N];
// Copy the data
final Cursor<FloatType> cur_data = data.cursor();
for (int i = 0; i < N; ++i)
{
cur_data.next();
p_t[i] = (float) ((cur_data.get().getRealFloat() - 0.5)*Math.PI);
}
// While the precision is bigger than eps
while (right-left>=eps)
{
// move left and right of 1/3 (m1 and m2)
m1=left+(right-left)/3;
m2=right-(right-left)/3;
// Evaluate on m1 and m2, ane move the extreme point
if (FindT_Evalue(p_t, N, OffSet, m1) <=FindT_Evalue(p_t, N, OffSet, m2)) {
right=m2;
}
else {
left=m1;
}
}
// return the average
return (m1+m2)/2;
}
private Img<FloatType> create2DGradientField() {
final long dims[] = new long[2];
dims[0] = N_Grad;
dims[1] = N_Grad;
final Img<FloatType> GradD = new ArrayImgFactory<FloatType>().create(dims, new FloatType());
return GradD;
}
private void calculateLapCDF(Img<FloatType> LapCDF) {
final RandomAccess<FloatType> Lap_hist2 = LapCDF.randomAccess();
//convert Lap to CDF
for (int i = 1; i < N_Lap; ++i)
{
Lap_hist2.setPosition(i-1,0);
final float prec = Lap_hist2.get().getRealFloat();
Lap_hist2.move(1,0);
Lap_hist2.get().set(Lap_hist2.get().getRealFloat() + prec);
}
}
private void calculateGradCDF(Img<FloatType> GradCDF, Img<FloatType> GradD) {
final RandomAccess<FloatType> Grad_dist = GradD.randomAccess();
// Gradient on x pointer
final IntervalView<FloatType> Gradx = Views.hyperSlice(GradCDF, GradCDF.numDimensions()-1 , 0);
// Gradient on y pointer
final IntervalView<FloatType> Grady = Views.hyperSlice(GradCDF, GradCDF.numDimensions()-1 , 1);
integrateOverRowAndCol(Grad_dist, Gradx, Grady);
scaleGradiens(Gradx, Grady);
}
private void scaleGradiens(IntervalView<FloatType> Gradx, IntervalView<FloatType> Grady) {
final RandomAccess<FloatType> Gradx_r2 = Gradx.randomAccess();
final RandomAccess<FloatType> Grady_r2 = Grady.randomAccess();
//scale, divide the number of integrated bins
for (int i = 0; i < N_Grad; ++i)
{
Gradx_r2.setPosition(i,0);
Grady_r2.setPosition(i,0);
Gradx_r2.get().set((float) (Gradx_r2.get().getRealFloat() / 255.0));
Grady_r2.get().set((float) (Grady_r2.get().getRealFloat() / 255.0));
}
}
private void integrateOverRowAndCol(RandomAccess<FloatType> Grad_dist, IntervalView<FloatType> Gradx, IntervalView<FloatType> Grady) {
final int[] loc = new int[2];
// pGrad2D has 2D CDF
final RandomAccess<FloatType> Gradx_r = Gradx.randomAccess();
// Integrate over the row
for (int i = 0; i < N_Grad; ++i)
{
loc[1] = i;
Gradx_r.setPosition(i,0);
// get the row
for (int j = 0; j < N_Grad; ++j)
{
loc[0] = j;
// Set the position
Grad_dist.setPosition(loc);
// integrate over the row to get 1D vector
Gradx_r.get().set(Gradx_r.get().getRealFloat() + Grad_dist.get().getRealFloat());
}
}
final RandomAccess<FloatType> Grady_r = Grady.randomAccess();
// Integrate over the column
for (int i = 0; i < N_Grad; ++i)
{
loc[1] = i;
Grady_r.setPosition(0,0);
for (int j = 0; j < N_Grad; ++j)
{
loc[0] = j;
Grad_dist.setPosition(loc);
Grady_r.get().set(Grady_r.get().getRealFloat() + Grad_dist.get().getRealFloat());
Grady_r.move(1,0);
}
}
}
private <T extends RealType<T>> void calculateLaplaceFieldAndGradient(Img<T> image, Img<FloatType> LapCDF, Img<FloatType> GradD) {
final RandomAccess<FloatType> Grad_dist = GradD.randomAccess();
final long[] origImgDimensions = new long[2];
image.dimensions(origImgDimensions);
final Img<FloatType> laplaceField = new ArrayImgFactory<FloatType>().create(origImgDimensions, new FloatType());
// Cursor localization
final int[] indexD = new int[2];
final int[] loc_p = new int[2];
final RandomAccess<T> img_cur = image.randomAccess();
final RandomAccess<FloatType> Lap_f = laplaceField.randomAccess();
final RandomAccess<FloatType> Lap_hist = LapCDF.randomAccess();
// Normalization 1/(Number of pixel of the original image)
long n_pixel = 1;
for (int i = 0 ; i < laplaceField.numDimensions() ; i++)
{n_pixel *= laplaceField.dimension(i)-2;}
// unit to sum
final double f = 1.0/(n_pixel);
// Inside the image for Y
final Cursor<FloatType> cur = laplaceField.cursor();
// For each point of the Laplacian field
while (cur.hasNext())
{
cur.next();
// Localize cursors
cur.localize(loc_p);
// Exclude the border
boolean border = false;
for (int i = 0 ; i < image.numDimensions() ; i++)
{
if (loc_p[i] == 0)
{border = true;}
else if (loc_p[i] == image.dimension(i)-1)
{border = true;}
}
if (border == true) {
continue;
}
// get the stencil value;
img_cur.setPosition(loc_p);
float L = -4*img_cur.get().getRealFloat();
// Laplacian
for (int i = 0 ; i < 2 ; i++)
{
img_cur.move(1, i);
final float G_p = img_cur.get().getRealFloat();
img_cur.move(-1,i);
final float G_m = img_cur.get().getRealFloat();
img_cur.move(-1, i);
final float L_m = img_cur.get().getRealFloat();
img_cur.setPosition(loc_p);
L += G_p + L_m;
// Calculate the gradient + convert into bin
indexD[1-i] = (int) (Grad_Offset + G_p - G_m);
}
Lap_f.setPosition(loc_p);
// Set the Laplacian field
Lap_f.get().setReal(L);
// Histogram bin conversion
L += Lap_Offset;
Lap_hist.setPosition((int)(L),0);
Lap_hist.get().setReal(Lap_hist.get().getRealFloat() + f);
Grad_dist.setPosition(indexD);
Grad_dist.get().setReal(Grad_dist.get().getRealFloat() + f);
}
}
private void convertGrad2dToCDF(Img<FloatType> GradD) {
final RandomAccess<FloatType> Grad_dist = GradD.randomAccess();
final int[] loc = new int[GradD.numDimensions()];
// for each row
for (int j = 0; j < GradD.dimension(1); ++j)
{
loc[1] = j;
for (int i = 1; i < GradD.dimension(0) ; ++i)
{
loc[0] = i-1;
Grad_dist.setPosition(loc);
// Precedent float
final float prec = Grad_dist.get().getRealFloat();
// Move to the actual position
Grad_dist.move(1, 0);
// integration up to the current position
Grad_dist.get().set(Grad_dist.get().getRealFloat() + prec);
}
}
//col integration
for (int j = 1; j < GradD.dimension(1); ++j)
{
// Move to the actual position
loc[1] = j-1;
for (int i = 0; i < GradD.dimension(0); ++i)
{
loc[0] = i;
Grad_dist.setPosition(loc);
// Precedent float
final float prec = Grad_dist.get().getRealFloat();
// Move to the actual position
Grad_dist.move(1, 1);
Grad_dist.get().set(Grad_dist.get().getRealFloat() + prec);
}
}
}
/**
* Show information about authors and paper.
*/
private void showMessage()
{
// Create main window with panel to store gui components
final JDialog win = new JDialog((JDialog)null, "Naturalization", true);
final JPanel msg = new JPanel();
msg.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
// Create message not editable but still focusable for copying
final JTextPane text = new JTextPane();
text.setContentType("text/html");
text.setText("<html>Y. Gong and I. F. Sbalzarini. Image enhancement by gradient distribution specification. In Proc. ACCV, <br>"
+ "12th Asian Conference on Computer Vision, Workshop on Emerging Topics in Image Enhancement and Restoration,<br>"
+ "pages w7–p3, Singapore, November 2014.<br><br>"
+ "Y. Gong and I. F. Sbalzarini, Gradient Distributions Priors for Biomedical Image Processing, 2014<br>http://arxiv.org/abs/1408.3300<br><br>"
+ "Y. Gong and I. F. Sbalzarini. A Natural-Scene Gradient Distribution Prior and its Application in Light-Microscopy Image Processing.<br>"
+ "IEEE Journal of Selected Topics in Signal Processing, Vol.10, No.1, February 2016, pages 99-114<br>"
+ "ISSN: 1932-4553, DOI: 10.1109/JSTSP.2015.2506122<br><br>"
+ "</html>");
text.setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));
text.setEditable(false);
msg.add(text);
// Add button "Close" for closing window easily
final JButton button = new JButton("Close");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
win.dispose();
}
});
msg.add(button);
// Finally show window with message
win.add(msg);
win.pack();
win.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
win.setVisible(true);
}
#Override
protected boolean showDialog() {
return true;
}
#Override
protected boolean setup(String aArgs) {
setFilePrefix("naturalized_");
return true;
}
}
I want it to compile it again and get a .class file or a whole .jar file of this plugin.
Which sturcuture and datas I need for get a .class data?
What are with the import files, where i can get the ij, java, javax and net files? In which structure must it be.
I am a novice in Java and only know, that the compiled command is javac.
on linux there is a command to do it which is javac
just : javac HelloWorld.java
it might be the same thing on windows but i am not sure (install a virtual linux box if there is no other way)
If something goes wrong google the error
If you want to compile a Java program from command line you should use the javac command and to invoke it just write java and then the name of your program.
Compiling a file you will have the .class file that you are looking for.
first excuse me for my English it is not strong.
Yesterday a friend tell me about The Sagrada Familia Magic Square that is conformed by 16 numbers in a 4x4 matrix.
According to the creator "Antoni Gaudi" there are 310 possible combinations of 4 number without getting repeated that sums 33 'age at which Jesus died'.
So, i have created a java program using Depth First Search algorithm "just for practice" but i just get 88 combinations, i would like to know if there is anything wrong with my code or if making 310 combinations is not possible.
PDT:"I have searched on internet if it is not possible to make 310 combinations but without lucky".
The program has three classes Nodo, IA, Pila.
"IA is the main part of the project which centralize everything, Nodo is just a Node and Pila is for Stacking purposes"
First, I have divided the matrix 4x4 Sagrada familia in position and values. Position starts at 0 and ends in 15 and each position has a specific values "wath the hastable on IA"
The program creates every possible combination of positions in a DFS way "combinations of four numbers" and then checks if they sum 33.
the value -1 is a special number that means that this position can take any number.
How does it works - tree ('posx','posy','posw','posz')
-1,-1,-1,-1
0,-1,-1,-1 1,-1,-1,-1 . . .
0,1,-1,-1 0,2,-1,-1 . . . 1,0,-1,-1 1,2,-1,-1 . .
0,1,2,-1 . . . . . . . .
0,1,2,3 . . .
Nodo Class
import java.util.Arrays;
/**
*
* #author Vicar
*/
public class Nodo {
private int posx;
private int posy;
private int posw;
private int posz;
private int valx;
private int valy;
private int valw;
private int valz;
public Nodo (){
posx=-1;
posy=-1;
posw=-1;
posz=-1;
valx=-1;
valy=-1;
valw=-1;
valz=-1;
}
public Nodo (int posx, int posy, int posw, int posz, int valx, int valy, int valw, int valz){
this.posx=posx;
this.posy=posy;
this.posw=posw;
this.posz=posz;
this.valx=valx;
this.valy=valy;
this.valw=valw;
this.valz=valz;
}
//returns the sum
public int sumar (){
return valx+valy+valw+valz;
}
//Returns the position of each value
public String retornarPos(){
return posx+","+posy+","+posw+","+posz;
}
//returns the value
public String retornarVal(){
return valx+","+valy+","+valw+","+valz;
}
//Returns the sorted position of the 4 combinations
public String retornarPosOrdenado(){
int [] arreglo ={posx,posy,posw,posz};
Arrays.sort(arreglo);
return arreglo[0]+","+arreglo[1]+","+arreglo[2]+","+arreglo[3];
}
/**
* #return the posx
*/
public int getPosx() {
return posx;
}
/**
* #param posx the posx to set
*/
public void setPosx(int posx) {
this.posx = posx;
}
/**
* #return the posy
*/
public int getPosy() {
return posy;
}
/**
* #param posy the posy to set
*/
public void setPosy(int posy) {
this.posy = posy;
}
/**
* #return the posw
*/
public int getPosw() {
return posw;
}
/**
* #param posw the posw to set
*/
public void setPosw(int posw) {
this.posw = posw;
}
/**
* #return the posz
*/
public int getPosz() {
return posz;
}
/**
* #param posz the posz to set
*/
public void setPosz(int posz) {
this.posz = posz;
}
/**
* #return the valx
*/
public int getValx() {
return valx;
}
/**
* #param valx the valx to set
*/
public void setValx(int valx) {
this.valx = valx;
}
/**
* #return the valy
*/
public int getValy() {
return valy;
}
/**
* #param valy the valy to set
*/
public void setValy(int valy) {
this.valy = valy;
}
/**
* #return the valw
*/
public int getValw() {
return valw;
}
/**
* #param valw the valw to set
*/
public void setValw(int valw) {
this.valw = valw;
}
/**
* #return the valz
*/
public int getValz() {
return valz;
}
/**
* #param valz the valz to set
*/
public void setValz(int valz) {
this.valz = valz;
}
}
Pila class
import java.util.ArrayList;
import java.util.Stack;
/**
*
* #author Vicar
*/
public class Pila {
private Stack <Nodo> pila;
private ArrayList<String> valor;
public Pila (){
pila = new Stack();
valor = new ArrayList<String>();
}
//add a Node to the stack
public void agregar(Nodo nodo){
pila.push(nodo);
valor.add(nodo.retornarPos());
}
//Pops a node from the stack
public Nodo sacar(){
valor.remove(valor.indexOf(pila.peek().retornarPos()));
return pila.pop();
}
// checks if the stack is empty
public boolean estaVacia(){
return pila.isEmpty();
}
// checks if the stack contains an specific node
public boolean contiene(String busqueda){
return valor.contains(busqueda);
}
}
IA Class
import java.util.*;
/**
*
* #author vicar
*/
public class IA {
Hashtable<Integer,Integer> tabla=new Hashtable<Integer,Integer>();
//add the matrix 4,4 to a hastable (pos,val)
public IA(){
tabla.put(0, 1);
tabla.put(1, 14);
tabla.put(2, 14);
tabla.put(3, 4);
tabla.put(4, 11);
tabla.put(5, 7);
tabla.put(6, 6);
tabla.put(7, 9);
tabla.put(8, 8);
tabla.put(9, 10);
tabla.put(10,10);
tabla.put(11, 5);
tabla.put(12, 13);
tabla.put(13, 2);
tabla.put(14, 3);
tabla.put(15, 15);
}
//DFS
public ArrayList<String> busquedaAProfundidad(){
Pila pila = new Pila();
ArrayList <String> visitados = new ArrayList<String>();
ArrayList <Nodo> hijos = new ArrayList<Nodo>();
ArrayList <String> resultado = new ArrayList<String>();
Nodo nodoRaiz = new Nodo();
pila.agregar(nodoRaiz);
//Chsck if the stack is empty
while(!pila.estaVacia()){
Nodo nodo = pila.sacar();
visitados.add(nodo.retornarPos());
//i get every possible children from the node
hijos=crearHijos(nodo);
for (int i = 0; i < hijos.size(); i++) {
//checks that the node is not visited and the sum results in 33
if(!visitados.contains(hijos.get(i).retornarPos()) && !pila.contiene(hijos.get(i).retornarPos())){
if(hijos.get(i).getPosx()!=-1 && hijos.get(i).getPosy()!=-1 && hijos.get(i).getPosw()!=-1 && hijos.get(i).getPosz()!=-1 && hijos.get(i).sumar()==33 ){
//this is the final result without repeted numbers
if(!resultado.contains(hijos.get(i).retornarPosOrdenado())){
resultado.add(hijos.get(i).retornarPosOrdenado());
}
}
else{
//System.err.println("pos: "+hijos.get(i).retornarPosOrdenado());
pila.agregar(hijos.get(i));
}
}
}
}
return resultado;
}
// method to create children from a father node
public ArrayList<Nodo> crearHijos(Nodo padre){
ArrayList <Nodo> hijos = new ArrayList<Nodo>();
//positions of the father
int x = padre.getPosx();
int y = padre.getPosy();
int w = padre.getPosw();
int z = padre.getPosz();
if (x==-1 && y==-1 && w==-1 && z==-1){
for (int i = 0; i < 16; i++) {
hijos.add(new Nodo(i,-1,-1,-1,tabla.get(i),-1,-1,-1));
}
return hijos;
}
else if(x>=0 && y==-1 && w==-1 && z==-1){
for (int i = 0; i < 16; i++) {
if (x != i){
hijos.add(new Nodo(x,i,-1,-1,tabla.get(x),tabla.get(i),-1,-1));
}
}
}
else if(x>=0 && y>=0 && w==-1 && z==-1){
for (int i = 0; i < 16; i++) {
if (x != i && y != i){
hijos.add(new Nodo(x,y,i,-1,tabla.get(x),tabla.get(y),tabla.get(i),-1));
}
}
}
else if(x>=0 && y>=0 && w>=0 && z==-1){
for (int i = 0; i < 16; i++) {
if (x != i && y != i && w !=i){
hijos.add(new Nodo(x,y,w,i,tabla.get(x),tabla.get(y),tabla.get(w),tabla.get(i)));
}
}
}
return hijos;
}
}
a final class to check the result and send the output to a txt file
import java.util.ArrayList;
import java.io.File;
import java.io.FileWriter;
/**
*
* #author vicar
*/
public class Probador {
public static void main(String[] args) {
IA run = new IA();
ArrayList<String> resultado = run.busquedaAProfundidad();
try {
File archivo = new File("/tmp/gaudi.in");
FileWriter escribir = new FileWriter(archivo, true);
for (String resul : resultado) {
escribir.write(resul+"\n");
}
escribir.close();
}
catch (Exception e) {
System.out.println("Error al escribir");
}
}
}
Thanks!!!
The number 310 refers to the number of combinations of any size taking elements from the matrix (without picking the same cell twice). See https://blog.sagradafamilia.org/en/divulgation/the-magic-square-the-passion-facade-keys-to-understanding-it/
Here are the seventeen possible combinations of three numbers: [...]
With four numbers, there are 88 possible combinations that add up to
33; with five, there are 131; and with six, 66. With seven numbers,
there are eight different combinations:...
17 + 88 + 131 + 66 + 8 = 310
Im currently trying to do an exercise for upcoming exam. But unfortunately he is already asleep and I have an exam tomorrow.
this is my code that I have done. Im not sure what to do with resetSpeed and I think there is also something wrong in trying to calculate timeToTravel method
package comp6700.mse;
/**
* COMP6700 Mid-Semester Exam, Question 3
*/
public class Q3Plane {
private String name;
private int speed;
private int distance;
private int time;
/**
* Constructor
*
* #param name The name of the plane
* #param speed The speed of the plane (in km/h),
*/
Q3Plane(String name, int speed) {
this.name = name;
this.speed = speed;
}
/** Return the speed of the plane */
int getSpeed() {
return this.speed;
}
/**
* Reset the speed of the plane according to the argument speed
* #param speed The new speed of the plane
*/
void resetSpeed(int speed) {this.speed = speed;}
/**
* Calculate the time to travel the specified distance at the current speed.
* #param distance The distance (in km)
* #return The time to travel the distance (in minutes)
*/
int timeToTravel(int distance) {
this.distance = distance;
this.time = time;
time = distance/speed;
return time ;
}
/**
* Return a string describing the plane and its speed,
* in the format
* "Plane NAME is travelling S km/h"
* where NAME is replaced by the plane's name, and S is replaced by
* the plane's speed.
*
* #return A string describing the plane and its speed
*/
#Override
public String toString() {
return ("Plane"+" "+name+" "+ "is travelling" +" " +speed+ " " + "km/h");
}
}
the error that i got is this
java.lang.AssertionError: Expected time of '42', but got '0'
updated: test case
public class Q3PlaneTest {
static final int DEFAULT_ITERATIONS = 10;
#Test
public void testGetSpeed() {
Random r = new Random();
for (int i = 0; i < DEFAULT_ITERATIONS; i++) {
String name = "NA"+r.nextInt(10000);
int speed = 600+r.nextInt(400);
Q3Plane p = new Q3Plane(name, speed);
int s = p.getSpeed();
assertTrue("Expected speed of '"+speed+"', but got '"+s+"'", s == speed );
}
}
#Test
public void testSetSpeed() {
Random r = new Random();
String name = "NA"+r.nextInt(10000);
int speed = 600+r.nextInt(400);
Q3Plane p = new Q3Plane(name, speed);
for (int i = 0; i < DEFAULT_ITERATIONS; i++) {
speed = 600+r.nextInt(400);
p.resetSpeed(speed);
int s = p.getSpeed();
assertTrue("Expected speed of '"+speed+"', but got '"+s+"'", s == speed );
}
}
#Test
public void testTimeToTravel() {
Random r = new Random();
String name = "NA"+r.nextInt(10000);
int s = 600+r.nextInt(400);
Q3Plane p = new Q3Plane(name, s);
for (int i = 0; i < DEFAULT_ITERATIONS; i++) {
s = 600+r.nextInt(400);
int d = 300+r.nextInt(500);
p.resetSpeed(s);
int t = p.timeToTravel(d);
int rt = (60 * d) / s;
assertTrue("Expected time of '"+rt+"', but got '"+t+"'", t == rt );
}
}
You are dividing long by an int and storing that value in an int type variable. Java will round down as you've told the JVM you want type int to hold time. You should use double instead.
Plane Class
public class Q3Plane {
private String name; // name of plane
private double speed; // km per hour
Q3Plane(String name, double speed) {
this.name = name;
this.speed = speed;
}
public double getSpeed() {
return this.speed;
}
public void setSpeed(double speed) {
this.speed = speed;
}
public double timeToTravel(int distance) {
return ((distance/this.speed) * 60);
}
}
Unit Test
public class Q3PlaneTest {
#Test
public void testTimeToTravel() {
Q3Plane plane = new Q3Plane("TESTPLANE", 500);
double timeInMinutes = plane.timeToTravel(1000);
System.out.println(timeInMinutes);
assertTrue(timeInMinutes == 120d);
}
}
Update:
The unit test that was provided doesn't really make sense in real world. There is no guarantee that the division operation would not result in a non whole number. Using int makes no sense as in the real world you would not always being going whole number distance or speeds.
It turns out to be really simple
the answer is
time = (60*distance)/speed
I am trying to use a third party java class code and I get this error
Cannot resolve method "getInstance()"
and
Cannot resolve symbol "INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH"
Does anyone know how to solve this?
Error Image:
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.hardware.input.InputManager;
import android.os.SystemClock;
import android.util.Log;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.MotionEvent;
import java.util.HashMap;
import java.util.Map;
/**
* Command that sends key events to the device, either by their keycode, or by
* desired character output.
*/
public class Input {
private static final String TAG = "Input";
private static final String INVALID_ARGUMENTS = "Error: Invalid arguments for command: ";
private static final Map<String, Integer> SOURCES = new HashMap<String, Integer>() {{
put("keyboard", InputDevice.SOURCE_KEYBOARD);
put("dpad", InputDevice.SOURCE_DPAD);
put("gamepad", InputDevice.SOURCE_GAMEPAD);
put("touchscreen", InputDevice.SOURCE_TOUCHSCREEN);
put("mouse", InputDevice.SOURCE_MOUSE);
put("stylus", InputDevice.SOURCE_STYLUS);
put("trackball", InputDevice.SOURCE_TRACKBALL);
put("touchpad", InputDevice.SOURCE_TOUCHPAD);
put("touchnavigation", InputDevice.SOURCE_TOUCH_NAVIGATION);
put("joystick", InputDevice.SOURCE_JOYSTICK);
}};
/**
* Command-line entry point.
*
* #param args The command-line arguments
*/
public static void main(String[] args) {
(new Input()).run(args);
}
private void run(String[] args) {
if (args.length < 1) {
showUsage();
return;
}
int index = 0;
String command = args[index];
int inputSource = InputDevice.SOURCE_UNKNOWN;
if (SOURCES.containsKey(command)) {
inputSource = SOURCES.get(command);
index++;
command = args[index];
}
final int length = args.length - index;
try {
if (command.equals("text")) {
if (length == 2) {
inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
sendText(inputSource, args[index+1]);
return;
}
} else if (command.equals("keyevent")) {
if (length >= 2) {
final boolean longpress = "--longpress".equals(args[index + 1]);
final int start = longpress ? index + 2 : index + 1;
inputSource = getSource(inputSource, InputDevice.SOURCE_KEYBOARD);
if (length > start) {
for (int i = start; i < length; i++) {
int keyCode = KeyEvent.keyCodeFromString(args[i]);
if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
keyCode = KeyEvent.keyCodeFromString("KEYCODE_" + args[i]);
}
sendKeyEvent(inputSource, keyCode, longpress);
}
return;
}
}
} else if (command.equals("tap")) {
if (length == 3) {
inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
sendTap(inputSource, Float.parseFloat(args[index+1]),
Float.parseFloat(args[index+2]));
return;
}
} else if (command.equals("swipe")) {
int duration = -1;
inputSource = getSource(inputSource, InputDevice.SOURCE_TOUCHSCREEN);
switch (length) {
case 6:
duration = Integer.parseInt(args[index+5]);
case 5:
sendSwipe(inputSource,
Float.parseFloat(args[index+1]), Float.parseFloat(args[index+2]),
Float.parseFloat(args[index+3]), Float.parseFloat(args[index+4]),
duration);
return;
}
} else if (command.equals("press")) {
inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
if (length == 1) {
sendTap(inputSource, 0.0f, 0.0f);
return;
}
} else if (command.equals("roll")) {
inputSource = getSource(inputSource, InputDevice.SOURCE_TRACKBALL);
if (length == 3) {
sendMove(inputSource, Float.parseFloat(args[index+1]),
Float.parseFloat(args[index+2]));
return;
}
} else {
System.err.println("Error: Unknown command: " + command);
showUsage();
return;
}
} catch (NumberFormatException ex) {
}
System.err.println(INVALID_ARGUMENTS + command);
showUsage();
}
/**
* Convert the characters of string text into key event's and send to
* device.
*
* #param text is a string of characters you want to input to the device.
*/
private void sendText(int source, String text) {
StringBuffer buff = new StringBuffer(text);
boolean escapeFlag = false;
for (int i=0; i<buff.length(); i++) {
if (escapeFlag) {
escapeFlag = false;
if (buff.charAt(i) == 's') {
buff.setCharAt(i, ' ');
buff.deleteCharAt(--i);
}
}
if (buff.charAt(i) == '%') {
escapeFlag = true;
}
}
char[] chars = buff.toString().toCharArray();
KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
KeyEvent[] events = kcm.getEvents(chars);
for(int i = 0; i < events.length; i++) {
KeyEvent e = events[i];
if (source != e.getSource()) {
e.setSource(source);
}
injectKeyEvent(e);
}
}
private void sendKeyEvent(int inputSource, int keyCode, boolean longpress) {
long now = SystemClock.uptimeMillis();
injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
if (longpress) {
injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 1, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_LONG_PRESS,
inputSource));
}
injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, 0,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
}
private void sendTap(int inputSource, float x, float y) {
long now = SystemClock.uptimeMillis();
injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x, y, 1.0f);
injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x, y, 0.0f);
}
private void sendSwipe(int inputSource, float x1, float y1, float x2, float y2, int duration) {
if (duration < 0) {
duration = 300;
}
long now = SystemClock.uptimeMillis();
injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f);
long startTime = now;
long endTime = startTime + duration;
while (now < endTime) {
long elapsedTime = now - startTime;
float alpha = (float) elapsedTime / duration;
injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha),
lerp(y1, y2, alpha), 1.0f);
now = SystemClock.uptimeMillis();
}
injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x2, y2, 0.0f);
}
/**
* Sends a simple zero-pressure move event.
*
* #param inputSource the InputDevice.SOURCE_* sending the input event
* #param dx change in x coordinate due to move
* #param dy change in y coordinate due to move
*/
private void sendMove(int inputSource, float dx, float dy) {
long now = SystemClock.uptimeMillis();
injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, dx, dy, 0.0f);
}
private void injectKeyEvent(KeyEvent event) {
Log.i(TAG, "injectKeyEvent: " + event);
InputManager.getInstance().injectInputEvent(event,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
private int getInputDeviceId(int inputSource) {
final int DEFAULT_DEVICE_ID = 0;
int[] devIds = InputDevice.getDeviceIds();
for (int devId : devIds) {
InputDevice inputDev = InputDevice.getDevice(devId);
if (inputDev.supportsSource(inputSource)) {
return devId;
}
}
return DEFAULT_DEVICE_ID;
}
/**
* Builds a MotionEvent and injects it into the event stream.
*
* #param inputSource the InputDevice.SOURCE_* sending the input event
* #param action the MotionEvent.ACTION_* for the event
* #param when the value of SystemClock.uptimeMillis() at which the event happened
* #param x x coordinate of event
* #param y y coordinate of event
* #param pressure pressure of event
*/
private void injectMotionEvent(int inputSource, int action, long when, float x, float y, float pressure) {
final float DEFAULT_SIZE = 1.0f;
final int DEFAULT_META_STATE = 0;
final float DEFAULT_PRECISION_X = 1.0f;
final float DEFAULT_PRECISION_Y = 1.0f;
final int DEFAULT_EDGE_FLAGS = 0;
MotionEvent event = MotionEvent.obtain(when, when, action, x, y, pressure, DEFAULT_SIZE,
DEFAULT_META_STATE, DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y,
getInputDeviceId(inputSource), DEFAULT_EDGE_FLAGS);
event.setSource(inputSource);
Log.i(TAG, "injectMotionEvent: " + event);
InputManager.getInstance().injectInputEvent(event,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
private static final float lerp(float a, float b, float alpha) {
return (b - a) * alpha + a;
}
private static final int getSource(int inputSource, int defaultSource) {
return inputSource == InputDevice.SOURCE_UNKNOWN ? defaultSource : inputSource;
}
private void showUsage() {
System.err.println("Usage: input [<source>] <command> [<arg>...]");
System.err.println();
System.err.println("The sources are: ");
for (String src : SOURCES.keySet()) {
System.err.println(" " + src);
}
System.err.println();
System.err.println("The commands and default sources are:");
System.err.println(" text <string> (Default: touchscreen)");
System.err.println(" keyevent [--longpress] <key code number or name> ..."
+ " (Default: keyboard)");
System.err.println(" tap <x> <y> (Default: touchscreen)");
System.err.println(" swipe <x1> <y1> <x2> <y2> [duration(ms)]"
+ " (Default: touchscreen)");
System.err.println(" press (Default: trackball)");
System.err.println(" roll <dx> <dy> (Default: trackball)");
}
}
I suspect you're building against the SDK, not against AOSP. The getInstance() method is hidden (note the #hide here). This means the method is not included in the android.jar file applications are built against.
You'll either need to access the method via reflection, or build against AOSP.
I guess you used wrong import, can you check if you imported InputManager from correct package, and that is not error , it just compilation error as your IDE couldn't find the references