Using Enumerated Types and Sets in Smart Pascal

As a beginner you do not need to use your own enumerated types (enumerations) and sets but as you progress you will find that they contribute to elegant code.

An enumerated type is a type which includes in its definition a list of all of the allowed values for variables of that type. You can define types relevant to the context of your program to make it more readable. In the example below the enumeration is for shapes. You might use an enumeration to represent the state of your game e.g. TGameState = (gsSetup, gsActive, gsFinished). The order of the elements that comprise an enumeration is important for the ord, pred and succ functions.

A set is a collection of values of the same ordinal type. (Each value of an ordinal type except the first has a unique predecessor and each value except the last has a unique successor). No use is made of the order of the values in a set. Also, a set never contains duplicates of any value. An empty set (also named a null set) is denoted by [].

The use of set constants with comma-separated values and ranges makes code more concise and easier to read.

The demonstration shows how enumerated types and sets are used together; we base a type of set upon an enumeration. Can you predict the output before trying it? You should learn from the code and comments:
  • the syntax for defining an enumeration and a set;
  • the declaration of a variable of each type;
  • use of the routines ord, succ, pred, high, include and exclude;
  • casting an integer to an element of an enumeration;
  • use of the set operator in;
  • use of elements of an enumeration for the initial and final values of the control variable in a for loop;
  • use of a set constant: if FrameNumber in [3..5, 7] then ....
unit Unit1;

interface

uses 
  System.Types, System.Colors, SmartCL.System, SmartCL.Components, SmartCL.Application,
  SmartCL.Game, SmartCL.GameApp, SmartCL.Graphics;

type
  // Note the following syntax; values in the list are NOT in quotes.
  TShape = (shTriangle, shSquare, shPentagon, shHexagon, shCircle);
  // TPolygon = shTriangle .. shHexagon;  //Possible in Lazarus
  TShapeSet = set of TShape;

  TCanvasProject = class(TW3CustomGameApplication)
  private
    Shape1, Shape2: TShape;
    ShapeSet: TShapeSet;
    FrameNumber: integer;
  protected
    procedure ApplicationStarting; override;
    procedure ApplicationClosing; override;
    procedure PaintView(Canvas: TW3Canvas); override;
  end;

implementation

procedure TCanvasProject.ApplicationStarting;
var
  Selection: TShape;
  Msg := 'The last item in the enumeration is shCircle with value ' +
         IntToStr(ord(shCircle));  //ord gives zero-based order in enumeration
begin
  inherited;
  inc(FrameNumber);
  if ord(shCircle) = high(TShape) then
    begin
      //ShowMessage(Msg);
      asm
        console.log(@Msg);
      end;
    end;
  Shape1 := succ(shTriangle); // successor
  Shape2 := pred(shPentagon); // predecessor

  Randomize;
  ShapeSet := [shTriangle, shPentagon]; //Initialise with zero, one or more elements

  repeat  //Choose shape  that is not already in the set
    Selection := RandomInt(4);
  until Selection not in ShapeSet; //keyword "in"
  include(ShapeSet, Selection);    //add to set
  exclude(ShapeSet, shTriangle);   //remove from set

  GameView.Delay := 2000;
  GameView.StartSession(False);
end;

procedure TCanvasProject.ApplicationClosing;
begin
  GameView.EndSession;
  inherited;
end;

procedure TCanvasProject.PaintView(Canvas: TW3Canvas);

begin
  inc(FrameNumber);
  // Clear background
  Canvas.FillStyle := ColorToWebStr(clMediumSlateBlue);
  Canvas.FillRectF(0, 0, GameView.Width, GameView.Height);

  // Draw output
  Canvas.Font := '10pt verdana';
  Canvas.FillStyle := 'rgb(255, 255, 255)';
  if Shape1 = Shape2 then
     Canvas.FillTextF('Shapes same', 10, 20, MAX_INT)
  else
     Canvas.FillTextF('Shapes now different', 10, 20, MAX_INT);
  Shape1 := Succ(Shape1); // moves up one position in the enumeration if possible
  if FrameNumber in [3..5, 7] then
    begin
      for var Shape := shTriangle to shCircle do // descriptive
        begin
          var txt := 'Shape number ' + intToStr(Shape + 1);
          if Shape in ShapeSet then
            txt += ' in set';
          Canvas.FillTextF(txt, 10, 50 + (40 * Shape), MAX_INT);
        end;
      include(ShapeSet, TShape(0)); // Casting 0 to TShape. Added shape can be already in set.
    end;
  if FrameNumber = 8 then
    Application.Terminate;
end;

end.
Programming - a skill for life!

How to learn the Pascal language the fun way by making games in Smart Mobile Studio