ArrayList of abstract subclasses (must have different hashcode) - java

I am creating a game for a school project, and I have a 2 classes called Pieces and Powers, with subclasses Piece_Yellow, Piece_Blue ... and Power_Explode, Power_ChangeColor etc...
I was doing it with enum and someone from this website (mikera to be more precise) help me changing that and creating a better interaction with the pieces and the powers.
But now I have to change the old code, and I have problems with that because I was doing like this :
int x = 10, y = 5;
for (int i=0; i<10; i++) {
if (pecas[x][y] == null)
pecas[x][y] = new Piece(arrayPecas.get(rand.nextInt(arrayPecas.size())));
}
Like this my array was partially filled with 10 new pieces Objects with different colors (but no powers, that was the problem), and every single one had a different hashcode (for finding , comparing and deleting the pieces later)...
But Since we can't initiliaze an abstract class, the only solution that I've found to this problem was to do this :
int x = 10, y = 5;
for (int i=0; i<10; i++) {
if (pecas[x][y] == null)
pecas[x][y] = arrayPecas.get(rand.nextInt(arrayPecas.size()));
}
Like this the object is still added, but now I have 1 problems :
1 - All the hashcode from the pieces with the same color are the same... I don't really know how to solve this. I've read that I could override the hashcode method but there is no information to make the difference between them (and I can't store the position because I had to change it every time the piece change position).

It doesn't seem that really the hashCodes that are your problem. It's that the objects are simply equal. Code that relies on two unequal objects having different hashCodes isn't strictly correct. return 1; is a perfectly legal implementation of Object#hashCode().
The simplest thing seems to be to put a clone() method on Piece that all the subclasses can implement in order to return copies in places where you want different, distinct, objects.
public abstract class Piece {
public abstract Piece clonePiece();
}
public class YellowPiece extends Piece {
#Override
public Piece clonePiece() {
return new YellowPiece(this.relevantThing1, this.relevantThing2 // etc etc)
}
}
int x = 10, y = 5;
for (int i=0; i<10; i++) {
if (pecas[x][y] == null)
pecas[x][y] = arrayPecas.get(rand.nextInt(arrayPecas.size())).clonePiece();
}

Related

How do I optimize 3D xyz nested for loops in Java and stream Vectors?

I write plugins for Minecraft and often hit a situation where I have to loop through every block in a 3-dimensional space to process the block in some way. For example:
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
for (int z = minZ; z <= maxZ; z++) {
// Do something
}
}
}
These kind of loops happen a lot and it struck me that perhaps there was a better way to do it that would make the code more concise but still be as fast to execute. All I really want to do is loop through every coordinate in a 3 dimensional type.
The Bukkit API has such a type - a Vector class that can hold x,y,z. The Vector class has methods such as getBlockX, getBlockY and getBlockZ that return integers. So, I was thinking of creating a utility method like this:
Stream<Vector> getXYZStream(minVector, maxVector)
This would return a stream of all the vectors (x,y,z) values between the min and max vectors given. So then I could do:
getXYZStream(minVector, maxVector).forEach(v -> doSomething);
How can I make a stream of vectors in this regard? If I can code this approach, then I'll measure the difference in performance and see if it makes sense.
Or is there a better way to do this?
Or should I accept these loops are necessary and the best approach?
I found an approach where one can make a stream using a custom iterator, so one could do something like this:
public Stream<Vector> get3dStream(Vector minVector, Vector maxVector) {
Iterator<Vector> it = new CustomIterator(minVector, maxVector);
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false);
}
class CustomIterator implements Iterator<Vector> {
private Vector minVector;
private Vector maxVector;
BoundingBox b = new BoundingBox();
// constructor
CustomIterator(Vector minVector, Vector maxVector) {
// initialize cursor
this.minVector = minVector;
this.maxVector = maxVector.add(new Vector(1,1,1));
}
// Checks if the next element exists
#Override
public boolean hasNext() {
return !minVector.equals(maxVector);
}
// moves the cursor/iterator to next element
#Override
public Vector next() {
Vector r = minVector;
increment();
return r;
}
private void increment() {
// Increment the vector - this takes a lot of code to do
}
}
However, as you can see, tracking the next() in the custom iterator will require quite a lot of code and comparing to the three for loops is much more complex and likely to be slower. I agree with the comment from kaya3, it could hide some of the looping, but it's not going to be faster, which is 100% a requirement.

Create a data structure with the features of an array in the constructor

I want to create a special list data structure that works like an array, in that it's like a list with values x[0], x[1], ... Any advice would be much appreciated.
I know all of my code isn't perfect I just want to figure out how to fix the one problem I've outlined below. This is some of the code I have:
public class SpecialList {
int[] specialList;
int lengthList;
public SpecialList(int x[]) {
this.lengthList = x.length;
this.specialList = new int[lengthList];
this.specialList = x;
for (int i=0; i<lengthList; i++) {
this.specialList[i] = x[i];
}
}
public SpecialList(SpecialList w) {
this.specialList = w.specialList;
}
public SpecialList doSomething(SpecialList y) {
int len = y.lengthList;
//The line below is an example to show the error I get
System.out.println(y[0]);
//Do some other stuff to the list y
return y;
}
//I test the code with this
public static void main(String[] args) {
SpecialList y = new SpecialList(new int[] {14, 17, 30});
SpecialList z = x.doSomething(y);
}
However I get the error 'array required, but SpecialList found' when I try to do stuff with y[i] like with System.out.println(y[0]); line of code.
'lengthList' works but getting the individual values of y[i] , the list doesn't. I cant work out whats wrong with my constructor for it to not work how I want it to.
You can't redefine what [n] means based on what object it's applied to; that's an array-specific notation. So y[0] where y is a SpecialList instance just won't work. If it could work, List (or at least ArrayList or other implementions where direct addressing is cheap) would probably have that feature.
Although you can do that in some other languages, you can't in Java. It's just not a feature Java offers. (Which is a good thing or a bad thing depending on your point of view...) Instead, you'll have to provide get and set methods or similar, just like List does.

How do you write a counter method to save space and time?

I am working with interface Multiset which is then used by two different classes: ArrayListMultiset and CounterMultiset
The ArrayListMultiset simply uses the .add method to put something in the list. So in a loop like,
Multiset<String> set = new Multiset<String>();
for(int i = 0; i < 10000; i++)
{
set.add("Hello");
}
this will cause the program to add Hello to a list 10,000 times.
Next we have CounterMultiset. It stores a Pair object (another class that takes in (T, Integer), where T is the String, "Hello" and Integer is the number of times it is trying to be added. I have written it like so:
public void add(Multiset<T> item)
{
if(!contains(item))
{
Pair newpair = new Pair(item, 0);
pairs.add(newpair);
}
for(int i = 0; i < pairs.size(); i++)
{
if(pairs.get(i).getFirst() == item)
{
pairs.get(i).changeSecond();
}
}
}
changeSecond() increments the second number in the Object by 1 to show that the word Hello has tried to be added again.
My question is, is this an appropriate way to save space and time for a program? When would it be faster to use a Counter and when would it be faster to simply add "Hello" 10,000 times?
Hello is an intern string in your code.
You will not have a copy of Hello for each element of ArrayListMultiset. You will have a reference to String Pool object.
What is faster for get/put (I assume) - depends on underlying data structures.

Best way to reference multiple (unknown number of) sprites in libgdx (Android)?

Im working on a game in which multiple "notes" (sprites) are generated.
The notes are created at random. Each of them has a random velocity and are created in a different thread. The Notes class is a child of the sprite class. It has 2 properties and 1 method:
vel - a Velocity2 object holding the x and y component on the
velocity of the note object
pos - a Vector2 object holding the x and y coordinates of the note object.
changepos() - a method that changes the position based on the velocity of the object
(I cannot post the code of that class due to privacy reasons)
I currently have a static class "NoteStack", which can hold up to 64 references to Notes objects.
public class NoteStack {
public Notes[] note_array;
public int stack_len;
public NoteStack(){
note_array = new Notes[64];
stack_len = 0;
}
public void push(Notes n){
if(stack_len<64){
note_array[stack_len] = n;
stack_len++;
Gdx.app.log("push", "pushed");
}
}
public void delete_note(int pos){
if(note_array[pos] != null){
note_array[pos] = null;
for(int i = pos; i<stack_len; i++){
note_array[pos] = note_array[pos+1];
}
note_array[stack_len] = null;
stack_len = stack_len - 1;
}
}
}
Here's the code for my "update" function
public void update(float d, SpriteBatch b){
core.draw(b);
for(int i = 0; i< noteStack.stack_len; i++){
Gdx.app.log("update", "Update function running" + i);
noteStack.note_array[i].changePos(d);
noteStack.note_array[i].draw(b);
// scr_w - screen width , scr_h - screen height
if(noteStack.note_array[i].pos.x > scr_w || noteStack.note_array[i].pos.x < 0 || noteStack.note_array[i].pos.y > scr_h || noteStack.note_array[i].pos.y < 0){
noteStack.delete_note(i);
}
}
}
The issue (as you may see) is that whenever a note object from NoteStack gets removed (i.e. the delete_note method is called), other Notes objects in the array are affected.
Hence my question: What is the best way to reference multiple sprite (note) objects in LibGDX?
Generally speaking in programming, you should never implement own "classic" datastructures, only if it's really necessary and you can't use or extend a collection type, because the standard implementations are well programmed and tested, so those are safer to use.
In your case, I would use libGDX Array. That class has add, get, size methods, and if you really want to, you can extend the Array class to have an update function.
But in short, if you replace public Notes[] note_array; with public Array<Notes> note_array = new Array<>(true, 64); and use get and remove and size for iterating and managing the collection that should work.

How to combine two methods with identical calculates but different fields

How do I combine two methods that have identical calculations but operate (read and write) different fields of the class.
A VERY simplified aircode example:
class TileCalculator
{
int length;
int width;
int tileLength;
int tileWidth
int cols;
int rows;
void calculateColumns()
{
this.cols = this.width/this.tileWidth;
}
void calculateRows()
{
this.rows = this.length/this.tileLength;
}
}
As these two methods do exactly the same calculation(s) but just using different fields for their input and output it would seem sensible to combine them but I don't know how.
UPDATE: I think I may have oversimplified it to the point where answerers are trying to solve the specific case. A more realistic example is:
void calculateCols()
{
int tileCols = width/tileWidth;
int remainder = width%tileWidth;
if (remainder==0) {
// there is an exact number of whole tiles
fullTileCols = tileCols;
firstT = tileWidth;
usedTileCols = tileCols;
} else {
// there is a remainder
fullTileCols = tileCols - 1;
firstT = (remainder+tileWidth)/2;
usedTileCols = tileCols + 1;
}
}
void calculateRows()
{
int tileRows = length/tileLength;
int remainder = length%tileLength;
if (remainder==0) {
// there is an exact number of whole tiles
fullTileRows = tileRows;
firstCut = tileLength;
usedTileRows = tileRows;
} else {
// there is a remainder
fullTileRows = tileRows - 1;
firstCut = (remainder+tileLength)/2;
usedTileRows = tileRows + 1;
}
}
I'm not saying a redesign isn't the answer but as you can see there are multiple fields involved so a simple return value probably isn't going to cut it. This is why I am using fields rather than a simple function and the maintainability of the current setup is of concern to me.
No, I wouldn't combine them, I would change them.
I'd get rid of rows and cols fields
I'd get rid of the above methods as it makes your object's state dependent on these methods always being called before an object is used -- a risky proposition.
Instead I'd create two calculated getter methods. This way the calculations are guaranteed to be done when needed.
e.g.,
public int getColumns() {
return width / tileWidth;
}
public int getRows() {
return length / tileLength;
}
Edit
I suppose you could create a RowCol class that has full, first, and used fields, and that has but one equation for doing the calculation above, and that you create two instances, one for row and one for column in the containing class, but if the rationale for this is to just combine these small methods, I question the need for this, or the benefit. Yes, you should follow the DNRY rule, but I worry more about this when I have three or more repeats of the same code.
You could make a convenience method. In the case you have shown this is actually more typing, longer program, extra complexity etc for no benefit. But if the calculation was more complicated it could be worth it
int calculate(int a, int b)
{
return a/b;
}
void calculateColumns()
{
this.cols = this.calculate(this.width, this.tileWidth);
}
after the update
you actually want 3 return values(full, first, used) so alter the "calculate" to either return a special class with 3 int or an array of int
Then feed in a and b as before but with the adjusted logic and return the 3 values and set them in the calling function
There is no easy way to do this in Java prior to Java 8. You can do it, but it involves using private internal interfaces and anonymous classes. It isn't worth it unless you're really talking about a lot of common lines of code.
With Java 8 though, you'll be able to use closures which will greatly simplify this kind of cases.

Categories