A* infinite loop - java

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();
}
}
}
}

Related

Breadth First Search from scratch in Java

I wrote a java-code to find the path in an 2d array. The array is filled with 0=valid node and 1=obstacle. The code runs perfetcly with small 2d arrays for example with the size of int [][] obstacleMap=new int[10][11];
When I increase the size of the array (e.g. int[][] obstacleMap =[600][300];) now the code doesn't work anymore, I get not an Error. I have tested a lot of times my code, I think the problem is the while loop within the findpath function (code below)
My code has following functions:
main: to test the other functions
2.findPath: find path with given map from start position to target position
3.addNeighbour: add neighbour
Following classes:
Node : x and y coordinates and distance to start
pathCoordinates: x and y values for path
The Code is here:
package strategyRobot;
//import java.awt.datatransfer.SystemFlavorMap;
import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.Queue;
import java.util.Set;
import java.util.LinkedList;
import java.util.List;
public class strategyRobotClass {
static Set<String> visitedNodes = new HashSet<>();
public static void main(String[] args) {
int[][] randomMap={
{ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
{ 1, 0, 1, 1, 1, 1, 0, 1, 1, 1 },
{ 1, 0, 0, 0, 1, 1, 0 ,1, 1, 1 },
{ 1, 1, 1, 0, 1, 1, 0, 1, 1, 1 },
{ 1, 1, 1, 0, 1, 1, 0, 1, 1, 1 },
{ 1, 1, 1, 0, 0, 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 },
};
int value = randomMap[2][6];
System.out.printf("value = %d", value);
System.out.println(" ");
LinkedList<pathCoordinates> pathMap= findPath(randomMap,0,0,3,6);
for(int i = 0; i<pathMap.size();i++) {
System.out.printf("(%d,%d) %n",pathMap.get(i).x,pathMap.get(i).y);
}
}
static public LinkedList<pathCoordinates> findPath(int map[][], int xStartPos, int yStartPos, int xTargetPos, int yTargetPos) {
LinkedList<pathCoordinates> pathMap = new LinkedList<pathCoordinates>();
Node source = new Node(xStartPos, yStartPos,0);
Queue<Node> queue= new LinkedList<Node>();
queue.add(source);
while(!queue.isEmpty()) { // IS THE BUG HERE ????
Node poped = queue.poll();
if(poped.x == xTargetPos && poped.y ==yTargetPos) {
return pathMap;
}
else {
map[poped.x][poped.y] = 1 ;
pathCoordinates coordinates = new pathCoordinates(poped.x,poped.y);
pathMap.add(coordinates);
List<Node> neighbourList = addNeighbours(poped,map);
queue.addAll(neighbourList);
}
}
return null;
}
static public List addNeighbours(Node poped, int[][] map) {
List<Node> list=new LinkedList<Node>();
if((poped.x-1 >0 && poped.x-1<map.length) && (map[poped.x-1][poped.y]== 0)) {
list.add(new Node(poped.x-1, poped.y, poped.distanceFromStart+1));
}
if((poped.x+1 >0 && poped.x+1<map.length) && (map[poped.x+1][poped.y]== 0)) {
list.add(new Node(poped.x+1, poped.y, poped.distanceFromStart+1));
}
if((poped.y-1 >0 && poped.y-1<map.length) && (map[poped.x][poped.y-1]== 0)) {
list.add(new Node(poped.x-1, poped.y, poped.distanceFromStart+1));
}
if((poped.y+1 >0 && poped.y+1<map.length) && (map[poped.x][poped.y+1]== 0)) {
list.add(new Node(poped.x, poped.y+1, poped.distanceFromStart+1));
}
return list;
}
static public class Node{
int x, y; //coordinates in a cell
int distanceFromStart;
Node parent;
Node(int x, int y, int distanceFromStart){
this.x=x;
this.y=y;
this.distanceFromStart=distanceFromStart;
}
}
static public class pathCoordinates {
int x,y;
pathCoordinates(int x, int y){
this.x=x;
this.y=y;
}
}

Java Array change value for half of half etc

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

2.5D Plane in Slick2D is curved for some reason

I'll readily admit that this code is weird and a pretty unorthodox way of creating anything 2.5D, however if anyone can see what's going on I would appreciate help.
The result of my code is as shown:
I do of course want a totally flat plane, however I'm unsure as to why it curves like so. The code is shown below if anyone has any answers:
public static int width = 640;
public static int height = 480;
private Image image;
private Graphics imageG;
private int mapWidth = 20, mapHeight = 15;
private int[] map;
private float x, y;
public Game(String title)
{
super(title);
}
#Override
public void render(GameContainer gc, Graphics g) throws SlickException
{
imageG.setBackground(Color.black);
imageG.clear();
for (int y = 0; y < mapHeight; y++)
for (int x = 0; x < mapWidth; x++)
{
switch (map[x + y * (mapWidth)])
{
case 0:
imageG.setColor(Color.green);
break;
case 1:
imageG.setColor(Color.yellow);
break;
}
imageG.fillRect(x * 32, y * 32, 32, 32);
}
imageG.flush();
Image frustrum;
for (int i = 0; i < 240; i++)
{
frustrum = image.getSubImage((int) (x - i), (int) (y - i), 32 + 2 * i, 1);
frustrum.draw(0, height - 1 - i, width, 1);
//g.drawImage(frustrum, x - i, y - i);
}
//g.setColor(Color.blue);
//g.fillRect(x, y, 32, 32);
}
#Override
public void init(GameContainer gc) throws SlickException
{
try
{
image = new Image(width, height);
imageG = image.getGraphics();
} catch (SlickException e)
{
e.printStackTrace();
}
/*map = new int[]
{
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
};*/
map = new int[mapWidth * mapHeight];
Random random = new Random();
for (int i = 0; i < map.length; i++)
{
map[i] = random.nextInt(2);
}
x = 10 * 32;
y = 7 * 32;
}
#Override
public void update(GameContainer gc, int delta) throws SlickException
{
if (gc.getInput().isKeyDown(Input.KEY_W)) y--;
if (gc.getInput().isKeyDown(Input.KEY_S)) y++;
if (gc.getInput().isKeyDown(Input.KEY_A)) x--;
if (gc.getInput().isKeyDown(Input.KEY_D)) x++;
}
public static void main(String[] args)
{
try
{
AppGameContainer appgc = new AppGameContainer(new Game("2.5D Game"));
appgc.setDisplayMode(width, height, false);
appgc.start();
} catch (SlickException e)
{
e.printStackTrace();
}
}
This is my first post, so sorry if things look a bit messy. I'm sure I'll get used to it eventually...

Auto generate 2 dimensional Array,

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;
}
}
}

Depth First Traversal and Adj Matrix

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

Categories