Given the game http://mypuzzle.org/sliding, which starts with square grid containing tiles with numbers
from 1 to N and one empty block represented with X.The goal is to put the tiles according to their numbers.The
moving is done by moving a tile from left,right,top,bottom to the position of the empty tile.I have to solve this problem using IDA* and Manhattan approach
My goal is to output
1.On the first row output the length of the "optimal" path from the start to the destination state
2.The steps which solve the problem in order to reach our final state. The steps are left,right,up,down
Here is my current code working on solution for 3x3 :
/**
*
* Problem Name: Eight Algorithm: IDA* (Iterative deepening A*) using Manhattan Distance Heuristic
* Source: AI: A Modern Approach
*
*/
// Beware my messy code follows!
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
*
*
*
*
* #class used to keep State Machine of Eight Puzzle with f,g,h along with board
*
*/
class StateEightPuzzle {
private int f, g, h;
private StringBuilder stateofBoard;
private int xEmptyTile, yEmptyTile;
private int pre;
public void setStateofBoard(StringBuilder stateofBoard) {
this.stateofBoard = stateofBoard;
}
public void setPre(int pre) {
this.pre = pre;
}
public void setXEmptyTile(int xEmptyTile) {
this.xEmptyTile = xEmptyTile;
}
public void setYEmptyTile(int yEmptyTile) {
this.yEmptyTile = yEmptyTile;
}
public void setF(int f) {
this.f = f;
}
public void setG(int g) {
this.g = g;
}
public void setH(int h) {
this.h = h;
}
public int getPre() {
return pre;
}
public int getXEmptyTile() {
return xEmptyTile;
}
public int getYEmptyTile() {
return yEmptyTile;
}
public StringBuilder getStateofBoard() {
return stateofBoard;
}
public int getF() {
return f;
}
public int getG() {
return g;
}
public int getH() {
return h;
}
}
/**
*
* #class used as return type where flimit is used as current flimit and sol indicates whether
* solution is found
*
*/
class ReturnResult {
int flimit;
StateEightPuzzle sol;
}
public class Main {
/**
* #param args
*/
static int flag;
static int[] tracePath;
static private int ROWSIZE = 3;
static private int BOARDSIZE = 9;
/*
*
* function used to see whether the current Eight puzzle can be solvable that is can we subjugate
* our beloved using inversion permutation
*/
public static boolean isSolvable(String dpState) {
int inversion = 0;
for (int i = 0; i < BOARDSIZE; i++)
for (int j = i + 1; j < BOARDSIZE; j++)
if (dpState.charAt(i) > '0' && dpState.charAt(j) > '0'
&& dpState.charAt(i) > dpState.charAt(j))
inversion++;
if (inversion % 2 == 1)
return false;
else
return true;
}
/*
*
* getManhattanDistance returns Manhattan distance between current Node of Eight puzzle State
* Machine and Goal State(Final Destination)
*/
public static int getManhattanDistance(StringBuilder knightBoard) {
int manhattanVal = 0;
for (int i = 0; i < ROWSIZE; i++)
for (int j = 0; j < ROWSIZE; j++) {
int pos = i * ROWSIZE + j;
int val = (knightBoard.charAt(pos) - '0') - 1;
if (val == -1)
continue;
manhattanVal = manhattanVal + Math.abs((val / ROWSIZE) - i) + Math.abs((val % ROWSIZE) - j);
}
return manhattanVal;
}
/**
*
*
*
* #param stat
* #param x
* #param y
* #return
*
* function used to generate next State Machine of Eight Puzzle aka Successor Node(Child
* Node) of Current State(Father Node)
*
*/
public static StateEightPuzzle findSuccessor(StateEightPuzzle fatherNode, int x, int y, int pre) {
int nextXCordiante, nextYCordiante;
nextXCordiante = fatherNode.getXEmptyTile();
nextYCordiante = fatherNode.getYEmptyTile();
StateEightPuzzle childNode = new StateEightPuzzle();
if ((nextXCordiante + x) < 0 || (nextYCordiante + y) < 0 || (nextXCordiante + x) > (ROWSIZE - 1)
|| (nextYCordiante + y) > (ROWSIZE - 1)) {
flag = 0;
return childNode;
}
int nextEmptyTile = (nextXCordiante + x) * ROWSIZE + (nextYCordiante + y);
StringBuilder s1 = new StringBuilder(fatherNode.getStateofBoard());
char ch = s1.charAt(nextEmptyTile);
s1.setCharAt(nextEmptyTile, '0');
s1.setCharAt(ROWSIZE * nextXCordiante + nextYCordiante, ch);
childNode.setStateofBoard(s1);
childNode.setXEmptyTile(nextXCordiante + x);
childNode.setYEmptyTile(nextYCordiante + y);
childNode.setG(fatherNode.getG() + 1);
childNode.setH(getManhattanDistance(s1));
childNode.setPre(pre);
int maxfValue = (fatherNode.getF()) > (childNode.getG() + childNode.getH()) ? fatherNode.getF()
: (childNode.getG() + childNode.getH());
childNode.setF(maxfValue);
flag = 1;
return childNode;
}
/**
*
* #param init
* #param flimit
* #param res
* #return function known as Iterative Deepening DFS for A* which uses f-cost for limiting it
* search depth. Once the search inside a given contour has been completed , a new
* iteration is started with new f-cost for the next DFS-CONTOUR.pls consult Artificial
* Intelligence A Modern Approach, 1st edition by Approach By Russell
*
*/
public static ReturnResult DFS_CONTOUR(StateEightPuzzle Node, int flimit, ReturnResult res) {
int newf = Integer.MAX_VALUE;
ReturnResult resTemp = new ReturnResult();
StateEightPuzzle stat;
tracePath[Node.getG()] = Node.getPre();
// distance matrix for Eight Puzzle which helps to get successor
int dist[][] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
// if current node exceeds flimit return it as flimit
if (Node.getF() > flimit) {
resTemp.flimit = Node.getF();
resTemp.sol = null;
return resTemp;
}
// I see : IDA* is going to give me juicy cool!
if (Node.getH() == 0) {
resTemp.flimit = flimit;
resTemp.sol = Node;
String sol = "uldr";
for (int i = 1; i <= Node.getG(); i++)
System.out.print(sol.charAt(tracePath[i]));
System.out.println("");
return resTemp;
}
// create next valid successor
for (int i = 0; i < 4; i++) {
if (Math.abs(i - Node.getPre()) == 2)
continue;
stat = findSuccessor(Node, dist[i][0], dist[i][1], i);
if (flag == 0)
continue;
resTemp = DFS_CONTOUR(stat, flimit, res);
if (resTemp.sol != null) {
resTemp.flimit = res.flimit;
return resTemp;
}
newf = resTemp.flimit < newf ? resTemp.flimit : newf;
}
resTemp.flimit = newf;
resTemp.sol = null;
return resTemp;
}
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String s_2;
while ((s_2 = in.readLine()) != null) {
String str = "";
tracePath = new int[1000];
int emptySquare = 0;
String[] s2 = s_2.split("\\s+");
for (int i = 0; i < s2.length; i++) {
if (s2[i].equals("x") == false)
str += s2[i];
else
str += "0";
}
if (isSolvable(str) == false) {
System.out.println("unsolvable");
} else {
StringBuilder str_bld = new StringBuilder(str);
for (int i = 0; i < str_bld.length(); i++)
if (str_bld.charAt(i) == '0') {
emptySquare += i;
break;
}
// Create Initial Eight puzzle State Machine and let him dance
// with
// prima donna :-)
StateEightPuzzle init = new StateEightPuzzle();
init.setStateofBoard(str_bld);
init.setG(0);
init.setH(getManhattanDistance(str_bld));
init.setF(init.getH() + init.getG());
init.setXEmptyTile(emptySquare / ROWSIZE);
init.setYEmptyTile(emptySquare % ROWSIZE);
init.setPre(5);
int flimit = init.getF();
ReturnResult result = new ReturnResult();
result.flimit = flimit;
result.sol = init;
// loop loop i m a strange loop living a mundane life with hopes
for (;;) {
ReturnResult resTemp = DFS_CONTOUR(init, flimit, result);
if (resTemp.sol != null) {
break;
}
flimit = resTemp.flimit;
}
}
}
}
}
The problem I find is for example for the puzzle when inputed 1 2 3 4 5 6 x 7 8 , it
should input just "ll" moving the "x" tile to the right two times however it inputs "urdlurdlurdr"
any ideas where the problem can be?
Related
A week ago I was given a challenge from my professor to make a program that has three operations for large numbers, given as as strings. I could only pass five of the ten test cases and got an A anyway, but I still want to know what you guys would do for this problem, as far as programming techniques or an approach I didn't think of..
You are given a String representation of a number that is up to 309 digits long. You can preform three operations:
1) Add 1 to the number
2) Subtract 1
3) Divide by 2
the purpose of the program is to find the shortest path, or smallest amount of operations that can be performed on this number so that the result is 1.
ex: given "11"
1 -> 2 -> 3 -> 6 -> 12 -> 11
result: 5 steps
I had two approaches that didn't work 100%:
1: start from one or the number itself and recursively step through each possible answer until number is reached within a maximum number of steps (eg. 11, 20).
2: define all possible answers with the help of a 2-d boolean array with all possible permutaions, then step through the possible movesets one by one. this array works as a map conceptually.
Both of these approaches had limited success, wether i encountered a stackoverflow error or just ran out of memory with my large arrays. This forced me to limit the number of steps so the code could function somewhat successfully. What would be your approach?
EDIT 1:30pm
attempt 1(sorry, it has been edited severely, hence why it wasn't shown earlier...):
import java.math.BigInteger;
import java.util.Scanner;
public class Answer {
public static void main(String[] args) {
// TODO Auto-generated method stub
String str;
Scanner sc = new Scanner(System.in);
while (true) {
str = sc.nextLine();
System.out.println(answer(str));
}
// System.out.println(answer("15"));
}
private static BigInteger minNumOfJumps;
private static BigInteger big2 = BigInteger.valueOf(2);
/** smallest Number of jumps reached so far */
private static BigInteger smallestAmountOfJumps;
public static int answer(String string) {
// TODO Auto-generated method stub
BigInteger src = new BigInteger(string);
// BigInteger currentJump = BigInteger.ZERO; //used to initialize the
// nodes
// minNumOfJumps = src.divide(big2).add(BigInteger.ONE); //this must
// execute...
minNumOfJumps = new BigInteger("14"); // this must execute...
smallestAmountOfJumps = new BigInteger(minNumOfJumps.toString());
// System.out.println(minNumOfJumps);
Node n = new Node(src); // ...before this
return Integer.parseInt(getSmallestAmountOfJumps().toString());
// System.out.println(n.getSmallestAmountOfJumps().toString());
}
public static BigInteger getBig2() {
return big2;
}
public static void setBig2(BigInteger big2) {
Answer.big2 = big2;
}
public static BigInteger getMinNumOfJumps() {
return minNumOfJumps;
}
public static BigInteger getSmallestAmountOfJumps() {
return smallestAmountOfJumps;
}
public static void setSmallestAmountOfJumps(String smallestAmountOfJumps) {
Answer.smallestAmountOfJumps = new BigInteger(smallestAmountOfJumps);
}
}
/*
* I have never made a shortest path algorithm before, so i hope this is toyour
* satisfaction
*/
class Node {
/** number of nodes per creation */
private static final int NUMBER_OF_NODES_PER_NODE = 3;
/** if this number is exceeded, no more jumps are necessary. */ // SAVE THAT
// THINKING
// JUICE!
// private static BigInteger POSSIBLE_MINIMUM_NUMBER_OF_JUMPS;
private static boolean lastTransformWasRemoveOne;
private static boolean lastTransformWasAddOne;
// if one is the given value(src)
// private boolean isOneReached;
/** if the current path isn't valid */
// private boolean threadIsBroken;
// value passed during creation
private BigInteger src;
// current jump
private BigInteger currentJump;
// all possible transformations during next jump
// private Node[] path;
private Node(BigInteger src, BigInteger jump) {
currentJump = jump;
this.src = src;
// POSSIBLE_MINIMUM_NUMBER_OF_JUMPS = Answer.getMinNumOfJumps();
// this.path = new Node[NUMBER_OF_NODES_PER_NODE];
// 0 = remove | 1 = add | 2 = divide
for (int i = 0; i < NUMBER_OF_NODES_PER_NODE; i++) {
// System.out.println("i: " + i);
// System.out.println("src: " + src);
// System.out.println("compare: " +
// currentJump.compareTo(smallestAmountOfJumps));
// System.out.println("currentJump: " + currentJump);
// System.out.println("smallestAmountOfJumps: " +
// smallestAmountOfJumps);
if (src.compareTo(BigInteger.ONE) == 0) {
if (currentJump.subtract(Answer.getSmallestAmountOfJumps()).compareTo(BigInteger.ZERO) == -1) {
Answer.setSmallestAmountOfJumps(currentJump.toString());
// this below may break the code, but i think it fits with
// the logic
break;
}
} else if (i == 0) { // remove 1
// System.out.println(lastTransformWasAddOne);
// System.out.println("compare: " +
// currentJump.compareTo(smallestAmountOfJumps));
// System.out.println("currentJump: " + currentJump);
// System.out.println("smallestAmountOfJumps: " +
// smallestAmountOfJumps);
if (!lastTransformWasAddOne && currentJump.compareTo(Answer.getSmallestAmountOfJumps()) < 0) {
lastTransformWasRemoveOne = true;
Node n = new Node(transform(i), currentJump.add(BigInteger.ONE));
}
} else if (i == 1 && !lastTransformWasRemoveOne
&& currentJump.compareTo(Answer.getSmallestAmountOfJumps()) < 0) { // add
// 1
lastTransformWasAddOne = true;
Node n = new Node(transform(i), currentJump.add(BigInteger.ONE));
} else if (src.mod(Answer.getBig2()) == BigInteger.ZERO
&& currentJump.compareTo(Answer.getSmallestAmountOfJumps()) < 0) { // divide
// by
// 2
lastTransformWasRemoveOne = false;
lastTransformWasAddOne = false;
Node n = new Node(transform(i), currentJump.add(BigInteger.ONE));
} else if (currentJump.compareTo(Answer.getSmallestAmountOfJumps()) == 0)
break;
}
}
private BigInteger transform(int i) {
// TODO Auto-generated method stub
return (i == 0) ? src.subtract(BigInteger.ONE)
: (i == 1) ? src.add(BigInteger.ONE) : (i == 2) ? src.divide(Answer.getBig2()) : BigInteger.ZERO;
}
/**
* To be called once and only once.
*/
public Node(BigInteger src) {
this(src, BigInteger.ZERO);
}
}`
and this is another attempt:
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class AnswerLessProficient {
public static void main(String[] args) {
// TODO Auto-generated method stub
String str;
Scanner sc = new Scanner(System.in);
while (true) {
str = sc.nextLine();
System.out.println(answer(str));
}
// System.out.println(answer("15"));
}
private static boolean notFirstCall;
private static boolean pathIsSet;
private static boolean[][] boolArray;
private static final String ZERO = "0";
private static final BigInteger TWO = BigInteger.ONE.add(BigInteger.ONE);
private static int maximumSteps;
private static int maximumPermutations;
private static ArrayList<byte[]> listOfPaths;
private static Set<byte[]> setOfPaths;
// private static final int maximumPermutations = halfMaximumPermutations *
// 2;
// private static byte[][] path;
private static BigInteger src;
private static int steps;
private static BigInteger tempSrc;
private static byte[] tempPath;
// private static boolean followThePathsWithAlternateRoutesWasCalledOnce;
public static int answer(String s) {
// listOfPaths = new ArrayList<>();
src = new BigInteger(s);
tempSrc = new BigInteger(s);
maximumSteps = 9;
steps = maximumSteps;
maximumPermutations = (int) Math.pow(2, maximumSteps);
if (!notFirstCall) {
tempPath = new byte[maximumSteps];
setOfPaths = new HashSet<>();
int mercyVar = (int) Math.pow(2, maximumSteps);
// path = new byte[maximumPermutations][maximumSteps];
// boolArray = new boolean[maximumPermutations][maximumSteps];
for (int i = 0; i < mercyVar; i++) {
listOfPaths = new ArrayList<>();
String bin = (Integer.toBinaryString(i));
while (bin.length() < maximumSteps)
bin = (ZERO + bin);
char[] chars = bin.toString().toCharArray();
byte[] tempPath = new byte[maximumSteps];
for (int j = 0; j < maximumSteps; j++) {
// if (!pathIsSet)
// path[j] = -1;
if (chars[j] == '0') {
tempPath[j] = 2;
// path[i][j] = 2;
// boolArray[i][j] = true;
} else {
tempPath[j] = -1;
// path[i][j] = -1;
}
}
//System.out.println(Arrays.toString(tempPath));
listOfPaths.add(tempPath);
setOfPaths.add(tempPath);
findAltRoute(listOfPaths.size() - 1, maximumSteps - 1);
}
/*
* for (int i = mercyVar, j = 0; i < maximumPermutations; i++, j++)
* { for (int k = 0; k < maximumSteps; k++) { if (path[j][k] == -1)
* { path[i][k] = 1; } else { path[i][k] = 2; } } }
*/
// for (byte[] bs : setOfPaths) {
// System.out.println(Arrays.toString(bs));
// }
/*
* for (int i = maximumSteps - 1, k = 0; i >= 0 &&
* tempSrc.compareTo(BigInteger.ZERO) > 0; i--, k++) { if
* (tempSrc.compareTo(BigInteger.ONE) <= 0) if (k < steps) { steps =
* k; maximumSteps = steps; System.out.println(Arrays.toString(bs));
* break; } else break; if (bs[i] == 2 && tempSrc.mod(TWO) !=
* BigInteger.ZERO) break; tempSrc = transform(tempSrc, bs[i]); }
* tempSrc = src.add(BigInteger.ZERO);
*/
// }
// System.out.println(bin);
/*
* for (int j = 0; j < maximumSteps && i >= halfMaximumPermutations;
* j++) { // if (!pathIsSet) // path[j] = -1; if (chars[j + 1] ==
* '0') { path[i][j] = 2; // boolArray[i][j] = true; } else {
* path[i][j] = 1; } }
*/
// System.out.println(bin);
// System.out.println(Arrays.toString(path[i]));
// pathIsSet = true;
notFirstCall = true;
}
justFollowThePath();
// System.out.println(Arrays.toString(path[0]));
// System.out.println
// (Arrays.toString(path[(int) (maximumPermutations/2)-1]));
// System.out.println(Arrays.toString(path[maximumPermutations-1]));
/**
* 561-508-2204 george rubio debt forgiveness; 305-709-8255
*/
// for (int i = 0; i < maximumPermutations; i++) {
// followThePathsWithAlternateRoutes(path[i], maximumSteps - 1);
// }
// followThePathsWithAlternateRoutesWasCalledOnce = false;
/*
* for (int i = 0; i < maximumPermutations; i++) { for (int k = 0; k <
* maximumSteps; k++) {
*
* }
*
* for (int k = maximumSteps - 1; k > 0; k--) {
*
* } }
*/
// for (boolean[] bs : boolArray) {
// System.out.println(Arrays.toString(bs));
// }
// System.out.println(Arrays.toString(boolArray[maximumPermutations -
// 1]));
// System.out.println(Arrays.toString(path));
return steps;
}
private static void findAltRoute(int listIndex, int startingSearchIndex) {
if (listOfPaths.get(listIndex)[startingSearchIndex] == -1) {
// followThePathsWithAlternateRoutesWasCalledOnce = true;
// recurAlt(tempPath, maximumSteps - 1, maximumSteps - 1, (byte) 1,
// maximumSteps - 1);
for (int i = startingSearchIndex - 1; i >= 0; i--) {
if (listOfPaths.get(listIndex)[i] == 2) {
returnAltRoute(listIndex, i + 1, startingSearchIndex, (byte) 1, i);
findAltRoute(listIndex + 1, i);
return;
}
else if (i == 0) {
returnAltRoute(listIndex, i, startingSearchIndex, (byte) 1);
return;
}
}
}
for (int i = startingSearchIndex - 1; i >= 0; i--) {
if (listOfPaths.get(listIndex)[i] == -1 && listOfPaths.get(listIndex)[i + 1] == 2) {
if (i != 0) {
for (int k = i - 1; k >= 0; k--) {
if (listOfPaths.get(listIndex)[k] == 2 && listOfPaths.get(listIndex)[k + 1] == -1) {
// recurAlt(tempPath, i, k + 1, (byte) 1, k);
returnAltRoute(listIndex, k + 1, i, (byte) 1, k);
findAltRoute(listIndex, i);
}
// returnAltRoute(listIndex, 0, i, (byte)1);
// return;
}
} else {
returnAltRoute(listIndex, 0, i, (byte) 1);
return;
}
}
}
}
private static void returnAltRoute(int listIndex, int tempStart, int tempEnd, byte adjust, int returnSearchInt) {
byte[] tempPath = new byte[listOfPaths.get(listIndex).length];
for (int i = maximumSteps - 1; i >= 0; i--) {
if (i >= tempStart && i <= tempEnd) {
tempPath[i] = adjust;
} else {
tempPath[i] = listOfPaths.get(listIndex)[i];
}
}
System.out.println(Arrays.toString(tempPath));
setOfPaths.add(tempPath);
listOfPaths.add(tempPath);
maximumPermutations = setOfPaths.size();
findAltRoute(listIndex, returnSearchInt);
}
private static void returnAltRoute(int listIndex, int tempStart, int tempEnd, byte adjust) {
byte[] tempPath = new byte[listOfPaths.get(listIndex).length];
for (int i = maximumSteps - 1; i >= 0; i--) {
if (i >= tempStart && i <= tempEnd) {
tempPath[i] = adjust;
} else {
tempPath[i] = listOfPaths.get(listIndex)[i];
}
}
System.out.println(Arrays.toString(tempPath));
setOfPaths.add(tempPath);
listOfPaths.add(tempPath);
maximumPermutations = setOfPaths.size();
}
private static void justFollowThePath() {
for (byte[] bs : setOfPaths) {
//System.out.println(tempSrc.toString());
for (int i = 0; i < maximumSteps && tempSrc.compareTo(BigInteger.ZERO) > 0; i++) {
if (tempSrc.compareTo(BigInteger.ONE) == 0)
if (i < steps) {
steps = i;
maximumSteps = steps;
//System.out.println(i);
// System.out.println(Arrays.toString(tempPath));
break;
} else
break;
if (bs[i] == 2 && tempSrc.mod(TWO) != BigInteger.ZERO)
break;
tempSrc = transform(tempSrc, bs[i]);
}
tempSrc = src.add(BigInteger.ZERO);
}
}
private static void followThePathsWithAlternateRoutes(byte[] tempPath, int startingSearchIndex) {
if (tempPath[maximumSteps - 1] == -1) {
// followThePathsWithAlternateRoutesWasCalledOnce = true;
recurAlt(tempPath, maximumSteps - 1, maximumSteps - 1, (byte) 1, maximumSteps - 1);
}
for (int i = startingSearchIndex - 1; i >= 0; i--) {
if (tempPath[i] == -1 && tempPath[i + 1] == 2) {
for (int k = i - 1; k > 0; k--) {
if (tempPath[k] == 2) {
recurAlt(tempPath, i, k + 1, (byte) 1, k);
}
}
}
}
System.out.println();
for (int i = maximumSteps - 1, k = 0; i >= 0 && tempSrc.compareTo(BigInteger.ZERO) > 0; i--, k++) {
if (tempSrc.compareTo(BigInteger.ONE) <= 0)
if (k < steps) {
steps = k;
maximumSteps = steps;
System.out.println(Arrays.toString(tempPath));
break;
} else
break;
if (tempPath[i] == 2 && tempSrc.mod(TWO) != BigInteger.ZERO)
break;
tempSrc = transform(tempSrc, tempPath[i]);
}
tempSrc = src.add(BigInteger.ZERO);
}
private static BigInteger transform(BigInteger temp, byte i) {
// TODO Auto-generated method stub
return (i == -1) ? tempSrc.subtract(BigInteger.ONE)
: (i == 1) ? tempSrc.add(BigInteger.ONE) : (i == 2) ? tempSrc.divide(TWO) : null;
}
private static void recurAlt(byte[] tempPath, int tempStart, int tempEnd, byte adjust, int returnSearchInt) {
// TODO Auto-generated method stub
byte[] temp = new byte[tempPath.length];
for (int i = 0; i < temp.length; i++) {
if (i >= tempStart && i <= tempEnd)
temp[i] = adjust;
else
temp[i] = tempPath[i];
}
followThePathsWithAlternateRoutes(temp, returnSearchInt);
}
}
there are other things i've tried, but you can see where i'm going. Any pointers?
If the number is even, divide by 2. If the number is 3 mod 4, add one unless the number is actually 3. Otherwise, subtract one. Repeat until you get to 1.
Here's a proof.
First note that if the number is even, it only makes sense to divide by 2. Because if you perform some number (say 2k) of +1 or -1, then divide by 2 that's the same as dividing by two and then adding or subtracting k 1's. So by dividing by two first, you save operations.
So the only question is whether to add or subtract 1 when the number is odd. You can prove by induction that the given strategy is correct.
An odd number n is either 4x+1 or 4x+3. Note that any sequence of operations (when we're dividing by 2 whenever possible) will at some point reach either x or x+1.
We'll consider each of these in turn, and count shortest paths to x and x+1. (Checking that I've correctly identified shortest paths is omitted).
In the first case (4x+1), by subtracting one first we can get to x in 3 steps (4x+1->4x->2x->x) and x+1 in 4 steps (4x+1->4x->2x->x->x+1). By adding one first, we can get to x in 4 steps (4x+1->4x+2->2x+1->2x->x) and x+1 in 4 steps (4x+1->4x+2->2x+1->2x+2->x+1). So we might as well always subtract 1 first.
In the second case (4x+3), by subtracting one first we can get to x in 4 steps (4x+3->4x+2->2x+1->2x->x), and x+1 in 4 steps (4x+3->4x+2->2x+1->2x+2->x+1). By adding one first, we can get to x+1 in 3 steps (4x+3->4x+4->2x+2->x+1), and x in 4 steps (4x+3->4x+4->2x+2->x+1->x). So we might as well always add 1 first in this case.
In the second case, if x=0 (that is n=4*0+3=3), then our reasoning doesn't quite work, since we won't, in fact, reach x. In this case we should subtract one and divide by 2 to reach 1.
The question is labelled java, but here's some pseudocode (actually Python) to produce optimal chains:
def chain(n):
while n:
print n,
if n % 2 == 0:
n //= 2
elif n % 4 == 3 and n != 3:
n += 1
else:
n -= 1
chain(11)
My first approach will be using BFS.
There are only 2 or 3 state transition ( I assume we can't divide odd number).
But this approach only fast enough for small number.
The second approach will be using A* with smallest number as heuristic function. For example when I start with "12", I can go to:
"11", "13", "6". I will choose "6" for the next state because it closer to "1".
However this approach still not fast enough.
My third approach will be generate the answer from "1" to "100" then looking for the pattern / formula.
Edit: remove wrong formula.
So the premise of this code is to build apon it as we learn different things like nodes and such through out the semester.
Currently, in this version of the code, I need to replace anything that uses 0 to signify the end of the collection of numbers. So let's say if array A has [1,2,5,4,0], 0 would be the indicator that we are at the end of the array.
Now in this version, we have to use a counter(a.k.a howmany in this code) to signify the end of the collection of numbers.
Currently, with this code, I'm getting out of bounds errors and I'm not fully understanding why. I'm getting it in the copy()method and also the omit() method.
Here is the main class:
import java.util.*;
public class Intcoll2client {
public static final int SENTINEL = 0;
public static void main(String[] args) {
int value;
Scanner keyboard = new Scanner(System.in);
Intcoll2 P = new Intcoll2(), N = new Intcoll2(), L = new Intcoll2(5);
System.out.println("Enter an integer to be inserted or 0 to quit:");
value = keyboard.nextInt();
while (value != SENTINEL) {
if (value > 0) {
P.insert(value);
L.insert(value);
} else {
N.insert(-value);
L.omit(-value);
}
// L.arraySize();
System.out.println("Enter next integer to be inserted or 0 to quit:");
value = keyboard.nextInt();
}
System.out.println("\nThe values in collection P are:");
P.print();
System.out.println("\nThe values in collection N are:");
N.print();
System.out.println("\nThe values in collection L are:");
L.print();
if (P.equals(N)) {
System.out.println("\nP and N are equal.");
} else {
System.out.println("\nP and N are NOT equal.");
}
Intcoll2 A = new Intcoll2();
A.copy(L);
System.out.println("\nThe values in the copy of L are:\n");
A.print();
}
}
Here is the class with all of the methods I'm working with:
import java.util.*;
public class Intcoll2 {
private int[] c;
private int howmany;
/**
* Creates a new array c with the size 500
*/
public Intcoll2() {
c = new int[500];
howmany = 0;
}
/**
* Creates a new array with the size i
*
* #param i positive integer
*/
public Intcoll2(int i) {
c = new int[i];
howmany = 0;
}
/**
* Pre-condition: Takes in an object of Intcoll2 Post-condition: If obj does
* not equal c, create a new array and copy all elements from c to obj
*
* #param obj
*/
public void copy(Intcoll2 obj) {
if (this != obj) {
c = new int[obj.c.length];
int j = 0;
while (obj.c[j] != 0) {
c[j] = obj.c[j];
j++;
}
c[j] = 0;
}
}
/**
* Pre-condition: Take in positive integer i
* Post-condition: Return true if
* i is greater than 0 and i is equal to element in array. Otherwise, false
*
* #param i positive integer
* #return
*/
public boolean belongs(int i) {
int j = 0;
while ((c[j] != 0) && (c[j] != i)) {
j++;
}
return ((i > 0) && (c[j] == i));
}
/**
* Pre-condition: Take in a positive integer i
* Post-condition: If i is greater than 0 and is not in the current collection, insert
* into collection. Otherwise, do nothing. If current array is too small to
* insert new integer, create new array double the size and copy all
* elements into new array. Redirect new array to old reference variable.
*
* #param i positive integer to insert in object
*/
public void insert(int i) {
if (i > 0) {
int j = 0;
while ((j < howmany) && (c[j] != 0)) {
j++;
}
if (j == howmany) {
if (j == c.length) {
int[] newC = new int[c.length * 2];
for (int index = 0; index < c.length; index++) {
newC[index] = c[index];
}
c = newC;
}
c[j] = i;
howmany++;
}
}
}
public void arraySize(){
int size = c.length;
System.out.println("Howmany: " + howmany);
System.out.println("Size of L: " + size);
}
/**
* if i is greater than 0, then scan array. If i is found in the array, take
* away and move any element after the index to fill in the 0 space
*
* #param i positive integer
*/
public void omit(int i) {
if (i > 0) {
int j = 0;
while ((c[j] != 0) && (c[j] != i)) {
j++;
}
if (c[j] == i) {
int k = j + 1;
while (c[k] != 0) {
k++;
}
c[j] = c[k - 1];
c[k - 1] = 0;
}
}
}
/**
* Returns number of integers in a collection until loop hits 0
*
* #return howmany
*/
public int get_howmany() {
return howmany;
}
/**
* Prints out the entire collection until it reaches an element of 0
*/
public void print() {
int j = 0;
System.out.println();
while (j < howmany) {
System.out.println(c[j]);
j++;
}
}
/**
* Pre-condition: Takes in an existing object of Intcoll1 Post-condition:
* Compares two objects, if both collections are equal, return true.
* Otherwise, false.
*
* #param obj object containing an array
* #return result
*/
public boolean equals(Intcoll2 obj) {
int j = 0;
boolean result = true;
while ((c[j] != 0) && result) {
result = obj.belongs(c[j]);
j++;
}
j = 0;
while ((obj.c[j] != 0) && result) {
result = belongs(obj.c[j]);
j++;
}
return result;
}
}
Any type of input or help would be greatly appreciated!
I am writing program which generates Vampire numbers https://en.wikipedia.org/wiki/Vampire_number.
I have main function with numberOfDigits argument, which must be even. If numberOfDigits is equal 4, then we are searching Vampire Numbers in range 1000 to 9999 - four digits. If numberOfDigits is equal 6, then we are searching Vampire Numbers from 100000 to 999999 - which is six digits.
In following file, when I want to search Vampire numbers in range of 10 digits, Java heap space is screaming. Note that I have default settings for memory. But for, numberOfDigits == 4, 6 or 8, code is working correctly. (compared output to https://oeis.org/A014575/b014575.txt , https://oeis.org/A014575 ). So I want to ask,
What I can do to optimize this code? I have thought about using String with digits inside, instead of long/BigInteger. I want to "omit" that heap problem. Saving big numbers to file would be too slow, am I right?
My mate wrote (bigNum.cpp) http://pastebin.com/0HHdE848 - class in C++, to operate on big numbers. Maybe with help from community I could implement that in my a.java? More important - would it be useful for my problem?
edit: My goal is to generate free range of Vampire Numbers, like 4,6,8 - a.java it can do it, even more (if I can bypass heap space problem). And that is when my questions to help comes.
a.java (permutation code from johk95, https://stackoverflow.com/a/20906510 )
import java.util.ArrayList;
import java.util.Arrays;
/**
*
* #author re
*/
public class a {
/**
*
* #param numberOfDigits {int}
* #return ArrayList of Integer
*/
public ArrayList<Integer> vdf(int numberOfDigits) {
if ((numberOfDigits % 2) == 1) {
//or throw Exception of unrecognised format/variable?
System.out.println("cant operate on odd argument");
return new ArrayList<>();
}
long maxRange = 9;
for (int i = 1; i < numberOfDigits; i++) {
maxRange *= 10;
maxRange += 9;
}//numberOfDigits==4 then maxRange==9999, nOD==5 then maxRange==99999,..
long minRange = 1;
for (int i = 1; i < numberOfDigits; i++) {
minRange *= 10;
}//nOD==4 then minRange==1000, nOD==5 then minRange==10000, ..
ArrayList<Integer> ret = new ArrayList<>();
for (long i = minRange; i < maxRange; i++) {
long a = i;
long[] b = new long[numberOfDigits];
for (int j = numberOfDigits-1; j >= 0 ; j--) {
long c = a % 10;
a = a / 10;
b[j] = c;
}
int x = 0;
int y = 0;
ArrayList<long[]> list = permutations(b);
b = null; //dont need now
for(long[] s : list) {
for (int j = 0; j < numberOfDigits/2; j++) {
x += s[(numberOfDigits/2)-j-1] * Math.pow(10, j);
y += s[numberOfDigits-j-1] * Math.pow(10, j);
}
StringBuilder builder = new StringBuilder();
for (long t : s) {
builder.append(t);
}
String v = builder.toString();
if ((v.charAt((v.length()/2)-1) != '0'||
v.charAt(v.length()-1) != '0') &&
x * y == i) {
ret.add(x);
ret.add(y);
System.out.println(x*y+" "+x+" "+y);
break;
}
x = y = 0;
}
}
System.out.printf("%d vampire numbers found\n", ret.size()/2);
return ret;
}
/**
*
*#return vdf(4)
*/
public ArrayList<Integer> vdf() {
return vdf(4);//without trailing zeros
}
/* permutation code copied from
* johk95
* https://stackoverflow.com/a/20906510
*/
private static ArrayList<long[]> permutations(long[] lol) {
ArrayList<long[]> ret = new ArrayList<>();
permutation(lol, 0, ret);
return ret;
}
private static void permutation(long[] arr, int pos, ArrayList<long[]> list){
if(arr.length - pos == 1)
list.add(arr.clone());
else
for(int i = pos; i < arr.length; i++){
swap(arr, pos, i);
permutation(arr, pos+1, list);
swap(arr, pos, i);
}
}
private static void swap(long[] arr, int pos1, int pos2){
long h = arr[pos1];
arr[pos1] = arr[pos2];
arr[pos2] = h;
}
public static void main(String[] args) {
a a = new a();
try{
a.vdf(10); //TRY IT WITH 4, 6 or 8. <<<<
}catch (java.lang.OutOfMemoryError e){
System.err.println(e.getMessage());
}
}
}
EDIT: http://ideone.com/3rHhep - working code above with numberOfDigits == 4.
package testing;
import java.util.Arrays;
public class Testing
{
final static int START = 11, END = 1000;
public static void main(String[] args)
{
char[] kChar, checkChar;
String kStr, checkStr;
int k;
for(int i=START; i<END; i++) {
for(int i1=i; i1<100; i1++) {
k = i * i1;
kStr = Integer.toString(k);
checkStr = Integer.toString(i) + Integer.toString(i1);
//if(kStr.length() != 4) break;
kChar = kStr.toCharArray();
checkChar = checkStr.toCharArray();
Arrays.sort(kChar);
Arrays.sort(checkChar);
if(Arrays.equals(kChar, checkChar)) {
System.out.println(i + " * " + i1 + " = " + k);
}
}
}
}
}
This will generate vampire numbers, just modify the start and end integers.
I've been working on the code for alpha-beta pruning for a Connect Four game and I can't seem to get it right. I thought I implemented it correctly at first, but the algorithm would return the column 1 every time. I have two ints val and nodeVal that I use to determine my alpha and beta values. When I instantiate them as 0 inside my alphaBetaPruning() algorithm, the column that is returned by the alphaBetaSearch() method is always 1. If I instantiate these values outside of the alphaBetaPruning() algorithm, the alphaBetaSearch() algorithm results in a Null Pointer Exception
.
Note: the ConnectFourBoard class holds the best child of a board state.
Any help would be appreciated!
public class ConnectFourPlayer
{
private final int columns = 7;
private char currentPlayer;
private char computer = 'C';
private char opponent = 'P';
private int depth = 8;
//private int val = 0;
//private int nodeVal = 0;
private int minMax;
/**
* Constructor method creates the computer
* player.
*/
public ConnectFourPlayer()
{
}
/**
* Method returns the number of children
* given a board state.
*/
public int numberOfChildren(ConnectFourBoard board)
{
int count = 0;
//count number of columns with empty slots
for (int col = 0; col < columns; col++)
{
for (int row = 0; row < 6; row++)
{
if ( board.board[row][col] == ' ')
{
count++;
break;
}
}
}
return count;
}
/**
* Method generates the children of a given
* board state and stores them in the array
* boardChildren[]. The array boardChildren
* is the size of the number of possible
* children.
*/
public void generateChildren(ConnectFourBoard board)
{
board.boardChildren = new ConnectFourBoard[this.numberOfChildren(board)];
int childNumber = 0;
for (int boardCol = 0; boardCol < columns; boardCol++)
{
for (int boardRow = 0; boardRow < 6; boardRow++)
{
if ( board.board[boardRow][boardCol] == ' ' )
{
ConnectFourBoard childBoard = new ConnectFourBoard();
for(int row = 0; row < 6; row++)
{
for(int col = 0; col < columns; col++)
{
childBoard.board[row][col] = board.board[row][col];
}
}
childBoard.row = boardRow;
childBoard.column = boardCol;
childBoard.board[boardRow][boardCol] = currentPlayer;
board.boardChildren[childNumber] = childBoard;
childNumber++;
break;
}
}
}
}
/**
* Method implements the alphaBetaPruning algorithm.
* Returns the column that corresponds to that
* column with the highest alphaBetaPruning value.
*/
public int alphaBetaSearch(ConnectFourBoard board)
{
minMax = 1;
currentPlayer = computer;
alphaBetaPruning(board, this.depth, Integer.MIN_VALUE, Integer.MAX_VALUE);
return board.best.column;
}
/**
* Method returns the static evaluation function value of the
* best possible move that will maximize the computer player's
* move value and also minimize the opponent's move value,
* given a depth limit.
*/
public int alphaBetaPruning(ConnectFourBoard board, int depth, int alpha, int beta)
{
//create StaticEvaluationFunction object to evaluate each possible move
StaticEvaluationFunction evaluator = new StaticEvaluationFunction();
int val = 0;
int nodeVal = 0;
//check if the computer is in a goal state
if(board.gameOver() == 'C')
{
board.best = null;
return evaluator.evaluate(board, this.currentPlayer);
}
//check if depth limit was reached
if(depth == 0)
{
board.best = null;
return evaluator.evaluate(board, this.currentPlayer);
}
//fill the boardChildren[] array with all children of the current board
this.generateChildren(board);
int width = this.numberOfChildren(board);
//check if the current board state has any children
if(width == 0)
{
board.best = null;
return evaluator.evaluate(board, this.currentPlayer);
}
else
{
int i = 0;
boolean prune = false;
while((!prune) && (i < width))
{
//recursive call to alphaBetaPruning()
val = alphaBetaPruning(board.boardChildren[i], (depth - 1), alpha, beta);
if(i == 0)
nodeVal = val;
//check if current board is a minNode
if(minNode(board))
{
//check current child < smallest child so far
if(val < nodeVal)
{
//set nodeVal to smaller child
nodeVal = val;
//set best to this child board
board.best = board.boardChildren[i];
}
//check current child < smallest child so far (local)
if(val < beta)
//set beta to smaller child
beta = val;
}
//check if current board is a maxNode
if(maxNode(board))
{
//check current child > biggest child so far
if(val > nodeVal)
{
//set nodeVal to bigger child
nodeVal = val;
//set best to this child board
board.best = board.boardChildren[i];
}
//check current child > biggest child so far (local)
if(val > alpha)
//set alpha to bigger child
alpha = val;
}
//check max so far > min so far
if(alpha > beta)
{
//prune
prune = true;
return nodeVal;
}
else i++;
}//end while
}
return nodeVal;
}
/**
* Method returns true if the given board state is
* a max node.
*/
public boolean maxNode(ConnectFourBoard board)
{
if(minMax == 1)
{
minMax = 0;
currentPlayer = opponent;
return true;
}
return false;
}
/**
* Method returns true if the given board state is
* a min node.
*/
public boolean minNode(ConnectFourBoard board)
{
if(minMax == 0)
{
minMax = 1;
currentPlayer = computer;
return true;
}
return false;
}
}
/**Holds the state of the board*/
public class ConnectFourBoard
{
public final int rows = 6;
public final int columns = 7;
public char board[][] = new char[rows][columns];
public ConnectFourBoard boardChildren[];
public ConnectFourBoard best;
public int column;
public int row;
...
/**
* Method makes the computer player's move. First,
* checks if a move is allowed. If it is, that
* slot is set to the computer player's character.
* Returns true is a move is made and false
* otherwise.
*/
public int generateComputerPlayerMove(ConnectFourPlayer computer)
{
int column = computer.alphaBetaSearch(this);
//update grid
for(int row = 0; row < board.length; row++)
{
if(board[row][column] == ' ')
{
board[row][column] = 'C';
break;
}
}
return column;
}
}
I am currently doing Algorithms in collage and we are asked to make a hex game using Weighted quick union, we were given most of the code for the project by the lecturer. But im running into a problem here.`public class Hex implements BoardGame {
private int[][] board; // 2D Board. 0 - empty, 1 - Player 1, 2 - Player 2
private int n1, n2; // height and width of board
private WeightedQuickUnionUF wqu; // Union Find data structure to keep track
// of unions and calculate winner
private int currentPlayer; // Current player in the game, initialised to 1
public Hex(int n1, int n2) // create N-by-N grid, with all sites blocked
{
this.n1 = n1;
this.n2 = n2;
currentPlayer = 1;
// TODO: Create instance of board
// TODO: Create instance WeightedQuickUnionUF class
wqu = new WeightedQuickUnionUF(14);
board = new int[n1][n2];
for(int i=0; i < n1 ; i++){
for(int j = 0; j < n2; j++){
board[i][j] = 0;
}
}
}
/*
* (non-Javadoc)
*
* #see BoardGame#takeTurn(int, int)
*/
#Override
public void takeTurn(int x, int y) {
if(((x > n1) || (x < 0)) || ((y > n2) || (y < 0)))
{
StdOut.println("Wrong");
}
else{
if(board[x][y] == 0){
board[x][y] = currentPlayer;
}
else{
StdOut.println("Taken");
}
}
// TODO: check coords are valid
// TODO: check if location is free and set to player's value(1 or 2).
// TODO: calculate location and neighbours location in
// WeightedQuickUnionUF data structure
// TODO: create unions to neighbour sites in WeightedQuickUnionUF that
// also contain current players value
// TODO: if no winner get the next player
}
/*
* (non-Javadoc)
*
* #see BoardGame#getCurrentPlayer()
*/
#Override
public int getCurrentPlayer() {
return currentPlayer;
}
public void setCurrentPlayer(int currentPlayer) {
this.currentPlayer = currentPlayer;
}
/*
* (non-Javadoc)
*
* #see BoardGame#getBoard()
*/
#Override
public int[][] getBoard() {
return board;
}
private void nextPlayer() {
if (currentPlayer == 1)
currentPlayer = 2;
else
currentPlayer = 1;
}
/*
* (non-Javadoc)
*
* #see BoardGame#isWinner()
*/
#Override
public boolean isWinner() {
// TODO:check if there is a connection between either side of the board.
// You can do this by using the 'virtual site' approach in the
// percolation test.
return false;
}
/**
* THIS IS OPTIONAL:
* Modify the main method if you wish to suit your implementation.
* This is just an example of a test implementation.
* For example you may want to display the board after each turn.
* #param args
*
*/
public static void main(String[] args) {
BoardGame hexGame = new Hex(4, 4);
while (!hexGame.isWinner()) {
System.out.println("It's player " + hexGame.getCurrentPlayer()
+ "'s turn");
System.out.println("Enter x and y location:");
int x = StdIn.readInt();
int y = StdIn.readInt();
hexGame.takeTurn(x, y);
}
System.out.println("It's over. Player " + hexGame.getCurrentPlayer()
+ " wins!");
}
}
`
I have already checked if the coordinates are valid and if the place on the board is free. But I can seem to get my head around finding the location and neighbours locations using WeightedQuickUnionUF. Any help would be great as I have tried everything I know so far. Here is the WeightedQuickUnionUF class.
public class WeightedQuickUnionUF {
private int[] id;
private int[] sz;
private int count;
public WeightedQuickUnionUF(int N){
count = N;
id = new int[N];
sz = new int[N];
for(int i = 0 ; i < N; i++){
id[i] = i;
sz[i] = i;
}
}
public int count(){
return count;
}
public int find(int p){
while(p != id[p])
p = id[p];
return p;
}
public boolean connected(int p, int q ){
return find(p) == find(q);
}
public void union(int p, int q){
int i = find(p);
int j = find(q);
if(i == j) return;
if(sz[i] < sz[j]){id[i] = j; sz[j] += sz[i];}
else {id[j] = i; sz[i] += sz[j];}
count--;
}
public static void main(String[] args) {
int N = StdIn.readInt();
WeightedQuickUnionUF uf = new WeightedQuickUnionUF(N);
while(!StdIn.isEmpty()){
int p = StdIn.readInt();
int q = StdIn.readInt();
if(uf.connected(p,q)) continue;
uf.union(p, q);
StdOut.println(p + " " + q);
}
StdOut.println(uf.count() + "components");
}
}
You have a bug in the initialization code for sz[]
It should be:
for(int i = 0 ; i < N; i++){
id[i] = i;
sz[i] = 1; // changed to 1 so it indicates the number of nodes for this 'root'
}