Issues with Recursion - java

I am having issues with creating this recursive method. The method needs to add objects to a stack.
Notes:
This is a path finder project.
getNextBird() polls from a bird queue inside the bird object. If the queue is empty it will return null; if it is not empty it will return the next bird inside the queue.
I cannot use any loops at all. (It would have been easy if I could.)
The last element in the stack has to be Bird "end". But if the code works fine it should be done recursively.
My issue is that there is a edge-case where the checks hit a wall where getNextBird becomes null (in this instance the object bird), and I want to pop the newest object from the stack. I will get a StackOverflow error, or a EmptyCollection error.
private static boolean recurse(Stack<Bird> path, Bird current, Bird end)
{
Bird bird = null;
if (current != null) {
bird = current.getNextBird();
if (bird != null) {
path.push(current);
recurse(path, bird, end);
return true;
}
}
return false;
}
import java.util.Stack;
public class Solve2
{
public static void main(String [] args)
{
// create the maze to solve
Maze maze = new Maze();
// create a Stack of Bird objects named path here
Stack<Bird> path = new Stack<Bird>();
// call recursive method to solve the maze and print the path
recurse(path, maze.getStart(), maze.getEnd());
print(path);
}
private static boolean recurse(Stack<Bird> path, Bird current, Bird end)
{
Bird bird = null;
if (current != null) {
bird = current.getNextBird();
if (bird != null) {
path.push(current);
recurse(path, bird, end);
return true;
} else {
path.pop();
recurse(path, path.peek(), end);
return false;
}
}
return false;
}
private static void print(Stack<Bird> stack)
{
// write your code for recursively printing the stack here
System.out.println(stack.pop());
print(stack);
}
}
The Bird class:
public class Bird
{
public static final int N = 0;
public static final int NE = 1;
public static final int E = 2;
public static final int SE = 3;
public static final int S = 4;
public static final int SW = 5;
public static final int W = 6;
public static final int NW = 7;
private static final String [] directions = {"N ", "NE", "E ", "SE", "S ", "SW", "W ", "NW"};
private String name;
private int direction;
private Queue<Bird> queue;
public Bird(int row, int column, int direction)
{
this.name = "Row/Column [" + row + "][" + column + "]";
this.direction = direction;
}
public void setBirdQueue(Queue<Bird> queue)
{
this.queue = queue;
}
public String toString()
{
return "Location: " + name + ", Direction: " + directions[direction];
}
public int getDirection()
{
return this.direction;
}
public Bird getNextBird()
{
// write code to return the next Bird from the queue or null if no Birds left.
return queue.poll();
}
}
import java.util.LinkedList;
import java.util.Queue;
public class Maze
{
private Bird start;
private Bird end;
public Maze()
{
// construct the diagrammed maze
int MAX_ROW = 5;
int MAX_COL = 7;
Bird [][] maze = new Bird[MAX_ROW][MAX_COL];
// row 0
maze[0][0] = new Bird(0, 0, Bird.S);
maze[0][1] = new Bird(0, 1, Bird.SW);
maze[0][2] = new Bird(0, 2, Bird.S);
maze[0][3] = new Bird(0, 3, Bird.SE);
maze[0][4] = new Bird(0, 4, Bird.SW);
maze[0][5] = new Bird(0, 5, Bird.SW);
maze[0][6] = new Bird(0, 6, Bird.SW);
// row 1
maze[1][0] = new Bird(1, 0, Bird.S);
maze[1][1] = new Bird(1, 1, Bird.W);
maze[1][2] = new Bird(1, 2, Bird.SW);
maze[1][3] = new Bird(1, 3, Bird.S);
maze[1][4] = new Bird(1, 4, Bird.N);
maze[1][5] = new Bird(1, 5, Bird.S);
maze[1][6] = new Bird(1, 6, Bird.W);
// row 2
maze[2][0] = new Bird(2, 0, Bird.NE);
maze[2][1] = new Bird(2, 1, Bird.NW);
maze[2][2] = new Bird(2, 2, Bird.N);
maze[2][3] = new Bird(2, 3, Bird.W);
maze[2][4] = new Bird(2, 4, Bird.SE);
maze[2][5] = new Bird(2, 5, Bird.NE);
maze[2][6] = new Bird(2, 6, Bird.E);
// row 3
maze[3][0] = new Bird(3, 0, Bird.SE);
maze[3][1] = new Bird(3, 1, Bird.NE);
maze[3][2] = new Bird(3, 2, Bird.E);
maze[3][3] = new Bird(3, 3, Bird.NW);
maze[3][4] = new Bird(3, 4, Bird.NW);
maze[3][5] = new Bird(3, 5, Bird.E);
maze[3][6] = new Bird(3, 6, Bird.W);
// row 4
maze[4][0] = new Bird(4, 0, Bird.N);
maze[4][1] = new Bird(4, 1, Bird.NE);
maze[4][2] = new Bird(4, 2, Bird.N);
maze[4][3] = new Bird(4, 3, Bird.N);
maze[4][4] = new Bird(4, 4, Bird.NE);
maze[4][5] = new Bird(4, 5, Bird.W);
maze[4][6] = new Bird(4, 6, Bird.N);
start = maze[2][0];
end = maze[2][6];
// write your code here
/*snipped the logic for adding the birds in the queue, but I do know that this part is 100% functional on my end*/
}
public Bird getStart()
{
return this.start;
}
public Bird getEnd()
{
return this.end;
}
}

Okay, one thing I am seeing that you have passed the parameter end in the recursion but never used that.
One key thing of recursion is having a control statement which will cause the recursion to break and return the right thing or nothing. You have returned true and false randomly (or may be there is a logic) which does not add any value to your execution path.
So, let's do it in a different way:
Don't push anything in the stack unless you need it so that you have to only pop when you are printing. The first bird you need to push in the stack is the final bird matching the expression (current == end).
If the bird does not have return something to the previous bird indicating that the path is blocked. Now to match with this, with Step 1, if (current == end) return something to the previous bird indicating that the final bird is found and pass it on with every bird in the chain to the first bird.
Pseudocode:
recursive(stack, current, end)
{
if(current == end){
stack.push(current); //push the final bird
return true; //indication that final is found
}
else if(current.getNext() != null){
result = recurse(stack, current.getNext(), end); //recurse
if(result == true)
stack.push(current); // using indication from the chain
return result;
}
return false;
}

Related

Binary Search returning -1 in spite of the element existing

For this program, I'm trying to use Binary searching to find a specific element of a given array, such as title, year, or artist. For now, I'm only testing for title and year since they are both strings. But it seems that for some of the input I put in, the program would return -1, even though the input I put in exists on the array. I'm not sure why this happens.
First is the tester class, second code is the constructor class.
public class TestMusic
{
public static void printMusic(Music[] arr)
{
for (Music music : arr)
{
System.out.println(music.toString());
}
}
public static int binaryTitle(Music[] arr, String title)
{
int l = 0, r = arr.length - 1;
while (l <= r) {
int m = l + (r - l) / 2;
int res = title.compareTo(arr[m].getTitle());
// Check if x is present at mid
if (res == 0)
return m;
// If x greater, ignore left half
if (res > 0)
l = m + 1;
// If x is smaller, ignore right half
else
r = m - 1;
}
return -1;
}
public static int binaryArtist(Music[] arr, String artist)
{
int l = 0, r = arr.length - 1;
while (r - l >= 1) {
int m = l + (r-l) / 2;
int res = artist.compareTo(arr[m].getArtist());
if (res == 0)
{
return m;
}
if (res > 0)
{
l = m + 1;
}
else
{
r = m - 1;
}
}
return -1;
}
public static void main(String[]args)
{
Music[] arr = new Music[12];
arr[0] = new Music("Montero", 2021, "Lil Nas X");
arr[1] = new Music("Dynamite", 2020, "BTS");
arr[2] = new Music("Bad Guy", 2019, "Billie Eilish");
arr[3] = new Music("Sicko Mode", 2018, "Travis Scott");
arr[4] = new Music("Shape of You", 2017, "Ed Sheeran");
arr[5] = new Music("Heathens", 2016, "Twenty One Pilots");
arr[6] = new Music("See You Again", 2015, "Wiz Khalifa");
arr[7] = new Music("All About That Bass", 2014, "Meghan Trainor");
arr[8] = new Music("Wrecking Ball", 2013, "Miley Cyrus");
arr[9] = new Music("Paradise", 2011, "Coldplay");
arr[10] = new Music("Shake it Off", 2014, "Taylor Swift");
arr[11] = new Music("Savage", 2021, "Aespa");
System.out.println("Original:");
printMusic(arr);
System.out.println("\nBinary searching Sicko Mode: Index " + binaryTitle(arr, "Sicko Mode"));
System.out.println("\nBinary searching Taylor Swift: Index " + binaryArtist(arr, "Taylor Swift"));
}
}
public class Music
{
// instance variables
private int year;
private String title;
private String artist;
// Constructor for objects of class Music
public Music(String t, int y, String a)
{
// initialize instance variables
title = t;
year = y;
artist = a;
}
public String getTitle()
{
return title;
}
public void setTitle(String t)
{
title = t;
}
public String getArtist()
{
return artist;
}
public void setArtist(String a)
{
artist = a;
}
public int getYear()
{
return year;
}
public void setTitle(int y)
{
year = y;
}
public String toString()
{
String str = String.format( "%-25s %4d %-20s ", title, year , artist);
return str;
}
}
for a binary search to work correctly it must be sorted in some way. If you're searching it by year you need to sort it from smallest to largest. if you're searching it by Title, those Titles must be in some alphabetical order, same with the Artist.
Ex:
{1,4,3,2,5} //searching for 4 returns -1 because it's looking between 3 and 5 and only finding 2.
{1,2,3,4,5} //searching for 4 returns 3 because it looks between 3 and 5 and finds 4 at index 3.
Binary search requires a sorted array. If you use an array that's not sorted, binary search is liable to not find what you need. For this type of thing you need a sequential search.
Example:
[0, 3, 7, 8, 12, 56, 2]
//say you have this array, and you're looking for number 2,
//your function will compare 2 to the middle element: 8.
//2 < 8, so it will throw out everything above 8.
[0, 3, 7]
//Obviously 2 is not there. But it was there originally.
//The problem is it was unsorted
I can confirm that you can only do a type of binary search to its corresponding sort. So title binary search can only happen after a title sort.

Method returning null no matter what

I have two classes I have posted here (plus a computer class that the objects are being created from).
When I try to use my findSys method, my method returns "null" no matter what. I am trying to compare the "search" variable the user inputs as a findSys parameter against null, and if it's null, it should output the message I have underneath the "else" clause. But instead, its just returning null no matter what. Stuck here.
import java.util.Scanner;
public class SystemTester {
public static void main(String args[]) {
Scanner scan = new Scanner(System.in);
String search;
ComputerStore cpu1 = new ComputerStore();
cpu1.add("Pentium II", 32, "2080", "Asus 370", "Corsair", 5, 123, 5);
cpu1.add("Pentium I", 16, "Nvidia 1080", "Asus 270", "CoolerMaster1", 5, 123, 5);
cpu1.add("Pentium III", 4, "GTX 1060", "Gigabyte", "Corssair 2", 5, 123, 5);
cpu1.add("AMD", 4, "GTX 980", "Gigabyte", "Corssair 2", 5, 123, 5);
cpu1.add("AMD Ryzen", 4, "GTX 680", "Gigabyte", "Corssair 2", 5, 123, 5);
cpu1.add("Core I5", 4, "GTX 1080ti", "Gigabyte", "Corssair 2", 5, 123, 5);
cpu1.add("Core I7", 4, "GTX 1060 SLI", "Gigabyte", "Corssair 2", 5, 123, 5);
cpu1.add("Core I9", 4, "GTX 780", "Gigabyte", "Corssair 2", 5, 123, 5);
cpu1.add("AMD Ryzen 2", 4, "Voodoo2", "Gigabyte", "Corssair 2", 5, 123, 5);
cpu1.add("I7 5820k", 4, "Voodoo1", "Gigabyte", "Corssair 2", 5, 123, 5);
ComputerStore cpu2 = new ComputerStore();
cpu2.add("Haswell", 64, "Nvidia 1080", "Aztek", "Corsair", 3.5, 455, 5.5);
System.out.println("Please enter a CPU to search for (Press q to quit)");
search = scan.nextLine();
while (!"q".equals(search)) {
if (search != null) {
System.out.println(cpu1.findSys(search));
}
else {
if (search.equals(null))
System.out.println("test");
}
System.out.println("Please enter a CPU to search for (Press q to quit)");
search = scan.nextLine();
}
}
}
public class ComputerStore {
private Computer[] systems;
private int sysNumbers;
public ComputerStore() {
systems = new Computer[200];
sysNumbers = 0;
}
public void add(String c, int r, String g, String m, String p, double co, int sn, double d) {
systems[sysNumbers++] = new Computer(c, r, g, m, p, co, sn, d);
}
public String toString() {
String result = "";
for (int i = 0; i < sysNumbers; i++)
result += systems[i].toString() + "\n";
return result;
}
public String findSys(String c) {
for (int i = 0; i < sysNumbers; i++) {
if (systems[i] != null && systems[i].getCpu().equals(c))
return systems[i].getMotherboard();
}
return null;
}
}
//
//This program will create Computer objects with different data members
//and will also upgrade those data members based on setters. This program
//also has a depreciation function and upgrade function. This (Computer) is the class
//and the SystemBuilder class is the class used for creating the objects.
public class Computer {
// Data Members - These belong to the class and are private.
// They all go to new objects.
private String cpu;
private int ram;
private String gpu;
private String motherboard;
private String psu;
private double cost;
private int serialnumber;
private double depreciation;
// Initial constructor with no arguments
Computer() {
cpu = "";
ram = 0;
gpu = "";
motherboard = "";
psu = "";
cost = 0.0;
serialnumber = 0;
depreciation = 0.0;
}
// Constructor with data members
Computer(String c, int r, String g, String m, String p, double co, int sn, double d) {
cpu = new String(c);
ram = r;
gpu = new String(g);
motherboard = new String(m);
psu = new String(p);
cost = co;
serialnumber = sn;
depreciation = d;
}
// Getters, allow retrieval of data members from outside of class
public String getCpu() {
return cpu;
}
public int getRam() {
return ram;
}
public String getGpu() {
return gpu;
}
public String getMotherboard() {
return motherboard;
}
public String getPsu() {
return psu;
}
public double getCost() {
return cost;
}
public int getSerialnumber() {
return serialnumber;
}
public double getDepreciation() {
return depreciation;
}
// Setters, allow setting of data members from outside of class
public void setCpu(String c) {
cpu = new String(c);
}
public void setRam(int r) {
ram = r;
}
public void setGpu(String g) {
gpu = new String(g);
}
public void setMotherboard(String m) {
motherboard = new String(m);
}
public void setPsu(String p) {
psu = new String(p);
}
public void setCost(double co) {
cost = co;
}
public void setSerialnumber(int sn) {
serialnumber = sn;
}
public void setDepreciation(double d) {
depreciation = d;
}
// Boolean below will compare computers to see if equal
// based on same motherboard SN#.
public boolean equals(Computer c) {
if (this.serialnumber == (c.serialnumber)) {
return true;
} else {
return false;
}
}
// To string method will print characteristics about object.
public String toString() {
return ("CPU:\t\t" + cpu + "\n" + "RAM:\t\t" + ram + "\n" + "GPU:\t\t" + gpu + "\n" + "Motherboard:\t"
+ motherboard + "\n" + "PSU:\t\t" + psu + "\n" + "Cost:\t\t" + "$" + cost + "\n" + "SN#:\t\t"
+ serialnumber + "\n" + "Depreciation:\t" + "$" + depreciation + " (annually)");
}
// A method to depreciate the cost of the computer
// The formula is observed below, but this is a
// straight line depreciation equation, calculated based
// on the values the user passes into the function. This method
// will show an output of annual depreciation based on useful
// life, entered in "years" by the user.
public void depreciate(double purchasePrice, double salvageValue, double lifeSpanYears) {
double depreciableCost;
double annualDepreciation;
depreciableCost = purchasePrice - salvageValue;
annualDepreciation = depreciableCost / lifeSpanYears;
depreciation = annualDepreciation;
}
// A method to upgrade the ram or the video card
// The method will accpet argumetns for ram (in int) and a gpu (string).
public void upgrade(int newRam, String newGpu) {
ram = newRam;
gpu = new String(newGpu);
}
}
For me your implementation is perfectly working. Here I attached screenshot, may be you did something wrong during console input when you are taking input search text.Console out put snapshot
Ok,
Mr. Mopp was right - but I had to remove the Computer class before the searchResult variable for it to work, and make a var type of String, SearchResult. So this works for me below:
String searchResult;
while (!"q".equals(search)) {
searchResult = cpu1.findSys(search);
if (searchResult != null) {
System.out.println(searchResult);
}
else {
System.out.println("not found");
}
You don't want to compare if search == null because search is the user input. You want to check if the result of the search is null:
while (!"q".equals(search)) {
Computer searchResult = cpu1.findSys(search);
if (searchResult != null) {
System.out.println(searchResult);
}
else {
System.out.println("not found");
}
You also should change the return type of findSys to be Computer. Returning just a String limits the usefulness of the function:
public Computer findSys(String c) {
for (int i = 0; i < sysNumbers; i++) {
if (systems[i] != null && systems[i].getCpu().equals(c))
return systems[i];
}
return null;
}

How to target specific list indexes (JAVA)

I'm trying to code a boardame called Mancala and i want to change the winner() function.
The game ends if one side has no stones in either of their pits, then the winner is determined if PlayerOne's mancala has more stones than PlayerTwo's, or vice versa.
But i have no idea how to target a specific element in an object so i can extend the win function... Any help would be appreciated!
What i'm trying to achieve is something like:
if (sideOne.get(13).number > sideOne.get(14).number) {
return...
}
I know the above code is incorrect, but i want to target is both the array lists, a specific index of that list and the integer element in the object.
I've included the constructors of the games board and the current winner() function.
Class of MancalaPit
public class MancalaPit {
String player;
Integer stones;
Boolean pit;
Integer number;
MancalaPit next;
public MancalaPit(String player, int stones, boolean pit, int number, MancalaPit next) {
this.player = player;
this.stones = stones;
this.pit = pit;
this.number = number;
this.next = next;
}
}
public class Board { // Creates the board
private MancalaPit a;
private MancalaPit b;
private MancalaPit c;
private MancalaPit d;
private MancalaPit e;
private MancalaPit f;
private MancalaPit mancalaOne;
private MancalaPit g;
private MancalaPit h;
private MancalaPit i;
private MancalaPit j;
private MancalaPit k;
private MancalaPit l;
private MancalaPit mancalaTwo;
private ArrayList<MancalaPit> sideOne;
private ArrayList<MancalaPit> sideTwo;
public Board() { // Constructs the bad boy
// Constructs the array lists
sideOne = new ArrayList<>();
sideTwo = new ArrayList<>();
// Constructs the pits and Mancala's
a = new MancalaPit("playerOne", 4, false, 1, null);
b = new MancalaPit("playerOne", 4, false, 2, null);
c = new MancalaPit("playerOne", 4, false, 3, null);
d = new MancalaPit("playerOne", 4, false, 4, null);
e = new MancalaPit("playerOne", 4, false, 5, null);
f = new MancalaPit("playerOne", 4, false, 6, null);
mancalaOne = new MancalaPit("playerOne", 0, true, 13, null);
g = new MancalaPit("playerTwo", 4, false, 7, null);
h = new MancalaPit("playerTwo", 4, false, 8, null);
i = new MancalaPit("playerTwo", 4, false, 9, null);
j = new MancalaPit("playerTwo", 4, false, 10, null);
k = new MancalaPit("playerTwo", 4, false, 11, null);
l = new MancalaPit("playerTwo", 4, false, 12, null);
mancalaTwo = new MancalaPit("playerTwo", 0, true, 14, null);
// Constructs the order of the pits
a.next = b;
b.next = c;
c.next = d;
d.next = e;
e.next = f;
f.next = mancalaOne;
mancalaOne.next = g;
g.next = h;
h.next = i;
i.next = j;
j.next = k;
k.next = l;
l.next = mancalaTwo;
mancalaTwo.next = a;
// Constructs sides
sideOne.add(a);
sideOne.add(b);
sideOne.add(c);
sideOne.add(d);
sideOne.add(e);
sideOne.add(f);
sideTwo.add(g);
sideTwo.add(h);
sideTwo.add(i);
sideTwo.add(j);
sideTwo.add(k);
sideTwo.add(l);
}
public String winner() {
Boolean one = true;
Boolean two = true;
for(MancalaPit pit : sideOne) {
if(pit.stones == 0) {
continue;
} else {
one = false;
break;
}
}
if(one == true) {
return "Your boy player one is the champion";
}
for(MancalaPit pit : sideTwo) {
if(pit.stones == 0) {
continue;
} else {
two = false;
break;
}
}
if(two == true) {
return "Your boy player two is the champion";
}
return "No winners so far";
}
I don't think you need to target an index at all (especially since these pits aren't in the lists you created), you already have variables defined to compare the win condition. You should be able to just compare mancalaOne.stones to mancalaTwo.stones if either "one" is true or "two" is true. BTW one and two should be booleans not Booleans.
i.e. do the two for loops, then do
if (one || two) {
if (mancalaOne.stones > mancalaTwo.stones) {
return "Player 1 wins!"
} else if ...
}

Read range of values in an array with unkown dimension

I 'm looking for a way to read a range of elements in an array of unknown dimension ( not length).
The client can send a read request for an object and specify the range to read. The input String could be like this : "1:2:3:2,2:3:1:4" for example. This would mean he wants to read the elements in the range from [1][2][3][2] to [2][3][1][4] of an array.
To read a concrete element I created this function:
public Object readValue(Object obj,int[] positions ) {
Object value = null; //Result
int objDimension = getDimension(obj); //Dimesion of the array
System.out.println("Dimension: " + objDimension );
try {
Object[] aux = (Object[]) obj;
for (int i = 0; i < objDimension - 1; i++) {
int pos = positions[i];
aux = (Object[]) aux[pos];
}
value = aux[positions[objDimension - 1]];
System.out.println("Result: " + value);
} catch (ArrayIndexOutOfBoundsException e) {
// TODO: Send a fault to the client.
System.out.println("Error: "+e.getMessage());
}
return value;
}
public static int getDimension(Object value) {
Class<?> clazz = value.getClass();
String className = clazz.getName();
int dimension = 0;
for (int i = 0; i < className.length(); i++) {
if (className.charAt(i) != '[') {
dimension = i;
break;
}
}
return dimension;
}
//Example.
public static void main(String[] args) {
// TODO code application logic here
TestMultiDimensioNRead test = new TestMultiDimensioNRead();
Integer[][][][] testSubject = new Integer[5][2][4][];
testSubject[0][0][2] = new Integer[8];
testSubject[0][0][0] = new Integer[15];
testSubject[0][0][1] = new Integer[20];
testSubject[0][0][3] = new Integer[2];
testSubject[1][1][2] = new Integer[7];
testSubject[1][1][2][0] = 80;
test.readValue(testSubject,new int[]{1, 1, 2, 0});
}
I was thinking a good way may be to calculate the differens between each dimension length.
If anyone can come with a good idea, I would really appreciatee.
Thanks in advance.
EDIT 1: The code posted in this question does read the value of a given position in an array of unknown dimension. My problem is to read all the elements that are between to given points. This might not have been clear in the initial question.
You could use a recursive solution:
public class Test {
private class TestMultiDimensioNRead {
public Integer readValue(Object testSubject, int[] coordinates) {
return readValue(testSubject, coordinates, 0);
}
private Integer readValue(Object testSubject, int[] coordinates, int which) {
if (testSubject instanceof Object[]) {
Object[] subject = (Object[]) testSubject;
if (coordinates.length > which + 1) {
return readValue(subject[coordinates[which]], coordinates, which + 1);
} else {
return (Integer) subject[coordinates[which]];
}
} else {
// Throw some sort of exception?
return -1;
}
}
public Iterator<Integer> readValues(Object testSubject, int[] coordinates, int count) {
return readValues(testSubject, coordinates, count, 0);
}
private Iterator<Integer> readValues(Object testSubject, int[] coordinates, int count, int level) {
if (testSubject instanceof Object[]) {
Object[] subject = (Object[]) testSubject;
if (coordinates.length > level + 1) {
return readValues(subject[coordinates[level]], coordinates, count, level + 1);
} else {
return new Iterator<Integer>() {
int i = 0;
Integer[] intSubject = (Integer[]) subject;
#Override
public boolean hasNext() {
return i <= count;
}
#Override
public Integer next() {
return intSubject[coordinates[level] + (i++)];
}
};
}
} else {
// Throw some sort of exception?
return null;
}
}
}
public void test() {
TestMultiDimensioNRead test = new TestMultiDimensioNRead();
Integer[][][][] testSubject = new Integer[5][2][4][];
testSubject[0][0][2] = new Integer[8];
testSubject[0][0][0] = new Integer[15];
testSubject[0][0][1] = new Integer[20];
testSubject[0][0][3] = new Integer[2];
testSubject[1][1][2] = new Integer[7];
testSubject[1][1][2][0] = 80;
testSubject[1][1][2][1] = 79;
testSubject[1][1][2][2] = 78;
Iterator<Integer> them = test.readValues(testSubject, new int[]{1, 1, 2, 0}, 3);
for (Integer x = them.next(); them.hasNext(); x = them.next()) {
System.out.println(x);
}
System.out.println();
}
public static void main(String args[]) {
try {
new Test().test();
} catch (Throwable t) {
t.printStackTrace(System.err);
}
}
}
Prints 80 as expected.
There's probably more to do in terms of sanity checks but this seems to work.
Found the way to do it, maybe it's helpfull at somepoint for someone.
I didn't include any checks, this is more a test case to see that is works.
public class TestReadMultiDimensionArray {
private int[] startPosition; //Start position.
private int[] endPosition; //End position.
private boolean inRange = false; //If the current position is in range.
private List<Object> result; //List to store the values we find.
public TestReadMultiDimensionArray() {
result = new ArrayList<>();
}
public static void main(String[] args) {
TestReadMultiDimensionArray test = new TestReadMultiDimensionArray();
Integer[][][][] testSubject = new Integer[2][2][4][];
//(0,0,y,z)
testSubject[0][0][0] = new Integer[]{1}; //(0,0,0,0)
testSubject[0][0][1] = new Integer[]{2}; //(0,0,1,0)
testSubject[0][0][2] = new Integer[]{3}; //(0,0,2,0)
testSubject[0][0][3] = new Integer[]{4}; //(0,0,3,0)
//(0,1,y,z)
testSubject[0][1][0] = new Integer[]{5}; //(0,1,0,0)
testSubject[0][1][1] = new Integer[]{6}; //(0,1,1,0)
testSubject[0][1][2] = new Integer[]{7, 8, 9}; //(0,1,2,0) (0,1,2,1) (0,1,2,2)
testSubject[0][1][3] = new Integer[]{10}; //(0,1,3,0)
//(1,0,y,z)
testSubject[1][0][0] = new Integer[]{11, 12}; //(1,0,0,0)..
testSubject[1][0][1] = new Integer[]{13, 14, 15};
testSubject[1][0][2] = new Integer[]{16, 17, 18};
testSubject[1][0][3] = new Integer[]{19, 20, 21}; //..(1,0,3,2)
//(1,1,y,z)
testSubject[1][1][0] = new Integer[]{22, 23}; //(1,1,0,0)..
testSubject[1][1][1] = new Integer[]{24, 25, 26};
testSubject[1][1][2] = new Integer[]{27, 28, 29, 30, 31, 32, 33, 34};
testSubject[1][1][3] = new Integer[]{35, 36}; //..(1,1,3,1)
//Launch the test.
test.readValue(testSubject);
}
/**
*
* #param obj The Array from where we want to get the data.
*/
public void readValue(Object obj) {
//Where should it start.
startPosition = new int[]{0, 1, 0, 0};
//Where should it stop.
endPosition = new int[]{1, 1, 1, 2};
System.out.println("Start Position:" + Arrays.toString(startPosition) + " End Position:" + Arrays.toString(endPosition));
int[] currentPosition = new int[]{-1, -1, -1, -1};
//Call to the method.
testRead((Object[]) obj, 0, currentPosition);
//Result to array.
Object[] arrayToReturn = result.toArray(new Object[0]);
System.out.println("Result: " + Arrays.toString(arrayToReturn));
}
/**
* Recursive method that looks for the values in a multi-dimensional array, in a given range. /!\ No checks are implemented here, wrong input can end in a
* StackOverFlow.
*
* #param obj The array in Object[] form.
* #param currentDimension The dimension we are currently in.
* #param result The reference to the list that will store all the values we found.
* #param currentPosition The current position we are in.
*/
private void testRead(Object[] obj, int currentDimension, int[] currentPosition) {
for (int i = 0; i < obj.length; i++) {
currentPosition[currentDimension] = i;
if (Arrays.equals(startPosition, currentPosition) && currentDimension == (currentPosition.length - 1)) {
//Found the start position.
System.out.println("############ START ############");
inRange = true;
}
if ((i >= startPosition[currentDimension] && i <= endPosition[currentDimension]) || inRange == true) {
//We are in the write track to get to the values we are looking for.
if (obj[i] instanceof Object[]) {
//The data contained in the cell is an array.
testRead((Object[]) obj[i], currentDimension + 1, currentPosition);
} else {
//The data contained in the cell is a scalar. This is what we where looking for.
System.out.println(Arrays.toString(currentPosition) + " Data: " + obj[i]);
result.add(obj[i]);
}
}
if (Arrays.equals(endPosition, currentPosition) && currentDimension == (currentPosition.length - 1)) {
//Found the end position.
System.out.println("############ END ############");
inRange = false;
}
}
}
}
Any question or idea to better the code is welcome.

Weird ArrayList Behaviour

I create 3 objects of ChipSet and put them in an ArrayList. The arraylist does not contain the right values. The debug messages are quite clear on what happening but I have no explanation for this behaviour at all. Could someone tell me my error(s)?
Here is my code:
import java.util.ArrayList;
import java.util.Arrays;
public class WierdArrayBehaviour {
public static void main(String[] args) {
ArrayList<ChipSet> chipSetCombos = createComboExample();
System.out.printf("\n\n---- Show created combolist ----");
System.out.printf("\nCombo 1: " + Arrays.toString(chipSetCombos.get(1).getChips()));
System.out.printf("\nCombo 2: " + Arrays.toString(chipSetCombos.get(1).getChips()));
System.out.printf("\nCombo 3: " + Arrays.toString(chipSetCombos.get(2).getChips()));
}
private static ArrayList<ChipSet> createComboExample() {
ArrayList<ChipSet> combos = new ArrayList<ChipSet>();
System.out.printf("---- Creating possible combos ----");
ChipSet combo1 = new ChipSet(new int[]{1, 1, 1, 1, 2});
System.out.printf("\nCombo 1: " + Arrays.toString(combo1.getChips()));
ChipSet combo2 = new ChipSet(new int[]{1, 1, 1, 1, 3});
System.out.printf("\nCombo 2: " + Arrays.toString(combo2.getChips()));
ChipSet combo3 = new ChipSet(new int[]{1, 1, 1, 1, 4});
System.out.printf("\nCombo 3: " + Arrays.toString(combo3.getChips()));
combos.add(combo1);
combos.add(combo2);
combos.add(combo3);
return combos;
}
}
class ChipSet {
public static final int WHITE_VALUE = 1;
public static final int RED_VALUE = 2;
public static final int GREEN_VALUE = 5;
public static final int BLUE_VALUE = 10;
public static final int BLACK_VALUE = 20;
public static final int[] VALUES = new int[]{WHITE_VALUE, RED_VALUE, GREEN_VALUE, BLUE_VALUE, BLACK_VALUE};
protected static int[] chips;
public ChipSet(int[] chips) {
if (chips == null || chips.length != 5) {
throw new IllegalArgumentException("ChipSets should contain exactly 5 integers!");
}
// store a copy of passed array
this.chips = new int[5];
for (int i = 0; i < this.chips.length; i++) {
this.chips[i] = chips[i];
}
}
public int getSum() {
return chips[0] * WHITE_VALUE
+ chips[1] * RED_VALUE
+ chips[2] * GREEN_VALUE
+ chips[3] * BLUE_VALUE
+ chips[4] * BLACK_VALUE;
}
public int[] getChips() {
return this.chips;
}
}
What happens is that your attribute chips is static, which means that it exists once per class.
Every time you create a new Chipset instance, you are overwriting the previous created chips.
What can you do? Don't declare it as static:
protected int[] chips;
You are printing combo1 every time. Change it to
System.out.printf("\nCombo 2: " + Arrays.toString(combo2.getChips())); // <-- 2
ChipSet combo3 = new ChipSet(new int[]{1, 1, 1, 1, 4});
System.out.printf("\nCombo 3: " + Arrays.toString(combo3.getChips())); // <-- 3
from
System.out.printf("\nCombo 2: " + Arrays.toString(combo1.getChips()));
ChipSet combo3 = new ChipSet(new int[]{1, 1, 1, 1, 4});
System.out.printf("\nCombo 3: " + Arrays.toString(combo1.getChips()));
Edit
Change
protected static int[] chips;
to
protected int[] chips;
As it is there are only one array of Chips for all of your instances.

Categories