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 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.