I recently gave an interview and was asked the following question.
A maze is a group of linked Places. Each Place has a North, South, East, and West Place adjacent to it. There are two special pre-defined Place's: Place Wall represents a wall - the mouse can't go there. Place Cheese is ... cheese! The connections between Places are symmetrical - if you start from any Place and go North and then South, you return to where you were.
To simplify things, the maze has no closed loops - that is, if you start in any Place and follow any path, you eventually either hit a wall or find cheese - you never come back to the Place you started unless you actually retrace your steps.
A mouse starts off in some Place and searches around for Cheese. When it finds Cheese, it returns a set of directions - a string of the letters NSEW that lead from where it started to the Cheese.
The following framework defines the classes and functions. Some other code not included here generates a maze by creating a bunch of Place's and linking them. It then calls mouse(), passing some starting Place from the maze:
interface Place {
// Return the adjacent Place in the given direction
public Place goNorth();
public Place goSouth();
public Place goEast();
public Place goWest();
// Returns true only for the special "Wall" place
public bool isWall();
// Returns true only for the special "Cheese" place
public bool isCheese();
};
class Mouse {
public Mouse() {}
// Return a string of the letters NSEW which, if used to traverse the
// the maze from startingPoint, will reach a Place where isCheese() is
// true. Return null if you can't find such a path.
public String findCheese(Place startingPoint) {
... fill this in ...
}
}
Implement findCheese(). You can add any fields or helper methods you need to Mouse.
Extra credit: Eliminate the "no closed loops" restriction. That is, change your code so that it works correctly even if there might be a path like SSNEEW that leads the mouse back to the Place it started from.
This is what I tried. I understand this won't be the best or optimized solution, and wanted feedback as to what I else I could try. I have not considered the extra credit part
public String findCheese(place startingPoint)
{
//Call helper function in all 4 directions;
return findCheeseHelper(startingPoint,new StringBuilder("N")).append(
findCheeseHelper(startingPoint,new StringBuilder("S"))).append(
findCheeseHelper(startingPoint,new StringBuilder("E"))).append(
findCheeseHelper(startingPoint,new StringBuilder("W"))).toString();
}
public StringBuilder findCheeseHelper(place startingPoint, StringBuilder direction)
{
StringBuilder nDir=new StringBuilder("");
StringBuilder sDir=new StringBuilder("");
StringBuilder eDir=new StringBuilder("");
StringBuilder wDir=new StringBuilder("");
//Rerturn which direction this step came from if cheese found
if(startingPoint.isCheese())
{
return direction;
}
//Specify this is not a correct direction by returning an empty String
else if(startingPoint.isWall())
{
return "";
}
//Explore all other 3 directions (except the one this step came from)
if(direction=="N")
{
sDir=findCheeseHelper(startPoint.goSouth(), new StringBuilder("N"));
eDir=findCheeseHelper(startPoint.goEast(), new StringBuilder("E"));
wDir=findCheeseHelper(startPoint.goWest(), new StringBuilder("W"));
}
else if(direction=="E")
{
nDir=findCheeseHelper(startPoint.goNorth(), new StringBuilder("N"));
sDir=findCheeseHelper(startPoint.goSouth(), new StringBuilder("S"));
wDir=findCheeseHelper(startPoint.goWest(), new StringBuilder("E"));
}
else if(direction=="W")
{
nDir=findCheeseHelper(startPoint.goNorth(), new StringBuilder("N"));
sDir=findCheeseHelper(startPoint.goSouth(), new StringBuilder("S"));
eDir=findCheeseHelper(startPoint.goEast(), new StringBuilder("W"));
}
else if(direction=="S")
{
nDir=findCheeseHelper(startPoint.goNorth(), new StringBuilder("S"));
eDir=findCheeseHelper(startPoint.goEast(), new StringBuilder("E"));
wDir=findCheeseHelper(startPoint.goWest(), new StringBuilder("W"));
}
//If I hit wall in every direction, I will get empty string and so specify to calling
//function that this is not a correct direction
if(nDir.equals("") && sDir.equals("") && eDir.equals("") && wDir.equals(""))
return new StringBuilder("");
//If Cheese was found in even 1 direction, return direction to come to this step, appended with the path
// forward to the calling function
return direction.append(nDir).append(sDir).append(eDir).append(wDir);
}
Related
So I'm writing a Rush Hour solver in Java, which is meant to be able to solve the configurations here. However, even the simplest puzzle from that page results in the solver running infinitely and eventually running out of memory. I'm using a breadth first search to work my way through all possible moves arising from each board state (using a HashSet to ensure I'm not repeating myself), and mapping each state to the move that got it there so I can backtrack through them later.
The thing is, I've tried it with more trivial puzzles that I've come up with myself, and it's able to solve them (albeit slowly).
Is there anything blatantly wrong with how I'm approaching this problem? I can put up some code from the relevant classes as well if I need to, but I've tested them pretty thoroughly and I'm pretty sure the problem lies somewhere in the code below. My gut says it's something to do with the HashSet and making sure I'm not repeating myself (since the Queue's size regularly reaches the hundred thousands).
Any suggestions?
// Start at the original configuration
queue.add(originalBoard);
// We add this to our map, but getting here did not require a move, so we use
// a dummy move as a placeholder move
previous.put(originalBoard, new Move(-1, -1, "up"));
// Breadth first search through all possible configurations
while(!queue.isEmpty()) {
// Dequeue next board and make sure it is unique
Board currentBoard = queue.poll();
if (currentBoard == null) continue;
if (seen.contains(currentBoard)) continue;
seen.add(currentBoard);
// Check if we've won
if (currentBoard.hasWon()) {
System.out.println("We won!");
currentBoard.renderBoard();
return solved(currentBoard);
}
// Get a list of all possible moves for the current board state
ArrayList<Move> possibleMoves = currentBoard.allPossibleMoves();
// Check if one of these moves is the winning move
for (Move move : possibleMoves) {
Board newBoard = move.execute(currentBoard);
// We don't need to enqueue boards we've already seen
if (seen.contains(newBoard)) continue;
queue.add(newBoard);
// Map this board to the move that got it there
previous.put(newBoard, move);
}
}
As requested, here are my initialisations of the HashSet (they're class level variables):
private static HashSet<Board> seen = new HashSet<>();
And my Board.equals() method:
#Override
public boolean equals (Object b) {
Board otherBoard = (Board) b;
boolean equal = false;
if (this.M == otherBoard.getM() && this.N == otherBoard.getN()) {
equal = true;
// Each board has an ArrayList of Car objects, and boards are only
// considered equal if they contain the exact same cars
for (Car car : this.cars) {
if (otherBoard.getCar(car.getPosition()) == null) {
equal = false;
}
}
}
System.out.println(equal);
return equal;
}
You must implement Board.hashCode() to override the default Object-based version, in such a way that, per its contract, any two equal Board objects have the same hash code. If you do not, then your seen set does not in fact accomplish anything at all for you.
On another issue, I suspect that the way you're checking the boards' cars is not fully correct. If it works the way I think it does, it would consider these two boards to be equal:
. = empty space
* = part of a car
......
.**.*.
....*.
.*....
.*.**.
......
......
.*..**
.*....
......
.**.*.
....*.
I am having difficulties coding this and was wondering if someone can help me code this program.
If someone can help me get started then that'd be great. Thank you.
Also I was wondering what sections that I need topics I need to study for this because I am trying to code and having a really difficult time coding this. I know, strange, because I havent had this difficulty since I started CS first.
//Homework: revise this file, see TODO items below.
//Given a maze of size N, the method findPath(maze) finds an open
//path from (0,0) to (N-1,N-1), if such a path exists.
//
//See main() comments for its command line usage.
//TODO: the current solution is recursive (dfs() calls itself). You
//need to make it non-recursive. One way is to use an explicit stack
//instead of the runtime stack. You do not need to find exactly the
//same open paths as found by the given code.
//TODO(EC): modify findPath so it finds a *shortest* open path from
//(0,0) to (N-1,N-1), when one exists. You can read about a method
//for this, "breadth first search", in Section 4.1 of your book.
//TODO(EC): define the method findWallPath. Whenever findPath fails to
//find a path, there should be a "blocking" path of walls. This path
//can start at any wall on the top or right sides of the maze, and
//end at any wall at the bottom or left sides of the maze. Two walls
//can be adjacent by a cardinal OR diagonal step. Again, recursion
//is not allowed. Finding a wall path is good, shortest is better.
//For grading, we ignore the main() method, so do what you like with
//that. We only test your findPath and findWallPath methods.
public class PathFinder
{
// Any data fields here should be private and static. They exist
// only as a convenient way to share search context between your
// static methods here. It should be possible to call your
// findPath() method more than once, on different mazes, and
// to get valid results for each maze.
// The maze we are currently searching.
private static Maze m;
// GOAL: for each reachable open position p, parent[p.i][p.j]
// should be an open position that is closer to the start position
// S. These parent links should form a tree, rooted at S.
private static Position[][] parent;
public static Deque<Position> findPath(Maze maze)
{
m = maze; // save the maze
int N = m.size(); // the maze is N by N
parent = new Position[N][N]; // initially all null
Position S = new Position(0,0); // start of search
Position T = new Position(N-1,N-1); // goal of search
// Compute parent for each position reachable from S.
// Since S is the root, we will let S be its own parent.
// Compute parent links, by recursive depth-first-search!
dfs(S, S);
// If T has no parent, it is not reachable, so no path.
if (parent[T.i][T.j]==null)
return null;
// Otherwise, we can reconstruct a path from S to T.
LinkedDeque<Position> path = new LinkedDeque<Position>();
for (Position u=T; !u.equals(S); u=parent[u.i][u.j])
path.addFirst(u);
path.addFirst(S);
return path;
}
// depth-first-search: set parent for each reachable p.
private static void dfs(Position p, Position from)
{
if (!m.inRange(p) || !m.isOpen(p) || parent[p.i][p.j] != null)
return;
// System.out.println("found " + p + " via parent " + from);
parent[p.i][p.j] = from;
// Now recursively try the four neighbors of p.
for (int dir=0; dir<4; ++dir)
dfs(p.neighbor(dir), p);
}
// This method is entirely up to you.
public static Deque<Position> findWallPath(Maze maze) { return null; }
// Usage:
// java PathFinder MAZEFILE
// Reads maze, finds path, prints maze with path.
public static void main(String[] args)
throws java.io.IOException
{
Maze m = new Maze(args[0]);
System.out.println(m);
Deque<Position> path = findPath(m);
if (path==null) {
System.out.println("No path found");
return;
}
System.out.println("Found path of " +
path.size() +
" positions");
System.out.println(path);
char[][] map = m.copyArray();
// Mark the path with X's
for (Position p: path)
{
assert map[p.i][p.j] == '0';
map[p.i][p.j] = 'X';
}
// Now print the marked map.
System.out.println(Maze.toString(map));
}
// Java "best practice": this class is all static, so we should
// never instantiate it. To enforce that, we make its default
// constructor private.
private PathFinder() {}
}
The simplest approach to this problem would be to translate the maze (if it isn't yet) into a graph and afterwards implement either in-depth or breadth-first search that searches for the exit of the maze. And btw. you shouldn't write anything about homework in your post.
I am using BlueJ with Karel the Robot.
The program is called SmarterSorter, and here are the instructions: (I need a bit of help with the program over all, not just with the NullPointerException).
Background: there are an unknown number of vertical piles of beepers (no gaps) – each vertical pile has an unknown number of beepers in it (one beeper per corner – no gaps). The bottom beeper of the left-most pile is always at the origin.
I’m intentionally not giving you the algorithm in bullet form (so you can’t just turn the bullets into methods). I’m pretending I’m an end-user (i.e., a quasi-intellect in terms of computer programming – so, I’m going to describe the problem in English).
So, here’s the algorithm:
The SmarterSorterRobot(SSR) does the sorting. She, however, has some helpers (delegates) – the PutterRobot(PUR) and the PickerRobot(PIR). The SSR knows that she always starts off facing East and is standing on the bottom-most beeper in the left-most vertical pile. She begins by walking along the bottom row of all the vertical piles and stopping when she reaches an empty corner. Then, she creates all those PIRs and then, after they are all created, commands each one in turn to pick up all of the beepers in their respective pile(so, for example, if the PIR in the first vertical pile had 5 beepers above him, he would be standing 6 corners above where he was, having picked up 6 beepers). SSR should now query each PIR for the number of beepers it picked up and she should store those counts as she gets them into a java array of ints. She should then sort that array (see API for Arrays). She should now, working left to right again, create a PUR at the bottom of the first soon-to-be-created pile of beepers – the PUR should know how many beepers it is about to put(the smallest number from the recently sorted array). The PUR should then put all the beepers and go HOME (described below) in the most efficient manner possible. The SSR should now create a second PUR and have it do the same – continue until all piles have been placed (i.e., all piles are now in sorted non-descending order and all the PURs are at HOME position). The SSR should now ask each PIR to go HOME. And, finally, the SSR should now go HOME.
HOME: home is the corner directly North of the top-most beeper in the left-most vertical column.
And here is my code:
import java.util.Arrays;
public class SmarterSorterRobot extends GoHomeBot
{
public SmarterSorterRobot(int av, int st, Direction dir, int beeps)
{
super(av, st, dir, beeps);
}
public int x =1;
private PickerRobot [] robot;
private PutterRobot [] bot;
private int numBeeps;
private int [] myPutterRobots;
private int [] numBeepers;
public int getNumBeeps()
{
return numBeeps;
}
public void sortBeepers()
{
turnRight();
countNumberOfRows();
robot = new PickerRobot [x];
createPickerRobots();
pickLotsOfBeepers();
transferToBeepers();
sortTheBeepers(numBeepers);
robot [x].goHome();
this.goHome();
}
public void countNumberOfRows()
{
while(nextToABeeper())
{
move();
x++;
}
}
public void createPickerRobots()
{
for (int i=1;i<robot.length;i++)
{
robot [i]= new PickerRobot (1,i,North,0);
}
}
public void pickBeepers()
{
while(nextToABeeper())
{
pickBeeper();
move();
numBeeps++;
}
}
public void pickLotsOfBeepers()
{
for (int i=1; i<robot.length; i++)
{
robot [i].pickBeepers();
}
}
public int[] transferToBeepers()
{
int [] numBeepers = new int [x];
for (int i=0; i<numBeepers.length;i++)
{
numBeepers [i] = ;
}
Arrays.sort (numBeepers);
return numBeepers;
}
public void sortTheBeepers(int [] numBeepers)
{
for (int i=0; i<numBeepers.length; i++)
{
PutterRobot robespierre = new PutterRobot (1, i, North, numBeepers [i]);
while(anyBeepersInBeeperBag())
{
putBeeper();
}
goHome();
}
}
}
I get a NullPointerException on the first line of the sortTheBeepers method.
I cannot figure out why.
Thank you for your help!
Let us look at the following method:
public void sortBeepers()
{
// ..
transferToBeepers();
sortTheBeepers(numBeepers);
// ..
}
It calls the method transferToBeepers() which is doing something with a local numBeepers array and then you're calling sortTheBeepers with a different (this time global) variable numBeepers. This numBeepers version is still null, because it was never initialized before, therefore the line for (int i=0; i<numBeepers.length; i++) throws the NullPointerException due to the call numBeepers.length (i.e. null.length).
So how can you fix that ... look at the method transferToBeepers again. As you can see, it returns the mentioned local version of numBeepers, but you're currently ignoring that returned value. So change the above lines as follows:
public void sortBeepers()
{
// ..
numBeepers = transferToBeepers();
sortTheBeepers(numBeepers);
// ..
}
That way, you're initializing the global numBeepers version with the result of transferToBeepers and it won't be null during the sortTheBeepers(numBeepers) call.
Btw, you should also fix the numBeepers [i] = ; line in the transferToBeepers method.
I'm trying to create a hand evaluator that it will allow me to compare if one hand is better than another. I know there many other post on SO about this topic however many of them are old now and the links no longer link to anything useful. The only way I can think of doing this at the moment is to manually check for every different combination. Eg check for ace of any suit, if this doesn't exist then move to the next combination eg straight flush then 4 of a kind and so on. However, then how would you compare a pair of 2s to a pair of 3s unless you gave an integer to every combination of cards that made something interesting. However, that would very hard to do manually. Is there a better way?
Why hard?
class Card{
String suite;
int value;
....
}
// ...if two combinations are equal, Do for both combinations
int power = 0;
for (Card card: combination){
power += card.getValue()
}
// and compare!
I don't know if this is the best approach, but this could be possible and this is all manually.
Let's say you already have the code to determine which hand the player has in this format:
22s, KKs, 98o, 11o
Now you have an array with three values e.g.:
["K", "K", "s"]
...and another array:
[9, 8, "o"]
You first have to class those hands (like flush, straight etc.) to make sure which one will win (royal flush always win). And after those checks, you have to do some checks in the array. Check if it's suited or offsuit, if "K" is higher than 9 etc.
You can give them values like this:
...
8=8
9=9
10=10
J=11
Q=12
K=13
A=14 (or 1)
And then compare with that. This is a hard algorithm to do it properly without doing so many things manually. I hope someone who has experience with this takes my answer over and recover my mistakes or wrong steps/thoughts.
I would separate the problem for each type of combinations, and assign an integer for a specific occurence of a combination called ie. strength (so a Straight Flush of 5-4-3-2-A is the weakest and K-Q-J-10-9 is the strongest).
Individual combinations can be handled pretty well i think. For a royal flush, you sort your 7 cards by their number descending, and check if the first 5 cards are (A-K-Q-J-10) and if they are of the same suit. A royal flush's strength is indefinite.
For flush you can sort your cards by suit, and check if you can move 4 times in your list of card without witnessing a suit change. A Flush's strength is determined by the highest valued card of it.
A very brief template for the idea:
// main logic of who wins, note it doesn't handle when two players have the same
// combo with same strength
class HandComparator {
public Player compare(Player player1, Player player2) {
HandEvaluator handEvaluator = new HandEvaluator();
Combination player1Combo = handEvaluator.evaluate(player1.hand);
Combination player2Combo = handEvaluator.evaluate(player2.hand);
if (player1Combo.type.equals(player2Combo.type)) {
// note, strength is only taken into account if the two players have
// the same combo (ie both has full house)
if (player1Combo.strength < player2Combo.strength) {
return player2;
} else {
return player1;
}
} else if (player1Combo.type.compareTo(player2Combo.type) < 0) {
return player2;
} else {
return player1;
}
}
}
class Card {
int suit;
int number;
}
class Player {
List<Card> hand;
}
// this is built by CombinationRecognisers. Note, that the member 'strength' is
// related to a specific combination, not all possible hands
class Combination {
enum Type {
ROYAL_FLUSH,
STRAIGHT_FLUSH;
// etc.
}
Type type;
int strength;
}
// implement this for all combinations (ROYAL_FLUSH,STRAIGHT_FLUSH, etc)
interface CombinationRecogniser {
public Combination evaluate(List<Card> hand);
}
/*
* this class holds all CombinationRecognisers and iterates throught them. It
* will stop the moment a combo has been found.
*/
class HandEvaluator {
static List<CombinationRecogniser> recognizers = new ArrayList<CombinationRecogniser>();
static {
recognizers.add(new RoyalFlushRecogniser());
recognizers.add(new StraightFlushRecogniser());
}
public Combination evaluate(List<Card> hand) {
for (CombinationRecogniser recogniser : recognizers) {
Combination combination = recogniser.evaluate(hand);
if (combination != null) {
return combination;
}
}
return null;
}
}
class RoyalFlushRecogniser implements CombinationRecogniser {
#Override
public Combination evaluate(List<Card> hand) {
// code goes here that decides if the given hand is a valid royal flush
return null; // of new Combination() if the given hand is a valid royal flush
}
}
class StraightFlushRecogniser implements CombinationRecogniser {
#Override
public Combination evaluate(List<Card> hand) {
// code goes here that decides if the given hand is a valid straight flush
return null; // of new Combination() if the given hand is a valid royal flush
}
}
This code actually works if you implement the CombinationRecogniser interface for all special combinations. An example:
Ok, so I have a 3 x 3 jig saw puzzle game that I am writing and I am stuck on the solution method.
public Piece[][] solve(int r, int c) {
if (isSolved())
return board;
board[r][c] = null;
for (Piece p : pieces) {
if (tryInsert(p, r, c)) {
pieces.remove(p);
break;
}
}
if (getPieceAt(r, c) != null)
return solve(nextLoc(r, c).x, nextLoc(r, c).y);
else {
pieces.add(getPieceAt(prevLoc(r, c).x, prevLoc(r, c).y));
return solve(prevLoc(r, c).x, prevLoc(r, c).y);
}
}
I know I haven't provided much info on the puzzle, but my algorithm should work regardless of the specifics. I've tested all helper methods, pieces is a List of all the unused Pieces, tryInsert attempts to insert the piece in all possible orientations, and if the piece can be inserted, it will be. Unfortunately, when I test it, I get StackOverflow Error.
Your DFS-style solution algorithm never re-adds Piece objects to the pieces variable. This is not sound, and can easily lead to infinite recursion.
Suppose, for example, that you have a simple 2-piece puzzle, a 2x1 grid, where the only valid arrangement of pieces is [2, 1]. This is what your algorithm does:
1) Put piece 1 in slot 1
2) It fits! Remove this piece, pieces now = {2}. Solve on nextLoc()
3) Now try to fit piece 2 in slot 2... doesn't work
4) Solve on prevLoc()
5) Put piece 2 in slot 1
6) It fits! Remove this piece, pieces is now empty. Solve on nextLoc()
7) No pieces to try, so we fail. Solve on prevLoc()
8) No pieces to try, so we fail. Solve on prevLoc()
9) No pieces to try, so we fail. Solve on prevLoc()
Repeat ad infinitum...
As commenters have mentioned, though, this may only be part of the issue. A lot of critical code is missing from your post, and their may be errors there as well.
I think you need to structure your recursion differently. I'm also not sure adding and removing pieces from different places of the list is safe; much as I'd rather avoid allocation in the recursion it might be safest to create a list copy, or scan the board
so far for instances of the same piece to avoid re-use.
public Piece[][] solve(int r, int c, List<Piece> piecesLeft) {
// Note that this check is equivalent to
// 'have r and c gone past the last square on the board?'
// or 'are there no pieces left?'
if (isSolved())
return board;
// Try each remaining piece in this square
for (Piece p : piecesLeft) {
// in each rotation
for(int orientation = 0; orientation < 4; ++orientation) {
if (tryInsert(p, r, c, orientation)) {
// It fits: recurse to try the next square
// Create the new list of pieces left
List<Piece> piecesLeft2 = new ArrayList<Piece>(piecesLeft);
piecesLeft2.remove(p);
// (can stop here and return success if piecesLeft2 is empty)
// Find the next point
Point next = nextLoc(r, c);
// (could also stop here if this is past end of board)
// Recurse to try next square
Piece[][] solution = solve(next.x, next.y, piecesLeft2);
if (solution != null) {
// This sequence worked - success!
return solution;
}
}
}
}
// no solution with this piece
return null;
}
StackOverflowError with recursive functions means that you're either lacking a valid recursion stop condition or you're trying to solve too big problem and should try an iterated algorithm instead. Puzzle containing 9 pieces isn't too big problem so the first thing must be the case.
The condition for ending recursion is board completion. You're only trying to insert a piece in the for loop, so the problem is probably either that the tryInsert() method doesn't insert the piece or it doesn't get invoked. As you're sure that this method works fine, I'd suggest removing break; from
if (p.equals(prev[r][c]))
{
System.out.println("Hello");
break;
}
because it's the only thing that may prevent the piece from being inserted. I'm still unsure if I understand the prev role though.