Wow, thanks a lot, that was really interesting.
I would not have thought to do it using a multi-dimensional array (that's what it's called, right?) instead of an arraylist of holder panels. That definitely makes some things a lot simpler.
It also occurred to me that part of the reason my code was probably confusing was because I was using netBeans and I let netBeans generate the code for the boring parts of the GUI and I just made the panel that actually had my game. But it completely works now and I'm a happy student!
If you'd like to enlighten me a little more, I am working through one new issue:
I discovered that if you randomly lay down tiles on a game like this, 50% of the generated puzzles will be unsolvable. To get around this, I made the program generate a solved board, then scramble it as a human would, simply moving one tile at a time a couple hundred times (depending on the size of the board).
I thought it would be cool for the user if I could make it display this process happening. I imagine all the tiles shifting around faster than the eye can follow, and I feel it would be a very cool effect. However, no matter what I do, I can't get it to update the view of the board in between each shift. It always generates the entire board, then displays it. It's not a big deal, so I'm not going to worry about posting my code, but are there some rules that need to be followed when i want to update graphics with iterations that are happening extremely quickly? Or is it just some error in my code?