I'm working on a self-assigned project over break, and am running into one major sticking point. This is a basic line-recognition program in Java.
I have a Points class which creates the Point from the ordered pairs & sends it to the Line class for slope & intercept calculation. The results are sent back to the Points class which deposits the results into the ArrayList linelist. There are three parts to each Line object: the slope & intercept integers and the Point from which they were calculated from.
From a loop, how can I access the slope & intercept variables from each object in the linelist for comparison? Since I don't want to compare the points, just the slope & intercept, the equals() method is not what I need.
It sounds like you want something like this:
class Point {
final int x;
final int y;
Point(int x, int y) { this.x = x; this.y = y; }
}
class Line {
final int slope;
final int intercept;
Line(Point p1, Point p2) {
this.slope = ...;
this.intercept = ...;
}
}
class Points {
public void doIt(ArrayList<Point> points) {
ArrayList<Line> lines = new ArrayList<Line>();
for (int i = 0; i < points.size(); i++) {
for (int j = i + 1; j < points.size(); j++) {
lines.add(new Line(points.get(i), points.get(j));
}
}
for (int i = 0; i < lines.size(); i++) {
for (int j = i + 1; j < lines.size(); j++) {
Line line1 = lines.get(i);
Line line2 = lines.get(j);
if (line1.slope == line2.slope && line1.intercept == line2.intercept) {
// blah blah blah
}
}
}
}
}
(For the peanut gallery, yes there is scope for micro-optimization. But no, it isn't worth the effort unless you've profiled the program and found there to be a real and significant bottleneck.)
[For a more elegant and scalable solution, override the equals(Object) (and hashcode()) methods on Line class and replace the lines list with a TreeSet. This will reduce O(N**2) comparisons to O(NlogN) comparisons. But that's overkill for a basic programming exercise.]
From a loop, how can I access the slope & intercept variables from each object in the linelist for comparison?
Just add another loop over the same list inside the loop and do the comparison in there.
You could have your Line object implement the Comparable interface. You could then put the comparison logic within the Line class in the compareTo method. The logic there will test whether the slope and the intercept match, and if so return 0. Other results could return 1 or -1 to enforce ordering, if you want.
Obviously, you don't need to implement this interface to effect your desired results. However, as this is homework, doing so will allow you to play around with some features of the JDK, like using sorted Lists, etc. With a sorted list, for example, you could obviate the need for a nested loop, as you would only need to compare the object in question against one you just removed from the Iterator in the previous iteration to see if you need to add it to an existing linelist or start a new one.
Related
I need to solve a crossword given the initial grid and the words (words can be used more than once or not at all).
The initial grid looks like that:
++_+++
+____+
___+__
+_++_+
+____+
++_+++
Here is an example word list:
pain
nice
pal
id
The task is to fill the placeholders (horizontal or vertical having length > 1) like that:
++p+++
+pain+
pal+id
+i++c+
+nice+
++d+++
Any correct solution is acceptable, and it's guaranteed that there's a solution.
In order to start to solve the problem, I store the grid in 2-dim. char array and I store the words by their length in the list of sets: List<Set<String>> words, so that e.g. the words of length 4 could be accessed by words.get(4)
Then I extract the location of all placeholders from the grid and add them to the list (stack) of placeholders:
class Placeholder {
int x, y; //coordinates
int l; // the length
boolean h; //horizontal or not
public Placeholder(int x, int y, int l, boolean h) {
this.x = x;
this.y = y;
this.l = l;
this.h = h;
}
}
The main part of the algorithm is the solve() method:
char[][] solve (char[][] c, Stack<Placeholder> placeholders) {
if (placeholders.isEmpty())
return c;
Placeholder pl = placeholders.pop();
for (String word : words.get(pl.l)) {
char[][] possibleC = fill(c, word, pl); // description below
if (possibleC != null) {
char[][] ret = solve(possibleC, placeholders);
if (ret != null)
return ret;
}
}
return null;
}
Function fill(c, word, pl) just returns a new crossword with the current word written on the current placeholder pl. If word is incompatible with pl, then function returns null.
char[][] fill (char[][] c, String word, Placeholder pl) {
if (pl.h) {
for (int i = pl.x; i < pl.x + pl.l; i++)
if (c[pl.y][i] != '_' && c[pl.y][i] != word.charAt(i - pl.x))
return null;
for (int i = pl.x; i < pl.x + pl.l; i++)
c[pl.y][i] = word.charAt(i - pl.x);
return c;
} else {
for (int i = pl.y; i < pl.y + pl.l; i++)
if (c[i][pl.x] != '_' && c[i][pl.x] != word.charAt(i - pl.y))
return null;
for (int i = pl.y; i < pl.y + pl.l; i++)
c[i][pl.x] = word.charAt(i - pl.y);
return c;
}
}
Here is the full code on Rextester.
The problem is that my backtracking algorithm doesn't work well. Let's say this is my initial grid:
++++++
+____+
++++_+
++++_+
++++_+
++++++
And this is the list of words:
pain
nice
My algorithm will put the word pain vertically, but then when realizing that it was a wrong choice it will backtrack, but by that time the initial grid will be already changed and the number of placeholders will be reduced. How do you think the algorithm can be fixed?
This can be solved in 2 ways:
Create a deep copy of the matrix at the start of fill, modify and return that (leaving the original intact).
Given that you already pass around the matrix, this wouldn't require any other changes.
This is simple but fairly inefficient as it requires copying the matrix every time you try to fill in a word.
Create an unfill method, which reverts the changes made in fill, to be called at the end of each for loop iteration.
for (String word : words.get(pl.l)) {
if (fill(c, word, pl)) {
...
unfill(c, word, pl);
}
}
Note: I changed fill a bit as per my note below.
Of course just trying to erase all letter may erase letters of other placed words. To fix this, we can keep a count of how many words each letter is a part of.
More specifically, have a int[][] counts (which will also need to be passed around or be otherwise accessible) and whenever you update c[x][y], also increment counts[x][y]. To revert a placement, decrease the count of each letter in that placement by 1 and only remove letters with a count of 0.
This is somewhat more complex, but much more efficient than the above approach.
In terms of code, you might put something like this in fill:
(in the first part, the second is similar)
for (int i = pl.x; i < pl.x + pl.l; i++)
counts[pl.y][i]++;
And unfill would look something like this: (again for just the first part)
for (int i = pl.x; i < pl.x + pl.l; i++)
counts[pl.y][i]--;
for (int i = pl.x; i < pl.x + pl.l; i++)
if (counts[pl.y][i] == 0)
c[pl.y][i] = '_';
// can also just use a single loop with "if (--counts[pl.y][i] == 0)"
Note that, if going for the second approach above, it might make more sense to simply have fill return a boolean (true if successful) and just pass c down to the recursive call of solve. unfill can return void, since it can't fail, unless you have a bug.
There is only a single array that you're passing around in your code, all you're doing is changing its name.
See also Is Java "pass-by-reference" or "pass-by-value"?
You identified it yourself:
it will backtrack, but by that time the initial grid will be already
changed
That grid should be a local matrix, not a global one. That way, when you back up with a return of null, the grid from the parent call is still intact, ready to try the next word in the for loop.
Your termination logic is correct: when you find a solution, immediately pass that grid back up the stack.
I'm very new to programming. However, I've written a method called "succ" that's adds 1 to a given parameter. It looks like this:
int succ(int x) {
return x += 1;
}
Now I'm supposed to write another method that adds 2 numbers using my first method. This is what my attempt looks like:
int add(int x, int y) {
for(int i = 0; i < y; i++) {
succ(x);
}
return x;
}
Unfortunately it doesn't seem to work; it always returns the initial x. For example: If I type add(8,5) it just returns 8. Can someone help me? What am I doing wrong?
Thanks in advance.
You're not doing anything with the returned value. If you want to assign it back to x, do that:
x = succ(x);
Edit: Or, perhaps you mean to add to x, since you're doing it in a loop? It's not entirely clear what this code is meant to do, and I suspect more applicable variable/method names would help. But if you want to keep adding the result, you'd just do this:
x += succ(x);
Additionally, you don't need to modify x in your succ function. Doing so in this manner may lead to unexpected behavior in the future in other examples. Keep the operations as simple as possible. Just return the calculated value:
return x + 1;
You are missing the return value of the succ method, replace the succ(x); with x = succ(x);
int add(int x, int y) {
for(int i = 0; i < y; i++) {
x = succ(x);
}
return x;
}
You keep overwriting the x value with the return value from the function. You need to add to it in each iteration, not overwrite it.
This is one of the first programs I am writing by myself. I want to make a physics calculator where many objects can interact with each other and give the user an option to add more objects. My idea is to have a for loop that runs through each object pulling on each other like this.
for(int n=1; n<=totalObjs; n++){
objName = "object"+n;
for(int i=1; i<n; i++){
obj2Name = "object"+i
objName.getMass();
//getting mass and position from both
//calculations here}
for(int x=n+1; x<=totalObjs; x++){
//same stuff as in the previous for loop}
}
I know there are probably huge syntax errors or logical errors in that but I'd like to sort through those on my own. Is there some way i could reference objects with the strings?
Is there some way i could reference objects with the strings?
Yes, via a Map<String, SomeType> such as a HashMap<String, SomeType>.
Think of this as being similar to an array or ArrayList, but instead of using number indices, you'd be using String indices.
Now looking at your code however, you might be better off using a simple ArrayList or array, since you appear to be trying to use numeric indices.
e.g.,
// assume a class called GravMass which has Mass, position, and momentum
List<GravMass> gravMassList = new ArrayList<GravMass>();
// fill your list
for(int i = 0; i < gravMassList.size() - 1; i++) {
GravMass gravMass1 = gravMassList.get(i);
int mass1 = gravMass1.getMass();
for(int j = i + 1; j < gravMassList.size(); j++){
GravMass gravMass2 = gravMassList.get(j);
int mass2 = gravMass2.getMass();
//getting mass and position from both
//calculations here}
}
}
What I am trying to do is create an array that pulls even numbers from another array. I'm not sure if I have gone about it the right way. I've look for ways of returning from statements like you would functions/methods and I can't find anything, not even sure if it is possible.
Anyway, the issue I am having here is the 'return evenArray' below 'cannot find symbol.' I am not sure what this means?
public static int[] getEvenArray(int[] array)
{
int dividedBy = 2;
int evenElement;
int evenCount = 0;
for(int i = 0; i < array.length; i++)
{
int[] evenArray;
evenElement = array[i] % dividedBy;
if(evenElement == 0)
{
evenCount++;
}
else
{
array[i] = 0;
}
evenArray = new int[evenCount];
for(int x = 0; x < evenArray.length; x++)
{
if(array[i] != 0)
{
evenArray[x] = array[i];
}
}
}
return evenArray;
}
This is for a tutorial from one of my lectures, it's a little bit challenging to say the least :-)0
evenArray is defined within the scope of the for loop. (Actually a little worse than that; you're redeclaring it on each iteration so discarding the previous contents).
So once you're outside the for loop you can't refer to it.
Quickest fix is to use a std::vector<int> for this type, and declare it at the start of the function. Also change the return type of the function to the same. Don't forget to size the vector appropriately.
(Moving on, a smart lecturer will ask you about returning a std::vector which could potentially take a deep copy of that vector. Pre C++11 you'd mention return value optimisation, now you can talk about r-value references. No deep copy will be taken since the move constructor will be used).
Variable declared inside a block is not visible outside of it; move this int[] evenArray; to very start of function.
I have a small block of code that is reading Line2D values from an array called lineList (in a different class) and storing them in the new array called list. from here I have been trying to convert all of the line values into Polygon points (a point for each x, y coordinate of a line end).
so far I have it working but its not working for the very first point of the first line in the array (that's what I suspect it is) that is added and I am having trouble finding a solution to this as I have tried including this in the first if statement.
I will greatly appreciate any help that anyone is able to provide for me on this.
Below is the code I am using for adding the points from the Line2D values:
Polygon p = new Polygon();
ArrayList<Line2D> list = new ArrayList<Line2D>();
Color pixel;
boolean firstTime = true;
list = segmentation.getLineList();
//loop through lineList and add all x and y coordinates to relative x and y arrays
for(int i = 0; i < list.size(); i++) {
if(firstTime == true){
Line2D line = list.get(i);
Point2D startPoint = line.getP1();
Point2D endPoint = line.getP2();
int startX = (int) startPoint.getX();
int startY = (int) startPoint.getY();
int endX = (int) endPoint.getX();
int endY = (int) endPoint.getY();
p.addPoint(p.xpoints[i] = startX, p.ypoints[i] = startY);
p.addPoint(p.xpoints[i] = endX, p.ypoints[i] = endY);
startPoint = null;
endPoint = null;
line = null;
firstTime = false;
}
else {
Line2D line = list.get(i);
Point2D endPoint = line.getP2();
int endX = (int) endPoint.getX();
int endY = (int) endPoint.getY();
p.addPoint(p.xpoints[i] = endX, p.ypoints[i] = endY);
endPoint = null;
line = null;
}
}
Below is an example of the first point (lower most point) not being included in the polygon points.
Seems like a lot of duplicated code to me. Before we try any more debugging, let's refactor the code and make it simpler to understand and debug.
Refactoring
The first bit of code we can pull out is the code to add a point to the Polygon. Here's the new method.
protected void addPoint(Polygon p, Point2D point) {
int x = (int) point.getX();
int y = (int) point.getY();
p.addPoint(x, y);
}
Now, I didn't get to this in one refactoring. I first pulled out the end point code, because it was identical. After reflecting on the code some more, I generalized it so I could use it for the start point code.
When I first saw this line of code
p.addPoint(p.xpoints[i] = startX, p.ypoints[i] = startY);
I thought, WTF? I'd never seen anyone set values in a method call. In a where clause, sure.
After about 5 minutes of thought, I realized that the Polygon class internal values were being set after the execution of the addPoint method. While this might be useful with some other method call, it's not necessary here. The method call can be simplified to
p.addPoint(x, y);
Java developers, if you need yet another reason for making your class variables non-public, this is a real good one. Keeps people from setting your class variables after you've set them in your setter method.
Priming Read
We can get rid of the first time switch, and a lot of code, if we use a little known algorithm called the priming read.
Most for loops have the input statement as the first statement in the loop. The for (String s : stringList) construction of a loop hides the fact that the input statement is the first statement in the loop.
But sometimes, you have a method where you need a priming read. This method is one of those times.
In pseudo code, a priming read works like this.
Read input
for loop
process input
read input
end loop
process last input
By using a priming read, I was able to greatly simplify the createPolygon method.
Any Cobol programmer reading this thought, "Yep, the priming read."
Java programmers, keep this priming read idea in your mind. You won't use it that often, but as you see, it greatly reduces the amount of code you need in certain cases.
Refactored Code
public Polygon createPolygon(Segmentation segmentation) {
Polygon p = new Polygon();
List<Line2D> list = segmentation.getLineList();
if (list.size() < 2) return p;
Line2D line = list.get(0);
addPoint(p, line.getP1());
// loop through lineList and add all x and y coordinates to relative x
// and y arrays
for (int i = 1; i < list.size(); i++) {
addPoint(p, line.getP2());
line = list.get(i);
}
addPoint(p, line.getP2());
return p;
}
protected void addPoint(Polygon p, Point2D point) {
int x = (int) point.getX();
int y = (int) point.getY();
p.addPoint(x, y);
}
I did two additional things to the code.
I added a test for less than 2 lines. Basically, it takes at least 2 lines to create a triangle (polygon). There was no point executing the method for 1 line or zero lines.
I changed the ArrayList reference to List. In Java, it's better to use an interface over a concrete class. Since the only List method we're using in the code is the get method, we can use the interface. The advantage to using the interface is that the createPolygon method doesn't care whether or not the getLineList method returns an ArrayList, a LinkedList, or a custom class that implements List. This makes future modifications easier.