DEV Community

Max Kleiner
Max Kleiner

Posted on

Memory Game

This Memory Game Master will be the Tutorial 195 from maXbox Starter Series.

You can program a simple memory game in maXbox using its built-in Object Pascal (Delphi-like) scripting engine and the precompiled VCL components. maXbox even includes a proof-of-concept memory game example using a grid of bitmaps.[sourceforge][sourceforge]

What maXbox is

maXbox is a self-contained scripting tool, compiler, and source library in one executable. It uses an Object Pascal/Delphi engine (RemObjects PascalScript) with hundreds of precompiled units and over 1,400 examples.[blogs.embarcadero][sourceforge][maxbox6.wordpress]

Memory game approach in maXbox
The documented approach uses a TStringGrid/TDrawGrid (or QGrid on Linux/CLX) filled with bitmap images to represent cards. The basic structure follows a typical game loop:[sourceforge][sourceforge]

  1. - Configure and open window – create the form and grid
  2. - Initialize resources – load card images, shuffle pairs
  3. - Register input callbacks – handle mouse clicks on grid cells
  4. - Event processing loop – manage game state (flipping, matching, scoring)[softwareschule] Example structure Here’s a minimal runnable skeleton you can adapt in maXbox:
const OPENDELAY = 500;

var
  Form1: TForm;
  Grid1: TDrawGrid;
  cCards: array of Integer;  // card values
  Flipped: array of Boolean;
  FirstCard, SecondCard: Integer;
  MatchCount, TotalPairs: Integer;

procedure FormGridCreate(Sender: TObject);
var i, j, k: Integer;
begin
  TotalPairs:= 8;  // 4x4 grid = 16 cards
  SetLength(cCards, TotalPairs * 2 +0);
  SetLength(Flipped, TotalPairs * 2 +0);

  // Initialize pairs
  for i:= 0 to TotalPairs - 1 do begin
    cCards[i * 2]:= i;
    cCards[i * 2 + 1]:= i;
  end;

  // Shuffle cards
  Randomize;
  writ('debug ccards count: '+itoa(high(ccards)+1))
  for i:= High(cCards) downto 1 do begin
    j:= Random(i + 1);
    k:= cCards[i];
    cCards[i]:= cCards[j];
    cCards[j]:= k;
  end;
  grid1.Font.Style2:=fsBold2;
  Grid1.font.size:= 20;
  Grid1.font.name:= 'Wingdings'
  Grid1.ColCount:= 4;
  Grid1.RowCount:= 4;
  // No fixed header row !
  Grid1.FixedRows:= 0;
  Grid1.FixedCols:= 0;
  Grid1.DefaultColWidth:= 80;     //60
  Grid1.DefaultRowHeight:= 80;
  //Grid1.Font.Color:= clred;
  Grid1.Options:= Grid1.Options+ [goFixedVertLine,goFixedHorzLine,goVertLine,goHorzLine];
end;

procedure Grid1DrawCell(Sender: TObject; ACol, ARow: Integer;
                                   Rect: TRect; State: TGridDrawState);
var Index: Integer;
begin
  Index:= ARow * Grid1.ColCount + ACol;
  with Grid1.Canvas do begin
    Brush.Color:= clSilver;
    FillRect(Rect);
    if Flipped[Index] then begin
      TextOut(Rect.Left+22, Rect.Top+16, IntToStr(cCards[Index]))
    end else
      TextOut(Rect.Left+ 22, Rect.Top+ 16, '*');  //or ?,!
  end;
end;

procedure Grid1SelectCell(Sender: TObject; ACol, ARow: Integer;
                                              var CanSelect: Boolean);
var Index: Integer;
begin
  Index:= ARow * Grid1.ColCount+ ACol;
  if Flipped[Index] or (FirstCard >= 0) and (SecondCard >= 0) then
    Exit;
  Flipped[Index]:= True;
  Grid1.Invalidate;

  if FirstCard < 0 then
    FirstCard:= Index
  else begin
    SecondCard:= Index;
    if cCards[FirstCard] = cCards[SecondCard] then begin
      Inc(MatchCount);
      writ('debug found: '+itoa(matchcount));
      Grid1.Font.Color:= clgreen; //clyellow; //clnavy;
      if MatchCount = TotalPairs then
        ShowMessage('You got it Mem Master, Gewonnen!');
    end else begin
      // Delay unflip (use Timer in real implementation or sleep)
      Flipped[FirstCard]:= False;
      Flipped[SecondCard]:= False;
      Grid1.Font.Color:= clblack;
      sleep(OPENDELAY)
      Grid1.Invalidate;
    end;
    FirstCard:= -1;
    SecondCard:= -1;
  end;
end;

procedure memoryMainRoutine;
begin
  Application.Initialize;
  Form1:= TForm.Create(Application);
  Form1.Caption:= 'Memory Game by maXbox5';
  form1.setbounds(10,10,420,390)
  Grid1:= TDrawGrid.Create(Form1);
  Grid1.Parent:= Form1;
  Grid1.Align:= alClient;
  Grid1.OnDrawCell:= @Grid1DrawCell;
  Grid1.OnSelectCell:= @Grid1SelectCell;
  FirstCard:= -1;
  SecondCard:= -1;
  MatchCount:= 0;
  FormGridCreate(Form1);
  form1.show;
  //Application.Run;
end;
Enter fullscreen mode Exit fullscreen mode

Getting started

  1. Download maXbox from SourceForge and unzip (preserve folder structure)[sourceforge][softwareschule]
  2. Open maXbox, create a new script, paste the code above
  3. Press F9 to compile and run[softwareschule][softwareschule]
  4. Extend with actual bitmap images instead of text, add timers for flip delays, and scoring We use the wingdings font as a straight graphical library By changing the font.name or comment out

1 grid1.Font.Style2:=fsBold2;
2 Grid1.font.size:= 20;
3 Grid1.font.name:= 'Wingdings'

For more examples, browse the 1,415+ examples in maXbox or check the Pascal Education Program (PEP) examples on SourceForge.[sourceforge][maxbox6.wordpress]

Source Code Script:
https://sourceforge.net/projects/maxbox5/files/examples/1495_memorygame.txt/download

Note: In Delphi, if you want to draw text in a TDrawGrid (or TStringGrid) with a custom font color, you need to handle the OnDrawCell event. This event gives you a Canvas to draw on, where you can set Font.Color before calling TextOut or TextRect.

Key Points:

  • Canvas.Font.Color — controls the text color.
  • Canvas.Brush.Color + FillRect — paints the background.
  • TextRect — draws text clipped to the cell rectangle.
  • gdSelected — lets you detect if the cell is selected and adjust colors accordingly.

Full article with Explainer:
http://www.softwareschule.ch/download/maxbox_starter195.pdf

Top comments (2)

Collapse
 
max_kleiner_9d12e786b3ecc profile image
Max Kleiner

When you want double digits from 10 to 17 on your display you have to set an offset, an initialize the offset pairs, thats all!:

const OPENDELAY = 500;
      OFFSET = 10;         //range in font index

 // Initialize pairs symbols
  for i:= 0 to TotalPairs - 1 do begin
    cCards[i * 2]:= i+OFFSET;
    cCards[i * 2 + 1]:= i+OFFSET;
  end;
Enter fullscreen mode Exit fullscreen mode
Collapse
 
max_kleiner_9d12e786b3ecc profile image
Max Kleiner