diff --git a/src/ch/bfh/sevennotseven/FieldCanvas.java b/src/ch/bfh/sevennotseven/FieldCanvas.java index cf5cd09..684b339 100644 --- a/src/ch/bfh/sevennotseven/FieldCanvas.java +++ b/src/ch/bfh/sevennotseven/FieldCanvas.java @@ -5,6 +5,7 @@ import java.awt.Graphics; import java.awt.Point; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.util.ArrayList; import java.util.List; import javax.swing.JPanel; @@ -36,6 +37,7 @@ public class FieldCanvas extends JPanel{ private Point src; private Point dst; private List path; + private List blockedFields; private boolean freeMoveMode = false; /** @@ -55,6 +57,12 @@ public class FieldCanvas extends JPanel{ src = null; } else { src = p; + if(freeMoveMode) { + blockedFields = game.getReachablePoints(src); + } else { + blockedFields = game.getUnreachablePoints(src); + } + repaint(); } } @@ -64,11 +72,21 @@ public class FieldCanvas extends JPanel{ if(src!=null) { Point lastDst = dst; dst = FieldCanvas.this.getClickPoint(e.getPoint()); - if(lastDst!=dst) { //hovered field changed - path= game.getPath(src, dst); + if(lastDst!=dst && dst!=null) { //hovered field changed + if(freeMoveMode) { + if(!game.canMove(src, dst) && game.getField()[dst.x][dst.y]==0) { + path = new ArrayList(); + path.add(src); + path.add(dst); + } else { + path= null; + } + } else { + path= game.getPath(src, dst); + } repaint(); } - } else { + }else { dst = null; path = null; } @@ -79,8 +97,10 @@ public class FieldCanvas extends JPanel{ super.mouseReleased(e); dst = FieldCanvas.this.getClickPoint(e.getPoint()); path = null; - if(freeMoveMode && !game.canMove(src, dst)) { - game.doFreeMove(src, dst); + if(freeMoveMode) { + if(!game.canMove(src, dst)) { + game.doFreeMove(src, dst); + } } else { if(dst != null && src!=null && !src.equals(dst)) { System.out.println("Moving from "+src.toString()+ " to "+dst.toString()); @@ -89,6 +109,7 @@ public class FieldCanvas extends JPanel{ } freeMoveMode = false; src = null; + blockedFields = null; repaint(); } }; @@ -104,10 +125,13 @@ public class FieldCanvas extends JPanel{ * * @author timo */ - public void doFreeMove() { - if(game.getAvailFreeMoves()>0) { + public void toggleFreeMove() { + if(freeMoveMode) { + freeMoveMode =false; + } else if(game.getAvailFreeMoves()>0) { freeMoveMode = true; } + repaint(); } /** @@ -146,7 +170,12 @@ public class FieldCanvas extends JPanel{ public void paintComponent(Graphics g) { super.paintComponent(g); - g.setColor(Color.lightGray); + //Draw field (background and lines) + if(freeMoveMode) { + g.setColor(Color.gray); + } else { + g.setColor(Color.lightGray); + } g.translate(borderLeft, borderTop); int total = Math.min(this.getHeight()-borderTop-borderBottom,FieldCanvas.this.getWidth()-borderLeft-borderRight); @@ -164,6 +193,8 @@ public class FieldCanvas extends JPanel{ if(game==null) return; + //Draw blocks + for(int x=0; x lastStates; //Last Game States. Has one entry per move private int size; //size of the field along one dimension private int freeBlocks; //number of free block positions on the field @@ -82,7 +82,10 @@ public class Game { private int numUndos; //number of undos left private Random rand; //instance to get random numbers from private ArrayList updateListeners; //registered listeners - private PathFinder pathfinder; + + //Stuff for pathfinding + private PathFinder pathfinder; //Path finder helper instance + private Point lastSrc; //last src point that was used with pathfinder public Game(){ this(7); @@ -210,10 +213,30 @@ public class Game { * @return Shortest path between src and dst, or null if there is no path */ public List getPath(final Point src, final Point dst){ - pathfinder.calculateCosts(field, size, src); + + //recalculate costs only if src changed + if(lastSrc==null || !src.equals(lastSrc)) { + pathfinder.calculateCosts(field, size, src); + } return pathfinder.getPath(dst); } + public List getReachablePoints(final Point src) { + //recalculate costs only if necessary + if(lastSrc==null || !src.equals(lastSrc)) { + pathfinder.calculateCosts(field, size, src); + } + return pathfinder.getReachablePoints(); + } + + public List getUnreachablePoints(final Point src) { + //recalculate costs only if necessary + if(lastSrc==null || !src.equals(lastSrc)) { + pathfinder.calculateCosts(field, size, src); + } + return pathfinder.getUnreachablePoints(); + } + /** * Undo the last move if there are enough available undos. * @@ -223,9 +246,12 @@ public class Game { public boolean doUndo(){ if(getAvailUndo() > 0 && lastStates.size() > 0){ - lastStates.remove(lastStates.size() - 1).restore(); + lastStates.remove(lastStates.size() - 1).restore(); //take last state from the stack and restore it numUndos--; + //Reset value for pathfinding cache, so that we are sure we recalculate the pathes/costs + lastSrc = null; + emitUpdateEvent(); return true; } @@ -234,6 +260,9 @@ public class Game { private void saveStep() { lastStates.add(new State()); //add a new State Object (which will be initialized to the current game state) to the backup list + + //Reset value for pathfinding cache, so that we are sure we recalculate the pathes/costs + lastSrc = null; } /** diff --git a/src/ch/bfh/sevennotseven/PathFinder.java b/src/ch/bfh/sevennotseven/PathFinder.java index a603d1f..f540a65 100644 --- a/src/ch/bfh/sevennotseven/PathFinder.java +++ b/src/ch/bfh/sevennotseven/PathFinder.java @@ -114,24 +114,28 @@ public class PathFinder { * @param src starting point */ public void calculateCosts(final int[][] field, int size, final Point src) { - ArrayList vertices = new ArrayList(); // List of vertices + ArrayList openVerticies = new ArrayList(); // List of vertices - vertices.add(new Vertex(0, src)); + openVerticies.add(new Vertex(0, src)); // Get a verticies list from the field data for(int i= 0; i < size; i++){ for(int j = 0; j < size; j++){ if(field[i][j] == 0 && (src.x!=i || src.y!=j)){ //field empty and not src - vertices.add(new Vertex(Integer.MAX_VALUE, new Point(i, j))); + openVerticies.add(new Vertex(Integer.MAX_VALUE, new Point(i, j))); } } } - ArrayList allVerticies = new ArrayList(vertices); // List of vertices + ArrayList allVerticies = new ArrayList(openVerticies); // List of vertices - while(!vertices.isEmpty()){ // As long as there are vertices - final Vertex u = findNearestVertex(vertices); - vertices.remove(u); // Remove u from the set of vertices + while(!openVerticies.isEmpty()){ // As long as there are vertices + final Vertex u = findNearestVertex(openVerticies); + openVerticies.remove(u); // Remove u from the set of vertices + + if(u.getDist()==Integer.MAX_VALUE) { + continue; + } final Point[] offsets = { new Point(0,1), @@ -147,7 +151,7 @@ public class PathFinder { int y = p.y + offs.y; if(x<0 || y<0 || x>=size || y>= size) continue; - final Vertex v = findVertex(x,y, vertices); + final Vertex v = findVertex(x,y, openVerticies); //distanz_update(u,v) if(v!=null){ int alternative = u.getDist()+1; //alternative has cost of current path + 1 (=cost to reach neighbor) @@ -162,7 +166,7 @@ public class PathFinder { lastSrc = src; verticies = allVerticies; lastField = field; - lastSize = size; + lastSize = size; } @@ -205,7 +209,7 @@ public class PathFinder { if(lastField[x][y]!=0) continue; Vertex u = findVertex(x, y, verticies); if(u==null) continue; - if(u.getPrev()!=null && u.getDist()!=Integer.MAX_VALUE) { + if(u.getPrev()!=null && u.getDist()!= Integer.MAX_VALUE) { res.add(u.getPos()); } } @@ -225,7 +229,7 @@ public class PathFinder { if(lastSrc.x == x && lastSrc.y ==y) continue; if(lastField[x][y]!=0) continue; Vertex u = findVertex(x, y, verticies); - if(u==null|| u.getPrev() == null) { + if(u==null|| u.getPrev() == null || u.getDist() == Integer.MAX_VALUE) { res.add(u.getPos()); } } diff --git a/src/ch/bfh/sevennotseven/Window.java b/src/ch/bfh/sevennotseven/Window.java index a143051..802c7a3 100644 --- a/src/ch/bfh/sevennotseven/Window.java +++ b/src/ch/bfh/sevennotseven/Window.java @@ -138,7 +138,7 @@ public class Window extends JFrame implements ActionListener{ if(command.equals("undo")) { field.doUndo(); } else if (command.equals("freemove")) { - field.doFreeMove(); + field.toggleFreeMove(); } else { int size = Integer.parseInt(command); cardLayout.last(mainPanel);