i am currently working on this for personal gratification and would like some advice on how i can make this code faster :
I have one ArrayList composed of an object note, which have coordinates and color value stored in it.
Each "note" is created in real time during the rendering call.
I have made this function :
void keyPressed() {
if (key == 's' || key == 'S') {
PImage img = createImage(posX, specSize, RGB);
for(int x = 0; x < posX; x++){
for(int y = 0; y < specSize; y++){
for(int i = 0; i < notes.size(); i++){
if( (notes.get(i).getX() == x)
&& (notes.get(i).getY() == y) ){
int loc = x + y*posX;
img.pixels[loc] = color(notes.get(i).getR(),
notes.get(i).getG(), notes.get(i).getB());
}
}
}
}
img.updatePixels();
img.save("outputImage.png");
}
}
So when i press the "S" key, i run a loop on the width and height because they can be different in each run, and then on my arrayList and get the corresponding "note" with it's x and y position.
then i write my picture file.
As you can imagine, this is really, really, slow...
Around 5 to 6 minutes for a 1976x256px file.
For me it's okay but it would be great to shorten this a little.
Is there a way to optimize this three loops?
If you need more code, please let me know it's a small code and i don't mind.
How about this?
void keyPressed() {
if (key == 's' || key == 'S') {
PImage img = createImage(posX, specSize, RGB);
for(int i = 0; i < notes.size(); i++){
int x = notes.get(i).getX();
int y = notes.get(i).getY();
int loc = x + y*posX;
img.pixels[loc] = color(notes.get(i).getR(),
notes.get(i).getG(), notes.get(i).getB());
}
img.updatePixels();
img.save("outputImage.png");
}
}
Update:
Not sure what the type of notes is, but something like this might work too. Insert the correct type for one element of Notes into the for loop where I wrote ???.
void keyPressed() {
if (key == 's' || key == 'S') {
PImage img = createImage(posX, specSize, RGB);
for(??? note : notes ){
int x = note.getX();
int y = note.getY();
int loc = x + y * posX;
img.pixels[loc] = color(note.getR(), note.getG(), note.getB());
}
img.updatePixels();
img.save("outputImage.png");
}
}
Can clone notes (and any other object that is used to save) and do this in a different thread so its async to UI. the code will take same or more time but the user can use the rest of the app. Clone is neccesary as you want a snap shot of state when save was clicked.
Dont make a thread put use a ThreadPoolExecutor with one thread max. In the run method could apply what David suggested - one loop instead of two.
Convert your list of notes into a structure mapped like
Map<Integer, Map<Integer, Note> noteMap
Then replace your inner-most loop with a single call like
yNoteMap = note.get(x);
if (yNoteMap != null) {
note = yNoteMap.get(y);
if (note != null) {
// do stuff with note
}
}
Your computational complexity will go from about O(n^3) to O(n^2).
Create a class such as Point with two properties of x and y and implement proper equals and hashcode methods as:
public class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Point point = (Point) o;
if (x != point.x)
return false;
if (y != point.y)
return false;
return true;
}
#Override
public int hashCode() {
int result = x;
result = 31 * result + y;
return result;
}
}
now put the Point as key of a map, and find your points using this, so you don't have to iterate over the whole lists.
Related
First, sorry for my bad english, especially for programming words, english isnt my first language.
So, i have programmed a software that detect all continuous sprites on an image and list their palettes.
Full explanation of the software here: https://www.vg-resource.com/thread-33373.html
It works alright, however, if the sprite has at least 4300-ish pixels, a stackoverflow exception is thrown.
In order to find the boundaries of every sprite, first i find the first pixel in the sheet that isnt the color of the background. Then, i start my recursive method that verify every adjacent pixels to see if they dont have the background color, then call itself on that position, their position being recorded in a boolean matrix.
The recursive method:
//pixelPosition > the position found of the current sprite, posX/posY > position of the current pixel being examined
public boolean[][] moveToNextPixel(boolean[][] pixelPosition, int posX, int posY)
{
pixelPosition[posX][posY] = true;
//If the next position isnt outside of the boundaries of the image AND if it hasnt already been recorded
// AND if it isnt the color of the background, move to that position.
if(posX + 1 < pixelPosition.length)
{
if(!pixelPosition[posX+1][posY] && !panBackgroundColor.isColorPresentInPalette(workingImage.getRGB(posX+1,posY)) )
{
moveToNextPixel(pixelPosition,posX+1,posY);
}
}
if(posX - 1 >= 0)
{
if(!pixelPosition[posX-1][posY] && !panBackgroundColor.isColorPresentInPalette(workingImage.getRGB(posX-1,posY)))
{
moveToNextPixel(pixelPosition,posX-1,posY);
}
}
if(posY + 1 < pixelPosition[0].length)
{
if(!pixelPosition[posX][posY+1] && !panBackgroundColor.isColorPresentInPalette(workingImage.getRGB(posX,posY+1)))
{
moveToNextPixel(pixelPosition,posX,posY+1);
}
}
if(posY - 1 >= 0)
{
if(!pixelPosition[posX][posY-1] && !panBackgroundColor.isColorPresentInPalette(workingImage.getRGB(posX,posY-1)))
{
moveToNextPixel(pixelPosition,posX,posY-1);
}
}
return pixelPosition;
}
//the method isColorPresentInPalette(int) check if the color in entry is in the background colors
public boolean isColorPresentInPalette( int colorRgb)
{
boolean result = false;
for( int i =0; i< backgroundPalette.length && !result;i++)
{
if(backgroundPalette[i] != null)
{
if(backgroundPalette[i].getRGB() == colorRgb)
{
result = true;
}
}
}
return result;
}
Also, if i load a sheet with normal-sized sprite first, and then load one with a huge sprite (4400+ pixels), it doesnt do the stackoverflow error... So, in the end, im pretty confused on what is the problem exactly.
So, is a recursive method really the right way for this kind of problem? If so what could i do to fix this? Otherwise, anyone see a way to determine each individuals continuous sprites and their positions?
EDITED: Originally I posted a recursive solution but didn't realize that you were doing that. I think after reading more carefully, it seems Recursion might not be the best since you will be adding so many calls given 4300 pixels.
I would just do DFS in memory in this case then. Alternatively, you might try BFS (which will search outwards from the center).
An example of DFS in memory. This basically does the same thing as the recursion above except instead of storing things on the callstack which has a limited buffer size, you would be storing memory:
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Stack;
public class FindNeedleInHaystack {
String[][] haystack;
class Coordinate {
int x;
int y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Coordinate that = (Coordinate) o;
return x == that.x &&
y == that.y;
}
#Override
public int hashCode() {
return Objects.hash(x, y);
}
}
public FindNeedleInHaystack() {
this.haystack = new String[10][10];
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
this.haystack[i][j] = "";
}
}
}
public void addNeedle(int a_x, int a_y) {
this.haystack[a_y][a_x] = "needle";
}
public boolean hasNeedle() {
boolean[][] visited = new boolean[10][10];
return hasNeedleHelper(0, 0);
}
private List<Coordinate> neighbors(Coordinate coord, boolean[][] visited) {
List<Coordinate> neighbors = new ArrayList<>();
int x = coord.x;
int y = coord.y;
if (y + 1 < 10 && !visited[y+1][x]) neighbors.add(new Coordinate(x, y+1));
if (y - 1 >= 0 && !visited[y-1][x]) neighbors.add(new Coordinate(x, y-1));
if (x + 1 < 10 && !visited[y][x+1]) neighbors.add(new Coordinate(x + 1, y));
if (x - 1 >= 0 && !visited[y][x-1]) neighbors.add(new Coordinate(x - 1, y));
return neighbors;
}
private boolean hasNeedleHelper(int x, int y) {
Stack<Coordinate> fringe = new Stack<>();
boolean[][] visited = new boolean[10][10];
fringe.push(new Coordinate(x, y));
while(!fringe.isEmpty()) {
Coordinate toVisit = fringe.pop();
if (this.haystack[toVisit.y][toVisit.x].equals("needle")) {
return true;
} else {
visited[toVisit.y][toVisit.x] = true;
for(Coordinate coord : this.neighbors(toVisit, visited)) {
fringe.push(coord);
}
}
}
return false;
}
public static void main(String...args) {
FindNeedleInHaystack hasNeedle = new FindNeedleInHaystack();
hasNeedle.addNeedle(3, 4);
System.out.println("Has a needle?: " + hasNeedle.hasNeedle());
FindNeedleInHaystack doesntHaveNeedle = new FindNeedleInHaystack();
System.out.println("Has a needle?: " + doesntHaveNeedle.hasNeedle());
}
}
I have a coordinate system such as this:
public enum Direction {
N ( 0, 1),
NE ( 1, 1),
E ( 1, 0),
SE ( 1, -1),
S ( 0, -1),
SW (-1, -1),
W (-1, 0),
NW (-1, 1);
private int x = 0, y = 0;
private Direction(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Direction combine(Direction direction) {
//unsure
}
}
I'm trying to combine directions with a method within the enum, like:
Direction.N.combine(Direction.E) -> should become Direction.NE
Direction.N.combine(Direction.N) -> null or Direction.N again
My thoughts are to loop through all the values in the enum, and find one that matches its x and y combined:
public Direction combine(Direction direction) {
Direction[] directions = Direction.values();
for (int i = 0; i < directions.length; i++)
if (x + direction.x == directions[i].x && y + direction.y == directions[i].y)
return directions[i];
return this;
}
But I feel like that's an inefficient way to approach this. Is there another way to combine these directions that doesn't involve looping through all the enums?
I also want to create an uncombine function that will reverse the combine.
Direction.NE.uncombine() -> Direction[] {Direction.N, Direction.E}
I could also use the same looping technique, like:
public Direction[] uncombine() {
Direction[] directions = Direction.values(),
rtn = new Direction[2];
for (int i = 0; i < directions.length; i++)
if (x == directions[i].x && directions[i].y == 0)
rtn[0] = directions[i];
for (int i = 0; i < directions.length; i++)
if (y == directions[i].y && directions[i].x == 0)
rtn[1] = directions[i];
return rtn;
}
So is there a more efficient way that I could try out?
I think that creating a Map<Direction, Direction> for each enum value is going to give you a good balance between performance and code neatness.
The combine method becomes:
public Direction combine(Direction other) {
return this.combinerMap.get(other);
}
Of course, you need to build the maps during initialization of the enum class.
Returning null from this method is a bad idea because it pushes the responsibility for sanity checking back onto the caller. So I'd write it like this:
public Direction combine(Direction other)
throws InsaneDirectionsException{
Direction res = this.combineMap.get(other);
if (res == null) {
throw new InsaneDirectionsException(
"Can't combine directions " + this +
" and " + other);
}
return res;
}
If your real class is as simply as the one from the question I think that the most efficient way would be to either manually "hardcode" or pre-calculate (e.g. in static init block) the relationship between argument and result and keep it in map and then only refer to already existing results.
You can keep Map<Byte, Map<Byte, Direction>> where x and y will be indexes. Once you compute new x and y, obtaining Direction will be as simple as matrix.get(x).get(y).
In my program I have a class called Cell, defined like so:
public class Cell {
private int x;
private int y;
public Cell (int x, int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals (Object o) {
boolean result = false;
if (o instanceof Cell) {
Cell other = (Cell) o;
result = (this.x == other.x && this.y == other.y)
}
return result;
}
#Override
public int hashCode() {
int result = x;
result = 31 * result + y;
return result;
}
}
I have a Grid class, like so (many methods cut out and variable names simplified):
public class Grid {
private Set<Cell> cellArray;
public Grid() {
cellArray = new HashSet<Cell>();
}
public Set<Cell> getCellArray() {
return cellArray;
}
public void addCellArray(Cell cell) {
cellArray.add(cell)
}
}
In my main body of code, I take in a grid object, like so:
public class Controller {
private Grid grid;
public Controller (Grid grid) (
this.grid = grid;
Then, I have a series of loops that look like this:
private set<Cell> cellArray = grid.getCellArray();
boolean endLoop = false;
do {
x = randomGenerator.nextInt(10);
y = randomGenerator.nextInt(10);
for (int i = 0; i < length; i++) {
if (cellArray.contains(new Cell(x, y+i))) {
continue;
}
}
for (int j = 0; j < length; j++) {
cellArray.add(new Cell(x, y+i));
}
endLoop = true;
} while(!endLoop);
I'm aware it's a very messy, with too much instantiation going on (and if anyone has pointers to make it cleaner, feel free to point them out) - however, the main issue is the fact that the first for loop is meant to check if the cellArray contains the items - it doesn't seem to be doing this.
There's no error message, no null pointer or anything like that. I've tried debugging it and have seen it compare two cells with identical x and y values, without proceeding to the continue statement to start the do while loop again.
I am assuming this is because even though they have identical values, they are different 'objects' and so aren't coming back as equal.
How could I fix this and get them to equate to one another if their values are the same?
Your continue statement continues the inner for-loop (which is quite useless here). You probably want to continue the outer loop: continue outerLoop;, with the label outerLoop: put in front of do {.
As the Java API states, the contains method should rely on your equals method, so object equality should work as you expect it.
I need to compare two buffered images to see if they are the exact same. Simply saying if that equals that doesn't work. My current method is
{
Raster var1 = Img1.getData();
Raster var2 = Img2.getData();
int Data1 = (var1.getDataBuffer()).getSize();
int Data2 = (var2.getDataBuffer()).getSize();
if (Data1 == Data2)
{
return true;
}
else
{
return false;
}
}
But that doesn't really work. What other more reliable way is there?
The obvious solution would be to compare, pixel by pixel, that they are the same.
boolean bufferedImagesEqual(BufferedImage img1, BufferedImage img2) {
if (img1.getWidth() == img2.getWidth() && img1.getHeight() == img2.getHeight()) {
for (int x = 0; x < img1.getWidth(); x++) {
for (int y = 0; y < img1.getHeight(); y++) {
if (img1.getRGB(x, y) != img2.getRGB(x, y))
return false;
}
}
} else {
return false;
}
return true;
}
Yeah, assuming they are both in the same format read them as byte strings and compare the bit strings. If one is a jpg and the other a png this won't work. But I'm assuming equality implies they are the same.
here's an example on how to do the file reading;
http://www.java-examples.com/read-file-byte-array-using-fileinputstream
What about hash codes?
img1.getData().hashCode().equals(img2.getData().hashCode())
I have a method with a flag argument. I think that passing a boolean to a method is a bad practice (complicates the signature, violates the "each method does one thing" principle). I think splitting the method into two different methods is better. But if I do that, the two methods would be very similar (code duplication).
I wonder if there are some general techniques for splitting methods with a flag argument into two separate methods.
Here's the code of my method (Java):
int calculateNumOfLiveOrDeadNeighbors(Cell c, int gen, boolean countLiveOnes) {
int x = c.getX();
int y = c.getY();
CellState state;
int aliveCounter = 0;
int deadCounter = 0;
for (int i = x - 1; i <= x + 1; i++) {
for (int j = y - 1; j <= y + 1; j++) {
if (i == x && j == y)
continue;
state = getCell(i, j).getCellState(gen);
if (state == CellState.LIVE || state == CellState.SICK){
aliveCounter++;
}
if(state == CellState.DEAD || state == CellState.DEAD4GOOD){
deadCounter++;
}
}
}
if(countLiveOnes){
return aliveCounter;
}
return deadCounter;
}
If you don't like the boolean on your signature, you could add two different methods without it, refactoring to private the main one:
int calculateNumOfLiveNeighbors(Cell c, int gen) {
return calculateNumOfLiveOrDeadNeighbors(c, gen, true);
}
int calculateNumOfDeadNeighbors(Cell c, int gen) {
return calculateNumOfLiveOrDeadNeighbors(c, gen, false);
}
OR
you could code a Result Class or int array as output parameter for storing both the results; this would let you get rid of the annoying boolean parameter.
I guess it depends on every single case.
In this example you have two choices, in my opinion.
Say you want to split the call calculateNumOfLiveOrDeadNeighbors()
in two:
calculateNumOfLiveNeighbors()
and
calculateNumOfDeadNeighbors()
You can use Template Method to move the loop to another method.
You can use it to count dead / alive cells in the two methods.
private int countCells(Cell c, int gen, Filter filter)
{
int x = c.getX();
int y = c.getY();
CellState state;
int counter = 0;
for (int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; j++)
{
if (i == x && j == y)
continue;
state = getCell(i, j).getCellState(gen);
if (filter.countMeIn(state))
{
counter++;
}
}
}
return counter;
}
private interface Filter
{
boolean countMeIn(State state);
}
public int calculateNumOfDeadNeighbors(Cell c, int gen)
{
return countCells(c, gen, new Filter()
{
public boolean countMeIn(CellState state)
{
return (state == CellState.DEAD || state == CellState.DEAD4GOOD);
}
});
}
public int calculateNumOfLiveNeighbors(Cell c, int gen)
{
return countCells(c, gen, new Filter()
{
public boolean countMeIn(CellState state)
{
return (state == CellState.LIVE || state == CellState.SICK);
}
});
}
It's cumbersome, maybe not even worth the pain. You can, alternatively, use a monad to store the results of your statistics calculation and then use getDeadCounter() or getLiveCounter() on the monad, as many suggested already.
you can try to extract the common functionality in a single method and only use the specific functionality
you can create a private method with that flag, and invoke it from the two public methods. Thus your public API will not have the 'complicated' method signature, and you won't have duplicated code
make a method that returns both values, and choose one in each caller (public method).
In the example above I think the 2nd and 3rd options are more applicable.
Seems like the most semantically clean approach would be to return a result object that contains both values, and let the calling code extract what it cares about from the result object.
Like Bozho said: But but combine point 2 and 3 in the other way arround:
Create a (possible private method) that returns both (living and dead) and (only if you need dead or alive seperate in the most cases) then add two methods that pick dead or both out of the result:
DeadLiveCounter calcLiveAndDead(..) {}
int calcLive(..) { return calcLiveAndDead(..).getLive; }
int calcDead(..) { return calcLiveAndDead(..).getDead; }
IMO, this so-called "each method does one thing" principle needs to be applied selectively. Your example is one where, it is probably better NOT to apply it. Rather, I'd just simplify the method implementation a bit:
int countNeighbors(Cell c, int gen, boolean countLive) {
int x = c.getX();
int y = c.getY();
int counter = 0;
for (int i = x - 1; i <= x + 1; i++) {
for (int j = y - 1; j <= y + 1; j++) {
if (i == x && j == y)
continue;
CellState s = getCell(i, j).getCellState(gen);
if ((countLive && (s == CellState.LIVE || s == CellState.SICK)) ||
(!countLive && (s == CellState.DEAD || s == CellState.DEAD4GOOD))) {
counter++;
}
}
}
return counter;
}
In terms of using refactoring, some things you can do are;
copy the method and create two version, one with true hard coded and the other false hard coded. Your refactoring tools should help you inline this constant and remove code as required.
recreate the method which calls the right true/false method as above for backward compatibility. You can then inline this method.
I would be inclined here to keep a map from the CellState enum to count, then add the LIVE and the SICK or the DEAD and the DEAD4GOOD as needed.
int calculateNumOfLiveOrDeadNeighbors(Cell c, int gen, boolean countLiveOnes) {
final int x = c.getX();
final int y = c.getY();
final HashMap<CellState, Integer> counts = new HashMap<CellState, Integer>();
for (CellState state : CellState.values())
counts.put(state, 0);
for (int i = x - 1; i < x + 2; i++) {
for (int j = y - 1; j < y + 2; j++) {
if (i == x && j == y)
continue;
CellState state = getCell(i, j).getCellState(gen);
counts.put(state, counts.get(state) + 1);
}
}
if (countLiveOnes)
return counts.get(CellState.LIVE) + counts.get(CellState.SICK);
else
return counts.get(CellState.DEAD) + counts.get(CellState.DEAD4GOOD);
}
have a private method which is an exact copy and paste of what you currently have.
Then create two new methods, each with a more descriptive name that simply call your private method with appropriate boolean