PuzzleRouteFinder.getDirections returns proper order of steps.
This commit is contained in:
@@ -36,7 +36,7 @@ public class PuzzleAnimator implements IPuzzleAnimator {
|
|||||||
//animator.queue( new Animator.NoMove(x,y) );
|
//animator.queue( new Animator.NoMove(x,y) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void undoable(XYPair xy )
|
public void moveImpossible(XYPair xy )
|
||||||
{
|
{
|
||||||
animator.queue( new Animator.NoMove(xy) );
|
animator.queue( new Animator.NoMove(xy) );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ public interface IPuzzleAnimator {
|
|||||||
public void select( XYPair xy );
|
public void select( XYPair xy );
|
||||||
public void unselect();
|
public void unselect();
|
||||||
public void buzz();
|
public void buzz();
|
||||||
public void undoable( XYPair xy );
|
public void moveImpossible(XYPair xy );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,18 +7,14 @@ package org.vostan.banvor.model;
|
|||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
|
||||||
import org.vostan.banvor.model.IPuzzleAnimator;
|
|
||||||
import org.vostan.banvor.model.Puzzle;
|
|
||||||
import org.vostan.banvor.model.PuzzleRouteFinder;
|
|
||||||
import org.vostan.banvor.model.XYPair;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class PuzzleChoreographer
|
public class PuzzleChoreographer
|
||||||
{
|
{
|
||||||
protected Puzzle puzzle = null;
|
private Puzzle puzzle = null;
|
||||||
protected PuzzleRouteFinder routeFinder;
|
private PuzzleRouteFinder routeFinder = null;
|
||||||
|
private IPuzzleAnimator animator;
|
||||||
|
|
||||||
public PuzzleChoreographer()
|
public PuzzleChoreographer()
|
||||||
{}
|
{}
|
||||||
@@ -29,8 +25,9 @@ public class PuzzleChoreographer
|
|||||||
routeFinder = new PuzzleRouteFinder(p);
|
routeFinder = new PuzzleRouteFinder(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean createSteps(IPuzzleAnimator animator, XYPair xy )
|
public boolean createSteps(IPuzzleAnimator _animator, XYPair xy )
|
||||||
{
|
{
|
||||||
|
animator = _animator;
|
||||||
//
|
//
|
||||||
// Check that the x,y are valid.
|
// Check that the x,y are valid.
|
||||||
//
|
//
|
||||||
@@ -51,19 +48,18 @@ public class PuzzleChoreographer
|
|||||||
// Check if worker selected a box and can push it to the location?
|
// Check if worker selected a box and can push it to the location?
|
||||||
// If yes then we are done.
|
// If yes then we are done.
|
||||||
//
|
//
|
||||||
if ( puzzle.isSelected()
|
if ( puzzle.isSelected() && tryMoveSelectedBox(xy) )
|
||||||
&& tryMoveBox(animator, xy) )
|
|
||||||
return true;
|
return true;
|
||||||
//
|
//
|
||||||
// Either nothing was selected or the box cannot be moved to
|
// Either nothing was selected or the box cannot be moved to
|
||||||
// tapped location. Try move worker alone.
|
// tapped location. Try move worker alone.
|
||||||
//
|
//
|
||||||
if ( tryMoveWorker( animator, xy ) )
|
if ( tryMoveWorker(xy) )
|
||||||
return true;
|
return true;
|
||||||
//
|
//
|
||||||
// Show that action is not allowed.
|
// Show that action is not allowed.
|
||||||
//
|
//
|
||||||
animator.undoable(xy);
|
animator.moveImpossible(xy);
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// The tapped is the worker. Try move the box. If not possible
|
// The tapped is the worker. Try move the box. If not possible
|
||||||
@@ -84,8 +80,9 @@ public class PuzzleChoreographer
|
|||||||
// Check if worker selected a box and can push it to the location?
|
// Check if worker selected a box and can push it to the location?
|
||||||
// If yes then we are done.
|
// If yes then we are done.
|
||||||
//
|
//
|
||||||
if ( tryMoveBox(animator, xy) )
|
if ( tryMoveSelectedBox(xy) ) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// If the box is not movable then unselect it.
|
// If the box is not movable then unselect it.
|
||||||
//
|
//
|
||||||
@@ -112,12 +109,13 @@ public class PuzzleChoreographer
|
|||||||
// Try move the worker next to the box and select it if the
|
// Try move the worker next to the box and select it if the
|
||||||
// box is not selected yet.
|
// box is not selected yet.
|
||||||
//
|
//
|
||||||
if ( trySelectBox( animator, xy ) )
|
if ( trySelectBox(xy) ) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// Show that action is not allowed if reached till here.
|
// Show that action is not allowed if reached till here.
|
||||||
//
|
//
|
||||||
animator.undoable(xy);
|
animator.moveImpossible(xy);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -126,25 +124,27 @@ public class PuzzleChoreographer
|
|||||||
//
|
//
|
||||||
// Routes to accessible cells from where worker stands.
|
// Routes to accessible cells from where worker stands.
|
||||||
//
|
//
|
||||||
protected boolean tryMoveWorker( IPuzzleAnimator animator, XYPair xy )
|
protected boolean tryMoveWorker(XYPair xy)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// If the filed is not accessable then move failed.
|
// If the filed is not accessable then move failed.
|
||||||
//
|
//
|
||||||
if ( !routeFinder.isAccessible(xy) )
|
if ( !routeFinder.isAccessible(xy) ) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// First unselect box.
|
// First unselect box.
|
||||||
//
|
//
|
||||||
if ( puzzle.isSelected() )
|
if ( puzzle.isSelected() ) {
|
||||||
animator.unselect();
|
animator.unselect();
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// Get directions and queue moves accordingly.
|
// Get directions and queue moves accordingly.
|
||||||
//
|
//
|
||||||
Vector<XYPair> dirs = routeFinder.getDirections(xy);
|
Vector<XYPair> dirs = routeFinder.getDirections(xy);
|
||||||
ListIterator<XYPair> it = dirs.listIterator(dirs.size());
|
ListIterator<XYPair> it = dirs.listIterator();
|
||||||
while ( it.hasPrevious() ) {
|
while ( it.hasNext() ) {
|
||||||
animator.move(it.previous());
|
animator.move(it.next());
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// Done.
|
// Done.
|
||||||
@@ -152,26 +152,57 @@ public class PuzzleChoreographer
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean tryMoveBox( IPuzzleAnimator animator, XYPair xy )
|
|
||||||
|
protected boolean tryMoveSelectedBox(XYPair xy)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// If no box is selected then we cannot move no box.
|
// If no box is selected then we cannot move no box.
|
||||||
//
|
//
|
||||||
if ( !puzzle.isSelected() )
|
if ( !puzzle.isSelected() ) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
final XYPair box_xy = puzzle.getSelected();
|
||||||
|
//
|
||||||
|
// There is no point to continue if we are asked to move the box to where is it.
|
||||||
|
//
|
||||||
|
if ( xy.isEqual(box_xy) ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// Check that asked move is orthogonal to the slected box.
|
// Check that asked move is orthogonal to the slected box.
|
||||||
//
|
//
|
||||||
|
// TODO: check that all cells are empty on the route.
|
||||||
|
//
|
||||||
|
if ( xy.x() == box_xy.x() || xy.y() == box_xy.y() ) {
|
||||||
|
return tryOrthogonalMoveSelectedBox(xy);
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// NOT IMPLEMENTED.
|
||||||
|
//
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean tryOrthogonalMoveSelectedBox(XYPair xy)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// If no box is selected then we cannot move no box.
|
||||||
|
//
|
||||||
|
if ( !puzzle.isSelected() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
final XYPair box_xy = puzzle.getSelected();
|
final XYPair box_xy = puzzle.getSelected();
|
||||||
XYPair dxy = xy.sub(box_xy);
|
|
||||||
if ( dxy.x() != 0 && dxy.y() != 0 )
|
|
||||||
return false;
|
|
||||||
//
|
//
|
||||||
// There is no point to continue also in case if the asked cell
|
// There is no point to continue if we are asked to move the box to where is it.
|
||||||
// is the box.
|
|
||||||
//
|
//
|
||||||
if ( dxy.isEqual(XYPair.ZERO) )
|
if ( xy.isEqual(box_xy) ) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Check that asked move is orthogonal to the selected box.
|
||||||
|
//
|
||||||
|
if ( xy.x() != box_xy.x() && xy.y() != box_xy.y() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// Now find the desired place for the worker to start push this
|
// Now find the desired place for the worker to start push this
|
||||||
// box.
|
// box.
|
||||||
@@ -189,8 +220,9 @@ public class PuzzleChoreographer
|
|||||||
// Check if the desired place for the worker is accessable? If not
|
// Check if the desired place for the worker is accessable? If not
|
||||||
// then there is no point to continue.
|
// then there is no point to continue.
|
||||||
//
|
//
|
||||||
if ( !routeFinder.isAccessible(w) )
|
if ( !routeFinder.isAccessible(w) ) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// Now check that all cell till x,y are empty and that we can
|
// Now check that all cell till x,y are empty and that we can
|
||||||
// push box till there.
|
// push box till there.
|
||||||
@@ -210,7 +242,9 @@ public class PuzzleChoreographer
|
|||||||
//
|
//
|
||||||
if ( !w.isEqual(puzzle.getWorker()) )
|
if ( !w.isEqual(puzzle.getWorker()) )
|
||||||
{
|
{
|
||||||
tryMoveWorker( animator, w );
|
if (!tryMoveWorker(w)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
animator.select(box_xy);
|
animator.select(box_xy);
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
@@ -225,16 +259,17 @@ public class PuzzleChoreographer
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean trySelectBox( IPuzzleAnimator animator, XYPair xy )
|
|
||||||
|
protected boolean trySelectBox(XYPair xy)
|
||||||
{
|
{
|
||||||
int north = puzzle.getSym(xy.up());
|
int north = puzzle.getSym(xy.up());
|
||||||
int south = puzzle.getSym(xy.down());
|
int south = puzzle.getSym(xy.down());
|
||||||
int west = puzzle.getSym(xy.left());
|
int west = puzzle.getSym(xy.left());
|
||||||
int east = puzzle.getSym(xy.right());
|
int east = puzzle.getSym(xy.right());
|
||||||
//
|
//
|
||||||
// First check if there is a worker in a nighbour cell. If
|
// First check if there is a worker in a neighboring cell. If
|
||||||
// yes then simplly select the box. If the box is already selected
|
// yes then simply select the box. If the box is already selected
|
||||||
// then do nothing and if othe box is selected then unselect it first
|
// then do nothing and if other box is selected then unselect it first
|
||||||
// and then select the box.
|
// and then select the box.
|
||||||
//
|
//
|
||||||
if ( Puzzle.hasWorker( west )
|
if ( Puzzle.hasWorker( west )
|
||||||
@@ -250,7 +285,7 @@ public class PuzzleChoreographer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// Otherwise, check which is of the cells is in closes walking
|
// Otherwise, check which of the cells is in closes walking
|
||||||
// distance and move worker to that cell, then select.
|
// distance and move worker to that cell, then select.
|
||||||
//
|
//
|
||||||
else
|
else
|
||||||
@@ -285,9 +320,9 @@ public class PuzzleChoreographer
|
|||||||
// Move the worker to the direction. If we cannot move worker
|
// Move the worker to the direction. If we cannot move worker
|
||||||
// next to the box then we cannot select it.
|
// next to the box then we cannot select it.
|
||||||
//
|
//
|
||||||
if ( !puzzle.isValid(pref)
|
if ( !puzzle.isValid(pref) || !tryMoveWorker(pref) ) {
|
||||||
|| !tryMoveWorker(animator, pref) )
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// Select the box.
|
// Select the box.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
package org.vostan.banvor.model;
|
package org.vostan.banvor.model;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
|
||||||
public class PuzzleRouteFinder {
|
public class PuzzleRouteFinder {
|
||||||
protected Puzzle puzzle = null;
|
protected Puzzle puzzle = null;
|
||||||
protected int [] moves;
|
protected int [] moves;
|
||||||
protected Vector<XYPair> setOfCells = new Vector<XYPair>();
|
|
||||||
|
//
|
||||||
|
// This is to avoid fragmentation of memory.
|
||||||
|
//
|
||||||
|
private Vector<XYPair> setOfCells = new Vector<XYPair>();
|
||||||
|
|
||||||
public PuzzleRouteFinder(Puzzle p) {
|
public PuzzleRouteFinder(Puzzle p) {
|
||||||
puzzle = p;
|
puzzle = p;
|
||||||
@@ -14,8 +19,7 @@ public class PuzzleRouteFinder {
|
|||||||
setOfCells.ensureCapacity(puzzle.getColumnCount() * puzzle.getRowCount());
|
setOfCells.ensureCapacity(puzzle.getColumnCount() * puzzle.getRowCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final int getMoves( XYPair xy )
|
protected final int getMoves( XYPair xy ) {
|
||||||
{
|
|
||||||
return moves[puzzle.getIndex(xy)];
|
return moves[puzzle.getIndex(xy)];
|
||||||
}
|
}
|
||||||
protected void setMoves( XYPair xy, int v )
|
protected void setMoves( XYPair xy, int v )
|
||||||
@@ -93,8 +97,7 @@ public class PuzzleRouteFinder {
|
|||||||
return getMoves(xy);
|
return getMoves(xy);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isAccessible( XYPair xy )
|
public final boolean isAccessible( XYPair xy ) {
|
||||||
{
|
|
||||||
return puzzle.isValid(xy) && stepsAway(xy) != Integer.MAX_VALUE;
|
return puzzle.isValid(xy) && stepsAway(xy) != Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,6 +129,7 @@ public class PuzzleRouteFinder {
|
|||||||
steps.add(xy.up());
|
steps.add(xy.up());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Collections.reverse(steps);
|
||||||
return steps;
|
return steps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ public class XYPair
|
|||||||
_y = op.y();
|
_y = op.y();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int x(){
|
public final int x(){
|
||||||
return _x;
|
return _x;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int y(){
|
public final int y(){
|
||||||
return _y;
|
return _y;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,44 +57,44 @@ public class XYPair
|
|||||||
return new XYPair(op1._x*scaliar, op1._y*scaliar);
|
return new XYPair(op1._x*scaliar, op1._y*scaliar);
|
||||||
}
|
}
|
||||||
|
|
||||||
public XYPair mul(int scaliar){
|
public final XYPair mul(int scaliar){
|
||||||
return mul(this, scaliar);
|
return mul(this, scaliar);
|
||||||
}
|
}
|
||||||
|
|
||||||
public XYPair sub(XYPair op){
|
public final XYPair sub(XYPair op){
|
||||||
return sub(this, op);
|
return sub(this, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
public XYPair add(XYPair op){
|
public final XYPair add(XYPair op){
|
||||||
return add(this, op);
|
return add(this, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int l1_norm(){
|
public final int l1_norm(){
|
||||||
return abs(_x)+abs(_y);
|
return abs(_x)+abs(_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEqual(XYPair op){
|
public final boolean isEqual(XYPair op){
|
||||||
return _x == op._x && _y == op._y;
|
return _x == op._x && _y == op._y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isInside(XYPair op1, XYPair op2){
|
public final boolean isInside(XYPair op1, XYPair op2){
|
||||||
return op1.x() <= this.x() && this.x() < op2.x()
|
return op1.x() <= this.x() && this.x() < op2.x()
|
||||||
&& op1.y() <= this.y() && this.y() < op2.y();
|
&& op1.y() <= this.y() && this.y() < op2.y();
|
||||||
}
|
}
|
||||||
|
|
||||||
public XYPair left(){
|
public final XYPair left(){
|
||||||
return this.add(LEFT);
|
return this.add(LEFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public XYPair right(){
|
public final XYPair right(){
|
||||||
return this.add(RIGHT);
|
return this.add(RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public XYPair up(){
|
public final XYPair up(){
|
||||||
return this.add(UP);
|
return this.add(UP);
|
||||||
}
|
}
|
||||||
|
|
||||||
public XYPair down(){
|
public final XYPair down(){
|
||||||
return this.add(DOWN);
|
return this.add(DOWN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user