How to make my HashMap work as expected? - java

Suppose one has a simple class:
public class Point implements Comparable<Point> {
public int compareTo(Point p) {
if ((p.x == this.x) && (p.y == this.y)) {
return 0;
} else if (((p.x == this.x) && (p.y > this.y)) || p.x > this.x) {
return 1;
} else {
return -1;
}
}
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
And a HashMap from Point to something, let's say Cell:
cellMap = new HashMap<Point, Cell>();
Then one fills in cellMap as follows:
for (int x = -width; x <= width; x++) {
for (int y = -height; y <= height; y++) {
final Point pt = new Point(x,y);
cellMap.put(pt, new Cell());
}
}
}
And then one does something like (trivial) this:
for (Point pt : cellMap.keySet()) {
System.out.println(cellMap.containsKey(pt));
Point p = new Point(pt.getX(), pt.getY());
System.out.println(cellMap.containsKey(p));
}
And gets true and false in, respectively, first and second cases. What is going on? Is this map comparing hashes instead of values? How to make the example return true in both cases?

Since you are using HashMap, not TreeMap, you need to override hashCode and equals, not compareTo, in your Point class:
#Override
public int hashCode() {
return 31*x + y;
}
#Override
public bool equals(Object other) {
if (other == null) return false;
if (other == this) return true;
if (!(other instanceof Point)) return false;
Point p = (Point)other;
return x == p.x && y == p.y;
}

Related

How to stop the normal force from being too small on a 2D rigidbody? (Java 2D)

I am trying to create a 2D game engine in Java with LWJGL 3. For now the objects are only rectangles with box colliders. For the collision detection I change the edge of the rectangles in to lines with the y = ax + b structure. One of the rectangles has a rigidbody component, that gives it the ability to move and interact with environment. The idea for now is to give the rigidbody a force at the start, gravity turned off, no friction, and a perfect bounce (bounciness=1). It all works very well, till it hits a rectangle with no vertical and horizontal edges. I found out that if the non-rigidbody objects are rotated by an angle other than 90 or 180 degrees the normal force is wrong (too small), how wrong depends on the rotation. The rotation of the rigidbody doesn't contribute to the problem.
Vector2 rotSurface = new Vector2(-collision.surface.ToVector().y, collision.surface.ToVector().x).getNormalized();
System.out.println("Angle: "+Physics.Angle(rotSurface, rb.force));
Vector2 normalForce = rotSurface.multiplyBy(rotSurface.multiplyBy(rb.force).getMagnitude());
rb.force = rb.force.add(normalForce).multiplyBy(1f - rb.friction).add(normalForce.multiplyBy(rb.bounciness));
System.out.println("Angle: "+Physics.Angle(rotSurface, rb.force));
System.out.println("===");
Am I doing something wrong here with calculating the new rigidbody force or the normal force itself? If you need more information to help me solve this problem please ask.
Classes that I use in the code above:
public class Collision {
Collider collider;
ArrayList<Vector2> contactPoints = new ArrayList<Vector2>();
Vector2 center = Vector2.zero;
Line surface;
public Collision(Collider collider, ArrayList<Vector2> contactPoints, Line surface) {
this.collider = collider;
this.contactPoints = contactPoints;
for(int i = 0; i < contactPoints.size(); i++) {
center = contactPoints.get(i).add(center).divideBy(2);
}
this.surface = surface;
}
}
class Line {
Vector2 begin, eind;
public float rc = 0;
public float b = 0;
public float x, y;
public boolean vertical = false;
public boolean horizontal = false;
public Line(Vector2 begin, Vector2 eind) {
this.begin = begin;
this.eind = eind;
if(begin.y == eind.y) {
this.y = begin.y;
this.horizontal = true;
}
else if(begin.x == eind.x){
this.x = begin.x;
this.vertical = true;
} else {
this.rc = (eind.y - begin.y) / (eind.x - begin.x);
this.b = GetB(rc, begin);
}
}
public float GetB(float rc, Vector2 punt) {
return punt.y - (rc * punt.x);
}
public Vector2 GetIntersection(Line l2) {
float x_ = rc - l2.rc;
if(vertical) {
x_ = x;
if(l2.horizontal) {
return new Vector2(x, l2.y);
}
else if(!l2.vertical){
//System.out.println("gert");
return new Vector2(x, l2.rc * x + l2.b);
}
} else if(horizontal) {
if(l2.vertical) {
return new Vector2(l2.x, y);
} else if(!l2.horizontal) {
return new Vector2((y-l2.b) / l2.rc, y);
}
} else {
if(l2.vertical) {
return new Vector2(l2.x, rc * l2.x + b);
} else if(l2.horizontal) {
return new Vector2((l2.y - b) / rc, l2.y);
}
}
if(x_ == 0) {
return null;
}
float getal = l2.b - b;
x_ = getal / x_;
float y_ = rc * x_ + b;
return new Vector2(x_, y_);
}
public Vector2 ToVector() {
return eind.substract(begin);
}
public float GetDisTo(Vector2 point) {
Vector2 point1 = begin.add(eind).divideBy(2);
return (float) Math.sqrt(Math.pow(point1.x - point.x, 2) + Math.pow(point1.y - point.y, 2));
}
public boolean Overlaps(Line line) {
if(horizontal && y == line.y) {
if(((line.begin.x > begin.x && line.begin.x < eind.x) || (line.eind.x > begin.x && line.eind.x < eind.x)) ||
((begin.x > line.begin.x && begin.x < line.eind.x) || (line.eind.x > line.begin.x && eind.x < line.eind.x)))
return true;
} else if(vertical && x == line.x) {
//return true;
}
return false;
}
}
class Vector2 {
float x, y;
public static Vector2 zero = new Vector2(0, 0);
public Vector2(float x, float y) {
this.x = x;
this.y = y;
}
public Vector2 multiplyBy(Vector2 vector) {
return new Vector2(x * vector.x, y * vector.y);
}
public Vector2 multiplyBy(float getal) {
return new Vector2(x * getal, y * getal);
}
public Vector2 divideBy(Vector2 vector) {
return new Vector2(x / vector.x, y / vector.y);
}
public Vector2 divideBy(float getal) {
return new Vector2(x / getal, y / getal);
}
public Vector2 add(Vector2 vector) {
return new Vector2(x + vector.x, y + vector.y);
}
public Vector2 substract(Vector2 vector) {
return new Vector2(x - vector.x, y - vector.y);
}
public float getMagnitude() {
return (float)Math.sqrt(x*x + y*y);
}
public Vector2 getNormalized() {
return divideBy(getMagnitude());
}
}
Fixed it by using a sinus.
I replaced
Vector2 normalForce = rotSurface.multiplyBy(rotSurface.multiplyBy(rb.force).getMagnitude());
with
Vector2 normalForce = rotSurface.multiplyBy((float)Math.sin(Math.toRadians((double) (90f - Physics.Angle(rotSurface, force)))) * force.getMagnitude());

Printing and comparing array data in java

I recently started learning Java and I'm having some trouble understanding how to make arrays to work the way I want them to.
Here I have an assignment of creating a polygon class with different methods inside.
Basically the class represents a convex polygon in a plane.
The array receives user input that consists of x and y coordinates and places them inside. (max number of vertices is 10).
There are some functions that I have no idea how to do and I would really appreciate some help with.
Point Class - which is used to get coordinates
public class Point {
private double _x;
private double _y;
public Point() {
this._x = 0.0D;
this._y = 0.0D;
}
public Point(double x, double y) {
this._x = x;
this._y = y;
}
public Point(Point other) {
this._x = other._x;
this._y = other._y;
}
public double getX() {
return this._x;
}
public double getY() {
return this._y;
}
public void setX(double x) {
if (x >= 0.0D)
this._x = x;
}
public void setY(double y) {
if (y >= 0.0D)
this._y = y;
}
public boolean isAbove(Point other) {
return (this._y > other._y);
}
public boolean isUnder(Point other) {
return other.isAbove(this);
}
public boolean isLeft(Point other) {
return (this._x < other._x);
}
public boolean isRight(Point other) {
return other.isLeft(this);
}
public double distance(Point other) {
double distance = Math.sqrt(Math.pow(this._x - other._x, 2.0D) + Math.pow(this._y - other._y, 2.0D));
return distance;
}
public void move(double dx, double dy) {
double x = this._x + dx;
double y = this._y + dy;
if (x >= 0.0D && y >= 0.0D) {
this._x = x;
this._y = y;
}
}
public boolean equals(Point other) {
return (this._x == other._x && this._y == other._y);
}
public String toString() {
return "(" + this._x + "," + this._y + ")";
}
}
Polygon Class - main class im working on
/**
* Write a description of class Polygon here.
*
* #author [REDACTED]
* #version (Ver 1.0)
*/
public class Polygon {
private Point[] _vertices;
private int _noOfVertices;
public Polygon() {
_vertices = (Point[]) new Point[10];
_noOfVertices = 0;
}
public Polygon(Point[] arr) {
_vertices = (Point[]) new Point[10];
_noOfVertices = 0;
if (arr.length > 10) {
return;
}
// for (Point P : arr)
for (int i = 0; i < arr.length; i++) {
if (arr[i] != null) {
_vertices[i] = arr[i];
_noOfVertices++;
}
}
}
public boolean addVertex(double x, double y) {
if (_noOfVertices >= 10)
return false;
Point p = new Point(x, y);
_vertices[_noOfVertices] = p;
_noOfVertices++;
return true;
}
public Point highestVertex() {
for (int i = 0; i < _noOfVertices; i++) {
}
}
public String toString() {
}
public double calcPerimeter() {
for (int i = 0; i < arr.length; i++) {
}
}
public double caclArea() {
Point ppp = _vertices[zzz]
}
public boolean isBigger(Polygon other) {
}
public int findVertex(Point p) {
for (int i = 0; i < _noOfVertices; i++) {
if (p.equals(_vertices[i])) {
return i;
}
}
return -1;
}
public Point getNextVertex(Point p) {
for (int i = 0; i < _noOfVertices; i++) {
if (p.equals(_vertices[i])) {
if (i == _noOfVertices - 1) {
return new Point(_vertices[0]);
}
return new Point(_vertices[i + 1]);
}
}
return null;
}
public Polygon getBoundingBox() {
}
}
I have no idea how to do these functions:
Line 44: public Point highestVertex() {} - returns a copy of the highest point in the polygon. If there is more than one vertice at the same Y - the method will return the first one it encountered (with the said Y) If there are no vertices aka the array is empty it will return null.
Line 52: public String toString() {} - method that returns a string of points representing the polygon. The string should be in the following format:
The polygon has 5 vertices:
((2.0,1.0),(5.0,0.0),(7.0,5.0),(4.0,6.0),(1.0,4,0))
If there are no vertices the method will return a string in the following format:
The polygon has 0 vertices.
English is not my first language so I apologize for any grammar mistakes in advance.
First, it's not really the best to ask homework questions here, this is a concept that you should learn.
In highestVertex(), they outline the 3 cases for you:
1st case: If point-y is equal to another point-y, return the first vertex that has point-y.
2nd case: if arr has no elements return null.
3rd case: in loop, check each element's y value in the array and compare it to the biggest y so far.
Use this line before your loop:
int max = Integer.MIN_VALUE;
Inside loop:
if (arr[i] > max) max = arr[i]
For toString(), again loop throughout the array, and add each point to a tracker string that you will return.
String str = "";
loop
str += arr[i].toString() + ",";
This works except you need to loop until arr's second to last element, as you will have an extraneous comma after the last point.

How can I write a Comparator comparing multiple arguments? [duplicate]

This question already has answers here:
How to compare objects by multiple fields
(23 answers)
Closed 4 years ago.
Im trying to write a Comparator which compares two objects of the class Coordinate. The Coordinate class is Pretty simple:
public class Coordinate {
private int x, y;
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;
}
}
Now I want the Comparator to compare the x and the y value for two instances of the class Coordinate. Here is an example:
I have a Coordinate c1 which has x = 42 and y = 23. My second Coordinate c2 has x = 23 and y = 54. Now i put them both in an ArrayList an want to sort the List. I wanted to be sorted like the following:
The Coordinate with the lowest y value goes Always first, when you have two Coordinates having the same y value the Coordinate goes first which has a lower x value.
Example:
c1 (y = 4, x = 5 ) < c2 (y = 4, x = 6) < c3 (y = 5, x = 2)
So how can I write a Comparator for this Purpose?
Thank you very much!
Comparator<Coordinate> c = Comparator.comparingInt(Coordinate::getY)
.thenComparingInt(Coordinate::getX);
You can build compound comparators by means of thenComparing and thenComparingX.
var list = List.of(
new Coordinate(6, 4),
new Coordinate(2, 5),
new Coordinate(5, 4)
);
list.sort(c);
System.out.println(list);
The snippet prints
[{y=4, x=5}, {y=4, x=6}, {y=5, x=2}]
Using Comparator
import java.util.ArrayList;
import java.util.Comparator;
class Coordinate {
private int x, y;
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;
}
public String toString() {
return "x = " + x + " y = " + y;
}
}
public class Temp {
public static void main(String[] args) {
ArrayList<Coordinate> A = new ArrayList<>();
A.add(new Coordinate(1, 2));
A.add(new Coordinate(2, 1));
A.add(new Coordinate(3, 2));
A.sort(new Comparator<Coordinate>() {
#Override
public int compare(Coordinate o1, Coordinate o2) {
if (o1.getY() < o2.getY()) {
return -1;
} else if (o1.getY() > o2.getY()) {
return 1;
} else {
if (o1.getX() < o2.getX()) {
return -1;
} else if (o1.getX() > o2.getX()) {
return 1;
}
return 0;
}
}
});
System.out.println(A.toString());
}
}
Using Comparable Interface
import java.util.ArrayList;
class Coordinate implements Comparable<Coordinate> { # Notice implementing Comparable interface
private int x, y;
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 compareTo(Coordinate o) { # implementing the abstract method of Comparable interface
if (y < o.y) {
return -1;
} else if (y > o.y) {
return 1;
} else {
if (x < o.x) {
return -1;
} else if (x > o.x) {
return 1;
}
return 0;
}
}
public String toString() {
return "x = " + x + " y = " + y;
}
}
public class Temp {
public static void main(String[] args) {
ArrayList<Coordinate> A = new ArrayList<>();
A.add(new Coordinate(1, 2));
A.add(new Coordinate(2, 1));
A.add(new Coordinate(3, 2));
A.sort(null);
System.out.println(A.toString());
}
}
Output
[x = 2 y = 1, x = 1 y = 2, x = 3 y = 2]

Java make custom object comparable?

I have the object below.
public class Coords {
public int x;
public int z;
public Coords(int x, int z) {
this.x = x;
this.z = z;
}
}
How can this implement Compareable?
Im not sure what the compareTo method should be doing.
#Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 0;
}
You could compare x and then compare z (alternatively, z and then x). Also, I suggest you override toString. Something like,
public class Coords implements Comparable<Coords> {
public int x;
public int z;
public Coords(int x, int z) {
this.x = x;
this.z = z;
}
#Override
public int compareTo(Coords o) {
if (this.x == o.x) {
if (this.z == o.z) {
return 0;
}
return this.z < o.z ? -1 : 1;
}
return this.x < o.x ? -1 : 1;
}
#Override
public String toString() {
return String.format("{%d, %d}", x, z);
}
}
Here are the details of compareTo:
Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
I'd suggest something like this:
#Override
public int compareTo(Coords other) {
return this.x == other.x ? (this.z == other.z ? 0 : this.z - other.z) : this.x - other.x
You can make z more significant if you switch them.

Overriding hashCode() not working

I'm trying to make class Point work correctly with a HashSet. Here is my Point class:
class Point {
int x;
int y;
Point(int x, int y) {
x = x;
y = y;
}
#Override
public int hashCode() {
int hash = 1;
hash = hash * 17 + x;
hash = hash * 31 + y;
return hash;
}
#Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
Point p = (Point) o;
return x == p.x && y == p.y;
}
}
When I test it out and do
HashSet<Point> h = new HashSet<Point>();
h.add(new Point(0, 0));
Point g = new Point(0, 1);
System.out.println(h.equals(g));
System.out.println(h.contains(g));
The output is this
false
true
Why is my hashCode not working?
In
Point(int x, int y) {
x = x;
y = y;
}
You are assigning x, the local parameter variable, to itself. Same for y. These are no-ops.
Use
Point(int x, int y) {
this.x = x;
this.y = y;
}
so that you assign the parameter value to the field.
As others have noted, you shouldn't do
Point p = (Point) o;
without knowing if o is a Point or not. It will throw a ClassCastException if it is not assignable to a Point. Instead use
if (o instanceof Point)
return false;
or
if (o.getClass() != Point.class)
return false;
before casting. Note that the two methods above are not equivalent. You can use the first in most cases, but use the second if Point is meant to have sub classes.

Categories