The Delphi Bricks Game Part 2

'

In part 1 of this tutorial we got to the stage of being able to start a new game and the board being drawn, in this part we will continue where we left off.

Then, the solution is to redraw each brick at start of each new game. The following procedure will help us:

procedure RedrawCells;
var
  i, j : integer;
begin
  for i := 0 to frmMain.DrawGrid.ColCount-1 do
    for j := 0 to frmMain.DrawGrid.RowCount-1 do
      frmMain.DrawGridDrawCell(frmMain, i, j, frmMain.DrawGrid.CellRect(i,j), [])
end;

And the code for itemNewGameClick procedure should be changed as follows:

procedure TfrmMain.itemNewGameClick(Sender: TObject);
begin
  AssignBrickColors;
  RedrawCells;
end;

Now try it again. For this time, the appearance will change at each click on "New Game".

Removing The Block of the Cells those have the same color

The algorithm is simple:

If the clicked brick has at least one neighbour of the same color (neigbour can be one of the four 
bricks around it: namely up, down, left and right bricks. Not the diagonals),
     Remove this brick;
     Apply this recursively to the neighbours of this cell those had the same colors with it

This means that a single cell that have no neigbours with the same color cannot be removed.

Before all, let's define the color of the wall, because when a brick is removed, the emptied cell will take the color of the wall:

const
  WALL_COLOR : TColor = clWhite;

Here I assumed that the wall will be white. You can select any other color you wish, but it should be different from all of the colors in our PossibleColors array.

Now, let's write our recursive procedure to remove the bricks properly:

procedure RemoveBricks (cl : TColor; ACol, ARow : integer);
begin
  // If the given color does not match with the color of the current brick,
  // Exit without doing anything

  if ColorOfBrick[ACol, ARow] <> cl then
    exit;

  // Remove the brick, by making its color
  // with the same as the color of the wall
  
ColorOfBrick[ACol, ARow] := WALL_COLOR;

  // Now, apply this to its neighbours recursively
  // But don't forget that this cell might be a border cell,
  // so that it may not have one of the left, right, up or down neighbours

  // left neighbour

  if ACol > 0 then
    RemoveBricks(cl, ACol-1, ARow);

  // right neighbour

  if ACol < frmMain.DrawGrid.ColCount-1 then
    RemoveBricks(cl, ACol+1, ARow);

  // upper neighbour

  if ARow > 0 then
    RemoveBricks(cl, ACol, ARow-1);

  // down neighbour

  if ARow < frmMain.DrawGrid.RowCount-1 then
    RemoveBricks(cl, ACol, ARow+1);
end;

When should we call this recursive procedure? We should call it when a clicked brick has at least one neighbour with the same color, that is, when the brick is not alone. That is, it would be good to have a function that checks whether a brick is alone or not:

function IsBrickAlone(ACol, ARow : integer) : Boolean;
begin
  // Initially assume that it is alone.

  Result := True;

  // If there is not a brick on the clicked cell,
  // exit without doing nothing. This means that
  // an empty cell on the wall will be interpreted to be alone.

  if ColorOfBrick[ACol, ARow] = WALL_COLOR then
    exit;

  // Now, check all of its neighbours whether at least one of them
  // has the same color. Don't forget to check whether the cell
  // is a border cell or not. If it is a border cell, we can get
  // a memory violation error when trying to check one of its non-existent
  // neighbours.

  // Check the left neighbour

  if ACol > 0 then
    if ColorOfBrick[ACol-1, ARow] = ColorOfBrick[ACol, ARow] then
      Result := False;

  // Check the right neighbour

  if ACol < frmMain.DrawGrid.ColCount-1 then
    if ColorOfBrick[ACol+1, ARow] = ColorOfBrick[ACol, ARow] then
      Result := False;

  // Check the upper neighbour

  if ARow > 0 then
    if ColorOfBrick[ACol, ARow-1] = ColorOfBrick[ACol, ARow] then
      Result := False;

  // Check the down neighbour

  if ARow < frmMain.DrawGrid.RowCount-1 then
    if ColorOfBrick[ACol, ARow+1] = ColorOfBrick[ACol, ARow] then
      Result := False
end;

Now we can use this function when a brick is selected by the player. If it is not alone, the recursive procedure will be applied:

procedure TfrmMain.DrawGridSelectCell(Sender: TObject; ACol, ARow: Integer; 
                                      var CanSelect: Boolean);
begin
   // Check if the cell is alone or not. If it is, we will do nothing
  // according to the game rule, but it is not alone, we should remove
  // that area from the wall. We do this by calling our recursive procedure
  // RemoveBricks.

  // If it is not alone, remove the block

  if not IsBrickAlone(ACol, ARow) then
  begin
    RemoveBricks(ColorOfBrick[ACol, ARow], ACol, ARow);

    // Redraw the cells
    RedrawCells
  end
end;

Now, run your application and then click on a region. You will see that the region disappears and it takes the color of the wall. Notice that an alone brick cannot be removed when clicked.

Will turn into

This concludes this part of the tutorial, in the third installment we will shift all the bricks along to fill the newly created gap.

If you enjoy addictive games you should probably check out Game Addicts, a blog on all the latest gaming news.

Delphi Bricks Game Part 1
Delphi Bricks Game Part 2


Google
Web www.Delphi-Central.com
Delphi Central - Delphi Programming Tutorials, Hints and Tips