• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Conway's Game of Life/Code efficiency

 
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
First of all - I've started doing Java 4 days ago, so the code is most likely riddled with "bugs" and inefficient approaches. I'm not as much looking for a way to optimize it, as to understand why is it inefficient, but I welcome any advice.


I decided to jump straight into making Conway's Game of Life. I made it to work. Kinda. The issue is that at higher speeds/lesser intervals between steps cells can't keep up with changing colors.

The basic design explanation:

100x100 GridLayout filled with two-dimensional Array of JButtons (5x5 pixels each), created through double if loop, each button is colored black, receives a MouseListener, name with its position in the Array (to help with locating the cell later on), then it's added to the GridLayout and the actual Array.

The algorythm for checking whether cell/button is alive or dead is also fairly simple - block of ifs checking and counting all the neighbours, cell's own color and returning either true or false, depending on the conditions.

Then there's a button to start the whole program. It does two things: sets a boolean "isPlaying" to true and initiates a thread creation.
Next is "STOP" button, which kills the thread and sets "isPlaying" to false. It works, but I'm pretty sure it's a really bad design.

When the thread is running, it runs a while loop, checks all the cells with the algorythm, repaints the grid based on that and waits a specified amount of time.

Both above paragraphs I've tried to do through "resume"/"sleep"/"suspend" threads and create/"wait"/"stop", neither method had any advantages or noticeable differences (at least noticeable from my point of view).


As for the execution of redrawing the grid... I have 2 approaches:

- make the first Array of buttons and display it, make a second Array as a placeholder for next step, run each button of the first Array through the algorythm, based on true/false change background of the button on specified position in the second Array, after every button is checked - compare colors of corresponding buttons in both Arrays and recolor the first Array based on data from the second one.

- make the first Array of buttons and display it, make 2 more Arrays of booleans to hold whether current button in first Array is alive or dead and whether it should be alive or dead after the next step, compare the second boolean Array to the Array filled with buttons and their color, and change the background colors as necessary.

I've put "CurrentTimeMillis()" in every place of the redrawing process and it's going smooth every time (9 milliseconds delay at most between changing background colors). For some reason when the whole grid gets filled (or "near to filled", what matters is that the dying/living process spread across the whole grid) and the delay is at 1000/500 ms, I can clearly see the grid being recolored in chunks (in horizontal chunks, even though both the algorythm and redrawing process runs through columns first). If the delay is lowered to 200/100/50 ms, the grid can't keep up with displaying information and I get really delayed, flashing cells (at least that's what it looks like) and the whole program becomes clogged, not responding until the grid catches up to where it should be (which takes only a couple of seconds at 50 ms delay, but it's still annoying).


Does anyone have any ideas as to what might be a cause of this? I decided to explain everything to the best of my ability, cause the code is an actual mess right now due to me trying to find a fix. I will add it if my explanation turns out to be not enough and when I manage to clean it up.
 
Marshal
Posts: 28193
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Welcome to the Ranch!

If you write a Swing program and try updating the GUI from any thread other than Swing's event dispatch thread, you're likely to run into problems. Some of the problems look like what is happening to you, too. And (if I guess right) you are doing exactly that -- you're updating the GUI from your own thread.

So don't do that. What I would recommend for a start, since you're a beginner, is that you should use a Swing Timer which updates one life cycle per second, or something like that. Here's a link to the tutorial: How to Use Swing Timers. If you did things right and wrote a method whose job is to calculate the next cycle and update the display, then you could get rid of your threading logic and just have the Timer's action listener call that method.
 
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
A problem is that the method that is invoked by the Timer, might simply be too slow for the required number of repaints per second.
If it IS too slow, alternatives are plenty.

Is there any reason for using Buttons?

An easy alternative is to use a BufferedImage, that is updated in a separate Thread. Whenever that Thread is ready, it issues a repaint request for the panel at hand, maybe even controlled by a Timer. That repaint then simply draws that BufferedImage (or even better: this BI gets copied to another BI, and that BI is used in the painting).
 
A. Arecks
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank You for the welcome

Indeed, dropping threads for the sake of SwingTimer fixed the chunking problem. The issue of slow execution is still there. Although when I was using another thread for running the redrawing process, the rest of the frame worked/responded immediately (like buttons/checkboxes highlighting, scrollbars not delayed, etc.), but with SwingTimer once the grid starts slowing down, everything else starts slowing down as well. It's not a huge issue and I think I can resolve it by separating the grid itself from the rest of frame (or something like that).

As for the slowness itself... I have no clue what can be causing it. I've set it up to send time at each point of the process and this is what I got:



"1" is for entering the recalculating method,
"2" is for finishing making the "future" version of the grid.
"3" is for entering the redrawing method,
"4" is for finishing the redrawing process.


From what I understand the process is going pretty quick (10 ms for recalculating and redrawing 100x100 grid), but for some reason time between timer cycles grows, the more cells or conditions it has to process, whether I set it at 1000 ms delay and cause the whole grid to paint black/red or I set just 2 conditions like "cell becomes alive if it has 1 or 2 alive neighbours".

There isn't (or at least there shouldn't) be anything else going on while the timer is running, only called methods are the methods for recalculating and redrawing the grid, and their speed can be seen above.

So what can be the cause? What else can I do to check for the cause?


Piet Souris wrote:Is there any reason for using Buttons?

An easy alternative is to use a BufferedImage, that is updated in a separate Thread. Whenever that Thread is ready, it issues a repaint request for the panel at hand, maybe even controlled by a Timer. That repaint then simply draws that BufferedImage (or even better: this BI gets copied to another BI, and that BI is used in the painting).



There is no real reason. I have no experience with programming or Java, I just watched ~50 tutorial videos, read ~70 pages of a Java book and figured I'm not learning anything practical, so I decided to use the information I have to make something. Just my way of learning. The amount of pain I suffered configuring all these buttons and listeners made me realize there are probably dozens of better ways to go about it, but at the time this was my first idea, so I stuck with it.
 
Piet Souris
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Fair enough.

Well, apart from calculating the new situation, there is the time needed for the drawing process itself.
You can say: button[x][y].setBackgroundColor(...) and measure that it is executed in the blink of an eye, but that does not mean that the actual painting of this button is done with that same speed.
But I'm speculating. Can you show us an SSCCE (http://sscce.org/)?
 
A. Arecks
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I hope this is enough. I don't think I missed anything important and the problem I had with the main version (drawing slowness) still happens here.
I could've changed few things (like how I add listener to the timer), but I was just typing out without thinking, optimazation of that sort isn't my main concern at the moment.


 
Piet Souris
Bartender
Posts: 5465
212
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I ran your code with a timerinterval of 1 second, and a grid of 10x10. There you see the change at once. Changing the grid to 100 * 100, is flooding the EDT with paint commands for your buttons, and that is a pretty slow process.

Therefore I asked if you had to use JButtons. It's okay to stay with that, but I do not see a solution then (but why is it a problem? The looks of it are fine, even with this 'continuous' updating).
 
A. Arecks
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Piet Souris wrote:I ran your code with a timerinterval of 1 second, and a grid of 10x10. There you see the change at once. Changing the grid to 100 * 100, is flooding the EDT with paint commands for your buttons, and that is a pretty slow process.

Therefore I asked if you had to use JButtons. It's okay to stay with that, but I do not see a solution then (but why is it a problem? The looks of it are fine, even with this 'continuous' updating).



That's interesting... I ran it just now with 10x10 and 30x30 grids, keeping 100ms intervals and even though it didn't lag, I could clearly see how some of the buttons were blinking, while other weren't, as if the grid was switching parts on and off. Maybe it's just because of working on a potatop.

I wonder if switching from Array to ArrayList and instead of updating Grid1 in real time, it would update a second, blank ArrayList and then replaceAll or rewrite the first ArrayList? Or would that use just as much resources? Since I would update a blank ArrayList, it wouldn't really need to change the color of buttons, but rather the information about the buttons' color, not sure if it makes much difference for the compiler.

I'm going to test it anyway, just not right now, so throwing questions in the void in case what would happen is obvious to someone more experienced.

As for problem with the problem itself - I mainly wanted to know why it was happening. Aside from that, with 100x100 grid the 1,3s lag/unresponsiveness can be a little annoying (not that I have any use for the program itself, I just don't like doing a half-assed job and if this was an actual job, I'd probably get fired). Initially I wanted to make the size customizable, with zooming in/out, so the fact buttons become this inefficient is somewhat of a bother. Also some people like watching the cells grow and die more than having a correct result after x time has passed, wouldn't want to take that fun away from them.


EDIT:

ArrayLists proven to be more than I could manage. I decided to rewrite the drawing methods to use 2 Arrays in 2 JPanels on a single JLayeredPane and just switch the layers every tick. It looks a lot better (no more "redrawing on the spot"), though I'm still not fully convinced that behind the scenes it actually does what it's supposed to. There's no lag, even when I went for two 200x200 Arrays, which surprises me a little. Could changing JButton's background color be faster for EDT if the drawing process isn't visible on the screen? If not, I might just be receiving like every 5th or so tick and can't even notice because of how smooth the transition looks like.

I still have no idea how am I going to implement this new-found method in the original project, but at least I've got something.

On another note - drawing the buttons seems to take a lot of time at the start. Is there any way to either optimize the creation process or to "force" loading until EDT is done with the buttons? Currently I get a frame with blank panel until the creation of buttons is finished. At least that's what I think is happening.


Adding the code just in case.


 
Paul Clapham
Marshal
Posts: 28193
95
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Piet Souris wrote:A problem is that the method that is invoked by the Timer, might simply be too slow for the required number of repaints per second.



The other possibility is that the method invoked by the Timer might be too fast. I wouldn't be surprised if the first 100 iterations took much less than a second to execute, and then the intermediate steps would flash by so quickly that you wouldn't be able to see them. (I think the reason that the OP's code appears to run so slowly is that it updates the GUI so much.)
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic