Related
I'm trying to create a screen full of 16x16 floor tiles using ImageIcons, JLabels, and a JPanel. My issue is that whenever I try to display these tiles using a 2D array, - even when looping the drawing method repeatedly - they don't display entirely. Rather, they only display a few tiles as opposed to the full arrays worth. Furthermore, the number of displayed tiles changes each time I run the program!
Here's the code I'm using:
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class JFrameTest {
static BufferedImage buf;
static JPanel panel;
public static void main(String[] args) {
createWindow();
loadImage();
showImage();
}
public static void createWindow() {
JFrame frame = new JFrame();
panel = new JPanel();
frame.setSize(1000, 1000);
frame.setTitle("Tester");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.add(panel);
frame.setVisible(true);
panel.setLayout(null);
}
public static void loadImage() {
try {
buf = ImageIO.read(new File("res/test.png"));
} catch (IOException ex) {
System.out.println("NOT FOUND");
}
}
public static void showImage() {
final int[][] MAP =
{
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1}
};
ImageIcon test = new ImageIcon(buf);
panel.setBackground(Color.WHITE);
System.out.println(test.getIconWidth());
System.out.println(test.getIconHeight());
JLabel[][] labelGrid = new JLabel[MAP.length][MAP[0].length];
for (int r = 0; r < labelGrid.length; r++) {
for (int c = 0; c < labelGrid[r].length; c++) {
labelGrid[r][c] = new JLabel();
labelGrid[r][c].setSize(test.getIconWidth(), test.getIconWidth());
labelGrid[r][c].setLocation(test.getIconWidth() * r, test.getIconHeight() * c);
labelGrid[r][c].setIcon(test);
panel.add(labelGrid[r][c]);
}
}
panel.revalidate();
}
}
Here about what's normally printed:
It seems that the program just gives up in displaying the images. However, note that the number of displayed images changes every time! Some times only five images may appear, other times 22.
When I try using a smaller map such as:,
final int[][] MAP =
{
{1, 1, 1},
{1, 1, 1},
{1, 1, 1}
};
the entire 3x3 grid of images will appear about half the time, only one or two images being displayed the other half.
What work around can be implemented to solve this problem?
Computer specs:
Windows 10
i8-8700
1080 ti
16gb ram
Your basic problem is one of misunderstanding ... and welcome to my world 🙄
Using panel.setLayout(null); means you are taking full responsibility for the layout, which is fine, when you know what you are doing.
Compound that with calling setVisible before you've established the UI and using revalidate which is used to run a layout pass and you're setting yourself up for trouble.
Instead of revalidate, you should be using repaint, to trigger a new paint pass (note, in the normal course of events, you should use both when updating the the UI, but since you're no longer using a layout manager, you don't need revalidate)
Possibly a better solution is to use a custom painting route, for example...
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
protected static final int[][] MAP
= {
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1}
};
protected static Dimension GRID_SIZE = new Dimension(20, 20);
private Rectangle buf; // This represents your image
private Dimension preferredSize;
public TestPane() {
buf = new Rectangle(0, 0, GRID_SIZE.width, GRID_SIZE.height);
int max = 0;
for (int row = 0; row < MAP.length; row++) {
max = Math.max(max, MAP[row].length);
}
preferredSize = new Dimension(GRID_SIZE.width * MAP.length, GRID_SIZE.height * max);
}
#Override
public Dimension getPreferredSize() {
return preferredSize;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (int row = 0; row < MAP.length; row++) {
for (int col = 0; col < MAP[row].length; col++) {
int x = GRID_SIZE.width * row;
int y = GRID_SIZE.height * col;
Graphics2D translated = (Graphics2D) g2d.create();
translated.translate(x, y);
translated.draw(buf);
translated.dispose();
}
}
g2d.dispose();
}
}
}
GridLayout
Another option is to use GridLayout
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
protected static final int[][] MAP
= {
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1}
};
protected static Dimension GRID_SIZE = new Dimension(20, 20);
private BufferedImage buf; // This represents your image
public TestPane() {
int max = 0;
for (int row = 0; row < MAP.length; row++) {
max = Math.max(max, MAP[row].length);
}
setLayout(new GridLayout(MAP.length, max));
buf = makeBuffer();
for (int row = 0; row < MAP.length; row++) {
for (int col = 0; col < MAP[row].length; col++) {
add(new JLabel(new ImageIcon(buf)));
}
}
}
protected BufferedImage makeBuffer() {
BufferedImage img = new BufferedImage(GRID_SIZE.width, GRID_SIZE.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.DARK_GRAY);
g2d.drawRect(0, 0, img.getWidth() - 1, img.getHeight() - 1);
g2d.dispose();
return img;
}
}
}
but this will resize the cells, which might not be desirable in which you could use a ...
GridBagLayout
This will honour the preferred size of the components better and, based on the way it's currently configured, won't resize the components when the window size changes
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
protected static final int[][] MAP
= {
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1}
};
protected static Dimension GRID_SIZE = new Dimension(20, 20);
private BufferedImage buf; // This represents your image
public TestPane() {
int max = 0;
for (int row = 0; row < MAP.length; row++) {
max = Math.max(max, MAP[row].length);
}
setLayout(new GridBagLayout());
buf = makeBuffer();
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridy = 0;
for (int row = 0; row < MAP.length; row++) {
gbc.gridx = 0;
for (int col = 0; col < MAP[row].length; col++) {
add(new JLabel(new ImageIcon(buf)), gbc);
gbc.gridx++;
}
gbc.gridy++;
}
}
protected BufferedImage makeBuffer() {
BufferedImage img = new BufferedImage(GRID_SIZE.width, GRID_SIZE.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.DARK_GRAY);
g2d.drawRect(0, 0, img.getWidth() - 1, img.getHeight() - 1);
g2d.dispose();
return img;
}
}
}
So I have a method that takes in a size of an array. My method makes half the array 0's.
int [] arrary2 = new int[arraySize];
for(int i = 0; i < arraySize/2; i++){
arr2[i] = 0;
}
//do rest of code?
return array2;
How do I make the half of the last half my array into 1's and so on.
For example an array of size 14, but the array size could be any size?
[0,0,0,0,0,0,0,1,1,1,1,2,2,3]
Rough algorithm:
Calculate half what's left to do (be careful with odd / even)
Fill that with the current value
Repeat
Sample code:
public static int[] createArray(int size)
{
int[] array = new int[size];
int half = (size / 2) + (size % 2);
int index = half;
int value = 0;
for (int i = 0; i < size; i++) {
if (i == index) {
half = (half / 2) + (half % 2);
index += half;
value++;
}
array[i] = value;
}
return array;
}
Sample output:
15 => 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3
14 => 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3
Here's one way:
import java.util.Arrays;
public class Main {
static int[] createArray(int size) {
int[] result = new int[size];
int limit = (size + 1) / 2;
int start = 0, value = 0, idx = 0;
do {
for (int i = start; i < start + limit && idx < size; ++i)
result[idx++] = value;
start += limit;
limit = (limit + 1) / 2;
++value;
} while (idx < size);
return result;
}
public static void main(String[] args) {
int[] result = createArray(70);
System.out.println(Arrays.toString(result));
}
}
A couple of tests:
14 => [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3]
70 => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4]
To do this keep track of where you want the input value to change, the input value and also how many inserts you want to perform until the next change.
int[] arrary2 = new int[arraySize];
int currentEndPoint = (arraySize / 2) + (arraySize % 2);
int endPointIncrement = currentEndPoint;
int currentInputValue = 0;
for (int i = 0; i < arraySize; i++)
{
if (i == currentEndPoint - 1)
{
currentInputValue++;
endPointIncrement = (endPointIncrement / 2) + (endPointIncrement % 2);
currentEndPoint = currentEndPoint + endPointIncrement;
}
arrary2[i] = currentInputValue;
}
return arrary2;
Hope this helps
Currently I have a 2D array, with values of 1 or 0. I hard coded 0 and 1's in their position in the array as i need them in this sequences.
//{ { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },N
// { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 },S
// { 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1 }, W
// { 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0 } };E
Is there a better solution to do this instead of placing each value of the array exactly like in the example above. As if i had to do this for 100 X 100 array it would be take several days
The code below will create your desired data structure when provided. This is a highly efficient solution.
We know that the first (1st) dimension will always be four, since North, South, West, and East are the only directions. The second (2nd) dimension will be calculated as the square of n.
After we have established the dimensions of the matrix and initialized it, we can begin to iterated over the range of 0 to the square of n.
Code
public int[][] generateDirectionalMatrix(int n) {
int sq = Math.pow(n, 2); // 2nd Dimension
int[][] matrix = new int[4][sq];
int top = n; // Top
int rgt = n - 1; // Right
int bot = sq - rgt; // Bottom
int lft = 0; // Left
for (int idx = 0; idx < sq; idx++) {
int col = idx % n; // Column
matrix[0][i] = idx < top ? 0 : 1; // North
matrix[1][i] = idx > bot ? 0 : 1; // South
matrix[2][i] = col == lft ? 0 : 1; // West
matrix[3][i] = col == rgt ? 0 : 1; // East
}
return matrix;
}
generateDirectionalMatrix(100) // Generates 4 x 10,000 (100 x 100) matrix.
Output
This is the output of a matrix where n = 5, as provided in your question.
{ // Structure: 4 x 25 (5 x 5)
{ // North
0, 0, 0, 0, 0,
1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
1, 1, 1, 1, 1
}, { // South
1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
0, 0, 0, 0, 0
}, { // West
0, 1, 1, 1, 1,
0, 1, 1, 1, 1,
0, 1, 1, 1, 1,
0, 1, 1, 1, 1,
0, 1, 1, 1, 1
}, { // East
1, 1, 1, 1, 0,
1, 1, 1, 1, 0,
1, 1, 1, 1, 0,
1, 1, 1, 1, 0,
1, 1, 1, 1, 0
}
};
Example
I ported the code above to JavaScript for a live demo.
The following code creates a 4 x 64 (8 x 8) matrix.
var dir = 'North,South,West,East'.split(',');
var n = 8;
var sq = Math.pow(n, 2);
var matrix = [[], [], [], []];
for (var i = 0; i < sq; i++) {
matrix[0].push(i < n ? 0 : 1); // North
matrix[1].push(i >= sq-n ? 0 : 1); // South
matrix[2].push(i % n === 0 ? 0 : 1); // West
matrix[3].push(i % n === n-1 ? 0 : 1); // East
}
// Display
for (var row = 0; row < matrix.length; row++) {
var div = document.createElement('div');
div.className += ' dir';
div.innerHTML = dir[row] + '\n' + Array(n*2).join('-') + '\n';
for (var col = 0; col < matrix[row].length; col++) {
div.innerHTML += matrix[row][col] + (col % n === n-1 ? '\n' : ' ');
}
document.body.appendChild(div);
}
.dir {
float: left;
padding: 4px;
margin: 2px;
background: #E7E7E7;
border: thin solid black;
font-family: monospace;
font-size: 12px;
white-space: pre;
}
you want like this
count=0;
for(i=0;i<=4;i++)
{
for(j=0;j<=25;j++)
{
if(i==0)
{
if(j>5)
a[i][j]=0;
else
a[i][j]=1;
}
else if(i==1)
{
if(j<19)
a[i][j]=0;
else
a[i][j]=1;
}
else if(i==2)
{
if(count==0)
{
a[i][j]=0;
}
else
a[i][j]=1;
if(count==4)
count=0;
else
count=count+1;
}
else if(i==3)
{
if(count==4)
{
a[i][j]=0;
}
else
a[i][j]=1;
if(count==4)
count=0;
else
count=count+1;
}
}
}
I'm trying to implement an A* algorithm for a pathfinding problem.
It works, like 9 out of 10 times, but at some points I get a (possibly) infinite loop, and the program doesn't find the optimal path. Can you see why it happens?
A*:
import java.util.*;
public abstract class AStar<T>
{
private class Path implements Comparable{
public T point;
public Double f;
public Double g;
public Path parent;
public Path(){
parent = null;
point = null;
g = f = 0.0;
}
public Path(Path p){
this();
parent = p;
g = p.g;
f = p.f;
}
public int compareTo(Object o){
Path p = (Path)o;
return (int)(f - p.f);
}
public T getPoint(){
return point;
}
public void setPoint(T p){
point = p;
}
}
protected abstract boolean isGoal(T node);
protected abstract Double g(T from, T to);
protected abstract Double h(T from, T to);
protected abstract List<T> generateSuccessors(T node);
private PriorityQueue<Path> paths;
private HashMap<T, Double> mindists;
private Double lastCost;
private int expandedCounter;
public int getExpandedCounter(){
return expandedCounter;
}
public AStar(){
paths = new PriorityQueue<Path>();
mindists = new HashMap<T, Double>();
expandedCounter = 0;
lastCost = 0.0;
}
protected Double f(Path p, T from, T to){
Double g = g(from, to) + ((p.parent != null) ? p.parent.g : 0.0);
Double h = h(from, to);
p.g = g;
p.f = g + h;
return p.f;
}
private void expand(Path path){
T p = path.getPoint();
Double min = mindists.get(path.getPoint());
if(min == null || min.doubleValue() > path.f.doubleValue())
mindists.put(path.getPoint(), path.f);
else
return;
List<T> successors = generateSuccessors(p);
for(T t : successors){
Path newPath = new Path(path);
newPath.setPoint(t);
f(newPath, path.getPoint(), t);
paths.offer(newPath);
}
expandedCounter++;
}
public Double getCost(){
return lastCost;
}
public List<T> compute(T start){
try{
Path root = new Path();
root.setPoint(start);
/* Needed if the initial point has a cost. */
f(root, start, start);
expand(root);
for(;;){
Path p = paths.poll();
if(p == null){
lastCost = Double.MAX_VALUE;
return null;
}
T last = p.getPoint();
lastCost = p.g;
if(isGoal(last)){
LinkedList<T> retPath = new LinkedList<T>();
for(Path i = p; i != null; i = i.parent){
retPath.addFirst(i.getPoint());
}
return retPath;
}
expand(p);
}
}
catch(Exception e){
e.printStackTrace();
}
return null;
}
}
And the pathfinding class with the main:
import java.util.*;
public class PathFinder extends AStar<PathFinder.Node>
{
private int[][] map;
private int endx;
private int endy;
public static class Node{
public int x;
public int y;
Node(int x, int y){
this.x = x;
this.y = y;
}
public String toString(){
return "(" + x + ", " + y + ") ";
}
public int getX(){
return x;
}
public int getY(){
return y;
}
} public PathFinder(int[][] map, int endx, int endy){
this.map = map;
this.endx=endx;
this.endy=endy;
}
protected boolean isGoal(Node node){
return (node.x == endx) && (node.y == endy);
}
protected Double g(Node from, Node to){
if(from.x == to.x && from.y == to.y){
// System.out.println("To x1 " + to.x);
// System.out.println("To y1 " + to.y);
return 0.0;}
if(map[to.y][to.x] == 1){
//System.out.println("To x2 " + to.x);
// System.out.println("To y2 " + to.y);
return 1.0;}
return Double.MAX_VALUE;
}
protected Double h(Node from, Node to){
return new Double(Math.abs(endx - to.x) + Math.abs(endy - to.y));
}
protected List<Node> generateSuccessors(Node node){
List<Node> ret = new LinkedList<Node>();
int x = node.x;
int y = node.y;
if(y < map[0].length-1 && map[y+1][x] == 1)
ret.add(new Node(x, y+1));
if(x <map.length-1 && map[y][x+1] == 1)
ret.add(new Node(x+1, y));
if(y !=0 && map[y-1][x] == 1)
ret.add(new Node(x, y-1));
if(x !=0 && map[y][x-1] == 1)
ret.add(new Node(x-1, y));
return ret;
}
public static void main(String [] args){
WorldGenerator gen = new WorldGenerator();
int ammountOfBlocks =200;
int width = 25;
int length = 25;
int startX = 1;
int startY = 1;
int endX = 24;
int endY = 24;
int[][] map = gen.createWorld(ammountOfBlocks,width,length,startX,startY,endX,endY);
int a=map.length;
int b=map[0].length;
int[][] map2=new int[b][a];
for(int i=0; i<map.length; i++){
for(int j=0; j<map[0].length;j++)
{map2[j][i]=map[i][j];
}
}
PathFinder pf = new PathFinder(map,endX,endY);
/* for(int i = 0; i < map.length; i++){
for(int j = 0; j < map[0].length; j++)
System.out.print(map[i][j] + " ");
System.out.println();
}*/
long begin = System.currentTimeMillis();
List<Node> nodes = pf.compute(new PathFinder.Node(startX,startY));
long end = System.currentTimeMillis();
System.out.println("Time = " + (end - begin) + " ms" );
//System.out.println("Expanded = " + pf.getExpandedCounter());
System.out.println("Cost = " + pf.getCost());
if(nodes == null)
System.out.println("No path");
else{
for(int i=0; i<nodes.size();i++){
Node n=nodes.get(i);
int x= n.getX();
int y= n.getY();
map[x][y]=4;
}
/* for(int i = 0; i < map.length; i++){
for(int j = 0; j < map[0].length; j++)
System.out.print(map[i][j] + " ");
System.out.println();
}*/
}
}
}
the WorldGenerator class only generates a 2 dimensional array of 1s and 0s.
Thanks in advance!
Shooting from my hip here, but if you want to use a 'direct line distance' as your heuristic you have a bug in your code.
The current heuristic is: The node with the smallest sum of delta x and y is closest.
Let's say we have a five x five grid and the target is in 2,2 then using this heuristic 2,0 would be equally optimal as 1,1 which of course is wrong.
Try using Pythagoras for a new heuristic: The node with the shortest distance to the end is the closest.
protected Double h(Node from, Node to) {
int dx = Math.abs(endx - to.x);
int dy = Math.abs(endy - to.y);
return new Double(Math.sqrt(dx*dx) + (dy*dy));
}
This would make your algorithm use an http://en.wikipedia.org/wiki/Admissible_heuristic which is a criteria for A*: http://en.wikipedia.org/wiki/A_star#Admissibility_and_optimality
Hope this helps.
A solution that works for me:
AStar.java
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.PriorityQueue;
public abstract class AStar<T> {
private class Path<T> implements Comparable {
public T point;
public Double f;
public Double g;
public Path<T> parent;
public Path() {
parent = null;
point = null;
g = f = 0.0;
}
public Path(Path<T> p) {
this();
parent = p;
g = p.g;
f = p.f;
}
#Override
public int compareTo(Object o) {
AStar.Path p = (AStar.Path) o;
return (int) (f - p.f);
}
public T getPoint() {
return point;
}
public void setPoint(T p) {
point = p;
}
}
protected abstract boolean isGoal(T node);
protected abstract Double g(T from, T to);
protected abstract Double h(T from, T to);
protected abstract List<T> generateSuccessors(T node, T parent);
private PriorityQueue<AStar.Path> paths;
private HashMap<T, Double> mindists;
private Double lastCost;
private int expandedCounter;
public int getExpandedCounter() {
return expandedCounter;
}
public AStar() {
paths = new PriorityQueue<>();
mindists = new HashMap<>();
expandedCounter = 0;
lastCost = 0.0;
}
protected Double f(AStar.Path p, T from, T to) {
Double g = g(from, to) + ((p.parent != null) ? p.parent.g : 0.0);
Double h = h(from, to);
p.g = g;
p.f = g + h;
return p.f;
}
private void expand(Path<T> path) {
if (expandedCounter > 1000000) {
return;
}
T p = path.getPoint();
Double min = mindists.get(path.getPoint());
if (min == null || min.doubleValue() > path.f.doubleValue()) {
mindists.put(path.getPoint(), path.f);
} else {
return;
}
List<T> successors = generateSuccessors(p, path.parent != null ? path.parent.getPoint() : null);
for (T t : successors) {
AStar.Path newPath = new AStar.Path(path);
newPath.setPoint(t);
f(newPath, path.getPoint(), t);
paths.offer(newPath);
}
expandedCounter++;
}
public Double getCost() {
return lastCost;
}
public List<T> compute(T start) {
try {
AStar.Path root = new AStar.Path();
root.setPoint(start);
/*
* Needed if the initial point has a cost.
*/
f(root, start, start);
expand(root);
for (;;) {
Path<T> p = paths.poll();
if (p == null) {
lastCost = Double.MAX_VALUE;
return null;
}
T last = p.getPoint();
lastCost = p.g;
if (isGoal(last)) {
LinkedList<T> retPath = new LinkedList<T>();
for (Path<T> i = p; i != null; i = i.parent) {
retPath.addFirst(i.getPoint());
}
return retPath;
}
expand(p);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
PathFinder.java
package playground;
import java.util.*;
public class PathFinder extends AStar<PathFinder.Node> {
private int[][] map;
private int endx;
private int endy;
public static class Node {
public int x;
public int y;
Node(int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return "(" + x + ", " + y + ") ";
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
public PathFinder(int[][] map, int endx, int endy) {
this.map = map;
this.endx = endx;
this.endy = endy;
}
protected boolean isGoal(Node node) {
return (node.x == endx) && (node.y == endy);
}
protected Double g(Node from, Node to) {
if (from.x == to.x && from.y == to.y) {
// System.out.println("To x1 " + to.x);
// System.out.println("To y1 " + to.y);
return 0.0;
}
if (map[to.y][to.x] == 1) {
//System.out.println("To x2 " + to.x);
// System.out.println("To y2 " + to.y);
return 1.0;
}
return Double.MAX_VALUE;
}
protected Double h(Node from, Node to) {
int dx = Math.abs(endx - to.x);
int dy = Math.abs(endy - to.y);
return new Double(Math.sqrt(dx * dx) + (dy * dy));
//return new Double(Math.abs(endx - to.x) + Math.abs(endy - to.y));
}
#Override
protected List<Node> generateSuccessors(Node node, Node parent) {
List<Node> ret = new LinkedList<Node>();
int x = node.x;
int y = node.y;
if (y < map[0].length - 1 && map[y + 1][x] == 1 && (parent == null || (parent != null && !(parent.x == x && parent.y == y + 1)))) {
ret.add(new Node(x, y + 1));
}
if (x < map.length - 1 && map[y][x + 1] == 1 && (parent == null || (parent != null && !(parent.x == x + 1 && parent.y == y)))) {
ret.add(new Node(x + 1, y));
}
if (y != 0 && map[y - 1][x] == 1 && (parent == null || (parent != null && !(parent.x == x && parent.y == y - 1)))) {
ret.add(new Node(x, y - 1));
}
if (x != 0 && map[y][x - 1] == 1 && (parent == null || (parent != null && !(parent.x == x - 1 && parent.y == y)))) {
ret.add(new Node(x - 1, y));
}
return ret;
}
public static void main(String[] args) {
int ammountOfBlocks = 200;
int width = 25;
int length = 25;
int startX = 1;
int startY = 1;
int endX = 24;
int endY = 24;
int[][] map = {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1},
{1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1},
{1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1},
{0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1}
};
int a = map.length;
int b = map[0].length;
int[][] map2 = new int[b][a];
for (int i = 0; i < map.length; i++) {
for (int j = 0; j < map[0].length; j++) {
map2[j][i] = map[i][j];
}
}
PathFinder pf = new PathFinder(map, endX, endY);
/*
* for(int i = 0; i < map.length; i++){ for(int j = 0; j <
* map[0].length; j++) System.out.print(map[i][j] + " ");
* System.out.println(); }
*/
long begin = System.currentTimeMillis();
List<Node> nodes = pf.compute(new PathFinder.Node(startX, startY));
long end = System.currentTimeMillis();
System.out.println("Time = " + (end - begin) + " ms");
//System.out.println("Expanded = " + pf.getExpandedCounter());
System.out.println("Cost = " + pf.getCost());
if (nodes == null) {
System.out.println("No path");
} else {
for (int i = 0; i < nodes.size(); i++) {
Node n = nodes.get(i);
int x = n.getX();
int y = n.getY();
map[x][y] = 4;
}
for(int i = 0; i < map.length; i++){
for(int j = 0; j < map[0].length; j++)
System.out.print(map[i][j] + " ");
System.out.println();
}
}
}
}
I'm trying to do a depth first traversal. I have no idea if I'm even close. Right now it's printing 1 3 4 5. It should be printing 1 2 4 7 3 5 6. Any help or advice is appreciated. Thanks. :)
Class:
public class myGraphs {
Stack<Integer> st;
int vFirst;
int[][] adjMatrix;
int[] isVisited = new int[7];
public myGraphs(int[][] Matrix) {
this.adjMatrix = Matrix;
st = new Stack<Integer>();
int i;
int[] node = {1, 2, 3, 4, 5, 6, 7};
int firstNode = node[0];
for (i = 1; i < node.length - 1; i++) {
depthFirst(firstNode, node[i]);
}
}
public void depthFirst(int vFirst, int n) {
int v, i;
st.push(vFirst);
while (!st.isEmpty()) {
v = st.pop();
if (isVisited[v]==0) {
System.out.print("\n"+v);
isVisited[v]=1;
}
for ( i=1;i<=n;i++) {
if ((adjMatrix[v][i] == 1) && (isVisited[i] == 0)) {
st.push(v);
isVisited[i]=1;
System.out.print(" " + i);
v = i;
}
}
}
}
//
public static void main(String[] args) {
// 1 2 3 4 5 6 7
int[][] adjMatrix = { {0, 1, 1, 0, 0, 0, 0},
{1, 0, 0, 1, 1, 1, 0},
{1, 0, 0, 0, 0, 0, 1},
{0, 1, 0, 0, 0, 0, 1},
{0, 1, 0, 0, 0, 0, 1},
{0, 1, 0, 0, 0, 0 ,0},
{0, 0, 1, 1, 1, 0, 0} };
new myGraphs(adjMatrix);
}
}
If you are looking at Depth First Traversal then following is the code changes you should make
1) First declare your node array as int[] node = {0, 1, 2, 3, 4, 5, 6}. This should be done to avoid array index start (which is 0 ) and your node start number (which is 1). SO here now we assume that new names of your node 1 is 0, node 2 is 1......and node 7 is 6.
2) Instead of doing
for (i = 1; i < node.length-1; i++){
depthFirst(firstNode, node[i]);
}
in myGraphs do :
depthFirst(firstNode, 7);
3)In depthFirst instead of for ( i=1;i<=n;i++) use for ( i=0;i<n;i++) While doing System.out.println in function depthFirst add one to the number as 0 represents node 1, 1 represents node 2 and so on.
Below is your fully functional code I modified :
import java.util.Stack;
public class DFS {
Stack<Integer> st;
int vFirst;
int[][] adjMatrix;
int[] isVisited = new int[7];
/**
* #param args
*/
public static void main(String[] args) {
int[][] adjMatrix = { {0, 1, 1, 0, 0, 0, 0},
{1, 0, 0, 1, 1, 1, 0},
{1, 0, 0, 0, 0, 0, 1},
{0, 1, 0, 0, 0, 0, 1},
{0, 1, 0, 0, 0, 0, 1},
{0, 1, 0, 0, 0, 0 ,0},
{0, 0, 1, 1, 1, 0, 0} };
new DFS(adjMatrix);
}
public DFS(int[][] Matrix) {
this.adjMatrix = Matrix;
st = new Stack<Integer>();
int i;
int[] node = {0, 1, 2, 3, 4, 5, 6};
int firstNode = node[0];
depthFirst(firstNode, 7);
}
public void depthFirst(int vFirst,int n)
{
int v,i;
st.push(vFirst);
while(!st.isEmpty())
{
v = st.pop();
if(isVisited[v]==0)
{
System.out.print("\n"+(v+1));
isVisited[v]=1;
}
for ( i=0;i<n;i++)
{
if((adjMatrix[v][i] == 1) && (isVisited[i] == 0))
{
st.push(v);
isVisited[i]=1;
System.out.print(" " + (i+1));
v = i;
}
}
}
}}
A working/tested solution in C#, if someone looking for it.
using System;
using System.Collections.Generic;
namespace GraphAdjMatrixDemo
{
public class Program
{
public static void Main(string[] args)
{
// 0 1 2 3 4 5 6
int[,] matrix = { {0, 1, 1, 0, 0, 0, 0},
{1, 0, 0, 1, 1, 1, 0},
{1, 0, 0, 0, 0, 0, 1},
{0, 1, 0, 0, 0, 0, 1},
{0, 1, 0, 0, 0, 0, 1},
{0, 1, 0, 0, 0, 0 ,0},
{0, 0, 1, 1, 1, 0, 0} };
bool[] visitMatrix = new bool[matrix.GetLength(0)];
Program ghDemo = new Program();
for (int lpRCnt = 0; lpRCnt < matrix.GetLength(0); lpRCnt++)
{
for (int lpCCnt = 0; lpCCnt < matrix.GetLength(1); lpCCnt++)
{
Console.Write(string.Format(" {0} ", matrix[lpRCnt, lpCCnt]));
}
Console.WriteLine();
}
Console.Write("\nDFS Recursive : ");
ghDemo.DftRecursive(matrix, visitMatrix, 0);
Console.Write("\nDFS Iterative : ");
ghDemo.DftIterative(matrix, 0);
Console.Read();
}
//====================================================================================================================================
public void DftRecursive(int[,] srcMatrix, bool[] visitMatrix, int vertex)
{
visitMatrix[vertex] = true;
Console.Write(vertex + 1 + " ");
for (int neighbour = 0; neighbour < srcMatrix.GetLength(0); neighbour++)
{
if (visitMatrix[neighbour] == false && srcMatrix[vertex, neighbour] == 1)
{
DftRecursive(srcMatrix, visitMatrix, neighbour);
}
}
}
public void DftIterative(int[,] srcMatrix, int srcVertex)
{
bool[] visited = new bool[srcMatrix.GetLength(0)];
Stack<int> vertexStack = new Stack<int>();
vertexStack.Push(srcVertex);
while (vertexStack.Count > 0)
{
int vertex = vertexStack.Pop();
if (visited[vertex] == true)
continue;
Console.Write(vertex + 1 + " ");
visited[vertex] = true;
for (int neighbour = 0; neighbour < srcMatrix.GetLength(0); neighbour++)
//for (int neighbour = srcMatrix.GetLength(0) - 1; neighbour >= 0; neighbour--)// To make same as recursive
{
if (srcMatrix[vertex, neighbour] == 1 && visited[neighbour] == false)
{
vertexStack.Push(neighbour);
}
}
}
}
}
}
To make display order of iterative same as recursion, we need to push neighbors in reverse order to stack. Took this logic from Amit answer here