Java: Solving 15 Puzzle using Fitness functions - puzzle

I am currently working on a project to solve a 15 Puzzle using fitness functions. There are 3 kinds of fitness functions that can be used,
Fitness function1= 1 - (number of misplaced tiles/total number of tiles);
Fitness function2= 1- (sum of distances of all misplaced tiles from goal position/64)
Fitness function3= (Fitness 2+ Fitness 1 )/2
The solver is meant to search for possible moves that improves the fitness function VALUE until the whole puzzle board is solved (where fitness function=1).
I am stocked while trying to generate moves because the solver print unsuccessful search routes along with the actual route e.g. W,S,W,N,S,N,S,N,S,N,S,N,S,N,S,N,S,N ( which is in reverse order) and means NWSW. However the solver searches back and forth several times and also prints the unwanted routes.
I would want to exclude previously visited locations in the recursion and also print only the valid moves and not the unsuccessful moves.
The code is available below:
<pre><code>
enter code here
package Definitions;
public class Puzzle {
public TreeNode boardsTree;
public Boolean searching;
public int lastPos;
Puzzle(Board b) {
boardsTree = new TreeNode(b);
lastPos = b.Blank_pos;
}
public String solver(Board b, String route, int level, double fitVal){
//System.out.println("route in the level " + level +": " +route + " Fitness: ");
//System.out.print(b.f1.getFitnessVal());
//If the depth of the Tree is level 15 or Board is solved return route(moves e.g. WNS)
if(level == 15||b.solved){
//if(route != ""){
//if(route.length()>1){
// return route.substring(0, route.length()-1);
//}else{
return route;
//}
}else{
//Create a temporary store for the last position
//Create four auxilliary puzzle boards has child puzzles
//Perform the different moves on the blank space on each board in different directions
//(N=0,S=1,E=2,W=3)
lastPos = b.Blank_pos;
Board auxN = new Board(4,b.tilesList);
Board auxS = new Board(4,b.tilesList);
Board auxE = new Board(4,b.tilesList);
Board auxW = new Board(4,b.tilesList);
//Builds the tree
//MOVES TO NORTH
//b.isValidMove(North=0,South=1,East=2,West=3)
if( b.isValidMove(0)){
//If the lastPosition (blankPosition in the parent board) is not the position of the
//cell in the north MoveBlank to North
if(lastPos != (lastPos - 4)){
auxN.MoveBlank(0);
boardsTree.addSon(0,auxN);
if(fitVal > boardsTree.getSon(0).getState().f1.getFitnessVal()){
auxN.print();
searching = false;
return route + "N";
}
}
}
//MOVES TO SOUTH
//b.isValidMove(North=0,South=1,East=2,West=3)
if( b.isValidMove(1) ){
//If the lastPosition (blankPosition in the parent board) is not the position of the
//cell in the north MoveBlank to North
if(lastPos != (lastPos + 4)){
auxS.MoveBlank(1);
boardsTree.addSon(1,auxS);
if(fitVal > boardsTree.getSon(1).getState().f1.getFitnessVal()){
auxS.print();
searching = false;
return route + "S";
}
}
}
//MOVES TO EAST
if( b.isValidMove(2) ){
if(lastPos != (lastPos + 1)){
auxE.MoveBlank(2);
boardsTree.addSon(2,auxE);
if(fitVal > boardsTree.getSon(2).getState().f1.getFitnessVal()){
auxE.print();
searching = false;
return route + "E";
}
}
}
//MOVES TO WEST
if( b.isValidMove(3) ){
if(lastPos != (lastPos -1)){
auxW.MoveBlank(3);
boardsTree.addSon(3,auxW);
if(fitVal > boardsTree.getSon(3).getState().f1.getFitnessVal()){
auxW.print();
searching = false;
return route + "W";
}
}
}
//EVALUATE NEW STATES
if(searching && b.isValidMove(0)){
System.out.println("Actual: " +auxN.Blank_pos+ " Previo: "+lastPos );
if(lastPos != auxN.Blank_pos){
lastPos = auxN.Blank_pos;
route = solver(auxN,route + "N", level+1, fitVal); //NORTH
}else{
//If a solution is not generated enter a recursion to find further solutions at a
//further depth of the tree
solver(auxN,route, level+1, fitVal); //NORTH
}
}
if(searching && b.isValidMove(1)){
//System.out.println("Actual: " +auxS.Blank_pos+ " Previo: "+lastPos );
if(lastPos != auxS.Blank_pos){
lastPos = auxS.Blank_pos;
route =solver(auxS,route + "S", level+1, fitVal); //NORTH
}else{
solver(auxS,route, level+1, fitVal); //NORTH
}
}
if(searching && b.isValidMove(2)){
//System.out.println("Actual: " +auxE.Blank_pos+ " Previo: "+lastPos );
if(lastPos != auxE.Blank_pos){
lastPos = auxE.Blank_pos;
route = solver(auxE,route + "E", level+1, fitVal); //NORTH
}else{
solver(auxE,route, level+1, fitVal); //NORTH
}
}
if(searching && b.isValidMove(3)){
//System.out.println("Actual: " +auxW.Blank_pos+ " Previo: "+lastPos );
if(lastPos != auxW.Blank_pos){
lastPos = auxW.Blank_pos;
route =solver(auxW,route + "W", level+1, fitVal); //NORTH
}else{
solver(auxW,route, level+1, fitVal); //NORTH
}
}
}
return route;
}
}

Related

I am having issues with a repeating while loop in a switch statement, the loop continues to repeat

I'm a newbie coder and for a class I was required to make a vending machine-like code. However, I used a switch statement as part of it. An issue I faced is that in those if statements I added a check. The check was to ask if the user would like to continue or not, but for some reason it repeats even after an input. I wasn't entirely sure if this question was asked before, but a lot of my friends share the issue.
import java.util.Scanner;
public class hw52 {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
String choice;
String answer = "";
int cr = 0;
int wb = 0;
int ch = 0;
int k = 0;
int j = 0;
boolean check = true;
double cost2;
double discount;
double change = 0;
double cost = 0;
double money = 0;
int counter = 0;
do {
answer = "";
System.out.println("Select an option in the vending machine. \n
Crunch:$1.50 \n Water bottle:$2.00 \n Chips:$1.00 \n Ketchup:$4.00 \n
Juice:$2.50");
choice = keyboard.nextLine();
switch(choice.toUpperCase()){
case "CRUNCH":
cost += 1.5;
cr ++;
counter ++;
System.out.println("Cost: " + cost);
while(check = true) {
System.out.println("Do you want to continue? Yes or no?");
answer = keyboard.nextLine();
if (answer.equalsIgnoreCase("Yes")) {
check = false;
}else if(answer.equalsIgnoreCase("Yes")) {
check = false;
}else {
System.out.println("Bad input.");
}
}
case "WATER BOTTLE":
cost += 2.00;
wb++;
counter ++;
System.out.println("Cost: " + cost);
while(check = true) {
System.out.println("Do you want to continue? Yes or no?");
answer = keyboard.nextLine();
if (answer.equalsIgnoreCase("Yes")) {
check = false;
}else if(answer.equalsIgnoreCase("Yes")) {
check = false;
}else {
System.out.println("Bad input.");
}
}
case "CHIPS":
cost += 1.00;
ch++;
counter ++;
System.out.println("Cost: " + cost);
System.out.println("Cost: " + cost);
while(check = true) {
System.out.println("Do you want to continue? Yes or no?");
answer = keyboard.nextLine();
if (answer.equalsIgnoreCase("Yes")) {
check = false;
}else if(answer.equalsIgnoreCase("Yes")) {
check = false;
}else {
System.out.println("Bad input.");
}
}
case "KETCHUP":
cost += 5.00;
k++;
counter ++;
System.out.println("Cost: " + cost);
while(check = true) {
System.out.println("Do you want to continue? Yes or no?");
answer = keyboard.nextLine();
if (answer.equalsIgnoreCase("Yes")) {
check = false;
}else if(answer.equalsIgnoreCase("Yes")) {
check = false;
}else {
System.out.println("Bad input.");
}
}
case "JUICE":
cost += 2.50;
j++;
counter ++;
System.out.println("Cost: " + cost);
while(check = true) {
System.out.println("Do you want to continue? Yes or no?");
answer = keyboard.nextLine();
if (answer.equalsIgnoreCase("Yes")) {
check = false;
}else if(answer.equalsIgnoreCase("Yes")) {
check = false;
}else {
System.out.println("Bad input.");
}
}
default:
System.out.println("Not a choice! Use exact names.");
answer = "yes";
}
}while(!answer.equalsIgnoreCase("no"));
counter /= 3;
for (int i = 0; i < counter;i++) {
discount = (double)(Math.random()*.1)+.1;
cost2 = cost * discount;
cost -= cost2;
}
while(money < cost) {
System.out.println("How much money would you like to use to pay?");
money = keyboard.nextDouble();
if (money < cost) {
System.out.println("That's not enough money.");
}
}
double Q = cost / .25;
double D = (cost % .25) / .10;
double N = ((cost % .25) % .10) / .05 ;
double P = (((cost % .25) % .10) %.05) /.01;
System.out.println("The items you bought are: \n Crunch Bars: " + cr +
"\n Water Bottles: " + wb + "\n Chips: " + ch + "\n Ketchup: " + k + "\n
Juice: " + j);
System.out.println("Your change is: $" + ((Q * .25) + (D * .1) + (N *
.05) + (P*.01)));
}
}
Please excuse my messy coding style. I personally like it better, but I know a lot of people find it strange.
Your code never allows the user to input "no" into the answer variable. So your code always forces the user to intput "yes" or it shows the message "Bad Input".
You have this if statement in each one of your while loops. Both if and else if check the exact same condition. I assume you were probably wanting one of them to check for the answer "no" and the check variable never gets assigned to false unless "yes" is chosen:
answer = keyboard.nextLine();
if (answer.equalsIgnoreCase("Yes")) { //this is same condition as next if line.
check = false;
}else if(answer.equalsIgnoreCase("Yes")) { //this is same condition as prior if line.
check = false;
}else {
System.out.println("Bad input.");
}
Also, this is your main issue. You are ALWAYS assigning check to true in the while loop condition. you want to use the == operator.
This assigns true to the check variable in your code:
while(check = true) {
You actually want to do this:
while(check == true) {
I recommend using an IDE with a debugger that allows you to systematically step through your code and see what is happening with each line of code as it executes. It will help you find logic problems like this one.

Questions on binary search tree mirroring

I have written 2 methods to find out If an tree is an BST. Most these samples are from stanford courses on web.
before mirroring:
Tree is BST: true (results from first method)
Tree is BST2: true (results from second method)
after mirroring:
Tree is BST: false (results from first method)
Tree is BST2: true (results from second method)
If a binary search tree is mirrored. I believe it will not be an BST anymore. Is that right?
Is the second method wrong?
//mirror
public void mirror(){
mirror(root);
}
private void mirror(Node node){
if(node == null) return;
if( node != null){
mirror(node.left);
mirror(node.right);
Node temp = node.left;
node.left = node.right;
node.right = temp;
}
}
public boolean isBST(){
return isBST(root);
}
private boolean isBST(Node node){
if( node == null) return true;
if( node.left != null && maxValue(node.left) > node.data) return false;
if( node.right != null && minValue(node.right) <= node.data) return false;
return (isBST(node.left) && isBST(node.right));
}
public boolean isBST2(){
return isBST2(root, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
private boolean isBST2(Node node, int minVal, int maxVal){
if( node == null) return true;
else{
boolean leftOk = isBST2(node.left, minVal, node.data);
if(!leftOk) return false;
boolean rightOk = isBST2(node.right, node.data+1, maxVal);
return rightOk;
}
}
//insert with inserts - tree increases on right if inserted in order
bt = new BinaryTree();
bt.insert(5);
bt.insert(3);
bt.insert(7);
bt.insert(1);
bt.insert(4);
bt.insert(6);
bt.insert(9);
bt.printTree();
bt.printPostorder();
System.out.println("max depth: " + bt.maxDepth());
System.out.println("min value: " + bt.minValue());
System.out.println("max value: " + bt.maxValue());
System.out.println("size of tree: " + bt.size());
System.out.println("Has path sum 8: " + bt.hasPathSum(8));
System.out.println("Has path sum 9: " + bt.hasPathSum(9));
bt.printPath();
System.out.println("Trees are same: " + bt.sameTree(bt));
System.out.println("Trees is BST: " + bt.isBST());
System.out.println("Trees is BST: " + bt.isBST2());
bt.mirror();
System.out.println("Path after mirroring BST");
bt.printPath();
System.out.println("Trees is BST: " + bt.isBST());
System.out.println("Trees is BST: " + bt.isBST2());
System.out.println("---------------------");
}
isBST2() does not correctly return if the tree is a BST or not.
In fact it always returns true. When node is null it will return true. Further see that in isBST2() there is no condition checking except if(!leftOk). So if leftOk is true it does not return false. So the function always returns true. Hence this function is not correct.
Whereas, the function isBST() is correct.
So your guess is correct.
Also, when a BST is mirrored, it does not remain a BST, unless it contains only one node.

Android 2D animation drawing: bad performance

I have an app that draws a grid of dots (let's say 5x5). The user is asked to draw lines on that grid. If the user's finger touches one of the dots in the grid, this dot is being colored to show that this dot is part of a path drawn. In addition a line will be drawn between each two touched dots.
The issue - I get very bad performance, which causes few things:
The application gets really slow.
Motion events in event.getAction() get bad granularity. I meanenter code here that instead of registering a movement each 10 pixels for example, it registers movements each 100 pixels. This, in turn, will causes the app to NOT redraw some dots the user had touched.
Sometimes the motion coordinates are simple wrong: lets say the user is moving her finger from pixel 100 to pixel 500, the reading might show 100...200...150...140...300...400. For some reason the touch location gets messed up in some cases.
Look at the example on how the app "misses out" on dots the user have touched and doesn't draw the green dots:
I've tried few thing:
Adding Thread.sleep(100); to else if(event.getAction() == MotionEvent.ACTION_MOVE) inside onTouchEvent(MotionEvent event), I read that this might give the CPU time to catch up on all those touch events - didn't change a thing
Adding this.destroyDrawingCache() to the very end of doDraw() (I use it instead of onDraw, as was suggested by one tutorial I used). I thought this will clear all event/drawing caching which seems to be slowing down the system - didn't change a thing.
I am fairly new to Android animation so I am not sure how to proceed:
I understand I should do as little as possible in doDraw() (my onDraw()) and onTouchEvent().
I read some stuff about invalidate() but not sure how and when to use it. If I understand correctly, my View gets drawn anew each time doDraw() is called. My grid, for instance, is static - how can I avoid redrawing it?
++++++++++++++++++++++++ UPDATE 7th Oct +++++++++++++++++++++
I tried using canvas.drawCircle(xPos, yPos, 8, mNodePaint); instead of canvas.drawBitmap(mBitmap, xPos, yPos, null);. I thought that if I DIDN'T use actual bitmaps this might improve performance. As a matter of fact - it didn't! I am a bit confused how such a simple application can pose such a heavy load on the device. I must be doing something really the wrong way.
++++++++++++++++++++++++ UPDATE 12th Oct +++++++++++++++++++++
I took into account what #LadyWoodi suggested - I've eliminated all variable declarations out of the loops - anyway it is a bad practice and I also got rid of all the "System.Out" lines I use so I can log app behavior to better understand why I get such a lame performance. I am sad to say that if there was a change in performance (I didn't actually measure frame rate change) it is negligible.
Any other ideas?
++++++++++++++++++++++++ UPDATE 13th Oct +++++++++++++++++++++
As I have a static grid of dots (see hollow black/white dots in screenShot) that never changes during the game I did the following:
-Draw the grid once.
-Capture the drawing as bitmap using Bitmap.createBitmap().
-Use canvas.drawBitmap() to draw the bitmap of the static dots grid.
-When my thread runs I check to see it the grid of dots is drawn. If it is running I will NOT recreate the static dots grid. I will only render it from my previously rendered bitmap.
Surprisingly this changed nothing with my performance! Redrawing the dots grid each time didn't have a true visual effect on app performance.
I decided to use canvas = mHolder.lockCanvas(new Rect(50, 50, 150, 150)); inside my drawing thread. It was just for testing purposes to see if I limit the area rendered each time, I can get the performance better. This DID NOT help either.
Then I turned to the DDMS tool in Eclipse to try and profile the app. What it came up with, was that canvas.drawPath(path, mPathPaint); (Canvas.native_drawPath) consumed about 88.5% of CPU time!!!
But why??! My path drawing is rather simple, mGraphics contains a collection of Paths and all I do is figure out if each path is inside the boundaries of the game screen and then I draw a path:
//draw path user is creating with her finger on screen
for (Path path : mGraphics)
{
//get path values
mPm = new PathMeasure(path, true);
mPm.getPosTan(0f, mStartCoordinates, null);
//System.out.println("aStartCoordinates X:" + aStartCoordinates[0] + " aStartCoordinates Y:" + aStartCoordinates[1]);
mPm.getPosTan(mPm.getLength(), mEndCoordinates, null);
//System.out.println("aEndCoordinates X:" + aEndCoordinates[0] + " aEndCoordinates Y:" + aEndCoordinates[1]);
//coordinates are within game board boundaries
if((mStartCoordinates[0] >= 1 && mStartCoordinates[1] >= 1) && (mEndCoordinates[0] >= 1 && mEndCoordinates[1] >= 1))
{
canvas.drawPath(path, mPathPaint);
}
}
Can anyone see any ill programmed lines of code in my examples?
++++++++++++++++++++++++ UPDATE 14th Oct +++++++++++++++++++++
I've made changes to my doDraw()method. Basically what I do is draw the screen ONLY if something was changed. In all other cases I simply store a cached bitmap of the screen and render it. Please take a look:
public void doDraw(Canvas canvas)
{
synchronized (mViewThread.getSurefaceHolder())
{
if(mGraphics.size() > mPathsCount)
{
mPathsCount = mGraphics.size();
//draw path user is creating with her finger on screen
for (Path path : mGraphics)
{
//get path values
mPm = new PathMeasure(path, true);
mPm.getPosTan(0f, mStartCoordinates, null);
//System.out.println("aStartCoordinates X:" + aStartCoordinates[0] + " aStartCoordinates Y:" + aStartCoordinates[1]);
mPm.getPosTan(mPm.getLength(), mEndCoordinates, null);
//System.out.println("aEndCoordinates X:" + aEndCoordinates[0] + " aEndCoordinates Y:" + aEndCoordinates[1]);
//coordinates are within game board boundaries
if((mStartCoordinates[0] >= 1 && mStartCoordinates[1] >= 1) && (mEndCoordinates[0] >= 1 && mEndCoordinates[1] >= 1))
{
canvas.drawPath(path, mPathPaint);
}
}
//nodes that the path goes through, are repainted green
//these nodes are building the drawn pattern
for (ArrayList<PathPoint> nodePattern : mNodesHitPatterns)
{
for (PathPoint nodeHit : nodePattern)
{
canvas.drawBitmap(mDotOK, nodeHit.x - ((mDotOK.getWidth()/2) - (mNodeBitmap.getWidth()/2)), nodeHit.y - ((mDotOK.getHeight()/2) - (mNodeBitmap.getHeight()/2)), null);
}
}
mGameField = Bitmap.createBitmap(mGridNodesCount * mNodeGap, mGridNodesCount * mNodeGap, Bitmap.Config.ARGB_8888);
}
else
{
canvas.drawBitmap(mGameField, 0f, 0f, null);
}
Now for the results - as long as the device doesn't have to render no paths and simply draws from a bitmap, stuff goes very fast. But the moment I have to rerender the screen using canvas.drawPath() performance becomes as sluggish as a turtle on morphine... The more paths I have (up to 6 and more, which is NOTHING!) the slower the rendering. How odd is this?? - My paths are even not really curvy - the are all straight lines with an occasional turn. What I mean is that the line is not very "complex".
I've add more code below - if you have any improvements ideas.
Many thanks in advance,
D.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Class "Panel" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public class Panel extends SurfaceView implements SurfaceHolder.Callback {
Bitmap mNodeBitmap;
int mNodeBitmapWidthCenter;
int mNodeBitmapHeightCenter;
Bitmap mDotOK;
ViewThread mViewThread;
ArrayList<PathPoint> mPathPoints;
private ArrayList<Path> mGraphics = new ArrayList<Path>(3);
private ArrayList<ArrayList<PathPoint>> mNodesHitPatterns = new ArrayList<ArrayList<PathPoint>>();
private Paint mPathPaint;
Path mPath = new Path();
//private ArrayList<Point> mNodeCoordinates = new ArrayList<Point>();
private int mGridNodesCount = 5;
private int mNodeGap = 100;
PathPoint mNodeCoordinates[][] = new PathPoint[mGridNodesCount][mGridNodesCount];
PathMeasure mPm;
float mStartCoordinates[] = {0f, 0f};
float mEndCoordinates[] = {0f, 0f};
PathPoint mPathPoint;
Boolean mNodesGridDrawn = false;
Bitmap mGameField = null;
public Boolean getNodesGridDrawn() {
return mNodesGridDrawn;
}
public Panel(Context context) {
super(context);
mNodeBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dot);
mNodeBitmapWidthCenter = mNodeBitmap.getWidth()/2;
mNodeBitmapHeightCenter = mNodeBitmap.getHeight()/2;
mDotOK = BitmapFactory.decodeResource(getResources(), R.drawable.dot_ok);
getHolder().addCallback(this);
mViewThread = new ViewThread(this);
mPathPaint = new Paint();
mPathPaint.setAntiAlias(true);
mPathPaint.setDither(true); //for better color
mPathPaint.setColor(0xFFFFFF00);
mPathPaint.setStyle(Paint.Style.STROKE);
mPathPaint.setStrokeJoin(Paint.Join.ROUND);
mPathPaint.setStrokeCap(Paint.Cap.ROUND);
mPathPaint.setStrokeWidth(5);
}
public ArrayList<ArrayList<PathPoint>> getNodesHitPatterns()
{
return this.mNodesHitPatterns;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
public void surfaceCreated(SurfaceHolder holder) {
//setPadding(100, 100, 0, 0);
if (!mViewThread.isAlive()) {
mViewThread = new ViewThread(this);
mViewThread.setRunning(true);
mViewThread.start();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
if (mViewThread.isAlive()) {
mViewThread.setRunning(false);
}
}
//draw the basic nodes grid that the user will use to draw the lines on
//store as bitmap
public void drawNodesGrid(Canvas canvas)
{
canvas.drawColor(Color.WHITE);
for (int i = 0; i < mGridNodesCount; i++)
{
for (int j = 0; j < mGridNodesCount; j++)
{
int xPos = j * mNodeGap;
int yPos = i * mNodeGap;
try
{
//TODO - changed
mNodeCoordinates[i][j] = new PathPoint(xPos, yPos, null);
}
catch (Exception e)
{
e.printStackTrace();
}
canvas.drawBitmap(mNodeBitmap, xPos, yPos, null);
}
}
mNodesGridDrawn = true;
mGameField = Bitmap.createBitmap(mGridNodesCount * mNodeGap, mGridNodesCount * mNodeGap, Bitmap.Config.ARGB_8888);
}
public void doDraw(Canvas canvas)
{
canvas.drawBitmap(mGameField, 0f, 0f, null);
synchronized (mViewThread.getSurefaceHolder())
{
//draw path user is creating with her finger on screen
for (Path path : mGraphics)
{
//get path values
mPm = new PathMeasure(path, true);
mPm.getPosTan(0f, mStartCoordinates, null);
//System.out.println("aStartCoordinates X:" + aStartCoordinates[0] + " aStartCoordinates Y:" + aStartCoordinates[1]);
mPm.getPosTan(mPm.getLength(), mEndCoordinates, null);
//System.out.println("aEndCoordinates X:" + aEndCoordinates[0] + " aEndCoordinates Y:" + aEndCoordinates[1]);
//coordinates are within game board boundaries
if((mStartCoordinates[0] >= 1 && mStartCoordinates[1] >= 1) && (mEndCoordinates[0] >= 1 && mEndCoordinates[1] >= 1))
{
canvas.drawPath(path, mPathPaint);
}
}
//nodes that the path goes through, are repainted green
//these nodes are building the drawn pattern
for (ArrayList<PathPoint> nodePattern : mNodesHitPatterns)
{
for (PathPoint nodeHit : nodePattern)
{
canvas.drawBitmap(mDotOK, nodeHit.x - ((mDotOK.getWidth()/2) - (mNodeBitmap.getWidth()/2)), nodeHit.y - ((mDotOK.getHeight()/2) - (mNodeBitmap.getHeight()/2)), null);
}
}
this.destroyDrawingCache();
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
synchronized (mViewThread.getSurefaceHolder()) {
if(event.getAction() == MotionEvent.ACTION_DOWN)
{
//System.out.println("Action downE x: " + event.getX() + " y: " + event.getY());
for (int i = 0; i < mGridNodesCount; i++)
{
for (int j = 0; j < mGridNodesCount; j++)
{
//TODO - changed
//PathPoint pathPoint = mNodeCoordinates[i][j];
mPathPoint = mNodeCoordinates[i][j];
if((Math.abs((int)event.getX() - mPathPoint.x) <= 35) && (Math.abs((int)event.getY() - mPathPoint.y) <= 35))
{
//mPath.moveTo(pathPoint.x + mBitmap.getWidth() / 2, pathPoint.y + mBitmap.getHeight() / 2);
//System.out.println("Action down x: " + pathPoint.x + " y: " + pathPoint.y);
ArrayList<PathPoint> newNodesPattern = new ArrayList<PathPoint>();
mNodesHitPatterns.add(newNodesPattern);
//mNodesHitPatterns.add(nh);
//pathPoint.setAction("down");
break;
}
}
}
}
else if(event.getAction() == MotionEvent.ACTION_MOVE)
{
final int historySize = event.getHistorySize();
//System.out.println("historySize: " + historySize);
//System.out.println("Action moveE x: " + event.getX() + " y: " + event.getY());
coordinateFound:
for (int i = 0; i < mGridNodesCount; i++)
{
for (int j = 0; j < mGridNodesCount; j++)
{
//TODO - changed
//PathPoint pathPoint = mNodeCoordinates[i][j];
mPathPoint = mNodeCoordinates[i][j];
if((Math.abs((int)event.getX() - mPathPoint.x) <= 35) && (Math.abs((int)event.getY() - mPathPoint.y) <= 35))
{
int lastPatternIndex = mNodesHitPatterns.size()-1;
ArrayList<PathPoint> lastPattern = mNodesHitPatterns.get(lastPatternIndex);
int lastPatternLastNode = lastPattern.size()-1;
if(lastPatternLastNode != -1)
{
if(!mPathPoint.equals(lastPattern.get(lastPatternLastNode).x, lastPattern.get(lastPatternLastNode).y))
{
lastPattern.add(mPathPoint);
//System.out.println("Action moveC [add point] x: " + pathPoint.x + " y: " + pathPoint.y);
}
}
else
{
lastPattern.add(mPathPoint);
//System.out.println("Action moveC [add point] x: " + pathPoint.x + " y: " + pathPoint.y);
}
break coordinateFound;
}
else //no current match => try historical
{
if(historySize > 0)
{
for (int k = 0; k < historySize; k++)
{
//System.out.println("Action moveH x: " + event.getHistoricalX(k) + " y: " + event.getHistoricalY(k));
if((Math.abs((int)event.getHistoricalX(k) - mPathPoint.x) <= 35) && (Math.abs((int)event.getHistoricalY(k) - mPathPoint.y) <= 35))
{
int lastPatternIndex = mNodesHitPatterns.size()-1;
ArrayList<PathPoint> lastPattern = mNodesHitPatterns.get(lastPatternIndex);
int lastPatternLastNode = lastPattern.size()-1;
if(lastPatternLastNode != -1)
{
if(!mPathPoint.equals(lastPattern.get(lastPatternLastNode).x, lastPattern.get(lastPatternLastNode).y))
{
lastPattern.add(mPathPoint);
//System.out.println("Action moveH [add point] x: " + pathPoint.x + " y: " + pathPoint.y);
}
}
else
{
lastPattern.add(mPathPoint);
//System.out.println("Action moveH [add point] x: " + pathPoint.x + " y: " + pathPoint.y);
}
break coordinateFound;
}
}
}
}
}
}
}
else if(event.getAction() == MotionEvent.ACTION_UP)
{
// for (int i = 0; i < mGridSize; i++) {
//
// for (int j = 0; j < mGridSize; j++) {
//
// PathPoint pathPoint = mNodeCoordinates[i][j];
//
// if((Math.abs((int)event.getX() - pathPoint.x) <= 35) && (Math.abs((int)event.getY() - pathPoint.y) <= 35))
// {
// //the location of the node
// //mPath.lineTo(pathPoint.x + mBitmap.getWidth() / 2, pathPoint.y + mBitmap.getHeight() / 2);
//
// //System.out.println("Action up x: " + pathPoint.x + " y: " + pathPoint.y);
//
// //mGraphics.add(mPath);
// // mNodesHit.add(pathPoint);
// // pathPoint.setAction("up");
// break;
// }
// }
// }
}
//System.out.println(mNodesHitPatterns.toString());
//create mPath
for (ArrayList<PathPoint> nodePattern : mNodesHitPatterns)
{
for (int i = 0; i < nodePattern.size(); i++)
{
if(i == 0) //first node in pattern
{
mPath.moveTo(nodePattern.get(i).x + mNodeBitmapWidthCenter, nodePattern.get(i).y + mNodeBitmapHeightCenter);
}
else
{
mPath.lineTo(nodePattern.get(i).x + mNodeBitmapWidthCenter, nodePattern.get(i).y + mNodeBitmapWidthCenter);
}
//mGraphics.add(mPath);
}
}
mGraphics.add(mPath);
return true;
}
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Class "ViewThread" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public class ViewThread extends Thread {
private Panel mPanel;
private SurfaceHolder mHolder;
private boolean mRun = false;
public ViewThread(Panel panel) {
mPanel = panel;
mHolder = mPanel.getHolder();
}
public void setRunning(boolean run) {
mRun = run;
}
public SurfaceHolder getSurefaceHolder()
{
return mHolder;
}
#Override
public void run()
{
Canvas canvas = null;
while (mRun)
{
canvas = mHolder.lockCanvas();
//canvas = mHolder.lockCanvas(new Rect(50, 50, 150, 150));
if (canvas != null)
{
if(!mPanel.getNodesGridDrawn())
{
mPanel.drawNodesGrid(canvas);
}
mPanel.doDraw(canvas);
mHolder.unlockCanvasAndPost(canvas);
}
}
}
}
It's just the idea, but I would try to take all the declarations out of the loops. I know that it can be useful to have them localized, however it's usually really time consuming so it could help a little. My second idea was already tested by you in your update so now I am also curious how it will go ;)
You are using a SurfaceView? First of all, I recommend you to use a graphic library for your game... AndEngine for example is pretty easy to use and you will achieve to develop a much more beautiful game than using the Java canvas. The performance is better too.
I canĀ“t find anything wrong with your code, but there is a lot of processing in the draw method, and more important, in the onTouch event. You should avoid to use divisions or heavy math operations in the loops and try to pre-calculate everything before.
But I insist; for something like what you are doing, take a look at this and you will have it up and running in no time!

Finding BST's height non-recursively?

This is a recursive method for finding the height, but i have a very large number of nodes in my binary search tree, and i want to find the height of the tree as well as assign the height to each individual sub-tree. So the recursive method throws stackoverflow exception, how do i do this non-recursively and without using stack?
private int FindHeight(TreeNode node)
{
if (node == null)
{
return -1;
}
else
{
node.Height = 1 + Math.Max(FindHeight(node.Left), FindHeight(node.Right));
return node.Height;
}
}
I believe i have to use post order traversal but without stack?
I was able to make this method, and it does return the correct height but it assigns each node with its depth not height.
public void FindHeight()
{
int maxHeight = 0;
Queue<TreeNode> Q = new Queue<TreeNode>();
TreeNode node;
Q.Enqueue(Root);
while (Q.Count != 0)
{
node = Q.Dequeue();
int nodeHeight = node.Height;
if (node.Left != null)
{
node.Left.Height = nodeHeight + 1;
Q.Enqueue(node.Left);
}
if (node.Right != null)
{
node.Right.Height = nodeHeight + 1;
Q.Enqueue(node.Right);
}
if (nodeHeight > maxHeight)
{
maxHeight = nodeHeight;
}
}
Console.WriteLine(maxHeight);
}

How to code the chess stalemate rule ?

I'm trying to write a chess game and find that I cannot find solutions to find a stalemate situation. I'm trying to google, but can't find anything. Is there a well-known algorithm or something?
Your move generator will be one of two different designs;
either it checks for legality while generating the moves
or you generate all possible moves and remove those that are illegal afterwards.
The former is better as it doesn't need post-processing.
A stalemate condition is simply one where there are no legal moves and the moving-side's king is not in check. A checkmate condition is one where there are no legal moves but the moving-side's king is in check.
In other words if you've figured out how to detect check and checkmate, you've already got everything necessary to detect stalemate.
Here is an Open-source code with all the rules for the classic Chess game:
https://github.com/cjortegon/basic-chess
You can run the project right after cloning the project (Android, iOS, Desktop and Web), or you can use the main logic, which is here: https://github.com/cjortegon/basic-chess/tree/master/libgdx/core/src/com/mountainreacher/chess/model
I based my solution on a 3-moments algorithm, first moment is when the player selects a piece from the board, then when the destination of this piece has been chosen and finally when the piece reaches that position (considering that it is an animated game, if not, you can merge step 2 and 3).
The following code has been implemented in Java. From the properties of the model class:
boolean turn;
GenericPiece selected, conquest;
ClassicBoard board;
List<int[]> possibleMovements;
int checkType;
The first method will handle moments 1, 2 and the special 'conquest' moment (applied to pawn piece only):
public boolean onCellClick(int row, int column) {
if (row == -1 && conquest != null) {
checkType = 0;
conquest.changeFigure(column);
return true;
} else if (selected != null) {
if (possibleMovements != null) {
for (int[] move : possibleMovements) {
if (move[0] == row && move[1] == column) {
// Move the PieceActor to the desired position
if (selected.moveTo(row, column)) {
turn = !turn;
}
break;
}
}
}
selected = null;
possibleMovements = null;
return true;
} else {
selected = board.getSelected(turn ? Piece.WHITE_TEAM : Piece.BLACK_TEAM, row, column);
if (selected != null) {
possibleMovements = new ArrayList<>();
possibleMovements.addAll(((GenericPiece) selected).getMoves(board, false));
// Checking the movements
board.checkPossibleMovements(selected, possibleMovements);
if (possibleMovements.size() == 0) {
possibleMovements = null;
selected = null;
return false;
} else {
return true;
}
}
}
return false;
}
And the following method will handle the 3rd moment (when animation finishes):
public void movedPiece(Piece piece) {
Gdx.app.log(TAG, "movedPiece(" + piece.getType() + ")");
// Killing the enemy
Piece killed = board.getSelectedNotInTeam(piece.getTeam(),
piece.getRow(), piece.getColumn());
if (killed != null) {
killed.setAvailable(false);
}
// Checking hacks
GenericPiece[] threat = board.kingIsInDanger();
if (threat != null) {
checkType = board.hasAvailableMoves(threat[0].getTeam()) ? CHECK : CHECK_MATE;
} else {
checkType = NO_CHECK;
}
// Checking castling
if (piece.getFigure() == Piece.ROOK && ((GenericPiece) piece).getMovesCount() == 1) {
Piece king = board.getSelected(piece.getTeam(),
piece.getRow(), piece.getColumn() + 1);
if (king != null && king.getFigure() == Piece.KING && ((GenericPiece) king).getMovesCount() == 0) {
// Left Rook
if (board.getSelected(piece.getRow(), piece.getColumn() - 1) == null) {
king.moveTo(piece.getRow(), piece.getColumn() - 1);
}
} else {
king = board.getSelected(piece.getTeam(),
piece.getRow(), piece.getColumn() - 1);
if (king != null && king.getFigure() == Piece.KING && ((GenericPiece) king).getMovesCount() == 0) {
// Right Rook
if (board.getSelected(piece.getRow(), piece.getColumn() + 1) == null) {
king.moveTo(piece.getRow(), piece.getColumn() + 1);
}
}
}
}
// Conquest
else if (piece.getFigure() == Piece.PAWN && (piece.getRow() == 0 || piece.getRow() == board.getRows() - 1)) {
conquest = (GenericPiece) piece;
checkType = CONQUEST;
}
}
That code covers all the rules from the classic chess, including: regular piece movements, castling, check, check-mate and conquests of pawns.