PuzzleRouteFinder.getDirections returns proper order of steps.

This commit is contained in:
2021-10-17 23:04:24 +01:00
parent faa6ccc296
commit 66d04087f8
5 changed files with 97 additions and 58 deletions

View File

@@ -36,7 +36,7 @@ public class PuzzleAnimator implements IPuzzleAnimator {
//animator.queue( new Animator.NoMove(x,y) );
}
public void undoable(XYPair xy )
public void moveImpossible(XYPair xy )
{
animator.queue( new Animator.NoMove(xy) );
}

View File

@@ -6,5 +6,5 @@ public interface IPuzzleAnimator {
public void select( XYPair xy );
public void unselect();
public void buzz();
public void undoable( XYPair xy );
public void moveImpossible(XYPair xy );
}

View File

@@ -7,18 +7,14 @@ package org.vostan.banvor.model;
import java.util.ListIterator;
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
{
protected Puzzle puzzle = null;
protected PuzzleRouteFinder routeFinder;
private Puzzle puzzle = null;
private PuzzleRouteFinder routeFinder = null;
private IPuzzleAnimator animator;
public PuzzleChoreographer()
{}
@@ -29,8 +25,9 @@ public class PuzzleChoreographer
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.
//
@@ -51,19 +48,18 @@ public class PuzzleChoreographer
// Check if worker selected a box and can push it to the location?
// If yes then we are done.
//
if ( puzzle.isSelected()
&& tryMoveBox(animator, xy) )
if ( puzzle.isSelected() && tryMoveSelectedBox(xy) )
return true;
//
// Either nothing was selected or the box cannot be moved to
// tapped location. Try move worker alone.
//
if ( tryMoveWorker( animator, xy ) )
if ( tryMoveWorker(xy) )
return true;
//
// Show that action is not allowed.
//
animator.undoable(xy);
animator.moveImpossible(xy);
}
//
// 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?
// If yes then we are done.
//
if ( tryMoveBox(animator, xy) )
if ( tryMoveSelectedBox(xy) ) {
return true;
}
//
// 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
// box is not selected yet.
//
if ( trySelectBox( animator, xy ) )
if ( trySelectBox(xy) ) {
return true;
}
//
// Show that action is not allowed if reached till here.
//
animator.undoable(xy);
animator.moveImpossible(xy);
}
return true;
}
@@ -126,25 +124,27 @@ public class PuzzleChoreographer
//
// 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 ( !routeFinder.isAccessible(xy) )
if ( !routeFinder.isAccessible(xy) ) {
return false;
}
//
// First unselect box.
//
if ( puzzle.isSelected() )
if ( puzzle.isSelected() ) {
animator.unselect();
}
//
// Get directions and queue moves accordingly.
//
Vector<XYPair> dirs = routeFinder.getDirections(xy);
ListIterator<XYPair> it = dirs.listIterator(dirs.size());
while ( it.hasPrevious() ) {
animator.move(it.previous());
ListIterator<XYPair> it = dirs.listIterator();
while ( it.hasNext() ) {
animator.move(it.next());
}
//
// Done.
@@ -152,26 +152,57 @@ public class PuzzleChoreographer
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 ( !puzzle.isSelected() )
if ( !puzzle.isSelected() ) {
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.
//
// 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();
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
// is the box.
// There is no point to continue if we are asked to move the box to where is it.
//
if ( dxy.isEqual(XYPair.ZERO) )
if ( xy.isEqual(box_xy) ) {
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
// box.
@@ -189,8 +220,9 @@ public class PuzzleChoreographer
// Check if the desired place for the worker is accessable? If not
// then there is no point to continue.
//
if ( !routeFinder.isAccessible(w) )
if ( !routeFinder.isAccessible(w) ) {
return false;
}
//
// Now check that all cell till x,y are empty and that we can
// push box till there.
@@ -210,7 +242,9 @@ public class PuzzleChoreographer
//
if ( !w.isEqual(puzzle.getWorker()) )
{
tryMoveWorker( animator, w );
if (!tryMoveWorker(w)){
return false;
}
animator.select(box_xy);
}
//
@@ -225,16 +259,17 @@ public class PuzzleChoreographer
return true;
}
protected boolean trySelectBox( IPuzzleAnimator animator, XYPair xy )
protected boolean trySelectBox(XYPair xy)
{
int north = puzzle.getSym(xy.up());
int south = puzzle.getSym(xy.down());
int west = puzzle.getSym(xy.left());
int east = puzzle.getSym(xy.right());
//
// First check if there is a worker in a nighbour cell. If
// yes then simplly select the box. If the box is already selected
// then do nothing and if othe box is selected then unselect it first
// First check if there is a worker in a neighboring cell. If
// yes then simply select the box. If the box is already selected
// then do nothing and if other box is selected then unselect it first
// and then select the box.
//
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.
//
else
@@ -285,9 +320,9 @@ public class PuzzleChoreographer
// Move the worker to the direction. If we cannot move worker
// next to the box then we cannot select it.
//
if ( !puzzle.isValid(pref)
|| !tryMoveWorker(animator, pref) )
if ( !puzzle.isValid(pref) || !tryMoveWorker(pref) ) {
return false;
}
//
// Select the box.
//

View File

@@ -1,12 +1,17 @@
package org.vostan.banvor.model;
import java.util.Arrays;
import java.util.Collections;
import java.util.Vector;
public class PuzzleRouteFinder {
protected Puzzle puzzle = null;
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) {
puzzle = p;
@@ -14,8 +19,7 @@ public class PuzzleRouteFinder {
setOfCells.ensureCapacity(puzzle.getColumnCount() * puzzle.getRowCount());
}
protected final int getMoves( XYPair xy )
{
protected final int getMoves( XYPair xy ) {
return moves[puzzle.getIndex(xy)];
}
protected void setMoves( XYPair xy, int v )
@@ -93,8 +97,7 @@ public class PuzzleRouteFinder {
return getMoves(xy);
}
public final boolean isAccessible( XYPair xy )
{
public final boolean isAccessible( XYPair xy ) {
return puzzle.isValid(xy) && stepsAway(xy) != Integer.MAX_VALUE;
}
@@ -126,6 +129,7 @@ public class PuzzleRouteFinder {
steps.add(xy.up());
}
}
Collections.reverse(steps);
return steps;
}

View File

@@ -27,11 +27,11 @@ public class XYPair
_y = op.y();
}
public int x(){
public final int x(){
return _x;
}
public int y(){
public final int y(){
return _y;
}
@@ -57,44 +57,44 @@ public class XYPair
return new XYPair(op1._x*scaliar, op1._y*scaliar);
}
public XYPair mul(int scaliar){
public final XYPair mul(int scaliar){
return mul(this, scaliar);
}
public XYPair sub(XYPair op){
public final XYPair sub(XYPair op){
return sub(this, op);
}
public XYPair add(XYPair op){
public final XYPair add(XYPair op){
return add(this, op);
}
public int l1_norm(){
public final int l1_norm(){
return abs(_x)+abs(_y);
}
public boolean isEqual(XYPair op){
public final boolean isEqual(XYPair op){
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()
&& op1.y() <= this.y() && this.y() < op2.y();
}
public XYPair left(){
public final XYPair left(){
return this.add(LEFT);
}
public XYPair right(){
public final XYPair right(){
return this.add(RIGHT);
}
public XYPair up(){
public final XYPair up(){
return this.add(UP);
}
public XYPair down(){
public final XYPair down(){
return this.add(DOWN);
}
}