Java: Grid-based path finding with sliding - java
I have made a simple puzzle game where you slide a ball either vertically or horizontally on a grid. The level format is just an array with 1 meaning a tile you can be onto and 0 being a wall. It's not possible to stop until the ball meets a wall.
Example level:
map[][] = {
{0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,0,0,2,0,1,1,1,1,0},
{0,0,1,1,1,1,1,1,1,1,0,1,0},
{0,1,1,1,1,0,1,1,1,1,1,1,0},
{0,1,0,1,1,1,1,1,1,1,1,1,0},
{0,1,0,1,1,1,1,1,0,1,1,1,0},
{0,1,1,0,1,1,1,1,1,1,1,1,0},
{0,1,1,1,0,1,1,0,1,1,1,1,0},
{0,1,1,1,1,0,1,1,1,1,1,1,0},
{0,1,1,1,1,1,0,1,1,0,1,1,0},
{0,1,1,1,1,1,3,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0}
}
(I know it's a bit troublesome to have Y-axis first)
The problem is how on earth can one make an algorithm that solves all possible routes from the starting point (3) to the goal (2). This made me look up some common algorithms online but they only solved:
a route on a grid with free movement
the most efficient route
I have written this:
//keep track of tiles the player has already been to
List<Integer> beenToX = new ArrayList<Integer>();
List<Integer> beenToY = new ArrayList<Integer>();
beenToX.add(0, 6); //starting x-coordinate
beenToY.add(0, 10); //starting y-coordinate
Boolean solving = true;
while (solving) {
for (int i = 0; i < 4; i++) { //num of directions N=0, E=1, S=2, W=3
for (int j = 1; j < 11; j++) {
if (i == 0) {
if (map[beenToY.get(0)+j][beenToX.get(0)] == 0) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
break;
}
if (map[beenToY.get(0)+j][beenToX.get(0)] == 2) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
solving = false;
break;
}
}
if (i == 1) {
if (map[beenToY.get(0)][beenToX.get(0)+j] == 0) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
break;
}
if (map[beenToY.get(0)][beenToX.get(0)+j] == 2) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
solving = false;
break;
}
}
if (i == 2) {
if (map[beenToY.get(0)-j][beenToX.get(0)] == 0) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
break;
}
if (map[beenToY.get(0)-j][beenToX.get(0)] == 2) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
solving = false;
break;
}
}
if (i == 3) {
if (map[beenToY.get(0)][beenToX.get(0)-j] == 0) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
break;
}
if (map[beenToY.get(0)][beenToX.get(0)-j] == 2) {
beenToX.add(0, currentX);
beenToY.add(0, beenToY.get(0)+j);
solving = false;
break;
}
}
}
}
}
Then I realized I have a problem: How do I deal with the program handling multiple direction possibly at the same time? How about dealing with multiple correct routes?
It's also missing a section to check which tiles the player has already been to, to avoid running in circles.
Your movement rules might be unconventional, but it's still a classic pathfinding problem.
Dijkstra, A-star and all the rest work on any graph representation. So you just need to abstract yout movement away into a graph representation. At the most basic level, it only means each Node (State) links to a few other Nodes.
A pathfinder does not need to know yabout movement rules, it only needs a State representation like so:
public interface State extends Comparable<State>{
List<? extends State> neighbours(); // Alternatively, return a Map<State, Integer> to associate a distance/cost
}
I assume you know how to code a Pathfinder class that matches this interface (otherwise look around on S:O):
public interface Pathfinder(){
List<State> path(State start, State end);
}
In this case, here's what a resonable State implementation would look like for you:
public class RollingBallState extends Point implements State{
private static map[][] map = [...];// This must be available somehow at the start, you decide how (hint: static var like I did is ugly AF)
public RollingBallState(int xStart, int yStart){
super(xStart, yStart);
}
#Override
public List<RollingBallState> neighbours(){
List<RollingBallState> neighbours = new ArrayList<>(4);
int xLeft = getX(); // Where the ball can travel left
for(int x=getX()-1; x>=0; x--){
if(map[x][getY()] == 0){
break;
} else{
xLeft = x;
}
}
if(xLeft < xBall){
neighbours.add(new RollingBallState(xLeft, getY()));
}
[...Get xRight, yUp, yDown, and add them in the same fashion ...]
return neighbours;
}
#Override
public int compareTo(RollingBallState other){
if(getX() == other.getX()){
return getY() - other.getY();
} else {
return getX() - other.getX();
}
}
}
You're all set up, just feed two RollingBallState (start & end) to your Pathfinder, it will give you the path.
Related
When the player hits the food make it disapear
I am new to programing, so bare with me lol. Our teacher has given us a game in which we need to add some elements to it. It's a game where we have a player, some enemies and some food made out of rectangles. If the player hits the food i want the food to spawn somewhere else in the window. Heres is the code where im trying to make it happen: private void updateFood(){ for(int i = 0; i < food.length; ++i) { //Should we follow or move randomly? //2 out of 3 we will follow.. if(rnd.nextInt(3) < 2) { //We follow int dx = player.getX() - food[i].getX(); int dy = player.getY() - food[i].getY(); if(abs(dx) > abs(dy)) { if(dx > 0) { //Player is to the right - opiste food[i].moveLeft(); } else { //Player is to the left - opiste food[i].moveRight(); } } else if(dy > 0) { //Player is down; - opiste food[i].moveUp(); } else {//Player is up; - opiste food[i].moveDown(); } } else { //We move randomly int move = rnd.nextInt(4); if(move == 0) { //Move right food[i].moveRight(); } else if(move == 1) { //Move left food[i].moveLeft(); } else if(move == 2) { //Move up food[i].moveUp(); } else if(move == 3) { //Move down food[i].moveDown(); } } if(food[i].getX() == player.getX() && food[i].getY() == player.getY()){ food[i].getX() = random(0,width); food[i].getY() = random(0,height); } } } the last 10 lines (or so) is where im having the problem. if(food[i].getX() == player.getX() && food[i].getY() == player.getY()){ food[i].getX() = random(0,width); food[i].getY() = random(0,height);
With limited info on what methods your food[index] objects have, I'm going to guess .getX() is read-only, meaning you can't set a value to it. Either find a .setX(number) method, or use the existing .moveLeft/Right/Up/Down(number) with a bit of maths.
When determining the winner in a Tic Tac Toe game, how do I avoid repetition?
Note: I am a beginner in Java (2 - 3 months of experience). Doing a project on JetBrains/Hyperskill about making a Tic Tac Toe game, I found myself repeating quite a bit of code when trying to determine the winner of the game. To represent the game as a coordinate system (Thus 1,1 being at the bottom left and 3,3 at the top right) I am using a two-dimensional array. This is the function for determining the winner: public String determineWinner() { int countX = 0; // amount of X's in a row int countO = 0; // amount of O's in a row for (int y = 0; y <= 2; y++) { // for all horizontal rows countX = 0; countO = 0; for (int x = 0; x <= 2; x++) { // loop through all x-coordinates String value = this.field[x][y]; if (value.equals("X")) { // if the value at that coordinate equals "X", add 1 to the count countX++; } if (value.equals("O")) { // same here countO++; } } if (countX == 3) { // if the count is 3 (thus 3 X's in a row), X has won return "X wins"; } if (countO == 3) { // same here return "O wins"; } } // Same thing, but for all vertical columns for (int x = 0; x <= 2; x++) { countX = 0; countO = 0; for (int y = 0; y <= 2; y++) { String value = this.field[x][y]; if (value.equals("X")) { countX++; } if (value.equals("O")) { countO++; } } if (countX == 3) { return "X wins"; } if (countO == 3) { return "O wins"; } } // Same thing, but for diagonal countX = 0; countO = 0; for (int i = 0; i <= 2; i++) { String value = this.field[i][i]; if (value.equals("X")) { countX++; } if (value.equals("O")) { countO++; } } if (countX == 3) { return "X wins"; } if (countO == 3) { return "O wins"; } // Same thing, but for other diagonal countX = 0; countO = 0; for (int i = 0; i <= 2; i++) { String value = this.field[i][2-i]; if (value.equals("X")) { countX++; } if (value.equals("O")) { countO++; } } if (countX == 3) { return "X wins"; } if (countO == 3) { return "O wins"; } if (this.getNumberOfMoves() == 9) { // if the number of moves equals 9, the game is over and it is a draw return "draw"; } return "game not finished"; } Currently, the code allows you to set a starting board (a starting arrangement for all the O's and X's) and then lets you do 1 move. After this, the game decides who is the winner or if it is a draw etc. As one quickly notices, the function is way too long and it has quite a portion of repetition, yet I am unable to come up with any ways to shorten it. Does anyone have any tips? Or any guidelines that apply to all code?
DISCLAIMER: Sorry if my answer started getting sloppy towards the end. Also, I have a code at the bottom showing all the things I talked about in action. I think the simplest thing I can say is to use more methods and possibly classes. Firstly, one of the ways to avoid repetition in all of your codes is to write them using object-oriented programming. This is the idea of having multiple classes that all interact with the main class to assist in writing code. I won't talk about that here, but if you are interested in making your code neat and "clean", I highly advise looking that up. Also, there is a great book on the subject called Clean Code by Robert C. Martin. I will simply be showing how you can take advantage of methods to shorten your code and clean it up. One of the things you repeat the most is this if (countX == 3) { return "X wins"; } if (countO == 3) { return "O wins"; } Your countX and countO are different each time, so you rewrote it. I simpler and more efficient way to do this is to use a method. I would advise you to research the syntax for Java in you don't know how to make methods or classes, but you do use the syntax for the determineWinner() method so I will assume you understand it. You can make functions have parameters that are essentially inputs that can be accessed and modified throughout the function. (By the way, you cannot make methods inside methods in Java so you would need to place this next method outside somewhere else in the class.) public String checkCounts() { if (countX == 3) { return "X wins"; } if (countO == 3) { return "O wins"; } else return "N/A"; } *You want to check to see if it returns "N/A" anytime you use the method with an if statement. If so, you should just ignore it since no one won. whoWon = checkCounts(); //In the code I put at the bottom I will make whoWon a global variable, which is why I'm not defining it here. //It will be already defined at the top of the code. if (!whoWon.equals("N/A")) return whoWon; *The ! symbol means not, a.k.a if whoWon does NOT equal "N/A", return whoWon. This way, anytime you need to write out that if statement code, you can just write checkCounts and plug in the two variables that you just got from your Array. You would write checkCounts(); in this case. Now if you just say return checkCounts(); then the code will run all those if statements without you having to type them all and return the result. You actually repeat something else a lot too. These couple of lines String value = this.field[x][y]; if (value.equals("X")) { countX++; } if (value.equals("O")) { countO++; } are quite similar to these lines String value = this.field[i][i]; if (value.equals("X")) { countX++; } if (value.equals("O")) { countO++; } and these lines String value = this.field[i][2-i]; if (value.equals("X")) { countX++; } if (value.equals("O")) { countO++; } so you can condense them all down into one method with three different inputs. The method will return either 0, 1, or 2. The goal is to check which one it returns with the given string input and then translate that to which variable to add 1 to. If it's 0, ignore, if it's 1, countX++, and if it's 2, countY++. public int checkString(String value) { int whichCount = 0; //if whichCount is 1, it means X //if whichCount is 2, it means O if (value.equals("X")) { whichCount = 1; } if (value.equals("O")) { whichCount = 2; } return whichCount; } Switch statements might be a little advanced, but they're pretty simple in concept. It's a bunch of if statements all at once in a very convenient syntax. The value inside the parenthesis is your input, or what to check. The cases say, when its equal to this, do this. When you needed to increment either countX or countY inside your for loops, you would write switch (checkString(this.field[coord1][coord2])) { case 1 -> countX++; case 2 -> countO++; } case 1 says, if addToCount() returns 1 then do the thing to the right of the arrow and case 2 says if it returns 2 to the thing to the right of that arrow. In your for loops, coord1 and coord2 could be anything from [x][y] to [i][i] to [i][2-i] so you can change that anytime you make the switch statement. Additionally, you can turn that switch statement itself into a method. public void adjustCounts(String stringFromArray) { switch (checkString(stringFromArray)) { case 1 -> countX++; case 2 -> countO++; } } You can also take a couple of lines off by shorting your if statements. If the thing inside the if statement is only one line long than you can just put in next to it. if (bool) { doSomething(); } //Change that to this if (bool) doSomething(); Another thing you repeat a lot is this countX = 0; countO = 0; I just made a very simple method that does that with no parameters. public void resetCounts() { countX = 0; countO = 0; } That's pretty much it for repetition, but I would argue your determineWinner method is still far too large. Even if you don't repeat any more code, taking large changes of it and separating it into smaller bites can make it easier to read and understand. I added in a bunch of methods that just contained your for loops. They will be at the very bottom of this final class I came up with. It's 85 lines long so it's technically only a 4 line improvement but it's a lot cleaner. Additionally, if you were to embed this in your actual class, and not just in a single method (because you can't put it all in one method) then it would be even more efficient because you would have access to all of the classes global variables. Here is the code I came up with, but I would highly recommend doing extra research on object-oriented programming to really improve your code. public class TicTacToe { String[][] field = new String[3][3]; int countX, countO = 0; // amount of X's and O's in a row String whoWon = "N/A"; public int getNumberOfMoves() {return 0;} //Whatever you method did that determined this. Obviously it didn't really just return 0. public String determineWinner() { String columns = checkColumnsForWinner(); String rows = checkRowsForWinner(); String diagonal1 = checkDiagonal(1, 0); String diagonal2 = checkDiagonal(-1, 2); if (checkForNA(columns)) return columns; if (checkForNA(rows)) return rows; if (checkForNA(diagonal1)) return diagonal1; if (checkForNA(diagonal2)) return diagonal2; if (this.getNumberOfMoves() == 9) return "draw"; // if the number of moves equals 9, the game is over and it is a draw return "game not finished"; } public String checkCounts(int countX, int countO) { if (countX == 3) return "X wins"; if (countO == 3) return "O wins"; else return "N/A"; } public int checkString(String value) { int whichCount = 0; //if whichCount is 1, it means X //if whichCount is 2, it means O if (value.equals("X")) whichCount = 1; if (value.equals("O")) whichCount = 2; return whichCount; } public void adjustCounts(String stringFromArray) { switch (checkString(stringFromArray)) { case 1 -> countX++; case 2 -> countO++; } } public void resetCounts() { countX = 0; countO = 0; } public String checkRowsForWinner() { for (int y = 0; y <= 2; y++) { // for all horizontal rows resetCounts(); for (int x = 0; x <= 2; x++) { // loop through all x-coordinates adjustCounts(field[x][y]); } whoWon = checkCounts(countX, countO); if (!whoWon.equals("N/A")) return whoWon; } return "N/A"; } public String checkColumnsForWinner() { for (int x = 0; x <= 2; x++) { resetCounts(); for (int y = 0; y <= 2; y++) { adjustCounts(field[x][y]); } whoWon = checkCounts(countX, countO); if (!whoWon.equals("N/A")) return whoWon; } return "N/A"; } public String checkDiagonal(int mutiply, int add) { resetCounts(); for (int i = 0; i <= 2; i++) { adjustCounts(field[i][i*mutiply + add]); } whoWon = checkCounts(countX, countO); if (!whoWon.equals("N/A")) return whoWon; return "N/A"; } public boolean checkForNA(String string) {return !string.equals("N/A");} } In regards to Object-Oriented Programming, the best example I could see you put into practice in this example is Abstraction. This is a very general concept but I think it would help a lot in this case. In my program above, I have a TicTacToe class, and all of my code in it. The problem is, you are seeing a lot of boilerplate to get the code to run. The biggest example is the 2D Array object you have. You have to do so many things to get X's or O's out of it. It would be much better (opinion) to make a new class, maybe called Board. It would contain a private 2D Array object, and public methods to get values from that object. Additionally, (this is really just my opinion) I would recommend using an enumeration instead of Strings for you Array values. For example public enum BoardValues { X, O, EMPTY } You could then create a class to place these board values in essentially a 3x3 Grid. public class Board { private BoardValues[][] values = new BoardValues[3][3]; public BoardValues getValue(int x, int y) { return values[x][y]; } public BoardValues[] getRow(int rowNumber) { BoardValues[] rowValues = new BoardValues[3]; for (int i = 0; i < values.length; i++) { rowValues[i] = getValue(i, rowNumber); } return rowValues; } public BoardValues[] getColumn(int columnNumber) { BoardValues[] columnValues = new BoardValues[3]; for (int i = 0; i < values.length; i++) { columnValues[i] = getValue(columnNumber, i); } return columnValues; } public void setValues(BoardValues[][] values) { this.values = values; } public void setValue(int x, int y, BoardValues value) { values[x][y] = value; } } Now instead of using that pesky old 2D Array you just create a board object and set and get it's values at will when needed. Also, I didn't add in getting diagonals but you still could quite easily, mine's just for proof of concept. This is Abstraction, probably the easiest of the OOP concepts to grasp, because it's so general. I am simply obscuring information you don't need to see when you're trying to code your game.
Programming test on algorithms? [closed]
Closed. This question needs details or clarity. It is not currently accepting answers. Want to improve this question? Add details and clarify the problem by editing this post. Closed 6 years ago. Improve this question I was given this question in a programming test for an IT company. I will try my best to explain it. The problem is as follows: Given an Ant at origin (0,0) which moves only in clockwise direction( takes only right turns) on a given path array. so for example if the path array is {2,3,4,5,7} the ant moves 2 units left, then moves 3 units down , then moves 4 units right, then moves 5 units up and then 7 units left so on and so forth. So write a code which displays the ant's final position(coordinates) and state if the ant intersects it's path in the format: Ant: (x1,y1) :(yes / no) for example: (1) array={1,6,3,5,4} output: Ant: (2,-1) :yes showing it graphically (0, 0)__(1,0) | (-2,-1) __ __ __ __(2,-1) | | | | | | | | | | (-2,-6) __ __ __ (1,-6) here the ant is intersecting its path at (1,-1) (2) array={2,2,2,1} output: Ant: (0,-1) :no showing it graphically (0, 0)__ __(2,0) .(0,-1) | | | (0,-2)__ __(2,-2) here the ant doesn't intersect its path. I wrote a code to find the final position: public class Ant { static void findAnt(int arr[]) { int count = 0; int x=0,y=0; for(int element: arr){ if(count>3) count = 0; switch(count++){ case 0: x=x+element; break; case 1: y=y-element; break; case 2: x=x-element; break; case 3: y=y+element; break; } } System.out.println("Ant: "+x+" "+y); } public static void main(String[] args) { int arr[] = new int[]{2,2,2,1}; findAnt(arr); } } However I cannot devise an algorithm that shows if the ant intersects or not. Please advise.
It will horizontally intersect if arr[1] <= arr[3] and vertically if arr[0] <= arr[2] you just need to check these positions. for (int i = 0; i < arr.length; i++){ if (i == arr.length-2) return false;//prevents indexoutofbounds if (arr[i] <= arr[i+2]) return true;//intersects } this should check to see if p0 is less than p2, p1, is less than p3, and p2 is less than p4, and so on. boolean intersect = false; for (int i = 0; i < arr.length; i++){ if (arr[i] == arr[arr.length-2]){//i changed this intersect = false;//prevents indexoutofbounds break; } if (arr[i] <= arr[i+2]) intersect = true;//intersects break; } and then print out intersect
One solution that doesn't keep a grid in memory, is to keep a set of visited locations in memory. This has the advantage that you don't need to know the boundary of the ant's potential path in advance. Whether it takes more or less memory than a grid, depends on the size of the grid, and the length of the ant's journey. public class VisitedTileLog { Set visitedTiles = new HashSet<Coordinates>(); boolean hasIntersected = false; public void logVisit(Coordinates c) { if(! visitedTiles.add(c)) { hasIntersected = true; } } public boolean hasIntersected() { return hasIntersected; } } Of course you need a Coordinates class with equals() and hashCode(): public class Coordinates { private int x,y; public Coordinates(int x, int y) { this.x = x; this.y = y; } public boolean equals(Object o) { // Let your IDE write this, or read up on best practice. } public int hashCode() { // Let your IDE write this, or read up on best practice. } // Examples of other methods this might have... public int getX() { ... } public int getY() { ... } public Coordinates move(int distance, Direction direction); } Now you can take your ant for a walk, and each time it moves, update hasIntersected: VisitedTileLog log = new VisitedTileLog(); for(int distance : distances) { ... log.logVisit(...); ... } This class could be enhanced with convenience methods that log a whole step's line -- logVisit(Coordinates from, Coordinates to) or logVisit(Coordinates start, int distance, CompassPoint direction). Depending on the interviewer, a solution like this might get you extra credit for being object-oriented. Indeed, this class could be enhanced to solve the whole of the problem, if it also maintained a currentPosition field.
One way to achieve this is to draw the line during each move for reference. And check before every move that if it is encountering the same coordinate that is already drawn. Below is the code for this approach. You can definitely fine tune it , but here is one way to tackle it. Steps : Create Coordinate type to store coordinates. Create Ant that can hold : current coordinate: this will hold the Ant Current Coordinate at any time Direction to Move next : right , left , up or down data set to keep track of traversed coordinate data structure to hold all coordinates that are revisited Now on every move of ant, it knows what direction to move next. And in each move , we draw all coordinates in between the current coordinate and the end point , and store them in traversed coordinate set. If there is hit, we store it in intersected coordinate set instead. At the end, current coordinate of ant gives us the final coordinate and the line crosses over if the intersected set is not empty. Here is the long code , that I assume is working fine. public class PathCross { public static void main(String[] args) { int[] movementArray = { 2, 2, 2, 1 };// {1,6,3,5,4}; PathCross driver = new PathCross(); Ant ant = driver.new Ant(); for (int i : movementArray) { ant.move(i); } System.out.println("Ant: (" + ant.currentCoordinate.getX() + "," + ant.getCurrentCoordinate().getY() + ") :" + !ant.getIntersectingCoordinates().isEmpty()); } class Ant { Coordinate currentCoordinate = new Coordinate(0, 0); Direction nextDirection = Direction.RIGHT; Set<Coordinate> intersectingCoordinates = new HashSet<>(); Set<Coordinate> traversedCoordinateSet = new HashSet<>(); public Ant() { traversedCoordinateSet.add(new Coordinate(0, 0)); } public Coordinate getCurrentCoordinate() { return currentCoordinate; } public void setCurrentCoordinate(Coordinate currentCoordinate) { this.currentCoordinate = currentCoordinate; } public Direction getNextDirection() { return nextDirection; } public void setNextDirection(Direction nextDirection) { this.nextDirection = nextDirection; } public Set<Coordinate> getIntersectingCoordinates() { return intersectingCoordinates; } public void setIntersectingCoordinates(Set<Coordinate> intersectingCoordinates) { this.intersectingCoordinates = intersectingCoordinates; } public Set<Coordinate> getTraversedCoordinateSet() { return traversedCoordinateSet; } public void setTraversedCoordinateSet(Set<Coordinate> traversedCoordinateSet) { this.traversedCoordinateSet = traversedCoordinateSet; } public void move(int distance) { Coordinate newCoordinate = null; switch (nextDirection) { case RIGHT: newCoordinate = new Coordinate(currentCoordinate.getX() + distance, currentCoordinate.getY()); for (int i = currentCoordinate.getX() + 1; i <= (currentCoordinate.getX() + distance); i++) { if (!traversedCoordinateSet.add(new Coordinate(i, currentCoordinate.getY()))) { intersectingCoordinates.add(new Coordinate(i, currentCoordinate.getY())); } } nextDirection = Direction.DOWN; break; case DOWN: newCoordinate = new Coordinate(currentCoordinate.getX(), currentCoordinate.getY() - distance); for (int i = currentCoordinate.getY() - 1; i >= (currentCoordinate.getY() - distance); i--) { if (!traversedCoordinateSet.add(new Coordinate(currentCoordinate.getX(), i))) { intersectingCoordinates.add(new Coordinate(currentCoordinate.getX(), i)); } } nextDirection = Direction.LEFT; break; case LEFT: newCoordinate = new Coordinate(currentCoordinate.getX() - distance, currentCoordinate.getY()); for (int i = currentCoordinate.getX() - 1; i >= (currentCoordinate.getX() - distance); i--) { if (!traversedCoordinateSet.add(new Coordinate(i, currentCoordinate.getY()))) { intersectingCoordinates.add(new Coordinate(i, currentCoordinate.getY())); } } nextDirection = Direction.UP; break; case UP: newCoordinate = new Coordinate(currentCoordinate.getX(), currentCoordinate.getY() + distance); for (int i = currentCoordinate.getY() + 1; i <= (currentCoordinate.getY() + distance); i++) { if (!traversedCoordinateSet.add(new Coordinate(currentCoordinate.getX(), i))) { intersectingCoordinates.add(new Coordinate(i, currentCoordinate.getY())); } } nextDirection = Direction.RIGHT; break; default: System.err.println("ERRor"); } this.currentCoordinate = newCoordinate; } } enum Direction { LEFT, DOWN, RIGHT, UP; } class Coordinate { int x; int y; public Coordinate() { } public Coordinate(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } #Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + getOuterType().hashCode(); result = prime * result + x; result = prime * result + y; return result; } #Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Coordinate other = (Coordinate) obj; if (!getOuterType().equals(other.getOuterType())) return false; if (x != other.x) return false; if (y != other.y) return false; return true; } private PathCross getOuterType() { return PathCross.this; } #Override public String toString() { return "x=" + x + ", y=" + y; } } }
The problem is hard to find out whether it intersect the previous paths. I create a boolean to record whether it is increase the circle or not. if it is always increasing, it will not intersect the previous paths. If it change to the decreasing, once it began to increasing again, it will intersects the paths. Otherwise, it will not intersects the path def ant(arr): length = len(arr) x = sum(arr[::4]) - sum(arr[2:][::4]) y = sum(arr[3:][::4]) - sum(arr[1:][::4]) if length < 4: return x, y, False t1, (t2, t3, t4) = 0, arr[:3] increase = (t2 < t4) for i in xrange(3, length): t5 = arr[i] if increase and t3 >= t5: if t1 + t5 - t3 < 0 or i+1 < length and arr[i+1] + t2 - t4 < 0: increase = False elif i + 1 < length: return x, y, True elif not increase and t3 <= t5: return x, y, True t1, t2, t3, t4 = t2, t3, t4, t5 return x, y, False
Java LWJGL - Monster not following me, runs between a bounds of 2
I have written a script to be set off whenever a player is within a distance of the monster. The script checks if the x position is greater than or less than the players x, and same for the z. (y is automatically set to terrain) public int checkWalkX(Vector3f position) { if (Math.floor(this.getX()) != Math.floor(position.x)) { if(this.getX() > position.x) return 1; //Greater if(this.getX() < position.x) return 2; //Less } return 0; } public int checkWalkZ(Vector3f position) { if (Math.floor(this.getZ()) != Math.floor(position.z)) { if(this.getZ() > position.z) return 1; //Greater if(this.getZ() < position.z) return 2; //Less } return 0; } public void follow(Player player) { walking = false; following = true; if(checkWalkX(player.getPosition()) == 1) this.setX(this.getX() - mobSpeed); else if(checkWalkX(player.getPosition()) == 2) this.setX(this.getX() + mobSpeed); if(checkWalkZ(player.getPosition()) == 1) this.setZ(this.getZ() - mobSpeed); else if(checkWalkZ(player.getPosition()) == 2) this.setZ(this.getZ() + mobSpeed); if(Math.floor(checkWalkX(walkToPosition)) == 0 && Math.floor(checkWalkZ(walkToPosition)) == 0) following = false; } For some reason when I run this script, the monster will only move within a distance of 2ish. He moves the right ways kinda, but he doesnt follow me. Would anyone know why this is?
You should leave out the Math.floor() condition.What you could get right now is that the player for example is at x=1 and the monster at x=1.99. The Floor condition would shorten this to 1 == 1 and declare that both are at the same place. In the worst case this would leave the monster at a distance of sqrt(2). You can leave out the condition to get: public int checkWalkX(Vector3f position) { if(this.getX() > position.x) return 1; //Greater if(this.getX() < position.x) return 2; //Less return 0; // equal } The drawback of this is that you almost never get a zero back. The monster will always move. And here we come to the next problem. It always moves a fixed distance. This can lead to jumping around the target if the mobspeed is greater than the distance. An approach to solve this could be to calculate the distance of the monster to the player (dist = sqrt(deltaX^2 + deltaZ^2)) and it this is greater than the desired distance move the monster along the monster-player-vector for a distance of mobspeed or monster-player-distance whichever is shorter.
tic tac toe using alpha beta prunning in java
I am trying to play tic tac toe using iterative Alpha-Beta prunning, I have one second limit for a move but for some reason it doesnt work well. I modified the regular alpha-beta code so instead of returning alpha or beta, it returns a state (which is the board with the next move) Each time I create children I update their depth. But again for some reason I keep losing and I see that my alpha beta doesnt see the best move to make. Here is my code: The outer loop: while (watch.get_ElapsedMilliseconds() < 900 && d <= board.length * board[0].length - 1) { s = maxiMin(beginSt, d, watch); if (s.getNextMove().getIsWin() == true) { break; } d++; } return new location(s.getNextMove().getRow(), s.getNextMove().getCol()); The alpha beta: public State maxiMin(State s, int depth, Stopwatch timer) { if (s.getDepth() == 7) { Console.WriteLine(); } if (timer.get_ElapsedMilliseconds() > 850 || s.getDepth() == depth || goalTest(s.getBoard()) != 0) { s.evaluationFunc(line_length, PlayerShape); s.setAlpha(s.getEvaluation()); s.setBeta(s.getEvaluation()); return s; } LinkedList<State> children = createChildren(s, true); // No winner, the board is full if (children.get_Count() == 0) { s.evaluationFunc(line_length, PlayerShape); s.setAlpha(s.getEvaluation()); s.setBeta(s.getEvaluation()); return s; } while (children.get_Count() > 0) { State firstChild = children.get_First().get_Value(); children.RemoveFirst(); State tmp = miniMax(firstChild, depth, timer); int value = tmp.getBeta(); if (value > s.getAlpha()) { s.setAlpha(value); s.setNextMove(tmp); } if (s.getAlpha() >= s.getBeta()) { return s; } } return s; } public State miniMax(State s, int depth, Stopwatch timer) { if (s.getDepth() == 7) { Console.WriteLine(); } if (timer.get_ElapsedMilliseconds() > 850 || s.getDepth() == depth || goalTest(s.getBoard()) != 0) { s.evaluationFunc(line_length, PlayerShape); s.setAlpha(s.getEvaluation()); s.setBeta(s.getEvaluation()); return s; } LinkedList<State> children = createChildren(s, false); // No winner, the board is full if (children.get_Count() == 0) { s.evaluationFunc(line_length, PlayerShape); s.setAlpha(s.getEvaluation()); s.setBeta(s.getEvaluation()); return s; } while (children.get_Count() > 0) { State firstChild = children.get_First().get_Value(); children.RemoveFirst(); State tmp = maxiMin(firstChild, depth, timer); int value = tmp.getAlpha(); if (value < s.getBeta()) { s.setBeta(value); s.setNextMove(tmp); } if (s.getAlpha() >= s.getBeta()) { return s; } } return s; } Would appriciate much if anyone can tell me if something is wrong. I suspect maybe it something to do with that I am returning "s" instead of the regular alpha beta which returns the evaluation but I didnt manage to find the error. Thanks in advance, Lena
Firstly tic-tac-toe is a very simple game, and I believe it is solvable with a much simpler code, mainly because we know there is always a tie option and the total number of states is less then 3^9 (including symmetrical and many impossible states). As for your code I believe one of your problems is that you don't seem to increment your depth in the recursive calls. you also have many issues of bad style in your code, you separated miniMax and MaxiMin into two functions though they are fundamentally the same. you iterate over a collection by removing elements from it as opposed to using for-each or an iterator(or even an int iterator).