The best way for storing 2D game map - java

I'm implementing Bomberman clone in Java. Its map has a scale of 17*13 tiles. Now I'm storing the game map in the ArrayList. Obviously it's unproductive since game mechanics provides only discrete moving (right, left, up, down). Bombs can have only discrete position too. So with the ArrayList I have to look for four adjacent tiles through whole list while processing collisions or fire generating. So what are the best practices for storing such maps in Java.

There are lots of ways you could model this. Here's a suggestion that I've used often for similar problems:
enum Direction {
NORTH, SOUTH, EAST, WEST;
}
class Position {
private final int x;
private final int y;
public static Stream<Position> getAllPositions();
public Stream<Position> getNeighbours();
public Optional<Position> positionInDirection(Direction direction);
// make sure you implement equals and hashCode
}
class Map {
private final Map<Position, Tile> tiles = new HashMap<>();
public Map() {
Position.getAllPositions().forEach(pos -> tiles.put(pos, new Tile());
}
public Tile getTile(Position position) {
return tiles.get(position);
}
}
This provides lots of useful encapsulation. For example the Position class is the only one that needs to know about the size of the map and edges.
Now to see if an adjacent position has a bomb (for example), you would use:
position.getNeighbours().map(map::getTile).anyMatch(Tile::hasBomb);

Related

Get Edge list between two graph Vertex

I have the own data structure for the graph, and I need the implementation method:
List<Edge<T>> getPath(T start, T finish)
Performance not important, I search the simplest and most readable way. But my data structure should support the directed and undirected graph types and I stuck with it.
public class Graph<T> {
private boolean isDirected = false;
private Map<Vertex<T>, List<Edge<T>>> graph = new HashMap<>();
public Graph() {
}
public Graph(boolean isDirected) {
this.isDirected = isDirected;
}
public List<Edge<T>> getPath(T start, T finish) {
if (start.equals(finish)) {
return new ArrayList<>();
}
// TODO here is the method I'm stuck with.
if (isDirected) {
// Call search for directed graph
} else {
// Call search for undirected graph
}
}
public void addEdge(T first, T second) {
final Vertex<T> master = new Vertex<>(first);
final Vertex<T> slave = new Vertex<>(second);
final Set<Vertex<T>> vertices = graph.keySet();
if (!vertices.contains(master) || !vertices.contains(slave)) {
throw new IllegalArgumentException();
}
graph.get(master).add(new Edge<>(master, slave));
if (!isDirected) {
graph.get(slave).add(new Edge<>(slave, master));
}
}
public void addVertex(T value) {
final List<Edge<T>> result = graph.putIfAbsent(new Vertex<>(value), new ArrayList<>());
if (result != null) {
throw new IllegalArgumentException();
}
}
}
This Vertex and Edge class:
#Data
#AllArgsConstructor
#EqualsAndHashCode
public class Vertex<T> {
private T value;
}
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Edge<T> {
private Vertex<T> first;
private Vertex<T> second;
}
I will be very grateful for Your help.
It is not totally clear what kind of path you want to find. The shortest path, any path,...?
If you want to find the shortest path, A* is a really simple algorithm to implement. The pseudo code can be found here. A* is a best-first search algorithm for a weighted graph (E.g. the distance of an edge or another kind of cost to travel on the edge like time). The algorithm uses a heuristic function to select the next node/vertex to evaluate. A* basically repeats the following steps:
Select a next node/vertex which has not already been visited. The selection is made using the heuristic function
If this new node equals the goal position, return the shortest path found
Evaluate all paths currently known and select the one with the lowest cost
I could also provide a Java code snippet (based on the pseudo code) if it's necessary. Be aware that the pseudo code in the end constructs the shortest path backwards (from goal to start).
You are also using a generic for your graph. Both your Vertext and Edge class use this generic. Let's assume that this generic T is a double. In your code this means that your Vertex is only a one-dimensional double. This does not make sense when you want to represent a graph of 2D or 3D points.
Is it even really necessary to use this generic? Wouldn't it be sufficient to simply support vertices which consists of floats, doubles or integers? Using a generic type or more abstract class (like Number) might give some problems when you for example want to compute the distance between vertices.

Match two java collections by property avoiding ConcurrentModificationException (example of Google Roads api)

I haven't found any similar questions, where one collection is accessed while looping through another. Most of the questions about two collections and loops refer to simultaneous looping through both collections.
I'm using Google Road API in my application.
(documentation: https://developers.google.com/maps/documentation/roads/snap)
Simplified pre-history:
There is a polyline of car route. It should be corrected according to real roads coordinates and then colored according to speed at each point.
So, I have my own RoutePoint object:
public class RoutePoint{
private double latitude;
private double longitude;
private double speed;
}
Out of List<RoutePoint> routePoints I take latitudes and longitudes, construct request to Google Roads Api with interpolate = true and receive my fixed points with real roads coordinates, all good.
Each received snappedPoint (as Google calls them) has originalIndex property which is the index of each inital point if the request. Since I use interpolate= true, size of snappedPoints will usually be bigger than originalPoints and each interpolated point will have originalIndex = null.
public class SnappedPoint{
private SnappedLocation location;
private Integer originalIndex;
private String placeId;
}
Once I received my snappedPoints, my task is to draw colored polylines, depending on speed in each point. In order to do that I need to match original points with snapped points by originalIndex. Then, assign speed to each of the snappedPoints. So, I add speed to SnappedPoint class:
public class SnappedPoint{
private SnappedLocation location;
private Integer originalIndex;
private String placeId;
private double speed;
}
In order to match original points with snapped points I decided to loop through snappedPoints and when originalIndex matches routePoint index, copy the speed to snappedPoint:
int counter = 0;
for (int i = 0; snappedPoints.size() > i; i++) {
SnappedPoint snappedPoint = snappedPoints.get(i);
RoutePoint routePoint = routePoints.get(counter); //ConcurrentModificationException at this line
//do my match speed logic, but I can never come to this point
if (snappedPoint.getOriginalIndex() == null) {
snappedPoint.setSpeed(routePoint.getSpeed());
} else {
if (snappedPoint.getOriginalIndex() <= counter) {
snappedPoint.setSpeed(routePoint.getSpeed());
} else {
counter++;
}
}
}
Now, we've come to my problem. I get ConcurrentModificationException when trying to access routePoints.get(). As far as I understand it's because I'm accessing one collection while looping through another.
How to avoid this exception?
Or how to match original points with snapped points, avoiding this situation?

Check if elements of different ArrayLists share position

I am programming a probe that moves through a 2D board in Java. To do this, I have two ArrayLists of Integer that contain the path that the probe has followed. The first ArrayList contains the x-coordinate, and the second one, the y-coordinate. What I would like to do is check whether the next tile of the movement has been visited or not, this is, whether the new x-coord and the new y-coord are in the corresponding ArrayList and share the same position.That way, if the new tile has been visited, I wouldn't move there. How could I possibly do this? I have tried with indexOf and lastIndexOf, but it doesn't work as each coordinate can be repeated an indefinite number of times. I also tried .contains but it didn't work either as I need that it is contained in both arrays in a specific position.
Any help would be appreciated.
First of all Java is object oriented so you should use objects. Why are you storing a coordinate in two separate arrays?
You can define your own type:
class Position implements Comparable<Position> {
public final int x;
public final int y;
Position(int x, int y) { this.x = x; this.y; }
#Override public int compareTo(Position other) { ... }
#Override public boolean equals(Object other) { ... }
#Override public int hashCode() { ... }
}
Then with this you can do whatever you want, for example
Set<Position> visited = new HashSet<Position>();
Map<Position, Integer> visitedWithSpecificPositionInPath = new HashMap<Position, Integer();
and so on.
A pretty messy approach would be to find all indexes of matching x-coordinates and for each index found check whether the y-coordinate for the given index is equal to the y in question.
So given coordinates x, y and array lists visitedX and visitedY you could do something like this:
public static boolean isVisited(int x, int y){
for(int i = 0; i < visitedX.size(), i++){
if(visitedX.get(i) == x){
if(visitedY.get(i) == y){
return true;
}
}
}
return false;
}
But as Jack has mentioned you should reconsider your data structure as looping over the complete x-coordinates list is not very efficient (though you could reduce limits of outer for loop with usage of visitedX.indexOf(x) and visitedX.lastIndexOf(x) ).

Java Constructors or new class

Hey I am new java so forgive me if what I am about to ask is obvious, but I will try to explain as best as I can.
Its just a project that has been set for university so its not in a serious manner.
I have a class called MarsRoom which holds the attributes say for all the dimensions of the room like the totalheight and width of the walls in order to calculate the heat loss that the room will suffer in order to adjust the amount of solar energy that is needed to keep the room at the room temperature set.
The problem I am having is what is better practice or solution, to pass the attributes of the size of the room in a constructor(but this could get quite long in size, as the ones below are not only the ones that I may need) or create a whole different class specifically for that room like ROOM TYPE U? and set the attributes in there.
As it stands I can create a whole new room just by instantiating the room with the new values, but its going to get a little long, whereas I would rather not create a whole new class for a different room which may only differ from another room by a few meters on one of the walls!.
So what I am really trying to get at it, is is it ok to pass that many attributes to the constructor on instantiation?
//the instantiation in the runnable
MarsRoom room1 = new MarsRoom("RoomU", 40, 40, 20, 20, 8, 2, 4);
//the constructor in the MarsRoom class
public MarsRoom(String roomname, int windowsH, int windowsW, int wallsH, int wallsW, int windowC, int heaters, int lights){
name = roomname;
TotalWindowHeight = windowsH;
TotalWindowWidth = windowsW;
TotalWallHeight = wallsH;
TotalWallWidth = wallsW;
windowCeiling = windowC;
numheaters = heaters;
numlights = lights;
roomheaters = new Heaters[numheaters];
}
I'd say that you should be adding factory methods here.
Basically, keep your constructor, but add methods like
static Room createLaundryRoom(laundryRoomParameters) {
return new Room(...laundry room parameters plus defaults
common to all laundry rooms...);
}
One of the great benefits object oriented programming is the possibility of not repeating yourself in code. Hence objects, which define data (members) and functionality (methods), and no requirement to create instances of these "prototypes" with hard values until run-time. To create a new class for each room when it
may only differ from another room by a few meters on one of the walls
would be to deny OOP (and Java) by gross repetition. I'd stick with the constructors, and if similar kinds of rooms end up emerging, try one of the static factory methods suggested, or break up common functionality using inheritanceOracle.
Create a map with the keys being
Map<String, Integer> map = new HashMap();
map.put("TotalWindowHeight", new Integer(10));
map.put("TotalWindowWidth", new Integer(5));
...
map.put("NumberOfHeaters", new Integer(3));
MarsRoom room1 = new MarsRoom("RoomU", map);
Constructor will be like:
public MarsRoom(String roomname, HashMap<String, Integer> params) {
name = roomname;
TotalWindowHeight = map.get("TotalWindowHeight").intValue();
TotalWindowWidth = map.get("TotalWindowWidth").intValue;
...
roomheaters = new Heaters[map.get("NumberOfHeaters").intValue()];
}
this is not good OO however, but it seems like you are looking for something quick. If you want good OO you need to create an object for Window and in it you have hieght and width, another for ceiling, and you should not have number of something as a field, you should have an array to store the heater objects, and so and so forth, but this is quick and meets your requirement.
While technically legal, constructors with very long argument lists may be inconvenient to use. It also depends on whether you this the list may grow in the future or in subclasses.
If you have many parameters, but they have defaults and sometimes only a few need to be changed, you may find the Builder pattern useful. The idea is to replace constructor arguments with function calls, and allow them to be chained, for example:
public MarsRoom() {
//empty or just basic stuff set here
}
public MarsRoom setTotalWindowHeight(int TotalWindowHeight) {
this.TotalWindowHeight = TotalWindowHeight;
return this;
}
public MarsRoom setTotalWindowWidth(int TotalWindowWidth) {
this.TotalWindowWidth = TotalWindowWidth;
return this;
}
...
then, you can call:
MarsRoom room1 = new MarsRoom()
.setTotalWindowHeight(20)
.setTotalWindowWidth(40);
Of course, if you wanted to set all parameters this way, it's longer (thou maybe more readable) than the single constructor. But if you only set 2 parameters out of 10, it will usually be more convenient.
You don't show what the fields of MarsRoom are, but for each feature, I would have a Collection of sub-objects. A MarsRoom has-a List of Windows. A MarsRoom has-a List of Walls. etc... Then have setters and getters for each and methods to add new instances of these features.
Since this is for school, I'm only including a little bit of pseudo code.
public class MarsWindow {
int height;
int length;
// Setters & Getters
// standard getters & setters go here
int getArea() {
return this.height * this.width;
}
}
public class MarsRoom {
List<MarsWindow> windows;
List<MarsWall> walls;
List<MarsLight> lights;
List<MarsHeater> heaters;
public List<MarsWindow> addWindow(MarsWindow window) {
// Add a window to the "windows" list here
}
public List<MarsWall> addWall(MarsWall wall) {
// Add a wall to the "walls" list here
}
// Do this for the other fields
int getTotalWindowArea() {
int area = 0;
// Iterate over all windows
for(MarsWindow window : windows) {
area += window.getArea();
}
return area;
}
// Add other calculation methods here
}
If what you're trying to do is simply not duplicate the parameters you're passing the constructor, you can simply put them in a separate static method, like so:
public static MarsRoom newRoomU() {
return new MarsRoom("RoomU", 40, 40, 20, 20, 8, 2, 4);
}
You could also use some polymorphism or have different types of rooms or something similar to this and then have a superclass with the common values that all rooms will have.
You can also have more than one constructor and have different ones for values you wish to set depending on the room type etc.
Its always better to work with objects rather than primitives, you could use factory to create objects.
//the constructor in the MarsRoom class
public MarsRoom(String roomname, WindowDimension windowDimension, WallsDimensions wallDimension, RoomAmbience ambience){
}
public class WindowDimension{
private int height; //int windowsH
private int width; //int windowsW
private int circumference; //assumed windowC is circumference
}
public class WallsDimension{
private int height; //int wallsH
private int width; //int wallsW
}
public class RoomAmbience{
private int heaters;
private int lights;
}

Combining shape objects to create a composite

i have a program i have to do where i have to take individual shape objects and combine them to create a final car shape. we are given premade shapes such as front tire, back tire, body, windshield, and roof and supposed to combine them into one car shape. the code already given to me is the following:
CompositeShape shape = new CompositeShape();
final double WIDTH = 60;
Rectangle2D.Double body
= new Rectangle2D.Double(0, WIDTH / 6,
WIDTH, WIDTH / 6);
Ellipse2D.Double frontTire
= new Ellipse2D.Double(WIDTH / 6, WIDTH / 3,
WIDTH / 6, WIDTH / 6);
Ellipse2D.Double rearTire
= new Ellipse2D.Double(WIDTH * 2 / 3, WIDTH / 3,
WIDTH / 6, WIDTH / 6);
shape.add(body);
shape.add(frontTire);
shape.add(rearTire);
now, i have to create the compositeShape class which is where the combining takes place, but im not sure what to do in the add(Shape) method. we were also told that we were supposed to use a pathiterator method, but we werent really taught about pathiterator or what we are supposed to do with it. Im not asking for someone to tell me what exactly to code, just some helpful starter points.
the first thing that came to my mind was something like this:
public class CompositeShape implements Shape {
Graphics2D g2;
public void add(Shape shape){
g2.draw(shape);
}
but it doesnt work because i cant instantiate a new graphics object and i get a null pointer exception. after that, im pretty much stumped as to what to do. any help would be greatly appreciated. thanks!
Probably, instead of drawing the Shape inside the add() method, you're just supposed to store the added Shape for drawing later. You could do that by giving CompositeShape some kind of collection to hold Shapes that are added, and that's all I'd put in the add() method. Beyond that, it would depend what other behavior CompositeShape is supposed to have. If you have to be able to draw a CompositeShape, then you'll probably be given an Graphics object to draw on. You won't have to create your own. Then drawing a CompositeShape would be drawing all of the Shapes that it contains.
java.awt.geom.Area can combine multiple shapes with methods add, subtract, exclusiveOr, and intersect. It's a ready-made class for CompositeShape.
It seems extremely weird that you've been asked to recreate it as "CompositeShape", because Area already does what you want.
The solution could be as simple as
class CompositeShape extends java.awt.geom.Area {}
and you're done.
Or, the fact that you've been given a hint about PathIterator, it might be that you're being encouraged to manage the added shapes in a list manually, then implement all the methods of the Shape interface in terms of iterating over the other shapes.
E.g., getBounds() needs to return the rectangular bounds of the shape, so get the rectangular bounds of the first, then use Rectangle.union to join it with the bounds of the others.
And for getPathIterator(), return a new inner class implementing PathIterator that will iterate over all the shapes in your collection, and iterate the path segments of each of their getPathIterator methods, returning each path segment.
It all sounds unnecessary in practice, since the needed class already exists. I think you should get clarification on what is wanted. Good luck.
To clarify what I said about the implementation of getPathIterator, return something like this. I didn't test this. This assumes your list is called shapes.
public PathIterator getPathIterator(final AffineTransform at, final double flatness) {
return new PathIterator() {
private PathIterator currentPathIterator;
private Iterator<Shape> shapeIterator = shapes.iterator();
{ nextShape(); }
private void nextShape() {
if (shapeIterator.hasNext()) {
currentPathIterator = shapeIterator.next().getPathIterator(at, flatness);
} else {
currentPathIterator = null;
}
}
public int getWindingRule() {
return WIND_NON_ZERO;
}
public boolean isDone() {
for (;;) {
if (currentPathIterator == null) return true;
if (!currentPathIterator.isDone()) return false;
nextShape();
}
}
public void next() {
currentPathIterator.next();
}
public int currentSegment(float[] coords) {
return currentPathIterator.currentSegment(coords);
}
public int currentSegment(double[] coords) {
return currentPathIterator.currentSegment(coords);
}
};
}

Categories