I've implemented the following MiniMax algorithm for my Android Reversi game:
#Override
public Field findBestMove(GameBoard gb, int depth, boolean player)
{
/** maximum depth of search reached, we stop */
if(depth >= max_depth) return null;
//player = (depth+1)%2 + 1;
/** getting a list of moves to chose from */
ArrayList <Field> moves = findAllPossibleMoves(gb, player);
Field best_move = null;
/** iterating over all possible moves, to find the best one */
for (int i=0; i<moves.size(); i++)
{
/** board to simulate moves */
GameBoard temp_board = new GameBoard(gb);
/** getting the current move */
Field move = moves.get(i);
/** simulating the move for the current node */
game.move(move, temp_board, player);
Log.i("board", "Depth:"+depth+" Player:"+player+" Move:"+i+" Rating:"+evaluate(temp_board));
Log.i("board", ""+moves.get(i).getX()+","+moves.get(i).getY());
temp_board.printBoard();
/** getting to the next inferior node */
Field best_deep_move = findBestMove (temp_board, depth + 1, !player);
/** if the maximum depth is reached, we have a null, so we evaluate */
if (best_deep_move == null)
{
move.setRating(evaluate (temp_board));
}
/** if we are not the deepest possible, we get the rating from the lower node */
else
{
move.setRating(best_deep_move.getRating());
Log.i("eval", ""+best_deep_move.getRating());
}
if(best_move == null)
{
best_move = move;
}
else
{
Log.i("update", "Current move rating:"+move.getRating());
Log.i("update", "New move rating:"+best_move.getRating());
if (depth%2==0)
{
Log.i("update", "MAX player");
/** for us, we look for the maximum */
if (best_move.getRating() < move.getRating())
{
best_move = move;
}
}
else
{
Log.i("update", "MIN player");
/** for the opponent, we look for the minimum */
if (best_move.getRating() > move.getRating())
{
best_move = move;
}
}
Log.i("update", "Updated move rating"+best_move.getRating());
}
}
return best_move;
}
I've made myself familiar with the Alpha-Beta pruning in theory, though I'm having some trouble proceeding with applying that knowledge in this algorithm. Thanks in advance
There following changes that need to done to your code to implement alpha-beta pruning:-
pass a parameter public Field findBestMove(GameBoard gb, int depth, boolean player,int aplha_beta)
Stop recursion if current best_move will never affect alpha_beta of previous depth.
if(player == max && best_move!=null && aplha_beta <= best_move.getRating()) {
return(best_move);
}
if(player == min && best_move!=null && alpha_beta >= best_move.getRating()) {
return(best_move);
}
Field best_deep_move = findBestMove(temp_board,depth+1,!player,best_move.getRating());
Related
I am making a Tic-Tac-Toe game with a computer player. However, whenever I call the computer's makeMove method, the computer continues to play without the user being able to do anything. Just to be sure that the function stopped, I made it return after each move, but it still plays the entire game without the user's input.
Here are the relevant parts:
Board Class:
public String addToBoard(char c, int square) {
if (!spaceFull(board, square)) {
int[] coords = getRowAndColumn(square);
//System.out.println("[" + coords[0] + "][" + coords[1] + "]");
board[coords[0]][coords[1]] = c;
return "VALID";
} else {
System.out.println("Space Is Occupied");
return "OCCUPIED";
}
}
public boolean spaceFull(char[][] b, int square) {
return (twoDimenToOneDimen(b).get(square - 1) == 'X' || twoDimenToOneDimen(b).get(square - 1) == 'O');
}
Computer Class
public void makeMove() {
int square;
//Checks For Any Winning Computer Moves
System.out.println("Here");
if ((square = nextMoveWinCheck(playerChar)) != 0) {
board.addToBoard(playerChar, square);
return;
//Checks For Any Opponent Winning Moves
} else if ((square = nextMoveWinCheck(opponentChar)) != 0) {
board.addToBoard(playerChar, square);
return;
} else {
//Checks If Computer Has First Move
if (boardEmpty()) {
board.addToBoard(playerChar, 9);
return;
} else {
//Moves Into Opposite Corner if Bottom Corner is Occupied By Itself
if (!board.spaceFull(board.board,1) && board.board[2][2] == playerChar) {
board.addToBoard(playerChar, 1);
return;
//Move Into Center If Second Move or Possible
} else if (!board.spaceFull(board.board,5)) {
board.addToBoard(playerChar, 5);
return;
} else if ((square = emptyCorner()) != 0) {
board.addToBoard(playerChar, square);
return;
} else {
board.addToBoard(playerChar, randomEmptySpot());
return;
}
}
}
}
If you want the full code, it's:
Computer
Board
Player
Tic-Tac-Toe Main Class
Your problem lies in your class Computer. On line 57, you assign board.board to tempBoard. However tempBoard still holds the reference to the object board.board, so whatever modifications you make there is reflected on the actual board. To resolve this, COPY the board values to tempboard:
http://www.java2s.com/Code/Java/Collections-Data-Structure/clonetwodimensionalarray.htm
I am trying to implement a depht first search alogrithm (my code is probably horrible, I'm sorry). Now I wanted to make this a recursive method but I just can't seem to be able to break out of it once the end condition is met. The first if-conditional you see in the method should break out of the method. When I was debugging the project it reached the return statement and then immediately jumped to the end of the method. But instead of stopping the whole thing it went back to the while(!allNeighboursVisited) loop and went on in an infinite loop.
I was trying to solve this by myself which did not work and started searching in the web, but I just could not find any solution to my problem.
EDIT: Decided to share the link to the project on my github for you guys to try it out: https://github.com/Equiphract/Maze
EDIT 2: Updated the code; I hacked it together so please don't expect anything that is pleasant to look at :)
Here is the recursive method:
public void depthFirstSearch(int x, int y, Tile[][] maze) {
// Return method after every Tile is visited.
if (this.visitedCounter == maze.length * maze[0].length) {
this.stack.clear();
return;
}
Tile currentTile = maze[x][y];
Random r = new Random();
int neighbourAmount = currentTile.getNeighbourAmount();
boolean allNeighboursVisited = false;
int stopCounter = 0;
// If it is a new Tile, mark it as visited
if (!currentTile.isVisited()) {
currentTile.setVisited(true);
this.visitedCounter++;
stack.add(currentTile);
}
// Check if neighbours are not yet visited and "visit" one of them.
while (!allNeighboursVisited) {
int random;
do {
random = r.nextInt(neighbourAmount);
} while (this.excludeList.contains(random));
Tile neighbour = currentTile.getNeighbours().get(random);
if (!neighbour.isVisited()) {
if (neighbour.getX() == currentTile.getX() - 1) {
currentTile.getWall(4).setOpen(true);
neighbour.getWall(2).setOpen(true);
} else if (neighbour.getX() == currentTile.getX() + 1) {
currentTile.getWall(2).setOpen(true);
neighbour.getWall(4).setOpen(true);
} else if (neighbour.getY() == currentTile.getY() - 1) {
currentTile.getWall(1).setOpen(true);
neighbour.getWall(3).setOpen(true);
} else if (neighbour.getY() == currentTile.getY() + 1) {
currentTile.getWall(3).setOpen(true);
neighbour.getWall(1).setOpen(true);
}
this.excludeList.clear();
depthFirstSearch(neighbour.getX(), neighbour.getY(), maze);
if (this.visitedCounter == maze.length * maze[0].length) {
this.stack.clear();
return;
}
} else {
this.excludeList.add(random);
stopCounter++;
}
if (stopCounter == neighbourAmount) {
allNeighboursVisited = true;
}
}
// If every neighbour has already been visited, go back one Tile.
if (!this.stack.isEmpty()) {
this.stack.remove(this.stack.size() - 1);
if (!this.stack.isEmpty()) {
Tile backtrackTile = this.stack.get(this.stack.size() - 1);
this.excludeList.clear();
depthFirstSearch(backtrackTile.getX(), backtrackTile.getY(), maze);
if (this.visitedCounter == maze.length * 3) {
this.stack.clear();
return;
}
}
this.excludeList.clear();
}
}
You know what, here is the Tile-Object (sorry for the high amount of edits in this short period):
public class Tile {
private ArrayList<Wall> walls;
private ArrayList<Tile> neighbours;
private int x;
private int y;
private boolean visited;
/*
* Constructor of the Tile class.
*/
public Tile(int x, int y) {
this.walls = new ArrayList<Wall>();
this.neighbours = new ArrayList<Tile>();
this.walls.add(new Wall(1));
this.walls.add(new Wall(2));
this.walls.add(new Wall(3));
this.walls.add(new Wall(4));
this.x = x;
this.y = y;
this.visited = false;
}
/*
* Returns the ArrayList walls.
*/
public ArrayList<Wall> getWalls() {
return walls;
}
/*
* Returns the value of visited.
*/
public boolean isVisited() {
return visited;
}
/*
* Sets the value of visited to a specified value.
*
* #param visited a boolean value
*/
public void setVisited(boolean visited) {
this.visited = visited;
}
/*
* Returns a wall with the specified position.
*
* #param position the position of the wall
*/
public Wall getWall(int position) {
for(Wall w : this.walls) {
if(w.getPosition() == position) {
return w;
}
}
return null;
}
public int getNeighbourAmount() {
return this.neighbours.size();
}
public ArrayList<Tile> getNeighbours(){
return this.neighbours;
}
/*
* Adds a Tile to the ArrayList neighbours-
*
* #param t a Tile
*/
public void addNeighbour(Tile t) {
this.neighbours.add(t);
}
/**
* #return the x
*/
public int getX() {
return x;
}
/**
* #return the y
*/
public int getY() {
return y;
}
}
Ok I think I found a solution to my question. It is far from perfect and needs a lot of optimisation, maybe one of you guys want to do that and post it here^^.
My main mistake was not adding returns after each time I invoked the method recursively, which resulted in an endless-loop.
Here is my solution:
public void depthFirstSearch(int x, int y, Tile[][] maze) {
// Return method after every Tile is visited.
if (this.visitedCounter == maze.length * maze[0].length) {
this.stack.clear();
return;
}
Tile currentTile = maze[x][y];
Random r = new Random();
int neighbourAmount = currentTile.getNeighbourAmount();
boolean allNeighboursVisited = false;
int stopCounter = 0;
// If it is a new Tile, mark it as visited
if (!currentTile.isVisited()) {
currentTile.setVisited(true);
this.visitedCounter++;
stack.add(currentTile);
}
// Check if neighbours are not yet visited and "visit" one of them.
while (!allNeighboursVisited) {
int random;
do {
random = r.nextInt(neighbourAmount);
} while (this.excludeList.contains(random));
Tile neighbour = currentTile.getNeighbours().get(random);
if (!neighbour.isVisited()) {
if (neighbour.getX() == currentTile.getX() - 1) {
currentTile.getWall(4).setOpen(true);
neighbour.getWall(2).setOpen(true);
} else if (neighbour.getX() == currentTile.getX() + 1) {
currentTile.getWall(2).setOpen(true);
neighbour.getWall(4).setOpen(true);
} else if (neighbour.getY() == currentTile.getY() - 1) {
currentTile.getWall(1).setOpen(true);
neighbour.getWall(3).setOpen(true);
} else if (neighbour.getY() == currentTile.getY() + 1) {
currentTile.getWall(3).setOpen(true);
neighbour.getWall(1).setOpen(true);
}
this.excludeList.clear();
depthFirstSearch(neighbour.getX(), neighbour.getY(), maze);
return;
} else {
this.excludeList.add(random);
stopCounter++;
}
if (stopCounter == neighbourAmount) {
allNeighboursVisited = true;
}
}
// If every neighbour has already been visited, go back one Tile.
if (!this.stack.isEmpty()) {
this.stack.remove(this.stack.size() - 1);
if (!this.stack.isEmpty()) {
Tile backtrackTile = this.stack.get(this.stack.size() - 1);
this.excludeList.clear();
depthFirstSearch(backtrackTile.getX(), backtrackTile.getY(), maze);
return;
}
this.excludeList.clear();
}
}
I'm trying to create a method in a class for Java for a game called Quoridor in which a Pawn has to reach the other side of the board. The Pawn class (one coordinate) traverses a 9x9 2D array whereas the Wall classes (2 coordinates) are placed on a 10x10 2D array. The Walls are basically placed between the Pawn squares. Pawns cant cross Walls or other Pawns, I'm not sure how to implement the BFS with two 2D arrays. I'm new to programming and was wondering if someone could give me a step by step on how to create such a method. Currently have a Pawn and Wall class with necessary get and set methods.enter code here
package Players.HaydenLindquist;
import java.util.*;
import Engine.Logger;
import Interface.Coordinate;
import Interface.PlayerModule;
import Interface.PlayerMove;
public class HaydenLindquist implements PlayerModule {
Coordinate newCoords;
Wall theWall;
private Logger logOut;
Pawn player;
Pawn opponent;
List<Wall> wallList;
List<Pawn> pawnList;
public int getID()
{
return player.getId();
}
public Set<Coordinate> getNeighbors(Coordinate c) {
// Creates HashSet we will use to store neighbor tiles
Set<Coordinate> neighbor = new HashSet<Coordinate>();
int x = c.getRow();
int y = c.getCol();
// Coordinates for the 4 adjacent spaces
Coordinate top = new Coordinate(x,y-1);
Coordinate bottom = new Coordinate(x,y+1);
Coordinate left = new Coordinate(x-1,y);
Coordinate right = new Coordinate(x+1,y);
if(x == 0) {
if(y == 0) {
if(! wallCheck(right))
neighbor.add(right);
if(! wallCheck(bottom))
neighbor.add(bottom);
}
else if(y == 8) {
if(! wallCheck(top))
neighbor.add(top);
if(! wallCheck(right))
neighbor.add(right);
}
else {
if(! wallCheck(top))
neighbor.add(top);
if(! wallCheck(right))
neighbor.add(right);
if(! wallCheck(bottom))
neighbor.add(bottom);
}
}
else if(x == 8) {
if(y == 0) {
if(! wallCheck(left))
neighbor.add(left);
if(! wallCheck(bottom))
neighbor.add(bottom);
}
else if(y == 8) {
if(! wallCheck(top))
neighbor.add(top);
if(! wallCheck(left))
neighbor.add(left);
}
else {
if(! wallCheck(top))
neighbor.add(top);
if(! wallCheck(left))
neighbor.add(left);
if(! wallCheck(bottom))
neighbor.add(bottom);
}
}
else if(y == 0) {
if(! wallCheck(right))
neighbor.add(right);
if(! wallCheck(left))
neighbor.add(left);
if(! wallCheck(bottom))
neighbor.add(bottom);
}
else if(y == 8) {
if(! wallCheck(right))
neighbor.add(right);
if(! wallCheck(left))
neighbor.add(left);
if(! wallCheck(top))
neighbor.add(top);
}
else {
if(! wallCheck(right))
neighbor.add(right);
if(! wallCheck(left))
neighbor.add(left);
if(! wallCheck(top))
neighbor.add(top);
if(! wallCheck(bottom))
neighbor.add(bottom);
}
return neighbor;
}
/**
*
*/
public Coordinate getPlayerLocation(int playerID)
{
if(playerID == player.getId())
{
return(player.getLocation());
}
else return(opponent.getLocation());
}
/**
*
*/
public Map<Integer, Coordinate> getPlayerLocations() {
// Creates HashMap of Integer, Coordinate type
HashMap<Integer, Coordinate> locations = new HashMap<Integer, Coordinate>();
// Adds the ID and locations of the 2 players to the HashMap
locations.put(player.getId(), player.getLocation());
locations.put(opponent.getId(), opponent.getLocation());
return locations;
}
/**
*
*/
public List<Coordinate> getShortestPath(Coordinate start, Coordinate end)
{
List<Coordinate> path = new ArrayList<Coordinate>();
return null;
}
/**
*
*/
public int getWallsRemaining(int playerID)
{
if(playerID == player.getId())
{
return(player.getWalls());
}
else return(opponent.getWalls());
}
/**
*
*/
public void init(Logger logger, int playerID, int numWalls, Map<Integer, Coordinate> playerHomes)
{
logOut = logger;
// Creates ArrayList used to store wall objects
wallList = new ArrayList<Wall>();
// Creates our two players and initializes them with data from engine
for ( Integer i : (Set<Integer>) playerHomes.keySet() )
{
if ( i == playerID )
player = new Pawn(playerID,numWalls,playerHomes.get(i));
else
{
opponent = new Pawn(2,numWalls,playerHomes.get(i));
}
}
}
public void lastMove(PlayerMove m)
{
// Check if m is a player move or wall placement
if(m.isMove())
{
// Switch to differentiate between player 1 and 2.
// then updates the appropriate players location
switch(m.getPlayerId())
{
case 1:
player.setLocation(m.getEnd());
break;
case 2:
opponent.setLocation(m.getEnd());
break;
}
}
else
{
switch(m.getPlayerId())
{
case 1:
addWall(m.getStart(), m.getEnd());
player.setWalls(player.getWalls() - 1);
break;
case 2:
addWall(m.getStart(), m.getEnd());
opponent.setWalls(player.getWalls() - 1);
break;
}
}
}
/**
*
*/
public Set<PlayerMove> allPossibleMoves()
{
return null;
}
/**
*
*/
public PlayerMove move()
{
return null;
}
/**
*
* #param player
* #return
*/
/**
*
*
*/
public void playerInvalidated(int playerID)
{
}
/**
* Method that creates a new wall object and adds it to the wallList ArrayList
*
* #param start
* #param end
*/
public void addWall(Coordinate start, Coordinate end)
{
Wall w = new Wall(start,end);
wallList.add(w);
}
/**
* A check method to see if entered coordinate contains a section of a wall
*
* #param c
* #return
*/
public boolean wallCheck(Coordinate c)
{
// Iterates through wall objects in wallList
for(int i = 0; i < wallList.size(); i++)
{
// Check if any adjacent squares contain a section of a wall
if(wallList.get(i).isWall(c))
{
return true;
}
}
return false;
}
}
Since you're starting with the idea of a BFS, and you've decided to represent your board with multidimensional arrays, why don't you start by thinking about how BFS maps to the representation of your board?
For example, can you write up the code to list all adjacent cells of a given cell? If you can do that, it should be easier to see how to implement the rest of BFS.
I'm trying to get an object to wander around the world randomly.
This object has a 25% chance of turning left, 25% chance of turning right, and 50% chance of moving straight.
I have to ensure that the random direction chosen is not one that will take the object out of bounds. I used getGridX() and getGridY() to check the current object's coordinate position to determine if it is at the edge. And I've only actively considered 2 of the corners of the world.
However, it keeps getting forced outside the world.
What is my code doing wrong?
import sofia.micro.*;
import sofia.util.Random;
//-------------------------------------------------------------------------
public class Food extends SimpleActor
{
//~ Constructor ...........................................................
/**
* Creates a new Food object.
*/
public Food()
{
super();
}
//~ Methods ...............................................................
// ----------------------------------------------------------
/**
* 25% chance of turning left
* 25% chance of turning right
* 50% chance of moving forward
*/
public void act()
{
int value = Random.generator().nextInt(100);
this.changeDirection();
if (value < 25)
{
this.turn(LEFT);
this.changeDirection();
}
else if (value < 50)
{
this.turn(RIGHT);
this.changeDirection();
}
else
{
this.move();
this.changeDirection();
}
}
/**
* make a U-turn
*/
public void turnAround()
{
this.turn(RIGHT);
this.turn(RIGHT);
}
/**
* detects edge condition and moves away
*/
public void changeDirection()
{
if ((this.getGridY() == this.getWorld().getHeight()) ||
(this.getGridX() == this.getWorld().getWidth()))
{
this.turnAround();
this.move();
}
if ((this.getGridY() == 0) || (this.getGridX() == 0))
{
this.turnAround();
this.move();
}
if ((this.getGridY() == this.getWorld().getHeight()) &&
(this.getGridX() == this.getWorld().getWidth()))
{
this.turnAround();
this.move();
}
if ((this.getGridY() == 0) && (this.getGridX() == 0))
{
this.turnAround();
this.move();
}
}
}
It looks like the following condition is written twice. If you're facing out of bounds, wouldn't you do a 360, instead of a 180? I would remove the latter 2 if statements.
if ((this.getGridY() == this.getWorld().getHeight()) &&
(this.getGridX() == this.getWorld().getWidth()))
{
this.turnAround();
this.move();
}
Assuming that the turn() method is properly implemented (I don't see it in your code), here is one problem I found:
if (value < 25)
{
this.turn(LEFT);
this.changeDirection();
}
else if (value < 50)
{
this.turn(RIGHT);
this.changeDirection();
}
else
{
this.move(); // < --- You shouldn't be using this here
this.changeDirection();
}
Remove that line. Because when this statement is reached, it is possible that your actor is in an edge and facing into emptiness - and you are literally telling it to move forward.
Instead, remove the line and just call changeDirection(), which will cause the actor to turn 180 degrees. I see that changeDirection() will also cause the actor move, so basically your actor will move away from the edge.
I need to find if Path2D intersects itself. For now, I do it by simply extracting an array of lines from path, and finding if any of these intersect. But it has O(n^2) complexity, and so it is very slow. Is there a faster way to do it?
You can do this faster using the sweep-line algorithm: http://en.wikipedia.org/wiki/Sweep_line_algorithm
Pseudocode:
Each line has a start point and an end point. Say that `start_x` <= `end_x` for all the lines.
Create an empty bucket of lines.
Sort all the points by their x coordinates, and then iterate through the sorted list.
If the current point is a start point, test its line against all the lines in the bucket, and then add its line to the
bucket.
if the current point is an end point, remove its line from the bucket.
The worst case is still O(N^2), but the average case is O(NlogN)
Here is my Java implementation of this algorithm:
import java.awt.Point;
import java.awt.geom.Line2D;
import java.awt.geom.PathIterator;
import java.util.*;
/**
* Path2D helper functions.
* <p/>
* #author Gili Tzabari
*/
public class Path2Ds
{
/**
* Indicates if a Path2D intersects itself.
* <p/>
* #return true if a Path2D intersects itself
*/
public static boolean isSelfIntersecting(PathIterator path)
{
SortedSet<Line2D> lines = getLines(path);
if (lines.size() <= 1)
return false;
Set<Line2D> candidates = new HashSet<Line2D>();
for (Line2D line: lines)
{
if (Double.compare(line.getP1().distance(line.getP2()), 0) <= 0)
{
// Lines of length 0 do not cause self-intersection
continue;
}
for (Iterator<Line2D> i = candidates.iterator(); i.hasNext();)
{
Line2D candidate = i.next();
// Logic borrowed from Line2D.intersectsLine()
int lineRelativeToCandidate1 = Line2D.relativeCCW(line.getX1(), line.getY1(), line.
getX2(),
line.getY2(), candidate.getX1(), candidate.getY1());
int lineRelativeToCandidate2 = Line2D.relativeCCW(line.getX1(), line.getY1(), line.
getX2(),
line.getY2(), candidate.getX2(), candidate.getY2());
int candidateRelativeToLine1 = Line2D.relativeCCW(candidate.getX1(),
candidate.getY1(),
candidate.getX2(), candidate.getY2(), line.getX1(), line.getY1());
int candidateRelativeToLine2 = Line2D.relativeCCW(candidate.getX1(),
candidate.getY1(),
candidate.getX2(), candidate.getY2(), line.getX2(), line.getY2());
boolean intersection = (lineRelativeToCandidate1 * lineRelativeToCandidate2 <= 0)
&& (candidateRelativeToLine1 * candidateRelativeToLine2 <= 0);
if (intersection)
{
// Lines may share a point, so long as they extend in different directions
if (lineRelativeToCandidate1 == 0 && lineRelativeToCandidate2 != 0)
{
// candidate.P1 shares a point with line
if (candidateRelativeToLine1 == 0 && candidateRelativeToLine2 != 0)
{
// line.P1 == candidate.P1
continue;
}
if (candidateRelativeToLine1 != 0 && candidateRelativeToLine2 == 0)
{
// line.P2 == candidate.P1
continue;
}
// else candidate.P1 intersects line
}
else if (lineRelativeToCandidate1 != 0 && lineRelativeToCandidate2 == 0)
{
// candidate.P2 shares a point with line
if (candidateRelativeToLine1 == 0 && candidateRelativeToLine2 != 0)
{
// line.P1 == candidate.P2
continue;
}
if (candidateRelativeToLine1 != 0 && candidateRelativeToLine2 == 0)
{
// line.P2 == candidate.P2
continue;
}
// else candidate.P2 intersects line
}
else
{
// line and candidate overlap
}
return true;
}
if (candidate.getX2() < line.getX1())
i.remove();
}
candidates.add(line);
}
return false;
}
/**
* Returns all lines in a path. The lines are constructed such that the starting point is found
* on the left (or same x-coordinate) of the ending point.
* <p/>
* #param path the path
* #return the lines, sorted in ascending order of the x-coordinate of the starting point and
* ending point, respectively
*/
private static SortedSet<Line2D> getLines(PathIterator path)
{
double[] coords = new double[6];
SortedSet<Line2D> result = new TreeSet<Line2D>(new Comparator<Line2D>()
{
#Override
public int compare(Line2D o1, Line2D o2)
{
int result = Double.compare(o1.getX1(), o2.getX1());
if (result == 0)
{
// Ensure we are consistent with equals()
return Double.compare(o1.getX2(), o2.getX2());
}
return result;
}
});
if (path.isDone())
return result;
int type = path.currentSegment(coords);
assert (type == PathIterator.SEG_MOVETO): type;
Point.Double startPoint = new Point.Double(coords[0], coords[1]);
Point.Double openPoint = startPoint;
path.next();
while (!path.isDone())
{
type = path.currentSegment(coords);
assert (type != PathIterator.SEG_CUBICTO && type != PathIterator.SEG_QUADTO): type;
switch (type)
{
case PathIterator.SEG_MOVETO:
{
openPoint = startPoint;
break;
}
case PathIterator.SEG_CLOSE:
{
coords[0] = openPoint.x;
coords[1] = openPoint.y;
break;
}
}
Point.Double endPoint = new Point.Double(coords[0], coords[1]);
if (Double.compare(startPoint.getX(), endPoint.getX()) < 0)
result.add(new Line2D.Double(startPoint, endPoint));
else
result.add(new Line2D.Double(endPoint, startPoint));
path.next();
startPoint = endPoint;
}
return result;
}
}