" == " change results of getClass()? - java

I implemented equals() method like this
public boolean equals(Object y) // does this board equal y?
{
if (y == null) return false;
if (this == y) return true;
if (this.getClass() != y.getClass()) return false;
Board that = (Board) y;
return Arrays.equals(this.newblocks, that.newblocks);
}
and I test this method using
Board initial = new Board(newblocks);
Board initial2 = new Board(newblocks);
StdOut.println(initial.equals(initial2));
However, the result is false. I found after the line y == null, the class of y change from Board to string. Why does this happen?
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Edit:
Here is a MVCE.
import edu.princeton.cs.algs4.In;
import edu.princeton.cs.algs4.StdOut;
import java.util.Arrays;
public final class Board {
private int[][] newblocks;
public Board(int[][] blocks) // construct a board from an n-by-n array of newblocks
{
newblocks = new int[blocks.length][blocks.length];
// this.blocks = new int[blocks.length][blocks.length];
for (int i = 0; i < blocks.length; i++)
for (int j = 0; j < blocks.length; j++)
newblocks[i][j] = blocks[i][j];
}
public int dimension() // board dimension n
{ return newblocks.length; }
public boolean equals(Object y) // does this board equal y?
{
if (y == null) return false;
if (this == y) return true;
if (this.getClass() != y.getClass()) return false;
Board that = (Board) y;
return Arrays.equals(this.newblocks, that.newblocks);
}
public String toString() // string representation of this board (in the output format specified below)
{
StringBuilder s = new StringBuilder();
s.append(dimension());
s.append("\n");
for (int i = 0; i < dimension(); i++) {
for (int j = 0; j < dimension(); j++) {
s.append(newblocks[i][j]);
s.append("\t");
}
s.append("\n");
}
return s.toString();
}
public static void main(String[] args) // unit tests (not graded)
{
In in = new In(args[0]);
int n = in.readInt();
int[][] newblocks = new int[n][n];
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
newblocks[i][j] = in.readInt();
Board initial = new Board(newblocks);
Board initial2 = new Board(newblocks);
StdOut.println(initial);
StdOut.println(initial.equals(initial2));
}
}
The test document is a txt file like
3
1 2 3
0 4 8
7 6 5
The first "3" shows it is a 3x3 matrix, and the next nine numbers belong to the matrix.

I found after the line y == null, the class of y change from Board to string.
I can state categorically that you are wrong about that. What you are describing / proposing is impossible in Java. An object's fundamental type (as returned by this.getClass()) will not change. Not ever1.
What must be going on is that y is not an instance of Board in the first place.
Alternatively, there is a mismatch between the code that you have shown us and reality2.
If you want us to understand / explain what is actually going on, you will need to write an MVCE and share it with us. (And I suspect that the process of doing that will reveal ... to you ... what the real problem is.)
1 - Since y is a local variable, not even a memory visibility anomaly could do this. The only way that this could happen is if you wrote some native code that trampled on object headers from a different thread. If you do that kind of stuff, your JVM is liable to crash horribly.
2 - For example, you could be calling a different overload of equals, OR you could have transcribed or simplified the code incorrectly, OR you could be running a different version of the code.
UPDATE
When I debug your program, it is clear that the code is not returning false at this line:
if (this.getClass() != y.getClass()) return false;
It is actually the call to Arrays.equals that is returning false.
And the reason is that Arrays.equals(Object[], Object[]) does not compare a pair of int[][] objects in the way that you think. (Read the javadoc carefully, thinking about what the elements of the Object[] instances actually are ... and what their equals methods will do.)
Hint: Arrays.equals won't work for what you are trying to do.

The == operator never changes anything, let alone a class.
Your bug hides elsewhere (most likely in code you have not posted).

Arrays.equals() compares each element using equals(). Since, in your case, those elements are themselves arrays, the equality check is failing. The solution is to use Arrays.deepEquals(), which will compare array elements at any depth.

Related

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.

Java - How do I check for a straight in a poker hand without sorting?

This is not a duplicate. I understand how easy this is if you can sort, but I am not allowed to use the sort method for arrays and I am not allowed to write my own. I can't find any help with this anywhere, including StackOverflow.
In this scenario, I have a method that is supposed to check whether or not a five card hand is a straight. I have a card object that holds a value (integer) and a suit (integer). I also have some rules about implementing this method.
There are no face cards besides the ace
The ace can count as either a 1 or a 10 but not both
A straight cannot wrap around
You cannot use the sorting method for arrays or write your own sorting method
That last rule is what is killing me. I have an array of cards. If I could just sort it, this would be so easy but I can't even write my own method to sort the array. For my other methods it simple to iterate through the hand and store the information about the hand in two separate arrays like this:
private static int[] cardValues = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
private static int[] cardSuits = {0, 0, 0, 0, 0};
private static void evaluationHelper(Card[] cards) {
for (int i = 0; i < cardValues.length; i++) {
cardValues[i] = 0;
}
for (int i = 0; i <cardSuits.length; i++) {
cardSuits[i] = 0;
}
for (int i = 0; i < 5; i++) {
cardValues[cards[i].getValue() - 1]++;
cardSuits[cards[i].getSuit()]++;
if (cards[i].getValue() == 1) {
cardValues[9]++;
}
}
}
So in my first attempt to solve this issue I tried something like this:
public static boolean hasStraight(Card [] cards) {
int sequenCounter = 0;
evaluationHelper(cards);
for (int i = 0; i < cardValues.length; i++) {
if (sequenCounter != 5) {
if (cardValues[i] != 0) {
sequenCounter++;
} else {
sequenCounter = 0;
}
} else {
return true;
}
}
return false;
}
That didn't work. So then I tried this:
public static boolean hasStraight(Card [] cards) {
int min = 100, max = 0;
boolean seenSix = false, seenAce = false;
evaluationHelper(cards);
for (int i = 0; i < cards.length; i++) {
if (cards[i].getValue() > max) {
max = cards[i].getValue();
}
if (cards[i].getValue() < min) {
min = cards[i].getValue();
}
if (cards[i].getValue() == 6) {
seenSix = true;
}
if (cards[i].getValue() == 1) {
seenAce = true;
}
}
if (seenSix && seenAce) {
max = 10;
}
if (max - min == 4) {
return true;
}
return false;
}
That doesn't work either. I'm getting frustrated as both of these attempts went through many different changes over the course of overs and nothing has worked. I can't even figure out why they aren't working. The only information I have is that this method isn't spitting out the correct value. I don't know what values are being passed to the method. I don't know what the method is spitting out during the test. It could be spitting out false when it's supposed to be spitting true or vice versa. Please help!
In your evaluationHelper you forgot to address when an ace is 10 adding:
if (cards[i].getValue() == 10) {
cardValues[0]++;
}
will make at least your first solution work (I haven't checked the second).
Note that what this method does is still a form of Radix sort so I'm not sure if it satisfies your requirement.
Rules:
max_value - min_value must be 4
Other 3 cards' value must be between min and max
All 5 cards must have the same suit
Assumes there are no duplicates of a suit-number.
If none of these rules are violate then you have a straight.
The only tricky thing if the Ace. Ace can be a 10? What about the number 10 card? Is Ace 1 or 10, or 1 or 11?
I assume you understand the purpose of the evaluationHelper() method; if not, I suggest you view the contents of the two arrays after it is run.
You need to find the first non-zero value in the cardValues[] array. If that entry and the subsequent 4 are all one, then return true; else return false.
In the future if you need to find a straight flush, you would first confirm one of the cardSuit[] entries equals 5 (i.e. all 5 must be the same suit); if not, then return false.

How do you check if 4 different numbers in an array are equal to each other?

This method is supposed to return true if four different numbers in the array are all equal. But whenever I try to run it with 4 equal numbers, I get an error that says:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
at Assignment4.containsFourOfaKind(Assignment4.java:93)
at Assignment4.main(Assignment4.java:16)
public static boolean containsFourOfaKind( int hand[] ){
for (int i = 0; i < 5; i++) {
if (hand[i ] == hand[i + 1] &&
hand[i + 1] == hand[i + 2] &&
hand[i + 2] == hand[i + 3]
) {
return true;
}
}
return false;
}
How can I fix this?
Most answers only address the ArrayIndexOutOfBoundsException, but they don't address that your original code wasn't detecting for of a kind. It was trying to detect four-in-a-row. Imagine a hand {3, 0, 3, 3, 3}: even if your code didn't cause the ArrayIndexOutOfBoundsException, it still would say that this wasn't four-of-a-kind, although it clearly is.
You need code that actually counts how many of-a-kind there are and then check if it is four or more out of the total hand. (In a typical playing card deck you couldn't have more than 4 of a kind so you can check with == to 4 as well)
The code below is even agnostic to the number of cards in a hand, although from your code above it looks like your hand size is 5 (which is very typical in poker)
public static boolean containsFourOfaKind(int hand[]) {
for (int i = 0; i < hand.length; i++) {
int countOfKind = 0;
for (int j = 0; j < hand.length; j++) {
if (hand[i] == hand[j]) {
countOfKind++;
}
}
if (countOfKind >= 4) {
return true;
}
}
return false;
}
(Note that this is a native approach. You can optimize this further; for example if you look at this closely you'll see that i doesn't have to go any further than 0 and 1.)
When you run your loop from (i=0; i<5;...) you are checking five values... In your if statement you are looking at hand[i] == hand[i+1] && hand[i+1] == hand[i+2] && hand[i+2] == hand[i+3]. This means that during the iteration when i=4 you are trying to access hand[4] through to hand[7].
I suspect your array, hand, doesn't have that many elements.
public static boolean containsFourOfaKind(int hand[]){
for(int x=0; x < hand.length; x++){
for(int y=0; y < hand.length; y++){
if(y!=x){
if(hand[x]!=hand[y]){
return false;
}
}
}
}
return true;
}
You were going outside the index using the +1 within the loop. The above code checks to see if all of the elements in the array are the same.
While others have addressed the ArrayIndexOutOfBoundsException quite clearly, I'd like to propose another method that uses no indexes:
private boolean isArrayEqual(int[] array) {
Arrays.sort(array); //Sort array to place four of a kind in sequence
int[] setOfFour = Arrays.copyOfRange(array, 0, 4); //Copy first four values
int[] compareArray = new int[4];
Arrays.fill(compareArray, setOfFour[0]); //Make an array containing only first value
if (Arrays.equals(compareArray, setOfFour)) { //Test if first four are equal
return true;
} else { //Test is last four are equal
setOfFour = Arrays.copyOfRange(array, 1, 5); //Copy of last four values
Arrays.fill(compareArray, setOfFour[0]);
return Arrays.equals(compareArray, setOfFour);
}
}
You create a second array which is filled with one of the values from the array in question (any value will do - I picked the first one). Then just see if the arrays are equal. Done.
//brain compiled code
public static boolean containsFourOfaKind(int hand[])
{
for(int i=0; i < hand.length - 1; i++)
{
if(hand[i] != hand[i + 1])
return false;
}
return true;
}
Going with your approach you could have had a simple check that was non-iterative that would just check to see if all the four cards were equal, however if you're going for an iterative approach then this is probably your best bet. Whenever you receive an arrayindexoutofbounds exception you always know that it has something to do with your arrays, and in your case there is only one spot that deals with arrays so it should be easy to visualize once you know what t he exception means.
A noniterative approach is as follows...
//brain compiled code
public static boolean containsFourOfaKind(int hand[])
{
if((hand[0] == hand[1]) && (hand[1] == hand[2]) && (hand[2] == hand[3]))
return true;
return false;
}
This can be used however it is not recommended.
An approach that doesn't specifically target a hand, could be to target a larger group; where the array could be much larger than 4. In this case, you could have a loop add onto a map that counts how many times a certain "object" (literal meaning) is in that list:
public static boolean fourOfaKind(Integer[] hand) {
HashMap<Integer,Integer> counts = new HashMap<Integer,Integer>();
for(Integer i : hand) {
if(counts.containsKey(i))
{
int count = counts.get(i);
counts.put(i, ++count);
if(count >= 4)
return true;
}
else
counts.put(i, 1);
}
return false;
}
simple code can be as follows, this will work for N number of element.
public static boolean containsFourOfaKind(int hand[]){
for(int i=1; i < hand.length; i++){
if(hand[i-1] != hand[i]){
return false;
}
}
return true;
}
In Java8 you can do it very easy:
private static boolean isEqualElements(int[] arr) {
return Arrays.stream(arr).allMatch(value -> arr[0] == value);;
}

I don't know what's wrong

if(handler.obj.isEmpty())
handler.addObject(new Box(x, y, ID.Box));
else{
for(int i = 0; i < handler.obj.size(); i++){
Object tempObj = handler.obj.get(i);
if (tempObj.getX() == x && tempObj.getY() == y && tempObj.getId() == ID.Box)
handler.removeObect(tempObj);
else
handler.addObject(new Box(x, y, ID.Box));
}
}
the handler.addObject() in the else statement seems unreachable or doesn't work
From comment:
public class Handler {
LinkedList<Object> obj = new LinkedList<Object>();
public void tick(){
for (int i = 0; i < obj.size();i++){
Object tempObj = obj.get(i);
tempObj.tick();
}
}
public void render(Graphics g){
for (int i = 0; i < obj.size(); i++){
Object tempObj = obj.get(i);
tempObj.render(g);
}
}
public void addObject(Object obj){
this.obj.add(obj);
}
public void removeObect(Object obj){
this.obj.remove(obj);
}
}
Let's see. Assume first time it runs, x,y is 1,1. So you add Box(1,1).
Next time is run, let's assume x,y is 2,3. So, enter for loop:
i = 0: Not same x,y, so enter else, and add Box(2,3).
i = 1: Same as x,y (yeah, we just added it), so enter if and remove Box(2,3).
Result: Box added and removed again.
Oh yeah, a debugger would have told you the same thing.
Your problem is that your for loop ends in the wrong place. This causes two undesirable symptoms.
Firstly, you're adding your new Box once for every element in your list that doesn't match the box, instead of adding it just once.
Secondly, you're removing some of those new Box objects that you just added, once you get to the end of the loop.
I would recommend rewriting the method like this. Notice how the for loop ends before the new object is added - this makes sure that the object is added at most once. Also notice the return statement after an object is removed - this can be done because once the object is removed, the method has no more work to do.
public void addOrRemoveBox(int x, int y) {
for(int i = 0; i < handler.obj.size(); i++){
Object tempObj = handler.obj.get(i);
if (tempObj.getX() == x && tempObj.getY() == y && tempObj.getId() == ID.Box) {
handler.removeObect(tempObj);
return;
}
}
handler.addObject(new Box(x, y, ID.Box));
}
Lastly, you appear to have written your own class called Object (otherwise this code wouldn't compile). This is probably a bad idea, because it will cause you to get confused between your Object class, and the Object class that's built into Java. I suggest you rename that class.

Array of arbitrary dimension as method parameter

I have a simple converter method for an array from boolean to int:
public static int[] convert1dToInt (boolean[] x) {
int la = x.length;
int[] y = new int[la];
for (int a = 0; a < la; a++) {
if (x[a]) {
y[a] = 1;
} else {
y[a] = 0;
}
}
return y;
}
Now I have the same method for 2-dimensional arrays:
public static int[][] convert2dToInt (boolean[][] x) {
int la = x.length;
int lb = x[0].length;
int[][] y = new int[la][lb];
for (int a = 0; a < la; a++) {
for (int b = 0; b < lb; b++) {
if (x[a][b]) {
y[a][b] = 1;
} else {
y[a][b] = 0;
}
}
}
return y;
}
How can I generalize those methods for arrays of arbitrary dimension without writing all the methods by hand?
This is possible, but reflection and recursion are both inevitable:
import java.lang.reflect.Array;
public class ArrayTransfer {
private static int getArrayDimension(Object array) {
Class<?> clazz = array.getClass();
int dimension = 0;
while (clazz.isArray()) {
clazz = clazz.getComponentType();
dimension += 1;
}
if (clazz != boolean.class) {
throw new IllegalArgumentException("Base array type not boolean");
}
return dimension;
}
// Transfers a boolean array of the specified dimension into an int
// array of the same dimension.
private static Object transferToIntArray(Object booleanArray, int dimension) {
if (booleanArray == null) {
return null;
}
// Determine the component type of the new array.
Class<?> componentType;
if (dimension == 1) {
componentType = int.class;
} else {
// We have a multidimensional array; the dimension of the component
// type is one less than the overall dimension. Creating the class
// of an array of an unknown dimension is slightly tricky: we do
// this by creating a 0 x 0 x ... x 0 array (with dimension - 1
// zeros) and then getting the class of this array. Handily for us,
// int arrays are initialised to all zero, so we can create one and
// use it straight away.
int[] allZeroDimensions = new int[dimension - 1];
componentType = Array.newInstance(int.class, allZeroDimensions).getClass();
}
// Create the new array.
int length = Array.getLength(booleanArray);
Object newArray = Array.newInstance(componentType, length);
// Transfer the elements, recursively if necessary.
for (int i = 0; i < length; ++i) {
if (dimension == 1) {
Boolean value = (Boolean)Array.get(booleanArray, i);
Array.set(newArray, i, (value.booleanValue()) ? 1 : 0);
}
else {
Object oldChildArray = Array.get(booleanArray, i);
Object newChildArray = transferToIntArray(oldChildArray, dimension - 1);
Array.set(newArray, i, newChildArray);
}
}
return newArray;
}
// Transfers a boolean array of some dimension into an int
// array of the same dimension.
public static Object transferToIntArray(Object booleanArray) {
if (booleanArray == null) {
return null;
}
int dimension = getArrayDimension(booleanArray);
return transferToIntArray(booleanArray, dimension);
}
}
This should work with any number of dimensions up to 255 - I gave it a quick test with 5 and it seemed to work. It should also work with 'jagged' arrays, and with nulls.
To use it, call ArrayTransfer.transferToIntArray(...) with your boolean array, and it will return the corresponding int array. You will of course need to cast the return value of this method to the relevant int array type.
There's certainly scope for improving this. In particular, it would be nicer if some cache of the various array classes was kept, rather than having to instantiate empty arrays just to get their class.
You can use a conditional recursivity on the type of the passed parameter and you use convert1dToInt for the dimension one , then you collect the result in one object, in the given context you will be forced to pass just an object of type Object and return an Object then you cast it , here is a small code that present idea of the recursive function that just print the value of the elements in the array :
public static void convertDimN(Object o) {
if (o.getClass().isArray() && Array.get(o, 0).getClass().isArray()) {
// is o a two dimentional array
for (int i = 0; i < Array.getLength(o); i++) {
convertDimN(Array.get(o, i));
}
} else
for (int i = 0; i < Array.getLength(o); i++) {
System.out.println(Array.get(o, i));
}
}
This would be your first method:
public static int[] convert1dToInt (boolean[] x) {
//int la = x.length; is useless since you are accessing an object member and not a method
int[] y = new int[x.length];
for (int a = 0; a < x.length; a++) {
y[a] = x[a] ? 1 :0;
}
return y;
}
Simply reuse your code - I had not much time since it is my lunch break so I don#t know if all is correct but the way should fit:
public static int[][] convert2dToInt (boolean[][] x) {
int[][] y = new int[x.length][];
for (int a = 0; a < x.length; a++) {
y[a] = convert1dToInt (x[a]) ;
}
return y;
}
Ok, this solution was not the answer for the problem since I did not read exactly what has been asked. Sorry for that. As far as I know a generalized method is not possible as long as you are working with primitive datatypes. This is because you can't add an int[] as a member for an int[]. So you should then work with Object[], Boolean[] and Integer[] but I don't know how you want to work with that. I don't think it is sensible to write such a method because when you are able to convert such a data-structure how do you want the targets to be accessed. Since you do not know how many dimensions your array will have you can't write generic methods to access the members. I will try to write a solution for that since I want to know if I find an other possible solution. Am I right that the question is, if it is possible and not if it is reasonable?
I think we can find the best solution for that if you tell us the usecase you want to have this code for. As I said, when I have more time later on I'll try to find another solution.

Categories

Resources