How I Fix an Array Index Error While Swiping in My Match-3 Game

Hey there! I recently ran into a frustrating bug in my match-3 game, and I want to share how I fixed it and how you can avoid it too if you’re building something similar.

The app would crash whenever I swiped outside the game board, throwing this scary error:

java.lang.ArrayIndexOutOfBoundsException: length=9; index=11

The Problem: ArrayIndexOutOfBoundsException

This is a classic error in Java. Basically, I was trying to access an element outside the range of my 2D array.

My game board is a 9x9 grid (which means valid indexes are from 0 to 8), but sometimes, if the user swiped on the edge or slightly outside, this happened:

board[poseI][poseJ + 1].poseX -= cellWidth / 8;

If poseJ + 1 was 9, boom crash.

So, I knew the problem: I needed to prevent the game from trying to access candies that don’t exist. Now, let me show you how I fixed it.

The Fix Add Boundary Check

I Updated the swap() Method

My swap() method moves the candy graphics and swaps the data in the array. I wrapped each direction in a boundary check before accessing the array.

Here’s what it looks like now:

public void swap()
{
int maxI = board.length - 1; // usually 8
int maxJ = board[0].length - 1; // usually 8

if (swapIndex > 0)
{
switch (direction)
{
case "right":
if (poseJ + 1 <= maxJ)
{
board[poseI][poseJ + 1].poseX -= cellWidth / 8;
board[poseI][poseJ].poseX += cellWidth / 8;
}
break;
case "left":
if (poseJ - 1 >= 0)
{
board[poseI][poseJ - 1].poseX += cellWidth / 8;
board[poseI][poseJ].poseX -= cellWidth / 8;
}
break;
case "up":
if (poseI - 1 >= 0)
{
board[poseI - 1][poseJ].poseY += cellWidth / 8;
board[poseI][poseJ].poseY -= cellWidth / 8;
}
break;
case "down":
if (poseI + 1 <= maxI)
{
board[poseI + 1][poseJ].poseY -= cellWidth / 8;
board[poseI][poseJ].poseY += cellWidth / 8;
}
break;
}
swapIndex--;
}
else
{
// Safety check before full swap
if (isInsideBoard(poseI, poseJ) && isInsideBoard(newPoseI, newPoseJ))
{
Candies temp = board[poseI][poseJ];
board[poseI][poseJ] = board[newPoseI][newPoseJ];
board[newPoseI][newPoseJ] = temp;

board[poseI][poseJ].poseX = (int) (poseJ * cellWidth + drawX);
board[poseI][poseJ].poseY = (int) (poseI * cellWidth + drawY);
board[newPoseI][newPoseJ].poseX = (int) (newPoseJ * cellWidth + drawX);
board[newPoseI][newPoseJ].poseY = (int) (newPoseI * cellWidth + drawY);

swapIndex = 8;

if (gameState == GameState.swapping)
{
gameState = GameState.checkSwapping;
increaseUserMove();
}
else
{
gameState = GameState.nothing;
}
}
}
}

And here’s my little helper function that makes the bounds check super clean:

private boolean isInsideBoard(int i, int j)
{
return i >= 0 && i < board.length && j >= 0 && j < board[0].length;
}

I Protect the Touch Event

I also had to update onTouchEvent() to make sure I was only reacting to valid board touches:

poseI = (int) (oldY - drawY) / cellWidth;
poseJ = (int) (oldX - drawX) / cellWidth;

// Reject touches outside the board
if (!isInsideBoard(poseI, poseJ)) {
move = false;
return true;
}

Now, if the user touches outside the board, the game just ignores it — no crashing, no drama.

Bonus Feature I Added for Practice

Since I was already deep into the code, I thought, why not improve the gameplay too, Here are a few extra features I worked on:

Highlight Valid Directions

If a candy can’t move in a certain direction (e.g., edge of the board), I don’t show a move hint in that direction.

Prevent Invalid Swipes

If a swipe would go out-of-bounds, I now prevent the game from even entering the swap state.

Edge Feedback

I added a soft sound and small vibration using Vibrator when the player tries to swipe into the wall. Nice UX touch!

Tap to Select (for Accessibility)

I made it possible to tap once to select a candy, then tap another to swap, just in case the user can’t swipe easily.

Snap Back on Invalid Swap

If the user tries to swap but there’s no match, I animate the candies snapping back to their original positions. It looks much more polished!

Final Thoughts

This bug taught me something really important just because your swipe logic works doesn’t mean it’s safe. Always check your array bounds when you’re dealing with user interaction.

With a couple of simple boundary checks and smarter input validation, my game became more stable, more playable, and more user-friendly.

Related blog posts