2

So I'm working on a game that's similar in mechanics to Bejeweled--you know the type, where you swap adjacent tiles in a grid to match groups of same-type tiles together. So here's my question: if I have an MxM grid of tiles, and there are N different tile types, how do I calculate a "random" placement of tiles such that the number of groups of 3 same-type tiles starts out minimized?

At the moment, I'm just completely randomly placing them, but this results in many groupings from the start, which removes all skill from the game. I don't even know where to begin coming up with an algorithm to minimize those initial groups. If it helps or matters, right now there are specifically 5 tile types in a 10x10 grid.

Daniel Burnett
  • 69
  • 1
  • 1
  • 10

2 Answers2

0

The simplest approach I can think of:

for each tile
  based on the surrounding already generated tiles,
    generate a random type among those which won't result in 3-in-a-row

And an unoptimized way to do this, assuming just horizontal and vertical matches (not diagonal): (pseudo-code)

for x = 1 to M
for y = 1 to M
  do
    board[x][y] = randomType()
  while ((x >= 3 && board[x-1][y] == board[x-2][y] && board[x-1][y] == board[x][y]) ||
         (y >= 3 && board[x][y-1] == board[x][y-2] && board[x][y-1] == board[x][y]))

A way to avoid the repeated generation completely: (assuming types are numbers)

for x = 1 to M
for y = 1 to M
  limit = N
  horizontal = (x >= 3 && board[x-1][y] == board[x-2][y] && board[x-1][y] == board[x][y])
  vertical   = (y >= 3 && board[x][y-1] == board[x][y-2] && board[x][y-1] == board[x][y])
  if horizontal
    limit--
  if vertical
    limit--
  board[x][y] = randomType(limit)
  offset = 0
  if (vertical && board[x][y] >= board[x][y-1])
    offset++
  if (horizontal && board[x][y] >= board[x-1][y])
    offset++

  board[x][y] += offset

The above method works similar to generating numbers in the ranges [0,A-1] and [A+1,B] by generating numbers in the range [0,B-1] and then, if the generated number is A or greater, we increase it by 1.

N needs to be at least 3, otherwise you may get something like:

..A
..A
BB?

For which the above algorithm will run into an infinite loop.

Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
  • I really don't like the potentially terrible runtime of this, but I'll try it out and see if it's tolerable. Thanks. – Daniel Burnett Oct 13 '13 at 00:05
  • Tested. It seems efficient enough, so I'll probably be using this brute-force method. I implemented it so that it can't pick the same tile type twice in that loop, so it should never go infinite. Thanks for the help! :) – Daniel Burnett Oct 13 '13 at 00:19
  • @DanielBurnett The running time shouldn't be bad. Even at N = 3, the expected average number of random generations per cell should be less than 2, thus at most 2x as slow as the perfect algorithm. You can avoid the repeated generation completely with something rather more complicated (added this to the answer). Also, my while-loop condition was wrong, fixed it. – Bernhard Barker Oct 13 '13 at 00:25
0

Two observations:

  • The number of tiles is very small, so our algorithm needn't be very efficient
  • Initial sequence need not be "perfectly" ungrouped, so we needn't solve the problem, but just best-effort approach it

This leads to a trivial algorithm, that could be "good enough" for you:

  • Start with an empty board and a list (e.g. array) of all tiles
  • Shuffle the list
  • Place one list element after the other on the board, following simple rules:
    • Make a list for the still possible positions for the current tile, every position starts with 1 point
    • For every diagonally neighbouring tile of the same color multiply position points by N
    • for every directly neighbouring tile of same color multiply position points by M (M>N)
    • Find position with lowest points
    • If this is not unique use the position with the lowest distance from the center
    • If this is still not unique, chose randomly
Eugen Rieck
  • 64,175
  • 10
  • 70
  • 92